Elf файл что это

Обновлено: 03.07.2024

Формат ELF имеет файлы нескольких типов, которые до сих пор мы называли по-разному, например, исполняемый файл или объектный файл. Тем не менее стандарт ELF различает следующие типы:

1. Перемещаемый файл (relocatable file), хранящий инструкции и данные, которые могут быть связаны с другими объектными файлами. Результатом такого связывания может быть исполняемый файл или разделяемый объектный файл.

2. Разделяемый объектный файл (shared object file) также содержит инструкции и данные, но может быть использован двумя способами. В первом случае, он может быть связан с другими перемещаемыми файлами и разделяемыми объектными файлами, в результате будет создан новый объектный файл. Во втором случае, при запуске программы на выполнение операционная система может динамически связать его с исполняемым файлом программы, в результате чего будет создан исполняемый образ программы. В последнем случае речь идет о разделяемых библиотеках.

3. Исполняемый файл хранит полное описание, позволяющее системе создать образ процесса. Он содержит инструкции, данные, описание необходимых разделяемых объектных файлов, а также необходимую символьную и отладочную информацию.

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


Рис. 2.4. Структура исполняемого файла в формате ELF

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

Поскольку заголовок ELF-файла определяет его структуру, рассмотрим его более подробно (табл. 2.4).

Таблица 2.3. Поля заголовка ELF-файла

Поле Описание е_ident[] Массив байт, каждый из которых определяет некоторую общую характеристику файла: формат файла (ELF), номер версии, архитектуру системы (32-разрядная или 64-разрядная) и т.д. e_type Тип файла, поскольку формат ELF поддерживает несколько типов e_machine Архитектура аппаратной платформы, для которой создан данный файл. В табл. 2.4 приведены возможные значения этого поля e_version Номер версии ELF-формата. Обычно определяется как EV_CURRENC (текущая), что означает последнюю версию e_entry Виртуальный адрес, по которому системой будет передано управление после загрузки программы (точка входа) e_phoff Расположение (смещение от начала файла) таблицы заголовков программы е_shoff Расположение таблицы заголовков секций е_ehsize Размер заголовка e_phentsize Размер каждого заголовка программы e_phnum Число заголовков программы e_shentsize Размер каждого заголовка сегмента (секции) е_shnum Число заголовков сегментов (секций) e_shstrndx Расположение сегмента, содержащего таблицу строк

Таблица 2.4. Значения поля e_machine заголовка ELF-файла

Значение Аппаратная платформа ЕМ_М32 AT&T WE 32100 ЕМ_SPARC Sun SPARC ЕМ_386 Intel 80386 ЕМ_68K Motorola 68000 EM_88K Motorola 88000 ЕМ_486 Intel 80486 ЕМ_860 Intel i860 ЕМ_MIPS MIPS RS3000 Big-Endian EM_MIPS_RS3_LE MIPS RS3000 Little-Endian EM_RS6000 RS6000 EM_PA_RISC PA-RISC EM_nCUBE nCUBE EM_VPP500 Fujitsu VPP500 EM_SPARC32PLUS Sun SPARC 32+

Информация, содержащаяся в таблице заголовков программы, указывает ядру, как создать образ процесса из сегментов. Большинство сегментов копируются (отображаются) в память и представляют собой соответствующие сегменты процесса при его выполнении, например, сегменты кода или данных.

Каждый заголовок сегмента программы описывает один сегмент и содержит следующую информацию:

? Тип сегмента и действия операционной системы с данным сегментом

? Расположение сегмента в файле

? Стартовый адрес сегмента в виртуальной памяти процесса

? Размер сегмента в файле

? Размер сегмента в памяти

? Флаги доступа к сегменту (запись, чтение, выполнение)

Часть сегментов имеет тип LOAD, предписывающий ядру при запуске программы на выполнение создать соответствующие этим сегментам структуры данных, называемые областями, определяющие непрерывные участки виртуальной памяти процесса и связанные с ними атрибуты. Сегмент, расположение которого в ELF-файле указано в соответствующем заголовке программы, будет отображен в созданную область, виртуальный адрес начала которой также указан в заголовке программы. К сегментам такого типа относятся, например, сегменты, содержащие инструкции программы (код) и ее данные. Если размер сегмента меньше размера области, неиспользованное пространство может быть заполнено нулями. Такой механизм, в частности используется при создании неинициализированных данных процесса (BSS). Подробнее об областях мы поговорим в главе 3.

В сегменте типа INTERP хранится программный интерпретатор. Данный тип сегмента используется для программ, которым необходимо динамическое связывание. Суть динамического связывания заключается в том, что отдельные компоненты исполняемого файла (разделяемые объектные файлы) подключаются не на этапе компиляции, а на этапе запуска программы на выполнение. Имя файла, являющегося динамическим редактором связей, хранится в данном сегменте. В процессе запуска программы на выполнение ядро создает образ процесса, используя указанный редактор связей. Таким образом, первоначально в память загружается не исходная программа, а динамический редактор связей. На следующем этапе динамический редактор связей совместно с ядром UNIX создают полный образ исполняемого файла. Динамический редактор загружает необходимые разделяемые объектные файлы, имена которых хранятся в отдельных сегментах исходного исполняемого файла, и производит требуемое размещение и связывание. В заключение управление передается исходной программе.

