«virtual
» определяет виртуальные данные по указанному адресу. Эти данные не будут включены в файл вывода, но но метки, определенные здесь, могут использоваться в других частях кода. За этой директивой может следовать оператор «at
» и числовое выражение, определяющее адрес виртуальных данных, иначе будет использован текущий адрес, что равносильно директиве «virtual at $
». Инструкции определяемых данных должны быть расположены на следующих строках и заканчиваться директивой «end virtual
». Блок виртуальных инструкций сам по себе независимое адресное пространство, и после того, как оно заканчивается, восстанавливается контекст предыдущего адресного пространства.
Директива «virtual
» может быть использована для создания объединения нескольких переменных, например:
GDTR dp?
virtual at GDTR
GDT_limit dw?
GDT_address dd?
end virtual
Здесь определяются две части 48-битной переменной по адресу «GDTR
».
Директива также может быть использована для определения меток некоторых структур, адресованных регистром, например:
virtual at bx
LDT_limit dw?
LDT_address dd?
end virtual
С таким определением инструкция «mov ax,[LDT_limit]
» будет сассемблирована в «mov ax,[bx]
».
Также может быть полезно объявление инструкций и значений данных внутри виртуально блока, так как директиву «load
» можно использовать для загрузки в константы значений из виртуально сгенерированного кода. Эта директива должна быть использована после загружаемого кода, но до окончания виртуального блока, так как она может загружать значения только из того же адресного пространства. Например:
virtual at 0
xor eax,eax
and edx,eax
load zeroq dword from 0
end virtual
Этот кусок кода определяет константу «zeroq
», которая будет содержать четыре байта машинного кода инструкций, указанных внутри виртуального блока. Этот метод также может быть использован для загрузки некоторых бинарных значений из внешнего файла. Например этот код:
virtual at 0
file 'a.txt':10h,1
load char from 0
end virtual
загружает один байт со смещением 10h из файла «a.txt
» в константу «char
».
Все директивы «section
», описанные в 2.4, также начинают новое адресное пространство.
2.2.4 Другие директивы
«align
» выравнивает код или данные по указанной границе. За ней должно следовать числовое выражение, определяющее количество байтов, на кратность которому должен быть выровнен текущий адрес. Значение границы должно быть степенью двойки.
Директива «align
» заполняет байты, которые должны быть пропущены, чтобы совершить выравнивание, инструкциями «nop
», и в это же время маркирует эту область как неинициализированные данные, то есть если её поместить среди других неинициализированных данных, это не займет места в файле вывода, выравнивание байтов происходит таким же образом. Если вам нужно заполнить область выравнивания какими-то другими значениями, вы можете сочетать «align
» и «virtual
», чтобы получить требуемый размер выравнивания и далее создать выравнивание самостоятельно, например:
virtual
align 16
a = $ — $$
end virtual
db a dup 0
Константа «a
» определяется как разница между адресом после выравнивания и адресом блока «virtual
» (смотрите предыдущий параграф), то есть она равна размеру требуемого пространства выравнивания.
«display
» во время ассемблирования показывает сообщение. За ней должны следовать строка в кавычках или значения байтов, разделенные запятыми. Директива может быть использована для показа значений некоторых констант, например:
bits = 16
display 'Current offset is 0x'
repeat bits/4
d = '0' + $ shr (bits-%*4) and 0Fh
if d> '9'
d = d + 'A'-'9'-1
end if
display d
end repeat
display 13,10
Этот блок директив рассчитывает четыре цифры 16-битного значения и конвертирует их в знаки для показа. Помните что это не будет работать, если адреса в текущем адресном пространстве перемещаемы (как это может быть с объектным форматом вывода и форматом PE), так как таким образом могут быть использованы только абсолютные значения. Абсолютное значение может быть получено вычислением относительного адреса, например «$-$$
» или «rva $
» в случае формата PE.