2014-02-20 3 views
3

Я пытаюсь понять формат ELF, и прямо сейчас есть некоторые вещи, которые я не получаю о сегментах, определенных в заголовке программы. У меня есть этот небольшой код, который я конвертировать в файл ELF с г ++ (x86_x64 на Linux):Размеры и смещения сегментов заголовка ELF

#include <stdlib.h> 
#include <iostream> 

using namespace std; 

int main(int argc, char *argv[]) 
{ 
    if (argc == 1) 
    { 
     cout << "Hello world!" << endl; 
    } 
    return 0; 
} 

С g++ -c -m64 -D ACIS64 main.cpp -o main.o и g++ -s -O1 -o Main main.o. Теперь, с readelf Я получаю этот список сегментов:

Program Headers: 
Type   Offset    VirtAddr   PhysAddr 
       FileSiz   MemSiz    Flags  Align 
PHDR   0x0000000000000040 0x0000000000400040 0x0000000000400040 
       0x00000000000001f8 0x00000000000001f8 R E  8 
INTERP   0x0000000000000238 0x0000000000400238 0x0000000000400238 
       0x000000000000001c 0x000000000000001c R   1 
[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2] 
LOAD   0x0000000000000000 0x0000000000400000 0x0000000000400000 
       0x0000000000000afc 0x0000000000000afc R E  200000 
LOAD   0x0000000000000df8 0x0000000000600df8 0x0000000000600df8 
       0x0000000000000270 0x00000000000003a0 RW   200000 
DYNAMIC  0x0000000000000e18 0x0000000000600e18 0x0000000000600e18 
       0x00000000000001e0 0x00000000000001e0 RW   8 
NOTE   0x0000000000000254 0x0000000000400254 0x0000000000400254 
       0x0000000000000044 0x0000000000000044 R   4 
GNU_EH_FRAME 0x00000000000009a4 0x00000000004009a4 0x00000000004009a4 
       0x0000000000000044 0x0000000000000044 R   4 
GNU_STACK  0x0000000000000000 0x0000000000000000 0x0000000000000000 
       0x0000000000000000 0x0000000000000000 RW   10 
GNU_RELRO  0x0000000000000df8 0x0000000000600df8 0x0000000000600df8 
       0x0000000000000208 0x0000000000000208 R   1 

С Bless Hex Editor Я смотрю на коде и попытаться найти каждую из этих сегментов.

  • Я нахожу сегмент PHDR сразу после заголовка ELF и имеющий размер всего этого заголовка программы. Он имеет 8 байтов и читается/исполняется. [!] Я не понимаю, почему исполняемый файл. PHDR

  • Я нахожу сегмент, где объявляется переводчик сразу после PHDR. Он имеет размер пути интерпретатора и выравнивание 1 байта. Правильное
    INTERP

  • Теперь у меня есть сегмент, который является читаемым и исполняемый файл, который [!] Я полагаю, сегмент кода. Я не понимаю, почему он начинается с 0x0000000000000000. Разве это не должно начинаться там, где находится точка входа? Почему он имеет размер 0xafc байт? Разве размер не только размера кода? Какая часть файла является исполняемым? Кроме того, я не понимаю, почему выравнивание составляет 0x200000 байт. Разве это пространство зарезервировано для сегмента LOAD в памяти?. Это где заканчивается этот сегмент и amout 764 0x0 байт следует за ним:
    LOAD1

  • Следующий (чтение и запись) Я полагаю, это сегмент, где переменные хранятся [!]. Он заканчивается только там, где что-то вроде заголовка разделов может начинаться.
    LOAD2
  • Теперь следующий заголовок DYNAMIC. Он начинается с 0xe18, который находится внутри одного выше. [!] Я думал, что это сегмент, где хранятся ссылки на внешние функции и переменные, но я не уверен. Он доступен для чтения и записи. Я просто не знаю, что сегмент это и почему это «внутри» сегмент НАГРУЗКИ выше DYNAM
  • ПРИМЕЧАНИЕ сегмент, содержащий некоторую информацию, что я полагаю, не важно прямо сейчас
  • GNU конкретные сегменты, один из них имеют любые смещения и размеры, равные 0x0000000000000000, другие вмешиваются в другие сегменты, которых я тоже не получаю.

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