Наконец, завершает файл таблица заголовков разделов или секций (section). Разделы (секций) определяют разделы файла, используемые для связывания с другими модулями в процессе компиляции или при динамическом связывании. Соответственно, заголовки содержат всю необходимую информацию для описания этих разделов. Как правило разделы содержат более детальную информацию о сегментах. Так, например, сегмент кода может состоять из нескольких разделов, таких как хэш-таблица для хранения индексов используемых в программе символов, раздел инициализационного кода программы, таблица связывания, используемая динамическим редактором, а также раздел, содержащий собственно инструкции программы.

Мы еще вернемся к формату ELF в главе 3 при обсуждении организации виртуальной памяти процесса, а пока перейдем к следующему распространенному формату — COFF.

Данный текст является ознакомительным фрагментом.

Продолжение на ЛитРес

Формат ELF

Формат ELF Формат ELF имеет файлы нескольких типов, которые до сих пор мы называли по-разному, например, исполняемый файл или объектный файл. Тем не менее стандарт ELF различает следующие типы:1. Перемещаемый файл (relocatable file), хранящий инструкции и данные, которые могут быть

19.5 Обобщенный формат URL

19.5 Обобщенный формат URL Обобщая вышесказанное, отметим, что:? URL начинается с указания используемого протокола доступа.? Для всех приложений, кроме сетевых новостей и электронной почты, далее следует разделитель ://.? Затем указывается имя хоста сервера.? Наконец

3.3.1. Формат RSS

Формат чисел

Формат чисел Наконец-то добрались до формата чисел. Я уже не раз о нем упоминала, теперь разложу все по полочкам (хотя общий смысл вы уже могли понять).Числа в Excel могут отображаться в различных форматах. В этом разделе мы поговорим о том, какие существуют форматы чисел и как

5.2.3. Формат Cookie-Jar

5.2.3. Формат Cookie-Jar Формат cookie-jar используется программой fortune(1) для собственной базы данных случайных цитат. Он подходит для записей, которые представляют собой просто блоки неструктурированного текста. В качестве разделителя записей в данном формате применяется символ

5.2.6. Формат Windows INI

5.2.6. Формат Windows INI Многие программы в Microsoft Windows используют текстовый формат данных, подобный фрагменту, приведенному в примере 5.6. В данном примере необязательные ресурсы с именами account, directory, numeric_id и developer связываются с именованными проектами python, sng, f etchmail и py-howto. В записи

5.2.2. Формат RFC 822

5.2.3. Формат Cookie-Jar

5.2.3. Формат Cookie-Jar Формат cookie-jar используется программой fortune(1) для собственной базы данных случайных цитат. Он подходит для записей, которые представляют собой просто блоки неструктурированного текста. В качестве разделителя записей в данном формате применяется символ

5.2.4. Формат record-jar

5.2.4. Формат record-jar Разделители записей формата cookie-jar хорошо сочетаются с метаформатом RFC 822 для записей, образующих формат, который в данной книге называется "record-jar". Иногда требуется текстовый формат, поддерживающий множественные записи с различным набором явных имен

5.2.6. Формат Windows INI

5.2.6. Формат Windows INI Многие программы в Microsoft Windows используют текстовый формат данных, подобный фрагменту, приведенному в примере 5.6. В данном примере необязательные ресурсы с именами account, directory, numeric_id и developer связываются с именованными проектами python, sng, fetchmail и py-howto. В записи

Формат PDF

Формат PDF PDF расшифровывается как Portable Document Format (портативный формат документа). Этот формат был создан специально для ликвидации проблем с отображением информации в файлах. Его преимущество состоит в том, что, во-первых, документ, сохраненный в формате PDF, будет одинаково

14.5.3. Формат ячейки

14.5.3. Формат ячейки Формат задает, как будет отображаться значение ячейки. Формат тесно связан с типом данных ячейки. Тип задаете вы сами. Если вы ввели число, то это числовой тип данных. Excel сама старается определить формат по типу данных. Например, если вы ввели текст, то

Формат файлов

Формат файлов Когда пользователь начинает работу с каким-либо файлом, системе необходимо знать, в каком формате он записан и с помощью какой программы его нужно открывать. Например, если файл содержит обычный текст, то он может быть прочитан в любой текстовой программе

Формат MP3

Формат MP3 Формат MP3 был создан для распространения музыкальных файлов, сжатых кодеком MPEG 1 level 3. В настоящее время — самый популярный формат распространения музыки через Интернет, и не только. Поддерживается абсолютно всеми программами записи и обработки звука, за

Формат MP3

Формат MP3 Метод сжатия звука, а также формат сжатых звуковых файлов, предложенный международной организацией MPEG (Moving Pictures Experts Group – Экспертная группа по видеозаписи), основан на перцептуальном кодировании звука. Работы по созданию эффективных алгоритмов кодирования

Содержание

История


Структура ELF-файла с точки зрения компоновщика и системного загрузчика

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

