Описание заголовка EXE файла.
Программа в формате EXE (MS-DOS) состоит из заголовка и самого загрузочного модуля. Заголовок содержит необходимую информацию для загрузки программы в память и специальную таблицу, необходимую для настройки ссылок на дальние сегменты программы (relocation table - таблица перемещения). Дело в том, что при создании COM программы весь код программы находится в одном сегменте. Чтобы такая программа корректно работала, ей не нужно знать, в каком сегменте располагается её код, имеет значение лишь адрес внутри сегмента (смещение). В EXE программе кодовых сегментов может быть несколько и для обращения к коду другого сегмента (например, дальний вызов процедуры) нужно знать не только смещение внутри этого сегмента, но и его сегментный адрес. Но программа, не загруженная в память, не может знать этот сегментный адрес, так как заранее не известно, в какое место памяти операционная система поместит код программы, прочитанный из EXE файла. Например, операционная система может поместить код программы начиная с сегментного адреса 0x1000 (64Кб) или с 0x2000 (128Кб) и т.д. Для решения этой проблемы и служит таблица перемещения. Каждый элемент таблицы состоит из 2-х слов (4 байта). Первое определяет смещение относительно начала загрузочного модуля, а второе - сегмент. При загрузке программы в память COMMAND.COM выполняет следующие действия:
1. Считывает код программы в память. 2. Вычисляет адрес (START_SEG + RELO_SEG):(OFFS), где START_SEG - сегмент, начиная с которого код программы располагается в памяти, RELO_SEG - сегмент, прописанный в элементе таблицы, OFFS - смещение, прописанное в элементе таблицы. 3. Извлекает слово по ранее вычисленному адресу и прибавляет к нему значение START_SEG. 4. Записывает это слово по вычисленному адресу. |
Шаги 2 - 4 выполняются столько раз, сколько элементов содержит таблица. Теперь все ссылки на дальние сегменты получили корректное значение и программа может начинать выполняться. Следующая таблица определяет функции элементов заголовка EXE файла и их смещения. Размер каждого элемента заголовка - 2 байта.
Смещение (в байтах) | Назначение |
0x00 | Шестнадцатеричное 0x4D5A. Компоновщик устанавливает это значение для идентификации правильного EXE файла. |
0x02 | Число байт в последнем блоке EXE файла (остаток от деления размера EXE файла на размер блока). |
0x04 | Число блоков по 512 байт EXE файла, включая заголовок. |
0x06 | Число элементов в таблице перемещения. |
0x08 | Число шестнадцатибайтовых блоков (параграфов) в заголовке. Необходимо для определения начала исполняемого модуля (кода программы) в EXE файле. |
0x0A | Минимальное число параграфов, которые должны находиться в памяти после загрузки программы. |
0x0C | Флаг загрузки в младшие или старшие адреса. Значение 0xFFFF означает загрузку в младшие адреса памяти, 0x0000 - в старшие. |
0x0E | Относительный адрес сегмента стека в выполняемом модуле. |
0x10 | Относительный адрес, который загрузчик помещает в регистр SP (адрес дна стека) перед передачей управления загруженной программе. |
0x12 | Контрольная сумма - сумма всех слов в файле без учёта переполнений. Может использоваться для проверки корректности данных файла, но обычно не используется и равна 0x0000. |
0x14 | Относительный адрес, который загрузчик помещает в регистр IP перед передачей управления загруженной программе. |
0x16 | Относительный адрес кодового сегмента в выполняемом модуле (это значение помещается в регистр CS). |
0x18 | Смещение таблица перемещения относительно начала EXE файла. |
0x1A | Номер оверлейного фрагмента. Нуль означает, что заголовок относится к главному модулю. |
0x1C | Таблица перемещения (см. выше). |
Для оверлейных EXE файлов, размер которых может быть больше объёма свободной памяти, да и вообще более 640Кб, заголовок определяет параметры той части загрузочного модуля, которая непосредственно загружается в память после того, как имя EXE файла вводится с командной строки. Остальная часть загрузочного модуля может подгружаться им самим в процессе работы программы.