Портативный исполняемый файл


Формат Portable Executable ( PE ) — это формат файлов для исполняемых файлов , объектного кода , DLL и других файлов, используемых в 32-разрядных и 64-разрядных версиях операционных систем Windows . Формат PE представляет собой структуру данных, которая инкапсулирует информацию, необходимую загрузчику ОС Windows для управления обернутым исполняемым кодом . Сюда входят ссылки на динамические библиотеки для связывания , таблицы экспорта и импорта API , данные управления ресурсами и данные локального хранилища потока (TLS). В операционных системах NT для EXE используется формат PE., DLL , SYS ( драйвер устройства ), MUI и другие типы файлов. В спецификации Unified Extensible Firmware Interface (UEFI) указано, что PE является стандартным исполняемым форматом в средах EFI. [2]

В операционных системах Windows NT PE в настоящее время поддерживает архитектуры набора инструкций (ISA) x86-32 , x86-64 (AMD64/Intel 64), IA-64 , ARM и ARM64 . До Windows 2000 Windows NT (и, следовательно, PE) поддерживала ISA MIPS , Alpha и PowerPC . Поскольку PE используется в Windows CE , он продолжает поддерживать несколько вариантов MIPS, ARM (включая Thumb ) и SuperH ISA. [3]

Форматами, аналогичными PE, являются ELF (используется в Linux и большинстве других версий Unix ) и Mach-O (используется в macOS и iOS ).

Microsoft перешла на формат PE с 16-битных форматов NE с появлением операционной системы Windows NT 3.1 . Все более поздние версии Windows, включая Windows 95/98/ME и дополнение Win32 к Windows 3.1x, поддерживают файловую структуру. Формат сохранил ограниченную устаревшую поддержку, чтобы преодолеть разрыв между системами на основе DOS и NT. Например, заголовки PE/COFF по-прежнему содержат исполняемую программу DOS , которая по умолчанию является заглушкой DOS и отображает сообщение типа «Эта программа не может быть запущена в режиме DOS» (или подобное), хотя это может быть полноценная программа DOS. версия программы (более поздний известный случай - установщик Windows 98 SE). [4]Это представляет собой форму жирного бинарного файла . PE также продолжает обслуживать изменяющуюся платформу Windows. Некоторые расширения включают формат .NET PE (см. ниже), 64-разрядную версию под названием PE32+ (иногда PE+) и спецификацию для Windows CE.

PE-файл состоит из нескольких заголовков и разделов, которые сообщают динамическому компоновщику , как отображать файл в памяти. Исполняемый образ состоит из нескольких разных областей, каждая из которых требует разной защиты памяти; поэтому начало каждого раздела должно быть выровнено по границе страницы. [5] Например, обычно раздел .text (который содержит программный код) отображается как исполняемый/только для чтения, а раздел .dataраздел (содержащий глобальные переменные) отображается как запрет на выполнение/чтение и запись. Однако, чтобы не тратить место впустую, различные разделы не выравниваются по страницам на диске. Частью работы динамического компоновщика является индивидуальное сопоставление каждого раздела с памятью и назначение правильных разрешений для результирующих регионов в соответствии с инструкциями, приведенными в заголовках. [6]

Следует отметить один раздел — таблицу адресов импорта (IAT), которая используется в качестве таблицы поиска, когда приложение вызывает функцию в другом модуле. Он может быть в виде как импорта по порядковому номеру, так и импорта по имени . Поскольку скомпилированная программа не может знать расположение в памяти библиотек, от которых она зависит, при каждом вызове API требуется непрямой переход. Когда динамический компоновщик загружает модули и объединяет их вместе, он записывает фактические адреса в слоты IAT, чтобы они указывали на ячейки памяти соответствующих библиотечных функций. Хотя это увеличивает стоимость внутримодульного вызова, что приводит к снижению производительности, оно дает ключевое преимущество: количество страниц памяти, которые необходимо копировать при записи .измененный загрузчиком, сводится к минимуму, экономя память и время дискового ввода-вывода. Если компилятор заранее знает, что вызов будет межмодульным (через атрибут dllimport), он может создать более оптимизированный код, который просто приводит к косвенному коду операции вызова . [6]


Структура переносимого исполняемого файла 32 бит