Стандарт формата ELF различает несколько типов файлов:

  • Перемещаемый файл — хранит инструкции и данные, которые могут быть связаны с другими объектными файлами. Результатом такой связи может быть разделяемый объектный файл или исполняемый файл. К этому типу относятся объектные файлы статических библиотек.
  • Разделяемый объектный файл — также содержит инструкции и данные и может быть связан с другими перемещаемыми файлами и разделяемыми объектными файлами, в результате чего будет создан новый объектный файл, либо при запуске программы на выполнение операционная система может динамически связать его с исполняемым файлом программы, в результате чего будет создан исполняемый образ программы. В последнем случае речь идет о разделяемых библиотеках.
  • Исполняемый файл — содержит полное описание, позволяющее системе создать образ процесса. В том числе: инструкции, данные, описание необходимых разделяемых объектных файлов и необходимую символьную и отладочную информацию.

Формат

Структуру файла можно рассматривать с двух сторон: со стороны компоновщика (линкера) и со стороны загрузчика [Источник 2] . Любой файл состоит из:

Сегмент - это непрерывная область адресного пространства со своими атрибутами доступа. Сегмент кода имеет атрибут исполнения, а сегмент данных - атрибуты чтения и записи. В зависимости от типа сегмента величина выравнивания в памяти может варьироваться от 4h до 1000h байт (для архитектуры x86). В самом ELF-файле сегменты не выравниваются и хранятся плотно прижатыми друг к другу. Ближайший аналог - секции в PE-файлах Windows

Сегмент в ELF-файлах может быть разбит на одну или несколько частей - секций. Типичный кодовый сегмент состоит из секций .init (процедуры инициализации), .plt (секции связок), .text (основной код программы) и .finit (процедуры финализации).

В формате компоновки таблица заголовков программы не является обязательной, так как компоновщик игнорирует сегменты и работает только на уровне секций. Системный загрузчик, загружающий исполняемый ELF-файл в память, игнорирует секции и оперирует целыми сегментами. Компоновщик комбинирует секции с похожими атрибутами и оптимальным образом размещает их по сегментам при сборке файла. Также он помещает копию таблицы секций в исполняемый файл, несмотря на то, что системный загрузчик игнорирует таблицу секций. При этом облегчается работа отладчиков (например, GDB) и дизассемблеров (например, IDA Pro).


Заголовок файла

Заголовок файла (ELF Header) имеет фиксированное расположение в начале файла и содержит общее описание структуры файла и его основные характеристики, такие как: тип, версия формата, архитектура процессора, виртуальный адрес точки входа, размеры и смещения остальных частей файла.

Структура ELF-заголовка

Назначение элементов массива e_ident
Элемент Значение Описание
e_ident[0] '\x7f' Сигнатура
e_ident[1] 'E' Сигнатура
e_ident[2] 'L' Сигнатура
e_ident[3] 'F' Сигнатура
e_ident[4] 1 Размер слова: 0 - неизвестно, 1 - 32 бита, 2 - 64 бита
e_ident[5] 1 Порядок байт: 0 - неизвестно, 1 - little-endian, 2 - big-endian
e_ident[6] 1 Версия формата ELF: 0 - неизвестно, 1 - текущая версия
e_ident[7] 0 ОС и бинарный интерфейс, для Linux - 0
e_ident[8] 0 Версия бинарного интерфейса, для Linux - 0
e_ident[9] - e_ident[15] 0 Зарезервировано
Возможные значения поля e_type
Имя Значение Описание
ET_NONE 0 Отсутствие типа файла
ET_REL 1 Перемещаемый объектный файл
ET_EXEC 2 Исполняемый файл
ET_DYN 3 Динамическая библиотека
ET_CORE 4 Дамп памяти
ET_LOPROC 0xff00 Назначение зависит от процессора
ET_HIPROC 0xffff Назначение зависит от процессора

Таблица заголовков программы

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

  • Тип сегмента и действия операционной системы с данным сегментом.
  • Расположение сегмента.
  • Точка входа сегмента.
  • Размер сегмента.
  • Флаги доступа к сегменту (запись, чтение, выполнение).

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

Структура таблицы заголовков программы

Некоторые возможные значения поля p_type
Значение Символьное имя Описание
0 PT_NULL Неиспользуемая запись
1 PT_LOAD Сегмент программы, загружаемый в память
2 PT_DYNAMIC Информация для динамического связывания
3 PT_INTERP Загрузчик программ
4 PT_NOTE Дополнительная информация
5 PT_PHDR Информация о таблице заголовков программы

Таблица заголовков секций

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

Структура таблицы заголовков секций

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

Возможные значения поля sh_type
Значение Символьное имя Описание
0 SHT_NULL Пустой заголовок секции
1 SHT_PROGBITS Секции программы (например, код или данные)
2 SHT_SYMTAB Таблица символов
3 SHT_STRTAB Таблица строк
4 SHT_RELA Данные о перемещаемых адресах
5 SHT_HASH Хэш-таблица имен для динамического связывания
6 SHT_DYNAMIC Информация для динамического связывания
7 SHT_NOTE Дополнительная информация
8 SHT_NOBITS Признак того, что секция занимает место в адресном пространстве процесса
9 SHT_REL Дополнительные данные о перемещаемых адресах

