ВходНаше всё Теги codebook PARTS Поиск Опросы Закон Четверг
24 сентября
/1036547
Топик полностью
fk0 (14.09.2020 19:30, просмотров: 132) в ответ на может кто занимался подобным жестким, грязным хардкором, какие грабли следует ожидать ? - автор: Aleksey_75
Не понял что ты хочешь. Ты не знаешь по какому адресу в итоге будет размещаться программа? Для этого существуют релокации и позиционно-независимый код. И программу при размещении во flash нужно либо релоцировать (поменять в ней все адреса), либо, если код позиционно-независимый, то релоцировать только данные (где адреса записаны) и запускать как есть. Последнее сильно проще, т.к. видов релокаций вместо ~130 штук (офигеешь код писать) остаётся практически одна (прибавить 

смещение к переменной типа uint32_t). Проще всегда во внешней флешке хранить прямо позиционно-независимые эльфы (скомпилированные как шаред либы с ключём -shared). И написать простенькй "загрузчик" эльфов: который скопирует куда надо, релоцирует, и заодно свяжет таблицу символов (чтоб загруженный код мог вызывать функции загрузчика и наоборот). Это абсолютно реально такой загрузчик руками сделать, без всяких библиотек, на голом C и руками. Я делал. Да, никакие свои заголовки не нужны, в ELF вся информация.


Но есть один нюанс: в шаред либе с PIC (position independent code) подразумевается, что между сегментами .text и .data есть некоторое фиксированное (и фактически захардкоженное в инструкциях, в момент линковки) расстояние. Идея в том, что на компе библиотеку в конкретный адрес загрузить сложно (библиотек много, и они будут конфликтовать). Поэтому в unix-системах грузится в первый свободный адрес, так чтоб и .text и .data влезли. Потом .data патчится из-за релокаций и запускается. Код адресует данные относительно текущего значения PC (поэтому расстояние между .data и .text -- константа и её не поменять). Да, .bss лежит сразу за .data и тоже адресуется относительно.


На windows всё не так, там страх, ужас и содомия. Там библиотека пытается загрузиться по конкретному, в ней прописанному, адресу, а если не получилось -- релоцируется (или ничего не работает). Поэтому cygwin постоянно конфликтует со своими библиотеками с кем попало (например, с драйвером мышки) и отказывается работать, требуя делать rebase...


И ещё существует второй метод адресации данных и функций -- через GOT, для чегo адрес GOT'a вычисляется тоже относительно PC. В GOT лежат адреса отдельных функций и переменных. Зачем так сложно? В GOT лежат адреса внешних по отношению к библиотеке функций (импортируемых), переменных и т.п., то что нельзя адресовать просто относительно PC. Содержимое GOT устанавливается загрузчиком -- либо путём релокации, либо путём резолва символов. Да, GOT лежит фактически в ОЗУ (но может защищаться от записи после модификации).


Теперь у тебя проблема. Код ты хочешь складывать во flash, а ОЗУ выделять где-то в сторонке... Если бы ты всё загружал в ОЗУ оно бы работало как задумано. Но у тебя между .text и .data получается неизменно разное расстояние и шаред либу ты незагрузишь. Процитирую себя по последней ссылке:


Из сказанного следствие: если планируется загрузка кода в ОЗУ то нет проблем, если код в flash, а .data в озу, то проблемы есть и нужна скорей полноценная релокация. Либо в программах в принципе отказаться от .data и .bss секций (от статических и глобальных переменных). Всё адресовать относительно какого-то указателя изначально переданного в программу (тяжело так, не реально). Ещё как вариант, некоторые компиляторы (gcc для m68000) позволяют адресовать данные относительно выделенного регистра -- тогда расстояние между .text и .data может быть какое угодно. Подразумевается, что этот регистр, например, всегда указывает на GOT-таблицу, а в ней уже настоящие адреса, смещённые при загрузке.



У gcc есть опции:


-msingle-pic-basе

Treat the register used for PIC addressing as read-only, rather than loading it in the prologue for each function. The runtime system is responsible for initializing this register with an appropriate value before execution begins.


-mpic-register=reg

Specify the register to be used for PIC addressing. For standard PIC base case, the default is any suitable register determined by compiler. For single PIC base case, the default is ‘R9’ if target is EABI based or stack-checking is enabled, otherwise the default is ‘R10’.


-mpic-data-is-text-relative

Assume that the displacement between the text and data segments is fixed at static link time. This permits using PC-relative addressing operations to access data known to be in the data segment. For non-VxWorks RTP targets, this option is enabled by default. When disabled on such targets, it will enable -msingle-pic-base by default.



Я догадываюсь, тебе нужны первые две, а последняя объясняет как раз классическую работу шаред либ. Сам поиграйся опциями: https://godbolt.org/z/Mv9eeY


https://static.docs.arm.com/ihi0044/e/IHI0044E_aaelf.pdf -- ARM-релокации (стр. 25)

https://developer.arm.com/documentation/dai0242/a -- о динамической линковке.

https://docs.oracle.com/cd/E19683-01/817-3677/6mj8mbtc7/index.html -- оракловская документация по теме очень хороша.

http://caxapa.ru/974721, http://caxapa.ru/904931 -- ранние обсуждения темы.

[ZX]
dynamic linkingдинамическое связывание
Ответить
Ответы