Встроенный Ассемблер
ТМТ Паскаль позволяет совмещать код Ассемблера и Паскаля двумя
различными методами:
Используя внешние ассемблерные файлы, которые откомпилированы
подходящим 32-битным Ассемблером. Они могут быть скомпонованы с
помощью директивы Паскаля {$L}.
Используя встроенный ассемблер, код которого может быть размещен
в исходном файле Паскаля.
Этот раздел описывает встроенный ассемблер (BASM).
Так как программа, созданная при помощи ТМТ Паскаля, выполняется в
плоской модели, то дальние вызовы и команды перехода, а также символы
@Code и @Data не осуществимы.
- Операторные скобки Ассемблера
- Ассемблерная процедура
- Кодовая процедура
- Синтаксис команд
- Метки
- Префиксы
- Коды операций
- Регистры
- Мнемонические коды операций
- Выражения операндов
- Операнды
- Операторы
- Приоритет операторов Ассемблера
- Различия между 16-ти и 32-разрядным кодом
Операторные скобки Ассемблера
Встроенный ассемблер вызывается ключевым словом
asm, которое является
операторной скобкой. Синтаксис:
asm
[Здесь находится код Ассемблера]
end;
Слово
asm может появляться везде, где Паскаль позволяет вставлять
операторные скобки.
asm
MOV Al, Value
MOV DX, ThePort
OUT DX, AL
end;
Ассемблерная процедура
Встроенный ассемблер может также использоваться для написания
полноценных процедур на языке Ассемблера. Такие процедуры должны
иметь ключевое слово
Assembler, добавленное после заголовка
процедуры.
function MultBy9(X: Longint): Longint;
Assembler;
asm
MOV EAX,[X]
LEA EAX,[EAX*8+EAX]
end;
Эта функция использует особенность процессора i80386 для очень
быстрого умножения на 9.
Процедуры Ассемблера отличаются от стандартных процедур Паскаля
следующими деталями:
Нет возвращения переменной
Вы должны возвращать результат функции в соответствующий регистр.
Более подробно,
Порядковое значение возвращается регистр AL (8-битное значение), АХ (16-битное значение) или ЕАХ (32-битное значение).
Вещественные значения возвращаются в DX:BX:AX.
Значения с плавающей точкой (8087) возвращаются в ST(0).
Указатели возвращаются в ЕАХ.
Строки возвращаются во временное местоположение, указанное символом @Result.
Структурированные переменные
Структурированные аргументы (такие как строки, объекты, записи) не
копируются в локальные переменные. Они должны быть обработаны как
параметры
Var.
Граница стека
Процедуры Ассемблера не имеют границ стека, если они не содержат
аргументов и локальных символов. Вообще, граница стека во встроенном
ассемблере, это
PUSH EBP // Appears if locals + params >0
MOV EBP,ESP // Appears if locals + params >0
SUB ESP, locals // Appears if locals + params >0
...
LEAVE // Appears if locals + params >0
RETN params // Always appears
Здесь
Locals - это общий размер локальных параметров,
Params
- общий размер параметров процедуры.
Сохранение регистров
Код Ассемблера не должен изменять значение следующих регистров: DS,
CS, SS, ES, EBP и ESP. Все другие регистры могут перезаписываться.
Учитывайте включение регистра ES. TMT Паскаль всегда предполагает,
что ES равен DS.
Кроме того, вы не должны изменять сегмент, страницу и таблицу
прерываний, также как управление, отладку и тестирование регистров,
если вы не очень хорошо знакомы с архитектурой 386-го в защищенном
режиме. Привилегированные команды, подобные LGDT и LIDT,
поддерживаются встроенным ассемблером. Однако, избегайте использовать
их, если вы не уверены в своих действиях.
Кодовая процедура
Помимо процедур ассемблерных, вы можете использовать кодовые
процедуры. Они имеют следующие отличия: компилятор не исполняет
команду ограничения на ввод и возвращает из процедуры (включая
команду RET), а локальные параметры являются основанными на ESP
на момент ввода.
Пример:
function hi (n: word); code;
asm
mov al, byte ptr [n+1]
ret
end;
Синтаксис команд
Общий синтаксис операторов ассемблера
[label:]
[prefixes]
[[opcode [operand1 [,operand2 [,operand3]]]]
Здесь:
label: дополнительное определение метки;
prefixes префикс команды;
opcode мнемоническая команда или директива;
operand выражение-операнд.
Метки
Встроенный ассемблер допускает два типа меток:
Глобальные метки объявляются в программе Паскаля в пределах
описания метки.
Локальные метки не объявляются. Они должны начинаться с символа
@ и содержать буквы, цифры или символ подчеркивания.
Локальные метки имеют силу только в пределах операторных скобок
asm.
Метки могут использоваться с любыми операндами ассемблера. Если
необходимо, можно использовать более одной метки. Метки не являются
обязательными.
Префиксы
Префиксы являются модификаторами для следующих команд. ТМТ Паскаль
позволяет следующие мнемоники префиксов:
* SEGCS Не принимать во внимание сегмент операнда с CS:
* SEGDS Не принимать во внимание сегмент операнда с DS:
* SEGES Не принимать во внимание сегмент операнда с ES:
* SEGFS Не принимать во внимание сегмент операнда с FS:
* SEGGS Не принимать во внимание сегмент операнда с GS:
* SEGSS Не принимать во внимание сегмент операнда с SS:
* LOCK Заблокировать шину
* REP Повторить команду
* REPE и REPZ Повторять, пока равно
* REPNE и REPNZ Повторять, пока не равно
Коды операций
Код операции - это мнемоническая команда или директива ассемблера.
Список поддерживаемых "опкодов" приведен ниже. ТМТ Паскаль допускает
только следующие директивы ассемблера: DB, DW и DD.
Пример:
asm
DB 'a','b','c'
DB 'This code was copyrighted by GnueWare'
DW 1,2,4,8,16,$20,40h
DD Offset HeapLo
end;
Директивы DB, DW и DD позволяют объявить некоторое количество
аргументов, разделенных запятыми. Другие обычно используемые
директивы ассемблера могут быть эмулированы при помощи операторов
Паскаля. Например, директива EQU может быть заменена на
const, а
STRUCT может быть определена описанием типа
record.
Регистры
Следующие регистры могут быть использованы встроенным ассемблером:
8-bit: AL BL CL DL AH BH CH DH
16-bit: AX BX CX DX SI DI BP SP
32-bit: EAX EBX ECX EDX ESI EDI EBP ESP
Segment: CS DS ES SS FS GS
8087: ST
Control: CRn
Debug: DRn
Test: TRn
Сегментный регистр может использоваться для отмены сегмента.
32-битные регистры могут использоваться для индексации на процессорах
80386 и выше. 16-битные регистры никогда не должны использоваться для
адресации, если ваша программа превышает размер 64кБ. Но и в том
случае, когда программа имеет размер менее 64кБ, 16-битная адресация
неэффективна. Вообще, адрес формируется так:
Базовый адрес + Индекс * Масштаб + Смещение
Где "Базовый адрес" - это любой 32-битный регистр, "Индекс" - любой
32-битный регистр, кроме ESP, "Масштаб" должен быть 1, 2, 4 или 8.
"Смещение" - целое число.
Ниже приведены некоторые правильные и неправильные способы адресации:
[EAX+EBX]; правильно.
[EAX+EAX]; правильно, здесь EAX - это и базовый адрес и индекс.
[ESP]; правильно, ESP - индекс, без базового адреса.
[EDX*2]; правильно, используется для адресации глобального массива
слов.
[EAX*4+EBP]; правильно, используется для адресации локального массива
двойных слов.
[SI]; правильно, но есть вероятность появления труднонаходимых
ошибок.
[ESI+BX]; неправильно, соединения 16- и 32-битных регистров.
[SI*4]; неправильно, 16-ти битный регистр не может быть использован
для масштабирования.
[ESP*4]; неправильно, ESP не может быть индексом.
Подробности ищите в справочных руководствах программиста Intel™ 80386/80486.
Мнемонические коды операций
Этот раздел представляет список значений мнемонических кодов операций.
Подробности ищите в справочных руководствах программиста 80386.
В списке используются следующие сокращения:
* acc - регистр-аккумулятор (AL, AX, EAX)
* brm - байтовый регистр или операнд памяти
* cdt - регистр управления, отладки или тестирования
* imm - байт
* label - смещение в коде
* mem - операнд памяти
* none - нет операндов
* reg - регистр
* rm - регистр или операнд памяти
* seg - сегментный регистр
* st - регистр вершины стека сопроцессора
* st(i) - регистр сопроцессора
Опкод: Возможные аргументы:
AAA: none
AAD: none
AAM: none
AAS: none
ADC: rm,reg | reg,rm | rm,imm
ADD: rm,reg | reg,rm | rm,imm
AND: rm,reg | reg,rm | rm,imm
ARPL: rm,reg
BOUND: reg,mem
BSF: reg,rm
BSR: reg,rm
BTC: rm,reg | rm,imm
BTR: rm,reg | rm,imm
BTS: rm,reg |rm,imm
BT: rm,reg | rm,imm
CALL: label | rm
CBW: none
CDQ: none
CLC: none
CLD: none
CLI: none
CLTS: none
CMC: none
CMP: rm,reg | reg,rm | rm,imm
CMPSB: none
CMPSD: none
CMPSW: none
CPUID: none
CWD: none
CWDE: none
DAA: none
DAS: none
DEC: rm
DIV: rm
ENTER: imm,imm
F2XM1: none
FABS: none
FADD: none | st,st(i) | st(i),st | mem
FADDP: st(i),st
FBLD: mem
FBSTP: mem
FCHS: none
FCLEX: none
FCOM: none | st(i) | mem
FCOMP: none | st(i) | mem
FCOMPP: none
FDECSTP: none
FDISI: none
FDIV: none | st,st(i) | st(i),st | mem
FDIVP: st(i),st
FDIVR: st(i),st
FDIVRP: st(i),st
FENI: none
FFREE: st(i)
FIADD: mem
FICOMP: mem
FICOM: mem
FIDIVR: mem
FIDIV: mem
FILD: mem
FIMUL: mem
FIMUL: mem
FINCSTP: mem
FINIT: none
FIST: mem
FISTP: mem
FISUB: mem
FISUBR: mem
FLD: st(i) | mem
FLD1: none
FLDCW: mem
FLDENV: none
FLDL2E: none
FLDL2T: none
FLDLG2: none
FLDLN2: none
FLDPI: none
FLDZ: none
FMUL: none | st,st(i) | st(i),st | mem
FMULP: none | st(i),st
FNCLEX: none
FNDISI: none
FNENI: none
FNINIT: none
FNOP: none
FNSAVE: none
FNSTCW: none
FNSTENV: none
FNSTSW: none
FPATAN: none
FPREM: none
FPREM1: none
FPTAN: none
FRNDINT: none
FRSTOR: mem
FSAVE: mem
FSCALE: none
FSETPM: none
FSQRT: none
FST: st(i) | mem
FSTP: st(i) | mem
FSTCW: mem
FSTENV: mem
FSTSW: mem | AX
FSUB: none | st,st(i) | st(i),st | mem
FSUBP: none | st(i)st
FSUBR: none | st,st(i) | st(i),st | mem
FSUBRP: none | st(i),st
FTST: none
FWAIT: none
FXAM: none
FXCH: none
FXTRACT: none
FYL2XP1: none
FYL2X: none
HLT: none
IDIV: rm
IMUL: rm | reg,imm | reg,rm,imm
IN: acc,imm | acc,DX
INC: rm
INSB: none
INSD: none
INSW: none
INT: imm
INTO: none
IRETD: none
IRET: none
JA: label
JAE: label
JB: label
JBE: label
JC: label
JCXZ: label
JE: label
JECXZ: label
JG: label
JGE: label
JL: label
JLE: label
JMP: label | rm
JNA: label
JNAE: label
JNB: label
JNBE: label
JNC: label
JNE: label
JNG: label
JNGE: label
JNL: label
JNLE: label
JNO: label
JNP: label
JNS: label
JNZ: label
JO: label
JP: label
JPE: label
JPO: label
JS: label
JZ: label
LAHF: none
LAR: reg,rm
LDS: reg,mem
LEAVE: none
LEA: reg,mem
LES: reg,mem
LFS: reg,mem
LGDT: mem
LGS: reg,mem
LIDT: mem
LLDT: rm
LMSW: rm
LODSB: none
LODSD: none
LODSW: rm
LOOP: label
LOOP16: label
LOOP32: label
LOOPE: label
LOOPNE: label
LOOPNZ: label
LOOPZ: label
LSL: reg,rm
LSS: reg,mem
LTR: reg,mem
MOV: reg,rm|rm,reg|rm,imm|rm,seg|seg,rm|reg,cdt|cdt,reg
MOVSB: none
MOVSD: none
MOVSW: none
MOVSX: reg,rm
MOVZX: reg,rm
MUL: rm
NEG: rm
NOP: none
NOT: rm
OR: none
OUT: imm,acc | DX,acc
OUTSB: none
OUTSD: none
OUTSW: none
POP: rm
POPA: none
POPAD: none
POPF: none
POPFD: none
PUSH: rm
PUSHA: none
PUSHAD: none
PUSHF: none
PUSHFD: none
RCL: rm,1 | rm,CL | rm,imm
RCR: rm,1 | rm,CL | rm,imm
RET: none,imm
RETF: none,imm
RETN: none,imm
ROL: rm,1 | rm,CL | rm,imm
ROR: rm,1 | rm,CL | rm,imm
SAHF: none
SAL: rm,1 | rm,CL | rm,imm
SAR: rm,1 | rm,CL | rm,imm
SBB: rm,reg | reg,rm | rm,imm
SCASB: none
SCASD: none
SCASW: none
SEGCS: none
SEGDS: none
SEGES: none
SEGSS: none
SEGFS: none
SEGGS: none
SETA: brm
SETAE: brm
SETB: brm
SETBE: brm
SETC: brm
SETE: brm
SETGE: brm
SETG: brm
SETL: brm
SETLE: brm
SETNA: brm
SETNAE: brm
SETNBE: brm
SETNB: brm
SETNC: brm
SETNE: brm
SETNGE: brm
SETNG: brm
SETNLE: brm
SETNL: brm
SETNO: brm
SETNP: brm
SETNS: brm
SETNZ: brm
SETO: brm
SETPE: brm
SETPO: brm
SETP: brm
SETS: brm
SETZ: brm
SGDT: mem
SHLD: rm,reg,imm
SHL: rm,1 | rm,CL | rm,imm
SHRD: rm,reg,imm
SHR: rm,1 | rm,CL | rm,imm
SIDT: mem
SLDT: rm
SMSW: rm
STC: none
STD: none
STI: none
STOSB: none
STOSD: none
STOSW: none
STR: rm
SUB: rm,reg | reg,rm | rm,imm
TEST: rm,reg | reg,rm | rm,imm
VERR: rm
VERW: rm
WAIT: none
XCHG: reg,rm | rm,reg
XLAT: none
XOR: rm,reg | reg,rm | rm,imm
Выражения операндов
Выражения операндов строятся из операндов и операторов. Операнды -
это константы, регистры, метки и адреса памяти. Операторы комбинируют
операндами и изменяют их свойства. Каждая команда допускает только
некоторые комбинации операндов.
Выражения операндов могут быть разделены на три класса:
Непосредственные операнды или константы.
Регистры.
Операнды памяти и метки.
Непосредственные операнды
PUSH 10
MOV AX, 10
MOV AX, offset Start
Здесь
10 и
Start - это непосредственные операнды.
Значения
AX и
10 могут быть определены непосредственно;
значение
offset Start определяется во время компоновки.
Регистры
Встроенный ассемблер ТМТ Паскаля позволяет использовать 8, 16 или
32-битные 80386 регистры.
XOR AH, AL
LSL EAX,EAX
MOV AX, FX
Операнды памяти и метки
Операнды памяти ссылаются на данные, записанные в памяти. Обычно
используются квадратные скобки
[..] или оператор типа
ptr
- это гарантирует, что аргумент будет обработан как адрес памяти.
Операнды-метки ссылаются на определенное место в коде.
MOV EBX,[0]
POP Word Ptr [88]
POP Word Ptr 88 // same as above
JMP @exit
LOOP16 @loop
Память и непосредственные операнды могут быть либо абсолютными,
либо неопределенными. Абсолютный операнд - это операнд, значение или
смещение которого известны во время компиляции. Неопределенный
операнд - это операнд, смещение которого станет известно только во время
компоновки.
Операнды
ТМТ Паскаль допускает следующие операнды: Числовые константы, Строки,
Регистры, Символы Паскаля и специальные символы.
Числовые константы
Числовые константы это 32-битные целые числа, например, целое число в
диапазоне -2147483648..4294967295. Числовые константы могут вводиться
как десятичные числа, двоичные числа (используется суффикс 'B'),
восмеричные числа (используются суффиксы 'Q' или 'O'),
шестнадцатиричные числа (используются суффикс 'H' или префикс '$').
Учтите, что шестнадцатиричные числа должны начинаться с цифры.
Строки
Строки заключаются в одинарные или двойные кавычки. Если между
кавычками встречается кавычка такого же типа, то она обрабатывается
как символ. Строковые константы произвольной длины могут иметь место
только в директиве 'DB'. Во всех других случаях строка не должна
превышать четырех символов и ее значение преобразуется в целое число.
Регистры
Использование регистров было описано выше.
Символы Паскаля
Со встроенным ассемблером Вы можете обращаться к большинству символов
Паскаля. Они включают метки, константы, переменные, типы и процедуры.
Значения, классы и типы символов Паскаля сведены в таблицу:
Символ Значение Класс Тип
label its address Memory NEAR
constant its value Immediate 0
type 0 Memory sizeof(type)
field its offset Memory sizeof(type)
variable its address Memory sizeof(type)
procedure its address Memory NEAR
function its address Memory NEAR
unit its address Immediate 0
Специальные Символы Ассемблера
Встроенный ассемблер поддерживает пять специальных символов: @CODE,
@DATA, @RESULT, @PARAMS и @LOCALS. @CODE и @DATA в реальности не
используются в плоской модели. Они всегда возвращают 0Ch и 14h,
которые являются стандартными селекторами сегментов для сегментов
данных и кода. Символ @RESULT указывает на псевдопеременную, которая
содержит возвращенный функцией результат, @PARAMS и @LOCALS возвращают
размер параметра и локальных областей в стеке.
Операторы
Встроенный Ассемблер ТМТ Паскаля допускает операторы, перечисленные
в следующем списке:
& |
Оператор отмены Идентификатора. Следующий идентификатор
рассматривается как определенный пользователем символ, даже если
он совпадает с зарезервированным словом ассемблера.
|
( ) |
Круглые скобки. Выражения, заключенные в круглые скобки имеют
приоритет и выполняются первыми.
|
[ ] |
Указатель памяти. Выражение в квадратных скобках обрабатывается
первым. Это выражение должно быть значением адреса, принятым в
архитектуре процессора 386. Результат выражения всегда
обрабатывается как адрес памяти.
|
HIGH, LOW |
Выбор старшего и младшего байта. Эти операторы возвращают
старшие и младшие 8 бит выражения, которое имеет размер слова
и следует после этих операторов.
|
+, - |
Операторы унарного сложения и вычитания. Выражение должно быть
абсолютным непосредственным.
|
SMALL, LARGE |
Заставляет встроенный ассемблер обрабатывать последующие
операнды как 16-ти или 32-битные.
|
OFFSET |
Возвращает 32-битное смещение следующего за ним выражения.
|
SEG |
Возвращает сегментную часть операнда.
|
TYPE |
Возвращает тип операнда. Тип символа NEAR - это -1, тип
символа FAR - это -2. Тип операнда памяти - это его размер.
Тип непосредственного значения - 0.
|
PTR |
Преобразует следующее за ним выражение в тип, который указан
перед оператором PRT. Допустимые значения: BYTE PRT, WORD PRT,
DWORD PRT, FWORD PRT, TBYTE PRT, QWORD PRT, NEAR PRT и FAR PRT.
|
* |
Умножение. Оба аргумента должны быть непосредственными
значениями, или один из аргументов должен быть индексирующим
регистром, а другой - масштабирующим множителем (1,2,4 или 8).
|
/ |
Деление. Оба аргумента должны быть непосредственными значениями.
|
MOD |
Остаток от целого деления. Оба аргумента должны быть
непосредственными значениями.
|
SHL, SHR |
Сдвиг влево и сдвиг вправо. Оба аргумента должны быть
непосредственными значениями.
|
+, - |
Сложение и вычитание. Больший из аргументов может быть
неопределенным значением, но это не может быть вычитаемый
аргумент. Другой аргумент должен быть абсолютным непосредственным
значением.
|
NOT |
Двоичное дополнение. Аргумент должен быть абсолютным
непосредственным значением.
|
AND |
Поразрядное И. Аргумент должен быть абсолютным
непосредственным значением.
|
OR |
Поразрядное ИЛИ. Аргумент должен быть абсолютным
непосредственным значением.
|
XOR |
Поразрядное ИСКЛЮЧАЮЩЕЕ ИЛИ. Аргумент должен быть абсолютным
непосредственным значением.
|
Приоритет операторов Ассемблера
Приоритет этих операторов показан в следующей таблице (от самого
высокого приоритета до самого низкого):
Оператор Комментарии
& Отмена идентификатора
() [] Подвыражение, указатель памяти,
поле структуры
HIGH LOW Выбор старших и младших байтов
LARGE SMALL Операция отмены 32- и 16- бит
+ - Унарные операторы
: Отделение сегмента
OFFSET SEG TYPE
PTR */MOD SHL SHR
+ - Бинарные операторы
NOT AND OR XOR Поразрядные операторы
Различия между 16-ти и 32-разрядным кодом
Это руководство не обучает 32-битному программированию. Мы только
перечислим здесь несколько соображений, важных при создании 32-битных
программ на ассемблере. Эти соображения могут быть полезны для
программиста на 16 битов, который начинает осваивать 32-битное
программирование.
Избегайте использовать 16-битные регистры для индексации.
Встроенный ассемблер будет правильно обрабатывать команды, подобные этим:
MOV BX, offset table
MOV AX, table[BX]
JMP table[BX]
Однако, эти программы не будут работать правильно, если размер вашей
программы превышает 64КБ и "таблица" переменных размещена за пределами
этого диапазона. Это потому, что 16-битные адреса охватывают только
сегмент, размером 64КБ. Последний из приведенных примеров наиболее
опасен, т.к. существует вероятность разрушения системы.
Jump таблицы
Jump таблицы должны строиться как таблицы 32-битных адресов, а не
16-битные адреса.
"Длинная" (32-bit) Арифметика
Старайтесь использовать "длинную" арифметику как можно чаще.
16-битные команды часто занимают больше места, чем соответствующие
32-битные команды. В коде
XOR AX, AX
MOV data1, AX
MOV data2, AX
было бы лучше заменить первую команду на
XOR EAX, EAX
которая является на один байт короче. Кроме того, если
data1 и
data2 могут быть заменены на 32-битные значения, вы можете
сохранить больше места (и времени) в программе как в разделе
Ассемблера, так и в разделе Паскаля.
ECX против CX
Циклы и команды повторения в 32-битном режиме используют регистр
ЕСХ быстрее, чем СХ. Следующий сегмент программы, возможно, создаст
проблемы:
MOV CX, size
MOV ESI, source
MOV EDI, dest
REP MOVSB
Также учтите, что регистры индексов источника и приемника ESI и EDI
быстрее, чем SI и DI.
POPAD/PUSHAD
Используйте POPAD и PUSHAD вместо POPA и PUSHA. Последние помещают в
стек только 16 бит.
POPFD/PUSHFD
Используйте POPFD и PUSHFD вместо POPF и PUSHF. Последние помещают
в стек только 16 бит.
IRETD
Используйте 'IRETD' вместо 'IRET'. Последняя "выталкивает" 16-битные
регистры.
Строковые команды
При выполнении операций со строками, используйте команды с двойным
словом вместо байта или слова. Используйте MOVSD вместо MOVSW или
MOVSB.
JECXZ против JCXZ
Различают команды JCXZ и JECXZ. Первая проверяет регистр СХ, в то
время как вторая проверяет регистр ЕСХ. Использование JCXZ вместо
JECXZ может привести к труднонаходимым ошибкам. Точно также LOOP
проверяет ECX, а LOOP16 проверяет CX.
Результаты функций
Помните, что 32-битный результат нужно возвращать в ЕАХ, а не DX:AX.
ES: сохранение
Не изменяйте значение регистра ES. TMT Pascal определяет ES = DS.
Immediate PUSH
TMT Pascal предполагает, что в стек помещается непосредственное
значение командой, подобной этим:
PUSH Small 0
PUSH Small offset data
Заметьте, что подобно TASM и в отличие от ассемблера PharLap, TMT
Pascal обработает команду
PUSH Word Ptr 0
Как будто это
PUSH Word Ptr [0]
Var-параметры
Подобно 16-битному режиму, var-параметры - это 32-битные указатели.
Однако, в ТМТ Паскале указатели являются только 32-битным смещением
в пределах сегмента данных. Поэтому
var-параметры возвращаются
командой MOV, а не LES или LDS.
Локальные символы
Локальные символы и параметры адресованы через регистр ЕВР.
Например, в
var
local: Longint;
asm
MOV EAX, local
end;
последняя строка ассемблируется в
MOV EAX, [EBP-4]