Утилиты

Существует множество утилит для работы с файлами elf, основные из них содержатся в наборе программных инструментов GNU Binutils:

  • elfedit — обновляет заголовок файла ELF.
  • objdump — показывает информацию об объектных файлах (в том числе и ELF).
  • readelf — показывает подробную информацию о файле.
  • elfutils — предоставляет альтернативные инструменты для GNU Binutils только для Linux.
  • elfdump — команда для просмотра ELF информации в файле ELF, доступна в Solaris и FreeBSD.

Загрузка исполняемого файла в память


Карта памяти загруженного образа исполняемого файла

При загрузке исполняемого файла в память ELF-заголовок по-умолчанию проецируется по адресу 8048000h, который прописан в его заголовке [Источник 3] . Это базовый адрес загрузки, который может быть изменен на стадии компоновки. Все сегменты проецируются в память в соответствии с виртуальными адресами, прописанными в таблице сегментов, причем виртуальная проекция сегментов всегда непрерывна.

Начиная с адреса 40000000h располагаются совместно используемые библиотеки. Например, ld-linux.so, libm.so и libc.so (ближайший аналог в Windows - kernel32.dll, реализующая Win32 API). За вызов функций операционной системы напрямую отвечает прерывание INT 80h.

Последний гигабайт адресного пространства от адреса C0000000h занимают код и данные операционной системы, к которым можно обращаться посредством прерывания INT 80h или через разделяемые библиотеки. Стек находится в нижних адресах. Он начинается с базового адреса загрузки и увеличивается по направлению к нулевым адресам.

В вычислении , то формат исполняемых и Linkable ( ELF , ранее названный Extensible Linking Format ), является общим стандартом формат файла для исполняемых файлов, объектного кода , разделяемых библиотек , а также основных свалках . Впервые опубликованный в спецификации бинарного интерфейса приложения (ABI) версии операционной системы Unix под названием System V Release 4 (SVR4), а затем в стандарте интерфейса инструментов, он был быстро принят различными поставщиками систем Unix . В 1999 году он был выбран в качестве стандартного формата двоичных файлов для Unix и Unix-подобных систем на процессорах x86 проектом 86open .

По своей конструкции формат ELF является гибким, расширяемым и кроссплатформенным . Например, он поддерживает разные порядки следования байтов и размеры адресов, поэтому он не исключает какой-либо конкретный центральный процессор (ЦП) или архитектуру набора команд . Это позволило использовать его во многих операционных системах на различных аппаратных платформах .

СОДЕРЖАНИЕ

Макет файла

Каждый файл ELF состоит из одного заголовка ELF, за которым следуют данные файла. Данные могут включать:

  • Таблица заголовков программы, описывающая ноль или более сегментов памяти
  • Таблица заголовков разделов, описывающая ноль или более разделов
  • Данные, на которые ссылаются записи в таблице заголовка программы или таблице заголовка раздела


Структура файла ELF с выделенными ключевыми записями

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

00000000 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 | .ELF. |

00000010 02 00 3e 00 01 00 00 00 c5 48 40 00 00 00 00 00 | ..>. H@. |

Пример шестнадцатеричного дампа заголовка файла ELF

Заголовок файла

Заголовок ELF определяет, использовать ли 32- или 64-битные адреса. Заголовок содержит три поля, на которые влияет этот параметр и смещает другие поля, следующие за ними. Заголовок ELF имеет длину 52 или 64 байта для 32-битных и 64-битных двоичных файлов соответственно.

Заголовок ELF
Компенсировать Размер (байты) Поле Цель
32-битный 64-битный 32-битный 64-битный
0x00 4 от e_ident [EI_MAG0] до e_ident [EI_MAG3] 0x7F за которым следует ELF ( 45 4c 46 ) в ASCII ; эти четыре байта составляют магическое число .
0x04 1 e_ident [EI_CLASS] Этот байт установлен в 1 или 2 для обозначения 32- или 64-битного формата соответственно.
0x05 1 e_ident [EI_DATA] Этот байт установлен в значение 1 или 2 для обозначения малой или большой последовательности байтов соответственно. Это влияет на интерпретацию многобайтовых полей, начинающихся со смещения 0x10 .
0x06 1 e_ident [EI_VERSION] Установите 1 для исходной и текущей версии ELF.
0x07 1 e_ident [EI_OSABI] Определяет ABI целевой операционной системы .
Ценить ABI
0x00 Система V
0x01 HP-UX
0x02 NetBSD
0x03 Linux
0x04 GNU Hurd
0x06 Солярис
0x07 AIX
0x08 IRIX
0x09 FreeBSD
0x0A Tru64
0x0B Novell Modesto
0x0C OpenBSD
0x0D OpenVMS
0x0E Ядро NonStop
0x0F AROS
0x10 ОС Феникс
0x11 CloudABI
0x12 Stratus Technologies OpenVOS

Часто устанавливается 0 независимо от целевой платформы.

