У меня есть встроенное приложение, в котором будет загрузчик, который решит запустить одно из двух приложений непосредственно из внутренней флэш-памяти. Я пытаюсь сделать эти приложения независимыми от позиции, чтобы их можно было скомпилировать для одного и того же базового адреса. Операционная система отсутствует, поэтому динамический компоновщик недоступен. До сих пор я пытался построить с параметром -fpie (используя gcc) без особого успеха. Вызовы функций кажутся правильными, но глобальные данные не имеют правильного адреса. Локально определенные глобальные данные, по-видимому, имеют адрес, смещенный на величину, на которую приложение смещено от своего исходного базового адреса. Глобальные данные, которые объявлены в других файлах, имеют совершенно неправильный адрес (и если я создам с -fpic, то и локально объявленные глобальные данные, и глобальные данные в других файлах будут совершенно неправильными). Я подозреваю, что мне нужно выполнить некоторые манипуляции с разделом GOT при запуске моего приложения, но я не уверен.
Попытка загрузить независимый от позиции код на cortex-m3
Ответы (2)
Наконец-то я заработал. Похоже, мне нужно сделать следующее: Весь код должен соответствовать -fpic (ранее я пробовал -fpie)
Также мне потребовалась модификация скрипта компоновщика. Я принудительно вставил GOT в раздел sram, и он был расположен после динамического раздела, который был во флэш-памяти. Похоже, все работает правильно, если раздел GOT расположен перед динамическим разделом во флэш-памяти. Не уверен, почему это имеет значение, но, похоже, все исправлено - до этого казалось, что код не нашел GOT должным образом, поскольку в GOT были сохранены правильные значения, но адреса всех моих переменных были неправильными.
Код PIE (и PIC) нуждается в процессе перемещения после загрузки по какому-то адресу (отличному от адреса по умолчанию) и до того, как он будет запущен. Я предлагаю вам ознакомиться с кодом ld.so
. Кроме того, вы должны проверить таблицу перемещений в вашем двоичном файле (например, используя readelf -r
).
Вот хорошая презентация по PIE (она про OpenBSD, но процесс такой же). http://www.openbsd.org/papers/nycbsdcon08-pie/ или http://www.dcbsdcon.org/speakers/slides/miller_dcbsdcon2009.pdf
Я думаю, вам нужно не только изменить GOT, но и найти все Relocations и сделать их.
По сути, обработка бинарника PIE с помощью ld.so почти не отличается от обработки динамической библиотеки с помощью PIC, только с перемещением не библиотеки, а самого исполняемого образа.
«Неправильные адреса», которые вы видите, - это место, где фактическое значение будет записано при решении проблемы перемещения. Что касается i386, http://books.google.com/books?id=Id9cYsIdjIwC&pg=PA174 есть релокации:
- R_386_GOTPC
- R_386_GOT32
- R_386_GOTOFF
- R_386_ОТНОСИТЕЛЬНЫЙ
Компоновщик должен разрешить их все, прежде чем код сможет получить доступ к глобальным данным.
Пример Readelf -r:
Динамически связанный
$ readelf -r fdyn
Relocation section '.rel.dyn' at offset 0x27c contains 1 entries:
Offset Info Type Sym.Value Sym. Name
08049ff0 00000106 R_386_GLOB_DAT 00000000 __gmon_start__
Relocation section '.rel.plt' at offset 0x284 contains 2 entries:
Offset Info Type Sym.Value Sym. Name
0804a000 00000107 R_386_JUMP_SLOT 00000000 __gmon_start__
0804a004 00000207 R_386_JUMP_SLOT 00000000 __libc_start_main
ПИРОГ:
$ readelf -r fPIE
Relocation section '.rel.dyn' at offset 0x388 contains 6 entries:
Offset Info Type Sym.Value Sym. Name
00001fe8 00000008 R_386_RELATIVE
00001ff0 00000008 R_386_RELATIVE
00002010 00000008 R_386_RELATIVE
00001fe0 00000106 R_386_GLOB_DAT 00000000 __gmon_start__
00001fe4 00000206 R_386_GLOB_DAT 00000000 _Jv_RegisterClasses
00001fec 00000406 R_386_GLOB_DAT 00000000 __cxa_finalize
Relocation section '.rel.plt' at offset 0x3b8 contains 3 entries:
Offset Info Type Sym.Value Sym. Name
00002000 00000107 R_386_JUMP_SLOT 00000000 __gmon_start__
00002004 00000307 R_386_JUMP_SLOT 00000000 __libc_start_main
00002008 00000407 R_386_JUMP_SLOT 00000000 __cxa_finalize