Как разместить несколько константных объектов из нескольких блоков перевода, отсортированных в одном блоке памяти? - PullRequest
1 голос
/ 15 марта 2020

Я разрабатываю прошивку для некоторых устройств, и каждое из них содержит объекты конфигурации, значения которых могут быть изменены внешним приложением. Вот пример такого объекта:

struct TObjectParams
{
   ObjectId       ID;            // enum
   void*          Data;          // pointer to configuration data
   unsigned short Length;        // size of data

   TAccessControl AccessControl; //object access control
};

Каждый экземпляр TObjectParams является постоянным и не может быть изменен во время выполнения. Прошивка состоит из нескольких модулей, и каждый из них имеет свои собственные объекты конфигурации. Это сделано так, потому что разные устройства могут содержать разные модули, и принуждение каждого устройства содержать все объекты будет пустой тратой ресурсов. Моя цель - сгруппировать все объекты в одно место (массив или отдельный раздел) и отсортировать их по номеру ID (сортировка значительно снизит сложность поиска с O(n) до O(log n).

My Первой идеей было использовать constexpr для регистрации объекта (в конструкторе объекта) и во время компиляции создать массив constexpr со всеми объектами. Но, насколько я знаю, это будет работать, только если все объекты находятся в одной и той же единице перевода .

Моя вторая идея - использовать __attribute__((used, section("objects_section"))), и теперь я уверен, что компоновщик не удалит какой-либо определенный объект, и все они будут в одном разделе. Проблема в сортировке. Есть ли способ заставить компоновщик сортировать эти объекты? Или, возможно, это возможно путем редактирования .elf файла? Я знаю, что я могу легко вывести objects_section, отсортировать его (с помощью собственного приложения) и обновить через objcopy, но это полностью испортит опыт отладки и прямой вызов любого объекта, поскольку обновление содержимого раздела не приведет к обновлению адресов символов (или, возможно, я ошибаюсь).

Знаете ли вы, как o не только обновлять содержимое раздела, но и символы адресов? Или, может быть, вы знаете лучший подход к такой проблеме? Я открыт для всех предложений.

1 Ответ

0 голосов
/ 15 марта 2020

Есть ли способ заставить линкер сортировать эти объекты?

Нет, особенно если учесть, что критерии упорядочения могут быть произвольными.

Однако вы не на самом деле не нужно сортировать объекты: вы можете сортировать массив указателей на объекты (созданные во время инициализации) и выполнять последующий поиск по этому массиву.

Я знаю, что могу легко вывести дамп object_section, сортируйте его (по собственному приложению) и обновляйте с помощью objcopy, но это полностью испортит опыт отладки и прямой вызов любого объекта, потому что обновление содержимого раздела не обновит адреса символов (или, возможно, я ошибаюсь).

Это не только вещь objcopy испортит. Это также испортит правильность : ваш Data член указывает на некоторые другие данные, что означает, что с каждым экземпляром связаны записи о перемещении. Если вы сортируете TObjectParams экземпляров без обновления записей перемещения, ваши указатели Data будут указывать на неправильные данные конфигурации после objcopy.

Обновление:

это решение частично удовлетворяет.

Если вы можете включить данные конфигурации напрямую в TObjectParams, они станут больше, а накладные расходы указателей уменьшатся.

Если сами данные конфигурации не имеют указателей на другие данные, то вы можете напрямую отсортировать содержимое раздела и полностью исключить накладные расходы.

Если вы не можете избавиться от указателей , тогда вам придется написать собственный инструмент для манипулирования ELF, который будет сортировать данные и связанные записи перемещения. Такой инструмент может также обновить раздел символов для устранения неполадок.

Однако я думаю, что существует значительно более простое решение, по крайней мере, в случае, когда в данном .o есть единичные случаи TObjectParams. файл (или если для данного .o гарантированно имеются только последовательные файлы ID s и .o, которые не перекрываются в содержащихся в них ID s):

  1. Put все TObjectParams в отдельном разделе, как вы делаете сейчас.
  2. Связать двоичный файл. Это создаст двоичный файл с несортированным разделом, и единственная причина для этой ссылки - получить список объектов, которые вошли в этот двоичный файл.

    Если вы уже ведете такой список отдельно, этот шаг можно пропустить.

  3. Для каждого объектного файла в списке, начиная с шага 2 (foo.o), используйте objcopy, чтобы получить два новых объекта: один только с интересующим разделом (foo_w.o) и один с этим разделом удален (foo_x.o).

  4. Сортировать список {foo,bar,baz}_w.o по ID, содержащемуся внутри.

  5. Выполните окончательную ссылку, используя {foo,bar,baz}_x.o в любом порядке и {foo,bar,baz}_w.o в отсортированном порядке. Компоновщик обычно не переупорядочивает содержимое раздела, и эта ссылка должна создавать желаемый конечный двоичный файл.

...