Ответ 1
Мне всегда нравилось полное объяснение Samael в следующем потоке:
Объяснение директивы ALIGN MASM, как эта директива интерпретируется компилятором?
Цитата:
1. ИСПОЛЬЗОВАНИЕ
ALIGN X
Директива ALIGN сопровождается числом (X).
Это число (X) должно быть степенью 2. Это 2, 4, 8, 16 и т.д.
Директива позволяет вам принудительно выполнить выравнивание инструкции или данных сразу после директивы по адресу памяти, который кратен значению X.
Дополнительное пространство между предыдущей инструкцией/данными и после директивы ALIGN дополняется инструкциями NULL (или эквивалентными, например MOV EAX, EAX) в случае сегментов кода, и NULL в случае сегментов данных.
Число X не может быть больше, чем выравнивание по умолчанию сегмента, на который ссылается директива ALIGN. Он должен быть меньше или равен стандартным выравниваниям сегмента. Подробнее об этом следовать...
2. ЦЕЛЬ
а. Работа с кодом
Если директива предшествует коду, причиной будет оптимизация (со ссылкой на скорость выполнения). Некоторые инструкции выполняются быстрее, если они выровнены на границе 4 байта (32 бита). Такой вид оптимизации обычно можно использовать или ссылаться на критически важные функции, такие как циклы, которые предназначены для управления большим количеством данных, постоянно. Тем не менее, помимо улучшения скорости выполнения, нет никакой необходимости использовать директиву с кодом.
В. Работа с данными
То же самое относится и к данным - мы в основном используем директиву для повышения скорости выполнения - как средство оптимизации скорости. Бывают ситуации, когда несоосность данных может оказать огромное влияние на наше приложение.
Но с данными есть ситуации, когда правильное выравнивание является необходимостью, а не роскошью. Это особенно актуально на платформе Itanium и наборе инструкций SSE/SSE2, где смещение на 128-битной границе (X = 16) может привести к общему исключению общей защиты.
Интересная и наиболее информативная статья о выравнивании данных, хотя и ориентирована на компилятор MS C/С++, выглядит следующим образом:
Выравнивание данных Windows на IPF, x86 и x64, Кан Су Гатлин, MSDN
3. Что такое выравнивание по умолчанию сегмента?
A. Если вы используете директиву .386, и вы явно объявили значение выравнивания по умолчанию для сегмента, выравнивание по умолчанию по умолчанию имеет размер DWORD (4 байта). Да, в этом случае X = 4. Затем вы можете использовать следующие значения с директивой ALIGN: (X = 2, X = 4). Помните, что X должен быть меньше или равно, чем выравнивание сегмента.
B. Если вы используете директиву .486 и выше, и вы явно объявили значение выравнивания по умолчанию для сегмента, выравнивание по умолчанию по умолчанию имеет размер PARAGRAPH (16 байт). В этом случае X = 16. Затем вы можете использовать следующие значения с директивой ALIGN: (X = 2, X = 4, X = 8, X = 16).
C. Вы можете объявить сегмент без выравнивания по умолчанию следующим образом:
;Here, we create a code segment named "JUNK", which starts aligned on a 256 bytes boundary
JUNK SEGMENT PAGE PUBLIC FLAT 'CODE'
;Your code starts aligned on a PAGE boundary (X=256)
; Possible values that can be used with the ALIGN directive
; within this segment, are all the powers of 2, up to 256.
JUNK ENDS
Ниже перечислены псевдонимы для значений параметров сегмента...
Align Type Starting Address
BYTE Next available byte address.
WORD Next available word address (2 bytes per word).
DWORD Next available double word address (4 bytes per double word).
PARA Next available paragraph address (16 bytes per paragraph).
PAGE Next available page address (256 bytes per page).
4. Пример
Рассмотрим следующий пример (прочитайте комментарии об использовании директивы ALIGN).
.486
.MODEL FLAT,STDCALL
OPTION CASEMAP:NONE
INCLUDE \MASM32\INCLUDE\WINDOWS.INC
.DATA
var1 BYTE 01; This variable is of 1 byte size.
ALIGN 4
; We enforce the next variable to be alingned in the next memory
;address that is multiple of 4.
;This means that the extra space between the first variable
;and this one will be padded with nulls. ( 3 bytes in total)
var2 BYTE 02; This variable is of 1 byte size.
ALIGN 2
; We enforce the next variable to be alingned in the next memory
;address that is multiple of 2.
;This means that the extra space between the second variable
;and this one will be padded with nulls. ( 1 byte in total)
var3 BYTE 03; This variable is of 1 byte size.
.CODE
; Enforce the first instruction to be aligned on a memory address multiple of 4
ALIGN 4
EntryPoint:
; The following 3 instructions have 7 byte - opcodes
; of the form 0F B6 05 XX XX XX XX
; In the following block, we do not enforce opcode
; alignment in memory...
MOVZX EAX, var1
MOVZX EAX, var2
MOVZX EAX, var3
; The following 3 instructions have 7 byte - opcodes
; of the form 0F B6 05 XX XX XX XX
; In the following block, we enforce opcode alignment
; for the third instruction, on a memory address multiple of 4.
; Since the second instruction opcodes end on a memory address
; that is not a multiple of 4, some nops would be injected before
; the first opcode of the next instruction, so that the first opcode of it
; will start on a menory address that is a multiple of 4.
MOVZX EAX, var1
MOVZX EAX, var2
ALIGN 4
MOVZX EAX, var3
; The following 3 instructions have 7 byte - opcodes
; of the form 0F B6 05 XX XX XX XX
; In the following block, we enforce opcode alignment
; for all instructions, on a memory address multiple of 4.
;The extra space between each instruction will be padded with NOPs
ALIGN 4
MOVZX EAX, var1
ALIGN 4
MOVZX EAX, var2
ALIGN 4
MOVZX EAX, var3
ALIGN 2
; The following instruction has 1 byte - opcode (CC).
; In the following block, we enforce opcode alignment
; for the instruction, on a memory address multiple of 2.
;The extra space between this instruction ,
;and the previous one, will be padded with NOPs
INT 3
END EntryPoint
Если мы скомпилируем программу, вот что сгенерировал компилятор:
.DATA
;------------SNIP-SNIP------------------------------
.data:00402000 var1 db 1
.data:00402001 db 0; This NULL was generated to enforce the alignment of the next instruction on an address that is a multiple of 4
.data:00402002 db 0; This NULL was generated to enforce the alignment of the next instruction on an address that is a multiple of 4
.data:00402003 db 0; This NULL was generated to enforce the alignment of the next instruction on an address that is a multiple of 4
.data:00402004 var2 db 2
.data:00402005 db 0; This NULL was generated to enforce the alignment of the next instruction oon an address that is a multiple of 2
.data:00402006 var3 db 3
.data:00402007 db 0; The rest of the NULLs are to fill the memory page in which the segment will be loaded
;------------SNIP-SNIP------------------------------
.CODE
;------------SNIP-SNIP------------------------------
.text:00401000 start:
.text:00401000 movzx eax, var1
.text:00401007 movzx eax, var2
.text:0040100E movzx eax, var3
.text:00401015 movzx eax, var1
.text:0040101C movzx eax, var2
.text:00401023 nop; This NOP was generated to enforce the alignment...
.text:00401024 movzx eax, var3
.text:0040102B nop; This NOP was generated to enforce the alignment...
.text:0040102C movzx eax, var1
.text:00401033 nop; This NOP was generated to enforce the alignment...
.text:00401034 movzx eax, var2
.text:0040103B nop; This NOP was generated to enforce the alignment...
.text:0040103C movzx eax, var3
.text:00401043 nop; This NOP was generated to enforce the alignment...
.text:00401044 int 3 ; Trap to Debugger
.text:00401044; ---------------------------------------------------------------------------
.text:00401045 db 0
.text:00401046 db 0
.text:00401047 db 0
.text:00401048 db 0
;------------SNIP-SNIP------------------------------
Как видите, после завершения кода/данных нашего приложения компилятор генерирует больше инструкций/данных. Это связано с тем, что разделы PE при загрузке в память выравниваются по размеру PAGE (512 байт).
Таким образом, компилятор заполняет дополнительное пространство для следующего 512-байтового байдара с помощью младших байтов (обычно INT 3 инструкций, NOP или NULL для сегментов кода и 0FFh, NULL для сегментов данных), чтобы гарантировать, что выравнивание памяти для загруженного изображения PE правильно...