ВходНаше всё Теги codebook 无线电组件 Поиск Опросы Закон Среда
24 апреля
974721 Топик полностью
Связанные сообщения
Dynamic LinkingДинамическое Связывание
Демонстрация проблемы по ссылке. Дело не в линкере, а ещё в компиляторе. При задании опций -mpic-register=r10 -msingle-pic-base ...2020-09-16
Не надо прибивать адреса. Верней надо, но ровно один адрес одной функции. Нужно лишь сделать самодельный недо-COM. Где эта одна ...2020-09-16
Не понял что ты хочешь. Ты не знаешь по какому адресу в итоге будет размещаться программа? Для этого существуют релокации и пози...2020-09-14
С отладкой некоторые сложности, потому, что имеем два ELF-файла и каждый со своим набором отладочной информации. Если отладчик н...2020-01-30
fk0, легенда (30.01.2020 02:23 - 11:47, просмотров: 677) ответил Chum_A на Требуются идеи по реализации нечто, типа BIOS для МК. Исходные данные: имеется железо - МК Cortex-M0 и физические драйверы CAN, RS-485, SPI... Для этого железа написан и отлажен (давно) HAL, диспетчер очереди событий, программные таймеры и т.п.
Тебе нужна динамическая компоновка (функций ОС к прикладной программе). Фактически это то, чем занимается ОС при загрузке процесса. Поэтому идея взять готовую ОС не самая глупая. Но в принципе не обязательно. Фактически, ты хочешь, чтоб у тебя часть кода (HAL) собиралась и компилировалась отдельно, часть кода отдельно (основная программа). При этом видимо HAL в исходниках будет не доступен (да и не нужен). В принципе сделать такое достаточно легко: для разных частей (HAL и основная программа) можно иметь разные линкер-скрипты кладующие код в разные части памяти. Трудность возникает с тем, что основной программе откуда-то нужно узнать адреса функций HAL. Это опять же легко реализуется путём передачи списка функций с адресами в линкер скрипте, но это плохая идея: при выпуске новой версии HAL на окажется несовместима с программами откомпилированными с адресами для старой версии HAL. Т.е. проблему можно сформулировать так, что нужен способ экспорта адресов HAL в таком виде, чтоб было возможно обновление HAL. Что можно реализовать: 1) с помощью функции с фиксированным адресом, принимающей код настоящей функции (а-ля INT21 в досе); 2) с помощью таблицы переходов (а-ля функции BIOS в CP/M -- серия вызовов "JMP xxx" располагающаяся по известному адресу); 3) наконец с помощью PLT/GOT как это делается с динамическими библиотеками на PC (когда та самая таблица "JMP xxx" размещается фактически в ОЗУ загружаемой программы, а адреса исправляются на нужные); 4) наконец с помощью релокаций (когда загружается файл в специальном формате, например ELF, и он имеет список релокаций, как нужно исправить саму загружаемую программу, где адреса функций вшиты прямо в код). Последний вариант обычно делает линкер при компиляции, а в рантайме это не делают -- дороговато (много патчить). На самом деле при ручной реализации (нет поддержки ОС, линкера, загрузчика...) удобней будет некоторая комбинация вариантов 2 и 3. Что для этого нужно: во-первых код загружаемой программы должен как-то запускаться, следовательно не только загружаемая программа должна узнать адреса функций HAL, но и сам HAL должен знать адрес по-меньшей мере одной функции загружаемой программы. Программа, положим, всегда загружается по фиксированному адресу (иначе там должен быть позиционно-независимый код, или опять релокации -- этот вариант рассматривать не будем). И допустим, HAL просто передаёт управление на адрес первого байта загруженной программы. Можно считать, что этот адрес -- на самом деле функция принимающая какие-то аргументы и одним из аргументов может быть адрес таблицы функций HAL. Т.е. где-то в хедере HAL'а, доступном так же для загружаемой программы (это интерфейс между программой и HAL) пишется что-то вроде следующего: struct HAL_API { void (*Hal_func1)(int); int (*Hal_func2)(const char*); ... }; И при этом единственная точка входа загружаемой программы реализуется примерно так: const struct HAL_API *_hal; void main(const struct HAL_API *hal) { _hal = hal; ... } Т.е. программа принимает адрес таблицы списка функций HAL и запоминает в своей глобальной переменной. Потом, чтобы использовать функции HAL и не писать выражения вида "_hal->func1(x)" реализуется, в коде загружаемой программы, примерно следующая прослойка (она просто заимствуется из кода HAL, в виде исходника на C): void Hal_func1(int x) { return _hal->Hal_func1(x); } int Hal_func2(const char *p) { return _hal->Hal_func2(p); } ... Теперь функции HAL можно вызывать просто по имени. Осталось правильно экспортировать таблицу функций HAL в коде самого HAL: void Hal_func1(int x) { ... imlementation ... } int Hal_func2(const char *p) { ... implementation .... return ... } ... static const struct HAL_API hal_table = { Hal_func1, Hal_func2, ... }; Вот и всё. Вроде понятно. Разумеется на практике в таблицу функций самым первым пунктом неплохо бы добавить функцию возвращающую версию API: тогда можно потом "const struct HAL_API*" преобразовать, например, к "const struct HAL_API2*", если понятно, что данная версия HAL имеет больше функций. А если не имеет то прослойки должны видеть, что HAL_API2 это NULL и возвращать ошибку вместо вызова функции которой нет. Как-то так.
[ZX]