glibc 2.12+ в случае, если e_ident [EI_OSABI] == 3 обрабатывает это поле как ABI-версию динамического компоновщика : он определяет список функций динамического компоновщика, обрабатывает e_ident [EI_ABIVERSION] как уровень функций, запрашиваемый общим объектом (исполняемым или динамическим библиотека) и отказывается загружать ее, если запрашивается неизвестная функция, т. е. e_ident [EI_ABIVERSION] больше, чем самая большая известная функция.

Заголовок программы

Таблица заголовка программы сообщает системе, как создать образ процесса. Он находится по смещению файла e_phoff и состоит из записей e_phnum , каждая из которых имеет размер e_phentsize . Макет немного отличается в 32-битном ELF от 64-битного ELF, потому что p_flags находятся в другом месте структуры по причинам выравнивания. Каждая запись структурирована следующим образом:

Заголовок раздела

Инструменты

  • readelf - это двоичная утилита Unix, которая отображает информацию об одном или нескольких файлах ELF. Свободное программное обеспечение реализации обеспечивается GNU Binutils .
  • elfutils предоставляет альтернативные инструменты GNU Binutils исключительно для Linux.
  • elfdump - это команда для просмотра информации ELF в файле ELF, доступная в Solaris и FreeBSD .
  • objdump предоставляет широкий спектр информации о файлах ELF и других форматах объектов. objdump использует библиотеку дескрипторов двоичных файлов в качестве серверной части для структурирования данных ELF.
  • file Утилита Unix может отображать некоторую информацию о файлах ELF, включая архитектуру набора инструкций, для которой предназначен код в перемещаемом, исполняемом или совместно используемом объектном файле или на котором был создан дамп ядра ELF .

Приложения

Unix-подобные системы

Формат ELF заменил старые исполняемые форматы в различных средах. Он заменил форматы a.out и COFF в Unix-подобных операционных системах:

Принятие не-Unix

ELF также получил некоторое распространение в операционных системах, отличных от Unix, таких как:

  • OpenVMS в версиях Itanium и amd64
  • BeOS Revision 4 и более поздние версии для компьютеров на базе x86 (где он заменил формат Portable Executable ; версия PowerPC осталась с Preferred Executable Format )
  • Haiku , повторная реализация BeOS с открытым исходным кодом
  • Stratus VOS , в версиях PA-RISC и x86
  • Юбилейное обновление Windows 10 с использованием подсистемы Windows для Linux .

Игровые приставки

Некоторые игровые консоли также используют ELF:

PowerPC

Другие (операционные) системы, работающие на PowerPC , использующие ELF:

  • AmigaOS 4 , исполняемый файл ELF, заменил предыдущий Extended Hunk Format (EHF), который использовался на Amigas, оснащенных платами расширения процессора PPC.

Мобильные телефоны

Некоторые операционные системы для мобильных телефонов и мобильных устройств используют ELF:

  • Symbian OS v9 использует формат E32Image, основанный на формате файла ELF;
  • Sony Ericsson , например, W800i , W610 , W300 и т. Д.
  • Siemens , платформы SGOLD и SGOLD2: от Siemens C65 до S75 и BenQ-Siemens E71 / EL71 ;
  • Motorola , например, E398, SLVR L7 , v360, v3i (и все телефоны LTE2, к которым применен патч).
  • Bada , например, Samsung Wave S8500 .
  • Телефоны или планшеты Nokia с ОС Maemo или Meego, например Nokia N900 .
  • Android использует библиотеки ELF .so (общий объект) для собственного интерфейса Java . В среде выполнения Android (ART), которая используется по умолчанию с Android 5.0 «Lollipop» , все приложения при установке компилируются в собственные двоичные файлы ELF.

Характеристики

Standard Base Linux (LSB) дополняет некоторые из вышеупомянутых спецификаций для архитектур , в которых он указан. Например, это относится к System V ABI, AMD64 Supplement.

86открыто

86open был проектом по формированию консенсуса по общему формату двоичного файла для Unix и Unix-подобных операционных систем на общей архитектуре x86, совместимой с ПК , чтобы побудить разработчиков программного обеспечения перейти на эту архитектуру. Первоначальная идея заключалась в стандартизации небольшого подмножества Spec 1170, предшественника Single UNIX Specification , и библиотеки GNU C (glibc), чтобы позволить немодифицированным двоичным файлам работать в Unix-подобных операционных системах x86. Первоначально проект получил обозначение «Спец 150».

В конечном итоге был выбран формат ELF, в частности, реализация ELF в Linux, после того, как он оказался стандартом де-факто, поддерживаемым всеми вовлеченными поставщиками и операционными системами.

Группа начала обсуждения по электронной почте в 1997 году и впервые встретилась вместе в офисе Операции в Санта-Крус 22 августа 1997 года.

