Что такое опция -fPIE для независимых по позиции исполняемых файлов в gcc и ld?

Как это изменит код, например вызовы функций?

PIE предназначен для поддержки рандомизации расположения пространства адресов (ASLR) в исполняемых файлах.

До того, как был создан режим PIE, исполняемый файл программы не мог быть помещен на случайный адрес в памяти, динамические библиотеки с независимым положением (PIC) могли быть перемещены на случайное смещение. Он очень похож на то, что PIC делает для динамических библиотек, разница заключается в том, что не создана таблица привязки к процедуре (PLT), вместо этого используется перенос PC-relative.

После включения поддержки PIE в gcc / linkers тело программы скомпилировано и связано как независимый от позиции код. Динамический компоновщик выполняет полную обработку перемещения в программном модуле, как и динамические библиотеки. Любое использование глобальных данных преобразуется в доступ через глобальную таблицу смещений (GOT) и добавляются переадресации GOT.

PIE хорошо описан в этой презентации PIE OpenBSD .

Изменения в функциях показаны на этом слайде (PIE vs PIC).

x86 pic vs pie

Локальные глобальные переменные и функции оптимизированы в пироге

Внешние глобальные переменные и функции такие же, как pic

и в этом слайде (PIE vs old-style linking)

x86 pie vs no-flags (исправлено)

Локальные глобальные переменные и функции аналогичны фиксированным

Внешние глобальные переменные и функции такие же, как pic

Обратите внимание, что PIE может быть несовместимым с -static

Минимальный runnable пример: GDB исполняемый файл дважды

Для тех, кто хочет увидеть некоторые действия:

 printf ' #include  int main() { puts("hello world"); } ' > main.c gcc -std=c99 -pie -fpie -ggdb3 -o pie main.c gcc -std=c99 -no-pie -fno-pie -ggdb3 -o nopie main.c echo 2 | sudo tee /proc/sys/kernel/randomize_va_space gdb -batch -nh -ex 'set disable-randomization off' \ -ex 'start' -ex 'info line' \ -ex 'start' -ex 'info line' \ ./pie gdb -batch -nh -ex 'set disable-randomization off' \ -ex 'start' -ex 'info line' \ -ex 'start' -ex 'info line' \ ./nopie 

Для одного с -pie мы видим, что адрес main изменений между прогонами:

 Temporary breakpoint 1 at 0x7a9: file memory_layout.c, line 31. [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1". Temporary breakpoint 1, main (argc=1, argv=0x7ffe57d75318) at memory_layout.c:31 31 int main(int argc, char **argv) { Line 31 of "memory_layout.c" starts at address 0x55db0066b79a 
and ends at 0x55db0066b7a9 . Temporary breakpoint 2 at 0x55db0066b7a9: file memory_layout.c, line 31. [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1". Temporary breakpoint 2, main (argc=1, argv=0x7ffd03b67d68) at memory_layout.c:31 31 int main(int argc, char **argv) { Line 31 of "memory_layout.c" starts at address 0x563910ccd79a
and ends at 0x563910ccd7a9 .

поэтому в этом примере адрес для первого запуска был 0x55db0066b79a и для второго 0x563910ccd79a .

Но для одного с -no-pie адрес main остается тем же 0x400627 для обоих прогонов:

 Temporary breakpoint 1 at 0x400636: file ./memory_layout.c, line 28. Temporary breakpoint 1, main (argc=1, argv=0x7ffd5f69c8b8) at ./memory_layout.c:28 warning: Source file is more recent than executable. 28 int bss = 0; Line 28 of "./memory_layout.c" starts at address 0x400627 
and ends at 0x400636 . Temporary breakpoint 2 at 0x400636: file ./memory_layout.c, line 28. Temporary breakpoint 2, main (argc=1, argv=0x7ffdd9f74bd8) at ./memory_layout.c:28 28 int bss = 0; Line 28 of "./memory_layout.c" starts at address 0x400627
and ends at 0x400636 .

echo 2 | sudo tee /proc/sys/kernel/randomize_va_space echo 2 | sudo tee /proc/sys/kernel/randomize_va_space гарантирует, что ASLR включен (по умолчанию в Ubuntu 17.10): Как временно отключить ASLR (рандомизация размещения адресного пространства)? | Спросите Ubuntu .

set disable-randomization off , иначе GDB, как следует из названия, отключает ASLR для процесса по умолчанию, чтобы дать фиксированные адреса в разных прогонах, чтобы улучшить опыт отладки: Разница между адресами gdb и «реальными» адресами? | Переполнение стека

readelf

Кроме того, мы можем также заметить, что:

 readelf -s ./nopie | grep main 

дает фактический адрес загрузки во время работы:

 69: 0000000000400627 370 FUNC GLOBAL DEFAULT 13 main 

в то время как:

 readelf -s ./pie | grep main 

дает только смещение:

 70: 000000000000079a 401 FUNC GLOBAL DEFAULT 14 main 

Если вы отключите ASLR (либо с randomize_va_space либо с set disable-randomization off ), GDB всегда дает main адрес: 0x5555555547a9 , поэтому мы 0x5555555547a9 , что -pie адрес состоит из:

 0x555555554000 + random offset + symbol offset (79a) 

TODO, где 0x555555554000 жестко закодирован в ядре Linux / glibc-загрузчик / где бы вы ни находились? Как определяется адрес текстового раздела исполняемого файла PIE в Linux?

Протестировано в Ubuntu 18.04.

Связанный вопрос: Как я могу сказать, с чем-то вроде objdump, если объект-файл был создан с -fPIC?

  • Шаблон C ++, ссылка на ошибку
  • Что такое Microsoft Visual Studio, эквивалентная опции GCC ld - whall-archive
  • Определение переменной в файлах заголовков
  • VA (виртуальный адрес) и RVA (относительный виртуальный адрес)
  • ошибка LNK2019: неразрешенный внешний символ _main, указанный в функции ___tmainCRTStartup
  • ошибка LNK2005: уже определена - C ++
  • Как принудительно включить определение «неиспользуемых» объектов в библиотеке
  • Что означает «статически связанное» и «динамически связанное»?
  • Interesting Posts

    Как создать .NET DateTime из ISO 8601

    Надежное определение количества элементов в массиве

    Как загрузить db: исходные данные в тестовую базу данных автоматически?

    Как изменить фон диалоговых окон Android alert?

    Получите MAC-адрес устройства Android без Wi-Fi

    Android context.getResources.updateConfiguration () устарел

    Получение значения XML-узла в Java DOM

    Что представляет собой складку для других типов, кроме списка?

    Как диагностировать замораживание при запуске в Windows XP?

    Почему X присоединяется к data.tables, не допускает полного внешнего соединения или левого соединения?

    Android, как запуститьOnUiThread в другом classе?

    PuTTY – автоматическое повторное подключение после прерывания интернета?

    Сделать Chrome всегда исполняемым с помощью флагов, например, непосредственно открывая HTML-файл

    Как сделать элемент встроенного блока заполнить оставшуюся часть строки?

    Преобразование растрового изображения в GrayScale в Android

    Давайте будем гением компьютера.