Введение
Стандартный формат файла для исполняемых файлов, объектного кода, разделяемых библиотек и дампов памяти. По своей конструкции формат ELF отличается гибкостью, расширяемостью и кроссплатформенностью. В частности, он поддерживает различные варианты порядка байтов и размеры адресов, что позволяет использовать его на различных процессорах и архитектурах наборов команд. Благодаря этому он был принят многими операционными системами на широком спектре аппаратных платформ.
Заголовок файла
В заголовке ELF определяется, используются ли 32-битные или 64-битные адреса. Заголовок содержит три поля, которые зависят от этой настройки и смещают последующие поля. Заголовок ELF имеет размер 52 или 64 байта для 32-битных и 64-битных исполняемых файлов соответственно. + ELF header Смещение Размер поля (байты) Назначение 32 бит 64 бит 32 бит 64 бит 0x00 4 по 0x7F, за которым следует ELF в ASCII; эти четыре байта образуют магическое число. 0x04 1 Этот байт устанавливается в 1 или 2 для обозначения 32- или 64-битного формата соответственно. 0x05 1 Этот байт устанавливается в 1 или 2 для обозначения порядка байтов little или big endian соответственно. Это влияет на интерпретацию многобайтовых полей, начинающихся со смещения 0x10. 0x06 1 Установлен в 1 для оригинальной и текущей версии ELF. 0x07 1 Определяет целевую операционную систему ABI. Значение ABI 0x00 System V 0x01 HP UX 0x02 NetBSD 0x03 Linux 0x04 GNU Hurd 0x06 Solaris 0x07 AIX (Monterey) 0x08 IRIX 0x09 FreeBSD 0x0A Tru64 0x0B Novell Modesto 0x0C OpenBSD 0x0D OpenVMS 0x0E NonStop Kernel 0x0F AROS 0x10 FenixOS 0x11 Nuxi CloudABI 0x12 Stratus Technologies OpenVOS 0x08 1 Дополнительно указывает версию ABI. Его интерпретация зависит от целевого ABI. Ядро Linux (после версии 2.6 и выше) не имеет определения этого поля, поэтому оно игнорируется для статически связанных исполняемых файлов. В этом случае смещение и размер EI PAD равны 8. glibc 2.12+ рассматривает это поле как версию ABI динамического компоновщика: оно определяет список возможностей динамического компоновщика, рассматривает как уровень возможностей, запрашиваемый общим объектом (исполняемым файлом или динамической библиотекой), и отказывается загружать его, если запрошена неизвестная возможность, то есть значение больше, чем самая большая известная возможность. 0x09 7 Зарезервированные байты заполнения. В настоящее время не используются. Должны быть заполнены нулями и игнорироваться при чтении. 0x10 2 Определяет тип объектного файла. Значение Тип Описание 0x00 ET NONE Неизвестный. 0x01 ET REL Перемещаемый файл. 0x02 ET EXEC Исполняемый файл. 0x03 ET DYN Общий объект. 0x04 ET CORE Файл дампа памяти. 0xFE00 ET LOOS Зарезервированный диапазон (включительно). Специфичный для операционной системы. 0xFEFF ET HIOS 0xFF00 ET LOPROC Зарезервированный диапазон (включительно). Специфичный для процессора. 0xFFFF ET HIPROC 0x12 2 Указывает целевую архитектуру набора инструкций. Примеры: Значение ISA 0x00 Нет определенного набора инструкций 0x01 AT&T WE 32100 0x02 SPARC 0x03 x86 0x04 Motorola 68000 (M68k) 0x05 Motorola 88000 (M88k) 0x06 Intel MCU 0x07 Intel 8086 0x08 MIPS 0x09 IBM System/370 0x0A MIPS RS3000 Little endian 0x0B 0x0E Зарезервировано для будущего использования 0x0F Hewlett Packard PA RISC 0x13 Intel 80960 0x14 PowerPC 0x15 PowerPC (64 бит) 0x16 S390, включая S390x 0x17 IBM SPU/SPC 0x18 0x23 Зарезервировано для будущего использования 0x24 NEC V8000 0x25 Fujitsu FR200 0x26 TRW RH 320 0x27 Motorola RCE 0x28 Arm (до Armv7/AArch32) 0x29 Digital Alpha 0x2A SuperH 0x2B SPARC Version 9 0x2C Siemens TriCore embedded processor 0x2D Argonaut RISC Core 0x2E Hitachi H8/3000 0x2F Hitachi H8/300H 0x30 Hitachi H8S 0x31 Hitachi H8/5000 0x32 IA 64 0x33 Stanford MIPS X 0x34 Motorola ColdFire 0x35 Motorola M68HC12 0x36 Fujitsu MMA Multimedia Accelerator 0x37 Siemens PCP 0x38 Sony nCPU embedded RISC processor 0x39 Denso NDR1 microprocessor 0x3A Motorola Star*Core processor 0x3B Toyota ME16 processor 0x3C STMicroelectronics ST100 processor 0x3D Advanced Logic Corp. TinyJ embedded processor family 0x3E AMD x86 64 0x3F Sony DSP Processor 0x40 Digital Equipment Corp. PDP 10 0x41 Digital Equipment Corp. PDP 11 0x42 Siemens FX66 microcontroller 0x43 STMicroelectronics ST9+ 8/16 bit microcontroller 0x44 STMicroelectronics ST7 8 bit microcontroller 0x45 Motorola MC68HC16 Microcontroller 0x46 Motorola MC68HC11 Microcontroller 0x47 Motorola MC68HC08 Microcontroller 0x48 Motorola MC68HC05 Microcontroller 0x49 Silicon Graphics SVx 0x4A STMicroelectronics ST19 8 bit microcontroller 0x4B Digital VAX 0x4C Axis Communications 32 bit embedded processor 0x4D Infineon Technologies 32 bit embedded processor 0x4E Element 14 64 bit DSP Processor 0x4F LSI Logic 16 bit DSP Processor 0x8C TMS320C6000 Family 0xAF MCST Elbrus e2k 0xB7 Arm 64 bits (Armv8/AArch64) 0xDC Zilog Z80 0xF3 RISC V 0xF7 Berkeley Packet Filter 0x101 WDC 65C816 0x102 LoongArch 0x14 4 Установлен в 1 для оригинальной версии ELF. 0x18 4 8 Это адрес памяти точки входа, с которой начинается выполнение процесса. Это поле имеет длину 32 или 64 бита, в зависимости от формата, определенного ранее (байт 0x04). Если файл не имеет связанной точки входа, то это поле равно нулю. 0x1C 0x20 4 8 Указывает на начало таблицы заголовков программ. Обычно она следует за заголовком файла сразу после этого, что делает смещение 0x34 или 0x40 для 32- и 64-битных ELF исполняемых файлов соответственно. 0x20 0x28 4 8 Указывает на начало таблицы заголовков секций. 0x24 0x30 4 Интерпретация этого поля зависит от целевой архитектуры. 0x28 0x34 2 Содержит размер этой заголовки, обычно 64 байта для 64-битного формата и 52 байта для 32-битного формата. 0x2A 0x36 2 Содержит размер записи в таблице заголовков программ. Как объяснено ниже, это обычно 0x20 (32 бит) или 0x38 (64 бит). 0x2C 0x38 2 Содержит количество записей в таблице заголовков программ. 0x2E 0x3A 2 Содержит размер записи в таблице заголовков секций. Как объяснено ниже, это обычно 0x28 (32 бит) или 0x40 (64 бит). 0x30 0x3C 2 Содержит количество записей в таблице заголовков секций. 0x32 0x3E 2 Содержит индекс записи в таблице заголовков секций, содержащей имена секций. 0x34 0x40 Конец заголовка ELF (размер).
glibc 2.12+ in case treats this field as ABI version of the dynamic linker: it defines a list of dynamic linker's features, treats as a feature level requested by the shared object (executable or dynamic library) and refuses to load it if an unknown feature is requested, i. e. is greater than the largest known feature. 0x09 7 Reserved padding bytes. Currently unused. Should be filled with zeros and ignored when read. 0x10 2 Identifies object file type. ValueTypeMeaning0x00ET NONEUnknown.0x01ET RELRelocatable file.0x02ET EXECExecutable file.0x03ET DYNShared object.0x04ET CORECore file.0xFE00ET LOOS Reserved inclusive range. Operating system specific.0xFEFFET HIOS0xFF00ET LOPROC Reserved inclusive range. Processor specific.0xFFFFET HIPROC 0x12 2 Specifies target instruction set architecture. Some examples are:
ValueISA0x00 No specific instruction set0x01 AT&T WE 321000x02SPARC0x03x860x04Motorola 68000 (M68k)0x05Motorola 88000 (M88k)0x06Intel MCU0x07Intel 808600x08MIPS0x09IBM System/3700x0AMIPS RS3000 Little endian0x0B 0x0EReserved for future use0x0FHewlett Packard PA RISC0x13Intel 809600x14PowerPC0x15PowerPC (64 bit)0x16S390, including S390x0x17IBM SPU/SPC0x18 0x23Reserved for future use0x24NEC V8000x25Fujitsu FR200x26TRW RH 320x27Motorola RCE0x28Arm (up to Armv7/AArch32)0x29Digital Alpha0x2ASuperH0x2BSPARC Version 90x2CSiemens TriCore embedded processor0x2DArgonaut RISC Core0x2EHitachi H8/3000x2FHitachi H8/300H0x30Hitachi H8S0x31Hitachi H8/5000x32IA 640x33Stanford MIPS X0x34Motorola ColdFire0x35Motorola M68HC120x36Fujitsu MMA Multimedia Accelerator0x37Siemens PCP0x38Sony nCPU embedded RISC processor0x39Denso NDR1 microprocessor0x3AMotorola Star*Core processor0x3BToyota ME16 processor0x3CSTMicroelectronics ST100 processor0x3DAdvanced Logic Corp. TinyJ embedded processor family0x3EAMD x86 640x3FSony DSP Processor0x40Digital Equipment Corp. PDP 100x41Digital Equipment Corp. PDP 110x42Siemens FX66 microcontroller0x43STMicroelectronics ST9+ 8/16 bit microcontroller0x44STMicroelectronics ST7 8 bit microcontroller0x45Motorola MC68HC16 Microcontroller0x46Motorola MC68HC11 Microcontroller0x47Motorola MC68HC08 Microcontroller0x48Motorola MC68HC05 Microcontroller0x49Silicon Graphics SVx0x4ASTMicroelectronics ST19 8 bit microcontroller0x4BDigital VAX0x4CAxis Communications 32 bit embedded processor0x4DInfineon Technologies 32 bit embedded processor0x4EElement 14 64 bit DSP Processor0x4FLSI Logic 16 bit DSP Processor0x8CTMS320C6000 Family0xAFMCST Elbrus e2k0xB7Arm 64 bits (Armv8/AArch64)0xDCZilog Z800xF3RISC V0xF7Berkeley Packet Filter0x101WDC 65C8160x102LoongArch 0x14 4 Set to 1 for the original version of ELF. 0x18 4 8 This is the memory address of the entry point from where the process starts executing. This field is either 32 or 64 bits long, depending on the format defined earlier (byte 0x04). If the file doesn't have an associated entry point, then this holds zero. 0x1C 0x20 4 8 Points to the start of the program header table. It usually follows the file header immediately following this one, making the offset 0x34 or 0x40 for 32 and 64 bit ELF executables, respectively. 0x20 0x28 4 8 Points to the start of the section header table. 0x24 0x30 4 Interpretation of this field depends on the target architecture. 0x28 0x34 2 Contains the size of this header, normally 64 Bytes for 64 bit and 52 Bytes for 32 bit format. 0x2A 0x36 2 Contains the size of a program header table entry. As explained below, this will typically be 0x20 (32 bit) or 0x38 (64 bit). 0x2C 0x38 2 Contains the number of entries in the program header table. 0x2E 0x3A 2 Contains the size of a section header table entry. As explained below, this will typically be 0x28 (32 bit) or 0x40 (64 bit). 0x30 0x3C 2 Contains the number of entries in the section header table. 0x32 0x3E 2 Contains index of the section header table entry that contains the section names.0x340x40End of ELF Header (size).
Заголовок программы
Таблица заголовков программы сообщает системе, как создать образ процесса. Она находится в файле по смещению, и состоит из записей, каждая из которых имеет размер. Расположение немного отличается в 32-битных и 64-битных ELF, поскольку они находятся в разных местах структуры из-за требований к выравниванию. Каждая запись имеет следующую структуру:
+ Смещение заголовка программы Размер (байты) Поле Назначение 32 бит 64 бит 32 бит 64 бит 0x00 4 Определяет тип сегмента. ЗначениеИмяОписание0x00000000 Запись таблицы заголовков программы не используется.0x00000001 Загружаемый сегмент.0x00000002 Информация о динамической линковке.0x00000003 Информация об интерпретаторе.0x00000004 Вспомогательная информация.0x00000005 Зарезервировано.0x00000006 Сегмент, содержащий саму таблицу заголовков программы.0x00000007 Шаблон локального хранения потока.0x60000000 Зарезервированный инклюзивный диапазон. Специфично для операционной системы.0x6FFFFFFF0x70000000 Зарезервированный инклюзивный диапазон. Специфично для процессора.0x7FFFFFFF 0x04 4 Флаги, зависящие от сегмента (позиция для 64-битной структуры). ЗначениеИмяОписание0x1Исполняемый сегмент.0x2Записываемый сегмент.0x4Читаемый сегмент. 0x04 0x08 4 8Смещение сегмента в файловом образе. 0x08 0x10 4 8 Виртуальный адрес сегмента в памяти. 0x0C 0x18 4 8 В системах, где важен физический адрес, зарезервировано для физического адреса сегмента. 0x10 0x20 4 8 Размер сегмента в файловом образе в байтах. Может быть равен 0. 0x14 0x28 4 8 Размер сегмента в памяти в байтах. Может быть равен 0. 0x18 4 Флаги, зависящие от сегмента (позиция для 32-битной структуры). См. выше поле флагов p для определений флагов. 0x1C 0x30 4 8 0 и 1 указывают на отсутствие выравнивания. В противном случае должно быть положительной целой степенью 2, где равно модулю. 0x200x38Конец заголовка программы (размер).
Заголовок раздела
Размер смещения (байты)ПолеНазначение32 бит64 бит32 бит64 бит0x004sh nameСмещение к строке в секции shstrtab, представляющей имя этой секции.0x044sh typeОпределяет тип этого заголовка. ЗначениеИмяОписание0x0SHT NULLНеиспользуемая запись таблицы заголовков секций0x1SHT PROGBITSПрограммные данные0x2SHT SYMTABТаблица символов0x3SHT STRTABТаблица строк0x4SHT RELЗаписи переходов с добавками0x5SHT HASHТаблица хешей символов0x6SHT DYNAMICИнформация о динамической линковке0x7SHT NOTEЗаметки0x8SHT NOBITSПрограммное пространство без данных (BSS)0x9SHT RELПереходы, без добавок0x0ASHT SHLIBЗарезервировано0x0BSHT DYNSYMTаблица символов динамического линкера0x0ESHT INIT ARRAYМассив конструкторов0x0FSHT FINI ARRAYМассив деструкторов0x10SHT PREINIT ARRAYМассив предварительных конструкторов0x11SHT GROUPГруппа секций0x12SHT SYMTAB SHNDXРасширенные индексы секций0x13SHT NUMКоличество определенных типов.0x60000000SHT LOOSНачало специфичных для ОС0x0848sh flagsОпределяет атрибуты секции. ЗначениеИмяОписание0x1SHF WRITEЗаписываемая0x2SHF ALLOCЗанимает память во время выполнения0x4SHF EXECINSTRВыполняемая0x10SHF MERGEМожет быть объединена0x20SHF STRINGSСодержит строки, завершенные нулем0x40SHF INFO LINKПоле 'info' содержит индекс SHT0x80SHF LINK ORDERСохраняет порядок после объединения0x100SHF OS NONCONFORMINGНестандартная обработка, специфичная для ОС0x200SHF GROUPСекция является членом группы0x400SHF TLSСекция содержит данные, локальные для потока0x0FF00000SHF MASKOSСпецифичная для ОС0xF0000000SHF MASKPROCСпецифичная для процессора0x4000000SHF ORDEREDСпециальные требования к порядку (Solaris)0x8000000SHF EXCLUDEСекция исключена, если не используется или не выделена (Solaris)0x0C0x1048sh addrВиртуальный адрес секции в памяти, для секций, которые загружаются.0x100x1848sh offsetСмещение секции в образе файла.0x140x2048sh sizeРазмер секции в байтах в образе файла. Может быть 0.0x180x284sh linkСодержит индекс связанной секции. Это поле используется для нескольких целей, в зависимости от типа секции.0x1C0x2C4sh infoСодержит дополнительную информацию о секции. Это поле используется для нескольких целей, в зависимости от типа секции.0x200x3048sh addralignСодержит требуемое выравнивание секции. Это поле должно быть степенью двойки.0x240x3848sh entsizeСодержит размер, в байтах, каждой записи, для секций, которые содержат записи фиксированного размера. В противном случае это поле содержит ноль.0x280x40Конец заголовка секции (размер).
Инструменты
readelf — это двоичная утилита Unix, которая отображает информацию об одном или нескольких ELF-файлах. Свободная реализация предоставляется GNU Binutils. elfutils предоставляет альтернативные инструменты GNU Binutils, предназначенные исключительно для Linux. elfdump — команда для просмотра информации ELF в ELF-файле, доступная в Solaris и FreeBSD. objdump предоставляет широкий спектр информации о файлах ELF и других форматах объектов. objdump использует библиотеку дескрипторов двоичных файлов в качестве бэк-энда для структурирования данных ELF. Утилита file Unix может отображать некоторую информацию о файлах ELF, включая архитектуру набора команд, для которой предназначен код в переносимом, исполняемом или совместно используемом объектном файле, или на которой был создан дамп ядра ELF.
86 открыто
86open был проектом, направленным на достижение консенсуса относительно единого двоичного формата файлов для Unix и Unix-подобных операционных систем на общей PC-совместимой архитектуре x86, с целью стимулировать разработчиков программного обеспечения к портированию на эту архитектуру. Изначальная идея заключалась в стандартизации на небольшом подмножестве Spec 1170, предшественнике спецификации Single UNIX Specification, и библиотеки GNU C (glibc), чтобы обеспечить запуск неизменённых двоичных файлов на x86 Unix-подобных операционных системах. Первоначально проект назывался "Spec 150". В конечном итоге был выбран формат ELF, а именно реализация ELF в Linux, поскольку он де-факто стал стандартом, поддерживаемым всеми участвующими поставщиками и операционными системами. Группа начала переписку по электронной почте в 1997 году и впервые встретилась в офисе Santa Cruz Operation 22 августа 1997 года. Руководящий комитет состоял из Марка Юинга, Диона Джонсона, Эвана Лейбовича, Брюса Перенса, Эндрю Роуча, Брайана Уэйна Спаркса и Линуса Торвальдса. Среди других участников проекта были Кит Бостик, Чак Кранор, Майкл Дэвидсон, Крис Г. Деметриу, Ульрих Дреппер, Дон Даггер, Стив Гинзбург, Джон "maddog" Холл, Рон Холт, Джордан Хаббард, Дэйв Дженсен, Кин Джонстон, Эндрю Хози, Роберт Лип, Бела Любкин, Тим Марсленд, Грег Пейдж, Рональд Джо Рекорд, Тим Ракл, Джоэл Сильверштейн, Чья пи Тьен и Эрик Троан. Представленные операционные системы и компании включали BeOS, BSDI, FreeBSD, Intel, Linux, NetBSD, SCO и SunSoft. Проект продвигался, и в середине 1998 года SCO начала разработку lxrun – открытого слоя совместимости, позволяющего запускать бинарные файлы Linux на OpenServer, UnixWare и Solaris. SCO объявила об официальной поддержке lxrun на LinuxWorld в марте 1999 года. Sun Microsystems начала официально поддерживать lxrun для Solaris в начале 1999 года, а затем перешла к интегрированной поддержке бинарного формата Linux через Solaris Containers for Linux Applications. Поскольку BSD-системы уже давно поддерживали бинарные файлы Linux (через слой совместимости), а основные поставщики Unix x86 добавили поддержку этого формата, проект пришел к выводу, что Linux ELF был выбран отраслью и объявил о самороспуске 25 июля 1999 года.
FatELF: универсальные двоичные файлы для Linux
FatELF — это расширение бинарного формата ELF, добавляющее поддержку создания универсальных бинарных файлов. Оно предназначено для Linux и других Unix-подобных операционных систем. Помимо абстракции архитектуры процессора (порядок байтов, размер слова, набор инструкций процессора и т. д.), существует потенциальная возможность абстракции программной платформы, например, бинарные файлы, поддерживающие несколько версий ABI ядра. По состоянию на 2021 год FatELF не был включен в основное ядро Linux.