В руководящий комитет входили Марк Юинг , Дион Джонсон, Эван Лейбович, Брюс Перенс , Эндрю Роуч, Брайан Уэйн Спаркс и Линус Торвальдс . Другими участниками проекта были Кит Бостик , Чак Крэнор, Майкл Дэвидсон, Крис Дж. Деметриу, Ульрих Дреппер, Дон Даггер, Стив Гинзбург, Джон «Мэддог» Холл , Рон Холт, Джордан Хаббард , Дэйв Дженсен, Кин Джонстон, Эндрю Джози, Роберт Липе, Бела Лубкин, Тим Марсленд, Грег Пейдж, Рональд Джо Рекорд, Тим Ракл, Джоэл Сильверстайн, Чиа-пи Тьен и Эрик Троан. Представленные операционные системы и компании были 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 для приложений Linux .

Поскольку BSD долгое время поддерживали двоичные файлы Linux (через уровень совместимости ), а основные поставщики Unix x86 добавили поддержку этого формата, проект решил, что Linux ELF был форматом, выбранным отраслью, и «объявил [d] сам распущенный» на 25 июля 1999 г.

FatELF: универсальные двоичные файлы для Linux

FatELF - это расширение двоичного формата ELF, которое добавляет толстые двоичные возможности. Он предназначен для Linux и других Unix-подобных операционных систем. В дополнение к абстракции архитектуры ЦП ( порядок байтов , размер слова , набор команд ЦП и т. Д.) Существует потенциальное преимущество абстракции программной платформы, например двоичные файлы, которые поддерживают несколько версий ядра ABI . По состоянию на 2 марта 2021 года FatELF не интегрирован в основное ядро ​​Linux.

В современных POSIX-системах основным форматом исполняемых файлов, объектных файлов, динамических библиотек является формат ELF. Этот формат используется и на 32-битных (Elf32), и на 64-битных (Elf64) системах и для машин с порядком байт Little-endian, и для машин с порядком байт Big-endian. Далее приведено краткое описание формата Elf32. Формат Elf64 отличается размерами полей, содержащих виртуальные адреса, размеры и смещения в файле.

В описании формата будут использоваться типы данных [u]intN_t, где u является признаком беззнаковости, а N определяет размер типа, например, uint16_t. Эти типы определены в стандартном заголовочном файле stdint.h.

Все типы данных и константы описаны в заголовочном файле elf.h.

Заголовок файла

В начале файла (со смещения 0 от начала) идет заголовок ELF-файла, описываемый следующей структурой:

Структура определена таким образом, что поля структуры выровнены по естественным для данной архитектуры правилам выравнивания (то есть 16-битные поля располагаются по четным адресам, а 32-битные - по адресам кратным 4), а полный размер структуры кратен 4 байтам. 16- и 32-битные значения представлены в порядке байт, естественном для соответствующей архитектуры.

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

Элемент Значение Описание
e_ident[0] '\x7f' "Магическое" значение
e_ident[1] 'E' "Магическое" значение
e_ident[2] 'L' "Магическое" значение
e_ident[3] 'F' "Магическое" значение
e_ident[4] 1 Размер слова: 0 - неизвестно, 1 - 32, 2 - 64
e_ident[5] 1 Порядок байт: 0 - неизвестно, 1 - little-endian, 2 - big-endian
e_ident[6] 1 Версия формата ELF: 0 - неизвестно, 1 - текущая версия
e_ident[7] 0 ОС и бинарный интерфейс, для Linux - 0
e_ident[8] 0 Версия бинарного интерфейса, для Linux - 0
e_ident[9] - e_ident[15] 0 Зарезервировано

В дальнейшем будут приводиться значения констант для ОС Linux на архитектуре i386. За значениями констант для других операционных систем или архитектур обращайтесь к документации.

Поле e_type идентифицирует тип файла: 0 (неизвестно), 1 (объектный файл), 2 (исполняемый файл), 3 (разделяемая библиотека), 4 (core-файл).

Поле e_machine идентифицирует тип процессора: 0 (неизвестно), 3 (Intel 80386 и совместимые).

Поле e_version идентифицирует версию файла: 0 (недопустимая версия), 1 (текущая версия).

Поле e_entry определяет виртуальный адрес точки входа в программу. После загрузки программы в память управление передается на этот адрес.

Поле e_phoff задает смещение от начала файла до начала таблицы заголовков программы (program header table). Информация о таблице заголовков программы будет дана ниже.

Поле e_shoff задает смещение от начала файла до начала таблицы заголовков секций (program section table). Информация о таблице заголовков секций будет дана ниже.

Поле e_flags задает дополнительные процессорно-специфичные флаги. В настоящее время значение данного поля должно всегда быть 0.

Поле e_ehsize хранит размер заголовка ELF-файла. Его значение должно быть равно 52 (sizeof(Elf32_Ehdr)).

Поле e_phentsize хранит размер одной записи в таблице заголовков программы. Его значение должно быть 32 (sizeof(Elf32_Phdr)) или 0, если таблица заголовков программы пуста.

Поле e_phnum хранит количество записей в таблице заголовков программы.

Поле e_shentsize хранит размер одной записи в таблице заголовков секций. Его значение должно быть равно 40 (sizeof(Elf32_Shdr)) или 0, если таблица заголовков секций пуста.

Поле e_shnum хранит количество записей в таблице заголовков секций.

Поле e_shstrndx хранит индекс заголовка секции, которая хранит имена всех секций (см. ниже).

