ei_magic - постоянное значение для всех ELF файлов, равное { 0x7f, 'E', 'L', 'F'} ei_class - класс ELF файла (1 - 32 бита, 2 - 64 бита который мы не рассматриваем) ei_data - определяет порядок следования байт для данного файла (этот порядок зависит от платформы и может быть прямым (LSB или 1) или обратным (MSB или 2)) Для процессоров Intel допустимо только значение 1. ei_version - достаточно бесполезное поле, и если не равно 1 (EV_CURRENT) то файл считается некорректным. В поле ei_pad операционные системы хранят свою идентификационную информацию. Это поле может быть пустым. Для нас оно тоже не важно.
Поле заголовка e_type может содержать несколько значений, для выполняемых файлов оно должно быть ET_EXEC равное 2 e_machine - определяет процессор на котором может работать данный выполняемый файл (Для нас допустимо значение EM_386 равное 3) Поле e_version соответствует полю ei_version из заголовка. Поле e_entry определяет стартовый адрес программы, который перед стартом программы размещается в eip. Поле e_phoff определяет смещение от начала файла, по которому располагается таблица программных секций, используемая для загрузки программ в память. Не буду перечислять назначение всех полей, не все нужны для загрузки. Лишь еще два опишу. Поле e_phentsize определяет размер записи в таблице программных секций. И поле e_phnum определяет количество записей в таблице программных секций.
Таблица секций (не программных) используется для линковки программ. мы ее рассматривать не будем. Так же мы не будем рассматривать динамически линкуемые модули. Тема эта достаточно сложная, для первого знакомства не подходящая. :)
Теперь про программные секции. Формат записи таблицы программных секций таков:
p_type - определяет тип программной секции. Может принимать несколько значений, но нас интересует только одно. PT_LOAD (1). Если секция именно этого типа, то она предназначена для загрузки в память. p_offset - определяет смещение в файле, с которого начинается данная секция. p_vaddr - определяет виртуальный адрес, по которому эта секция должна быть загружена в память. p_paddr - определяет физический адрес, по которому необходимо загружать данную секцию. Это поле не обязательно должно использоваться и имеет смысл лишь для некоторых платформ. p_filesz - определяет размер секции в файле. p_memsz - определяет размер секции в памяти. Это значение может быть больше предыдущего. Поле p_flag определяет тип доступа к секциям в памяти. Некоторые секции допускается выполнять, некоторые записывать. Для чтения в существующих системах доступны все.