ответ

5

Выход readelf отображает таблицу заголовков программ. Он содержит список сегментов (которые могут быть загружаемыми или не загружаемыми) в файле ELF.Обычно сегмент содержит другие сегменты, как показано здесь.

Я нахожу сегмент PHDR сразу после заголовка ELF и имеет размер всего этого заголовка программы. Он имеет выравнивание 8 байтов и является читаемым/исполняемым. [!] Я не понимаю, почему исполняемый файл.

Если вы внимательно прочитали вывод readelf, вы заметите, что PHDR на самом деле является частью сегмента кода (обратите внимание на поля VirtAddr и MemSiz). Это объясняет, почему он разделяет те же разрешения, что и сегмент кода (RX).

Теперь у меня есть сегмент, который является читаемым и исполняемым, который [!] I предположим, является сегментом кода. Я не понимаю, почему он начинается с 0x0000000000000000. Не следует ли начинать, где находится точка входа ? Почему он имеет размер 0xafc байт? Разве только размер размер кода? Какая часть файла является исполняемым? Кроме того, I не понимают, почему выравнивание составляет 0x200000 байт. Это то, что зарезервировано для сегмента LOAD в памяти ?. Это где это сегмент заканчивается и amout 764 0x0 байт следует за ним:

Да, это сегмент кода. Он начинается в начале файла (т. Е. Смещение 0) и продолжается до 0xafc байтов в файле. Заголовок указывает, что эта часть файла сопоставляется с 0x0000000000400000 в памяти при загрузке ELF. Сегмент не только состоит из основного() из файла C++, но и другого исполняемого файла также добавляется компилятором. Выравнивание только указывает, где должен начинаться следующий сегмент, а не размер сегмента. Загружаемые сегменты должны иметь согласованные значения полей VirtAddr и PhysAddr по модулю размера страницы (или выравнивать поле, если Align! = 0 & & Выравнивание! = 1). Это объясняет, почему VirtAddr для сегмента данных 0x0000000000600df8 (0x0000000000600df8 - 0x0000000000000df8% 0x200000 == 0). Область в файле между текстовым сегментом и сегментом данных (то есть между 0xafc и 0xdf8) заполняется нулями.

Следующий (доступен для чтения и записи) [!] Я полагаю, что это сегмент, где хранятся переменные . Он заканчивается только там, где может начинаться нечто вроде разделов .

Правильно, это сегмент данных, в котором хранятся глобальные и статические переменные (среди прочего). Он заканчивается непосредственно перед заголовками раздела.

Теперь следующий заголовок DYNAMIC. Он начинается с 0xe18, то есть внутри одного выше. [!] Я думал, что это сегмент, где хранятся ссылки на внешние функции и переменные, но я не уверен. Он доступен для чтения и записи. Я просто не знаю, что сегмент этого и почему это «внутри» сегмент НАГРУЗКИ выше

Точно так же как сегмент PHDR является частью сегмента кода, DYNAMIC сегмент является частью сегмента данных , Вот почему одни и те же разрешения (RW). Он содержит .dynamic раздел, который содержит массив структур, таких как адреса символов и строковых таблиц.

GNU конкретные сегменты, один из них имеет какие-либо смещения и размеры равны в 0x0000000000000000, другие вмешательства в другие сегменты, которые я не получают, либо.

GNU_EH_FRAME является частью сегмента кода, а GNU_RELRO является частью сегмента данных (см. Поля VirtAddr и MemSiz). GNU_STACK - это просто заголовок программы, который сообщает системе, как управлять стеком, когда ELF загружается в память. (FileSiz и MemSiz равны 0).

Ссылки:

  1. ELF File format specification
  2. Linkers и погрузчики, Джон Р. Левина
+0

Гораздо яснее. Это действительно помогло. Спасибо. – ali

Смежные вопросы