Исполняемые файлы подкачки и PIC

Мне трудно понять необходимость исполняемых файлов PIC при использовании виртуальной памяти. Из того, что я понял, каждой программе назначается запись в таблице страниц, и поэтому у нее создается иллюзия, что вся память находится в ее распоряжении, в то время как механизм подкачки заботится о возможных перемещениях, сбоях страниц и т. д. Итак, если у какой-либо программы есть иллюзия владения всеми возможными адресами памяти, зачем использовать PIC?


person Trey    schedule 18.05.2019    source источник


Ответы (2)


Нам это не нужно, и до последнего года или двух все исполняемые файлы Linux были зависимы от позиции (не PIC). См. 32-битные абсолютные адреса больше не разрешены в x86-64 Linux?.

Вы по-прежнему можете создавать исполняемые файлы, отличные от PIE, с помощью gcc -fno-pie -no-pie, а статические исполняемые файлы ELF всегда не являются PIE, а их адрес загрузки выбирается во время компоновки. Обычно по умолчанию начало текстового сегмента устанавливается на 401000.

Позиционно-независимые исполняемые файлы ELF начинались как хак: общий объект ELF с точкой входа. Но в наши дни это широко используется и gcc по умолчанию в большинстве дистрибутивов Linux. Адрес загрузки может быть рандомизирован во время выполнения.


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

Например, общие объекты ELF в Linux могут содержать перемещения для 64-битных абсолютных адресов, поэтому вы можете использовать традиционные таблицы переходов (массив кодовых указателей) или статически инициализированные массивы указателей (на данные или функции) в коде, скомпилированном с помощью gcc -fPIC для x86 и x86-64.


Обратите внимание, что gcc -fPIC также включает поддержку вставки символов, поэтому функции не могут напрямую обращаться к глобальным переменным; они должны загрузить адрес из GOT, если символ не имеет «скрытой» видимости ELF. (Или, конечно, если вы сделаете его static вместо глобального).

См. https://www.macieira.org/blog/2012/01/sorry-state-of-dynamic-libraries-on-linux/

(Некоторые из идей, предложенных в этом блоге, были реализованы, например, GCC поддерживает -fno-plt.)

Фактическая стоимость просто независимости от позиции с -fpie довольно мала. Но по-прежнему отлично от нуля в ОС, где исполняемые файлы, зависящие от позиции, гарантированно загружаются в младшие 32 бита виртуального адресного пространства (например, Linux), поэтому вы можете использовать 32-битные абсолютные адреса для 5-байтовых mov r32, imm32 вместо 7- byte RIP-relative LEA для помещения статического адреса в регистр или [array + reg] для индексации статического массива с его адресом в смещении disp32 как часть режима адресации.

person Peter Cordes    schedule 19.05.2019

Две основные причины:

  1. Общие библиотеки. Нельзя гарантировать загрузку библиотек по определенному адресу — даже в 64-битной системе невозможно гарантировать, что каждая библиотека будет иметь уникальный адрес загрузки, который не будет конфликтовать с другими библиотеками или с динамической памятью. ассигнования. Таким образом, код в разделяемых библиотеках компилируется как PIC, поэтому его можно загрузить по любому адресу, по которому он необходим.

  2. Безопасность. Наличие определенного кода в предсказуемых местах памяти представляет собой угрозу безопасности, так как это позволяет использовать эксплойты, которые переходят к коротким закодируйте "гаджеты" в памяти, которые можно связать вместе для выполнения произвольных операций. Случайное перемещение кода при запуске приложения помогает противостоять этим атакам.

person Community    schedule 18.05.2019