Структура файла
Win32Asm Tutorial |
назад | 6- Структура файла | вперед |
6.0 - Структура файла
Исходные файлы разделены на секции, такие как код, данные, неинициализированные данные, константы, ресурс и смещение. Секция ресурса создается из файла ресурсов, подробнее об этом я расскажу позже. Секция смещений не важна для нас (она содержит информацию, PE-загрузчика, чтобы он мог загрузить программу в любое место в памяти). Важные секции это код, данные, неинициализированные данные и константы. Секция кода содержит, рабочий код программы. Секция данных содержит данные, доступные для чтения и записи. Вся секция данных включается в exe файл и может быть инициализирована данными.
Неинициализированные данные не имеют никакого содержания при запуске, и даже не включены в exe файл непосредственно, это только часть памяти, зарезервированной windows. Эта секция доступна для чтения и записи. Секция констант такае же как секция данных, но доступна только для чтения. Хотя эта секция может использоваться для констант, проще и быстрее объявлять константы в файлах для включения, и использовать их как непосредственные значения.
6.1 Идентификаторы секций
В ваших исходных файлах (*.asm), вы объявляете секции:
.code ; начало секции кода
.data ; начало секции данных
.data? ; начало секции неинициализированных данных
.const ; начало секции констант
Исполняемые файлы (*.exe, *.dll и другие) (в win32) это файлы в PE формате. Я не буду подробно объяснять о нем, а раскажу только о некоторых важных вещах. Разделы определены в PE-заголовке с некоторыми характеристиками:
Название секции, RVA, offset, raw size, virtual size и флаги.
RVA (relative virtual address) - PE-загрузчик использует значение в этом поле, когда загружает секцию в память. Если значение в этом поле равняется 1000h, а файл файл загружен в 400000h, секция будет загружена в 401000h.
Offset это файловое смещение на начало секции. PE-загрузчик использует это значение для того, чтобы найти ее начало.
Raw size это размер секции, выравненный согласно установкам в PE-заголовке. PE-загрузчик проверяет это значение, чтобы знать, сколько байт он должен загрузить в память.
Virtual size это размер, занимаемый в памяти.
Флаги определяют характеристики (только чтение/запись/исполняемый и т.д.).
6.2 Пример программы
Имеется пример программы:
.data
Number1 dd 12033h
Number2 dw 100h,200h,300h,400h
Number3 db "blabla",0
.data?
Value dd ?
.code
mov eax, Number1
mov ecx, offset Number2
add ax, word ptr [ecx+4]
mov Value, eax
Эта программа не будет транслирована, но это не важно.
В секции данных (.data) есть 3 метки: Number1, Number2, Number3. Эти метки используются как указатели на то место в программе, где они расположены.
Директивы db, dw и dd используются для определения и инициализации основных единиц памяти, байт (db), слово (dw) и двойное слово (dd), на которую будет указывать метка стоящая перед этой директивой. Метка заменяет численное значение адреса распределенных единиц памяти символическим именем.
С директивой db, вы также можете определить строку, потому, что строка это фактически порядок байт, соответствующих символам в строке.
Секция данных (из примера выше) в памяти будет выглядеть вот-так: 33,20,01,00,00,01,00,02,00,03,00,04,62,6c,61,62,6c,61,00
(все числа шестнадцатиричные)
Я выделил цветами некоторые числа. Метка Number1 указывает на место в памяти, где синий байт 33, метка Number2 указывает на место в памяти, где красный 00, Number3 на зеленый 62.
Теперь, если вы мспользуете это в своей программе:
mov ecx, Number1
Это фактически будет означать:
mov ecx, dword ptr [место в памяти, где расположена dword 12033h]
А это:
mov ecx, offset Number1
означает:
mov ecx, место в памяти, где расположена dword 12033h
В первом примере, ecx получит значение, которое находится в памяти указанной меткой Number1. Во втором, ecx станет указателем на то место в памяти, на которое указывает метка Number1.
Эти два примера ниже, имеют тот же самый эффект:
(1)
mov ecx, Number1
(2)
mov ecx, offset Number1
mov ecx, dword ptr [ecx] ( или mov ecx, [ecx])
Давайте вернемся к примеру:
.data
Number1 dd 12033h
Number2 dw 100h,200h,300h,400h
Number3 db "blabla",0
.data?
Value dd ?
.code
mov eax, Number1
mov ecx, offset Number2
add ax, word ptr [ecx+4]
mov Value, eax
Метки Value может использоваться точно так же как Number1, Number2 и Number3, но при запуске она будет содержать 0, потому что она находится в секции неинициализированных данных. Преимущество этого в том, что все, что вы определяете в секции .data? не будет включено в исполнимый файл, а будет только в памяти.
.data?
ManyBytes1 db 5000 dup (?)
.data
ManyBytes2 db 5000 dup (0)
(5000 dup означает: 5000 копий. Value db 4,4,4,4,4,4,4 это тоже самое, что Value db 7 dup (4).)
ManyBytes1 не будет находится непосредственно в исполнимом файле, а только зарезервирует 5000 байт в памяти. А ManyBytes2 будет полностью вложена в испонимый файл, делая его на 5000 байт больше. Таким образом ваш файл будет содержать 5000 нулей, а это не рационально.
Секция кода (.code) будет ассемблирована (преобразованна в коды) и помещена в исполнимый файл.
[наверх]