Таблица заголовков секций

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

Таблица заголовков секций представляет собой массив структур Elf32_Shdr. Количество элементов массива определяется полем e_shnum заголовка ELF-файла. Массив находится по смещению, хранящемуся в поле e_shoff. Элемент массива 0 зарезервирован и не используется для описания секций. Таким образом, описания секций находятся в элементах массива с индексами от 1 и до e_shnum - 1.

Структура Elf32_Shdr определена следующим образом:

Поле sh_name хранит индекс имени секции. Индекс имени - это смещение в данных секции, индекс которой задается в поле e_shstrndx заголовка ELF-файла. По этому смещению размещается строка, завершающаяся нулевым байтом, являющаяся именем секции.

Таким образом, чтобы получить имя секции необходимо выполнить следующие действия:

  • Загрузить заголовок секции, индекс которой хранится в поле e_shstrndx заголовка ELF-файла.
  • Загрузить тело соответствующей секции.
  • По смещению, заданному в поле sh_name относительно начала области памяти, в которую загружена секция, находится требуемая строка имени секции.

Поле sh_type хранит тип секции. Возможные значения поля перечислены ниже.

ЗначениеСимв. имяОписание
0 SHT_NULL Пустой заголовок секции. Значения всех прочих полей заголовка секции неопределены.
1 SHT_PROGBITS Секции программы (код или данные или что-либо еще).
2 SHT_SYMTAB Таблица символов (для объектных файлов или динамических библиотек).
3 SHT_STRTAB Таблица строк.
4 SHT_RELA Записи о перемещаемых адресах (relocations).
5 SHT_HASH Хеш-таблица имен для динамического связывания.
6 SHT_DYNAMIC Информация для динамического связывания.
7 SHT_NOTE Произвольная дополнительная информация.
8 SHT_NOBITS Секция не занимает место в файле, но занимает место в адресном пространстве процесса.
9 SHT_REL Записи о перемещаемых адресах.

Поле sh_flags хранит битовые флаги, описывающие дополнительные атрибуты.

ЗначениеСимв. константаОписание
1 SHF_WRITE Содержимое секции должно быть доступно на запись в адресном пространстве процесса.
2 SHF_ALLOC Для содержимого секции выделяется память в адресном пространстве процесса.
4 SHF_EXECINSTR Секция содержит инструкции процессора.

Флаги могут комбинироваться с помощью операции побитового или.

Поле sh_addr хранит адрес в виртуальном адресном пространстве процесса в случае, если секция загружается в виртуальное адресное пространство процесса.

Поле sh_offset хранит смещение от начала файла, по которому размещаются данные секции.

Поле sh_size хранит размер секции в байтах.

Поле sh_link хранит индекс другой секции (в некоторых специальных случаях).

Поле sh_info хранит дополнительную информацию о секции.

Поле sh_addralign хранит требование по выравниванию адреса начала секции в памяти. Значения 0 или 1 означают отсутствие требования по выравниванию. В противном случае значением поля должна быть степень 2. Например, секции, загружаемые в виртуальное адресное пространство процесса, как правило, выровнены по размеру страницы процессора (4096).

Поле sh_entsize хранит размер одной записи, если секция хранит таблицу из записей фиксированного размера.

Таблица заголовков программы

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

Таблица заголовков программы представляет собой массив структур Elf32_Phdr. Массив размещается по смещению от начала файла, которое хранится в поле e_phoff заголовка ELF-файла, а количество элементов массива хранится в поле e_phnum заголовка ELF-файла.

Структура Elf32_Phdr определена следующим образом.

Поле p_type хранит тип заголовка. Некоторые возможные значения типа заголовка приведены в таблице ниже.

ЗначениеСимв. константаОписание
0 PT_NULL Обозначает не используемую запись
1 PT_LOAD Сегмент программы, загружаемый в память
2 PT_DYNAMIC Информация для динамического связывания
3 PT_INTERP Загрузчик программ
4 PT_NOTE Дополнительная информация
6 PT_PHDR Информация о самой таблице заголовков программы
7 PT_TLS Thread-local storage

Поле p_offset хранит смещение от начала файла, по которому располагается данный сегмент.

Поле p_vaddr хранит виртуальный адрес начала сегмента в памяти.

Значение поля p_paddr должно быть равно 0.

Поле p_filesz хранит размер сегмента в файле (может быть 0).

Поле p_memsz хранит размер сегмента в памяти (может быть 0).

Поле p_flags хранит флаги доступа к сегменту в памяти (могут объединяться с помощью побитового "или").

ЗначениеСимв. константаОписание
1 PT_X Сегмент доступен на выполнение
2 PT_W Сегмент доступен на запись
4 PT_R Сегмент доступен на чтение

Сегмент PT_NOTE

В сегменте ELF-файла с типом PT_NOTE хранится дополнительная информация о состоянии выполнения программы. Сегмент сам содержит произвольное количество записей произвольного размера. Сегмент всегда имеет размер, кратный 4 байтам (для Elf32), и каждая запись в сегменте начинается со смещения, кратного 4 байтам. В начале каждой записи находится заголовок записи, описываемый следующей структурой:

