Как правило, после компоновки формат файла ELF предоставляет всю необходимую информацию для загрузчиков, чтобы загрузить программу в память и запустить ее.
Каждый фрагмент кода и данных помещается в пределах смещения внутри раздела, такого как раздел данных, текстовый раздел и т. Д., И доступ к определенной функции или глобальной переменной осуществляется путем добавления правильного смещения к начальному адресу раздела.
Теперь формат файла ELF также включает таблицу заголовков программ:
Таблица заголовка программы исполняемого файла или файла общего объекта представляет собой массив
структур, каждая из которых описывает сегмент или другую информацию,
Система должна подготовить программу к исполнению. Объектный файл
сегмент содержит один или несколько разделов , как описано в разделе «Сегмент»
Содержание».
Эти структуры затем используются загрузчиком ОС для загрузки изображения в память. Структура:
typedef struct {
Elf32_Word p_type;
Elf32_Off p_offset;
Elf32_Addr p_vaddr;
Elf32_Addr p_paddr;
Elf32_Word p_filesz;
Elf32_Word p_memsz;
Elf32_Word p_flags;
Elf32_Word p_align;
} Elf32_Phdr;
Обратите внимание на следующие поля:
p_vaddr
Виртуальный адрес, по которому первый байт сегмента находится в памяти
p_offset
Смещение от начала файла, в котором первый байт
сегмент находится.
А p_type
Вид сегмента, который описывает этот элемент массива, или как интерпретировать информацию элемента массива. Типовые значения и их значения указаны в таблице 7-35.
Из таблицы 7-35, примечание PT_LOAD
:
Определяет загружаемый сегмент , описываемый p_filesz и p_memsz.
байты из файла отображаются в начало сегмента памяти.
Если размер памяти сегмента (p_memsz) больше, чем размер файла
(p_filesz), дополнительные байты определены для хранения значения 0 и
следуйте инициализированной области сегмента. Размер файла не может быть больше
чем объем памяти. Загружаемые записи сегмента в заголовке программы
таблицы отображаются в порядке возрастания, отсортированы по элементу p_vaddr.
Таким образом, просматривая эти поля (и более), загрузчик может найти сегменты (которые могут содержать несколько разделов) в файле ELF и загрузить их (PT_LOAD
) в память по заданному виртуальному адресу.
Теперь можно ли изменить виртуальный адрес сегмента файла ELF во время выполнения (время загрузки)? да:
Виртуальные адреса в заголовках программы могут не представлять
фактические виртуальные адреса памяти программы . Смотрите "Программа"
Загрузка (зависит от процессора) ".
Таким образом, заголовок программы содержит сегменты, которые загрузчик ОС будет загружать в память (загружаемые сегменты, которые содержат загружаемые разделы), но виртуальные адреса, которые загружает их загрузчик, могут отличаться от адресов в файле ELF.
Как?
Чтобы понять это, давайте сначала прочитаем о Base Address
Исполняемые и совместно используемые объектные файлы имеют базовый адрес , который является
минимальный виртуальный адрес, связанный с образом памяти
объектный файл программы. Одно использование базового адреса - переместить
память образ программы при динамическом связывании.
Вычисляется базовый адрес исполняемого файла или файла общего объекта
при выполнении из трех значений: адрес загрузки памяти,
максимальный размер страницы и минимальный виртуальный адрес программы
загружаемый сегмент. Виртуальные адреса в заголовках программы могут
не представляют действительные виртуальные адреса памяти программы
изображение . См. «Загрузка программы (зависит от процессора)».
Итак, практика следующая:
независимый от позиции код . Этот код включает виртуальный сегмент
изменение адреса от одного процесса к другому без аннулирования
поведение при исполнении.
Хотя система выбирает виртуальные адреса для отдельных процессов,
он поддерживает относительные позиции сегментов. Так какпозиционно-независимый код использует относительную адресацию между сегментами, разница между виртуальными адресами в памяти должна совпадать с разницей между виртуальными адресами в файле .
Таким образом, используя относительную адресацию, (PIE- позиционно-независимый исполняемый файл) фактическое размещение может отличаться от адреса в файле ELF.
От ответа PeterCordes
:
0x400000
- база Linux по умолчаниюадрес для загрузки исполняемых файлов PIE с отключенным ASLR (как GDB делает по умолчанию).
Так что для вашего конкретного случая (исполняемый файл PIE в Linux) загрузчик выбирает этот base address
.
OfНезависимо от позиции курса это просто вариант.Программа может быть скомпилирована без нее, и тогда имеет место режим абсолютной адресации, в котором не должно быть разницы между адресом сегмента в ELF и реальным адресом памяти, сегмент которого загружен в:
Исполняемый файлСегменты файла обычно содержат абсолютный код.Для правильного выполнения процесса сегменты должны находиться по виртуальным адресам, используемым для создания исполняемого файла. Система использует значения p_vaddr без изменений в качестве виртуальных адресов .
Я бы порекомендовал вам взглянуть на реализацию linux загрузки изображений elf здесь ,и эти два потока SO здесь и здесь .
Абзацы взяты из документов Oracle ELF ( здесь и здесь )