Поле n_namesz содержит длину названия записи. Название должно быть непустой строкой, завершающейся байтом 0. Сама строка названия записи начинается сразу же после структуры Elf32_Nhdr.

Поле n_descsz содержит длину информационной части записи. Длина должна быть кратна 4 байтам. Информационная часть записи начинается сразу после названия записи с учетом выравнивания по границе 4 байт.

Поле n_type содержит тип записи. Возможные типы записи зависят от типа файла (объектный, core) и рассматриваются в соответствующих разделах.

Ниже приведен пример сегмента PT_NOTE.

См. от началаЗначениеКомментарий
0x00000x070x000x000x00n_namesz == 7
0x00040x080x000x000x00n_descsz == 8
0x00080x010x000x000x00n_type == 1
0x000c'G''N''U''D'имя записи: "GNUDBG"
0x0010'B''G''\0'0x00
0x00140x010x020x030x04информация: 0x04030201 0x08070605
0x00180x050x060x070x08

core-файлы

core-файл - это ELF-файл, у которого значение поля e_type заголовка равно ET_CORE (4). В core-файле таблица заголовков секций пуста, а таблица заголовков программ состоит из записей типа PT_LOAD, хранящих содержимое адресного пространства процесса на момент завершения работы процесса, и записи типа PT_NOTE, хранящей состояние процесса на момент завершения работы процесса.

Для тестового файла sample.core содержимое таблицы заголовков программ имеет следующий вид.

p_typep_flagsp_offsetp_vaddrp_fileszp_memszp_align
PT_NOTE---0x000002340x00000000121600
PT_LOADr-x0x000010000x08048000409681924096
PT_LOADrw-0x000020000x0804a000409640964096
PT_LOADrw-0x000030000x085420001351681351684096
PT_LOADr-x0x000240000x4f2d000040961269764096
PT_LOADr--0x000250000x4f2ef000409640964096
PT_LOADrw-0x000260000x4f2f0000409640964096
PT_LOADr-x0x000270000x4f2f7000409617489924096
PT_LOAD---0x000280000x4f4a2000040964096
PT_LOADr--0x000280000x4f4a3000819281924096
PT_LOADrw-0x0002a0000x4f4a5000409640964096
PT_LOADrw-0x0002b0000x4f4a600012288122884096
PT_LOADrw-0x0002e0000xb778a000409640964096
PT_LOADrw-0x0002f0000xb77a1000819281924096
PT_LOADr-x0x000310000xb77a3000409640964096
PT_LOADrw-0x000320000xbfe6d0001392641392644096

Первый сегмент (сегмент PT_NOTE) содержит информацию о состоянии процесса на момент создания core-файла.

Для core-файлов возможны следующие значения поля n_type (в таблице ниже перечислены не все возможные значения).

ЗначениеСимв. константаОписание
1 NT_PRSTATUS Информационная часть записи имеет тип prstatus_t
2 NT_FPREGSET Информационная часть записи имеет тип prfpregset_t
3 NT_PRPSINFO Информационная часть записи имеет тип prpsinfo_t

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

Структура prstatus_t определена следующим образом:

Тип elf_gregset_t определен следующим образом:

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

индексрегистр
0ebx
1ecx
2edx
3esi
4edi
5ebp
6eax
7ds
8es
9fs
10gs
11orig_eax
12eip
13cs
14eflags
15sp
16ss

Формат отладочной информации stabs

При компиляции в исполняемый файл может добавляться отладочная информация, которую отладчик использует для отображения хода исполнения программы в терминах языка высокого уровня. Существует несколько форматов отладочной информации (STABS, DWARF), здесь описывается формат STABS как самый простой.

Для компиляции программы с добавлением отладочной информации в формате STABS используется опция gcc -gstabs, например

В формате STABS отладочная информация хранится в секциях .stab и .stabstr ELF-файла.

Секция .stab содержит массив структур:

Секция .stabstr хранит символьные строки, завершающиеся байтом 0, которые используются в записях в секции .stab.

Поле n_type хранит тип записи. Возможные типы записей можно найти в stab.h, нас будут интересовать только некоторые из них.

Каждой единице компиляции соответствуют две записи N_SO. Первая запись находится в начале описания единицы компиляции и содержит ее имя в поле n_strx и адрес первой инструкции в поле n_value. Вторая запись находится в конце описания единицы компиляции и содержит нулевое значение (пустая строка) в поле n_strx и адрес непосредственно следующий за концом кода данной единицы компиляции в поле n_value.

Записи N_SLINE упорядочены по смещениям внутри функции.

Первая запись в таблице .stab является служебной и имеет тип N_UNDF. Индекс этой записи полагается равным 0.

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

Как обычно, предполагается, что все диапазоны адресов и значений включают в себя нижнее значение, но не включают в себя верхнее значение, то есть имеют вид [low;high).

Имя файла, в котором располагается функция, может находиться в записи N_SOL после записи N_FUN самой функции, но до первой записи N_SLINE. Следует полагать, что имя файла, в котором определена функция совпадает с именем файла, установленному до первой записи N_SLINE в данной функции.

Читайте также: