Dos7book
.pdfГлава 7: Ассемблерные команды отладчика Debug.exe
Примечание 3: когда команда JMP получает адрес перехода по ссылке, характер операции зависит от наличия в строке вызова маркера "FAR". Когда он имеется, из памяти считывается полный четырехбайтовый адрес, и выполняется дальний переход. А при отсутствии маркера "FAR" из памяти считывается двухбайтовое слово. Оно интерпретируется как смещение, и тогда выполняется ближний переход.
Примечание 4: если команда JMP получает адрес перехода из регистра, то в этот регистр заранее должно быть записано смещение. Обращение JMP к 16-битовому регистру всегда вызывает ближний переход.
Примечание 5: после каждого переключения процессора из реального режима в защищенный и обратно, как правило, сразу же выполняют дальний переход (JMP FAR) на адрес следующей команды в том же сегменте кода. Эта команда JMP FAR нужна не для осуществления перехода, а ради двух других действий: во-первых, она приводит статус числа в регистре CS: (сегментный адрес или селектор) в соответствие с устанавливаемым режимом, и, во-вторых, она сбрасывает очередь команд, которую процессоры формируют на основании опережающей выборки, чтобы не оставлять там команды, дешифрированные по правилам прежнего режима.
Примечание 6: отладчик DEBUG.EXE дизассемблирует коды "FF E(8-F)" как команду "JMP FAR bx".
7.03-40 JNB – переход, если больше или равно
Команда JNB (Jump if Not Below) суммирует байт данных с содержимым регистра IP, если флаг CF сброшен в состояние NC (No Carry). В результате происходит "короткий" переход к исполнению машинной команды, находящейся в пределах ±7Fh от прежнего значения смещения в регистре IP.
Команда JNB используется для исполнения переходов по условию успешного завершения прерываний, которые отмечают успех сбросом флага CF в состояние NC, а также по результатам операций над числами без знака, в частности, после команд CMP, SBB, SUB (для чисел со знаком условие "больше или равно" проверяет команда JGE, 7.03-36).
Отладчик DEBUG.EXE принимает команду JNB также под именем JNC (Jump if Not Carry), но тем не менее дизассемблирует код 73h всегда как команду JNB.
1-й байт |
2-й байт |
Байты данных |
Пример |
73 |
|
1 |
JNB aaaa |
– 279 –
Глава 7: Ассемблерные команды отладчика Debug.exe
7.03-41 JNO – переход, если нет переполнения
Команда JNO (Jump if No Overflow) суммирует байт данных с содержимым регистра IP, если флаг OF сброшен в состояние NV (No oVerflow). В результате происходит "короткий" переход к исполнению машинной команды, расположенной в пределах ±7Fh от прежнего значения смещения в регистре IP.
1-й байт |
2-й байт |
Байты данных |
Пример |
71 |
|
1 |
JNO aaaa |
7.03-42 JNS – переход по положительному знаку числа
Команда JNS (Jump if not Sign) суммирует байт данных с содержимым регистра IP, если флаг SF сброшен в состояние PL, что соответствует положительному знаку числа. В результате происходит "короткий" переход к исполнению машинной команды, расположенной в пределах ±7Fh от прежнего значения смещения в регистре IP.
1-й байт |
2-й байт |
Байты данных |
Пример |
79 |
|
1 |
JNS aaaa |
7.03-43 JNZ – переход по ненулевому результату или по условию неравенства
Команда JNZ (Jump if Not Zero) суммирует байт данных с содержимым регистра IP, если флаг ZF сброшен в состояние NZ (No Zero). В результате происходит "короткий" переход к исполнению машинной команды, расположенной в пределах ±7Fh от прежнего значения смещения в регистре IP.
Отладчик DEBUG.EXE принимает команду JNZ также под именем JNE (Jump if Not Equal), но тем не менее дизассемблирует код 75h всегда как команду JNZ .
1-й байт |
2-й байт |
Байты данных |
Пример |
75 |
|
1 |
JNZ aaaa |
7.03-44 JO – переход при переполнении
Команда JO (Jump if Overflow) суммирует байт данных с содержимым регистра IP, если флаг OF установлен в состояние OV (OVerflow). В результате происходит "короткий" переход к исполнению машинной команды, расположенной в пределах ±7Fh от прежнего значения смещения в регистре IP.
– 280 –
Глава 7: Ассемблерные команды отладчика Debug.exe
|
1-й байт |
2-й байт |
Байты данных |
Пример |
|
|
70 |
|
|
1 |
JO aaaa |
7.03-45 |
JPE – переход по четному результату |
|
Команда JPE (Jump if Parity Even) суммирует байт данных с содержимым регистра IP, если флаг четности PF установлен в состояние PE, что соответствует
четной сумме битов в младшем байте результата предшествовавшей операции (остальные байты не учитываются). При этом условии происходит "короткий" переход к исполнению машинной команды, расположенной в пределах ±7Fh от прежнего значения смещения в регистре IP.
Отладчик DEBUG.EXE принимает команду JPE также под именем JP (Jump if Parity), но тем не менее дизассемблирует код 7Ah всегда как команду JPE.
1-й байт |
2-й байт |
Байты данных |
Пример |
7A |
|
1 |
JPE aaaa |
7.03-46 JPO – переход по нечетному результату
Команда JPO (Jump if Parity Odd) суммирует байт данных с содержимым регистра IP, если флаг четности PF сброшен в состояние PO, что соответствует
нечетной сумме битов в младшем байте результата предшествовавшей операции (остальные байты не учитываются). При этом условии происходит "короткий" переход к исполнению машинной команды, расположенной в пределах ±7Fh от прежнего значения смещения в регистре IP.
Отладчик DEBUG.EXE принимает команду JPO также под именем JNP (Jump if Not Parity), но тем не менее дизассемблирует код 7Bh всегда как команду JPO.
1-й байт |
2-й байт |
Байты данных |
Пример |
7B |
|
1 |
JPO aaaa |
7.03-47 JS – переход по отрицательному знаку числа
Команда JS (Jump if Sign) суммирует байт данных с содержимым регистра IP, если флаг SF установлен в состояние NG, что соответствует отрицательному знаку числа. В результате происходит "короткий" переход к исполнению машинной команды, расположенной в пределах ±7Fh от прежнего значения смещения в регистре IP.
– 281 –
Глава 7: Ассемблерные команды отладчика Debug.exe
1-й байт |
2-й байт |
Байты данных |
Пример |
78 |
|
1 |
JS aaaa |
7.03-48 JZ – переход по нулевому результату или по условию равенства
Команда JZ (Jump if Zero) суммирует байт данных с содержимым регистра IP, если флаг ZF установлен в состояние ZR (ZeRo). В результате происходит "короткий" переход к исполнению машинной команды, расположенной в пределах ±7Fh от прежнего значения смещения в регистре IP.
Отладчик DEBUG.EXE принимает команду JZ также под именем JE (Jump if Equal), но тем не менее дизассемблирует код 74h всегда как команду JZ .
1-й байт |
2-й байт |
Байты данных |
Пример |
74 |
|
1 |
JZ aaaa |
7.03-49 LAHF – копирование флагов в регистр
Команда LAHF (Load AH with Flags) копирует младший байт из регистра флагов в однобайтовый регистр AH, так что состояние знакового флага SF отображается битом 7 в AH, состояние флага нуля ZF отображается битом 6, состояние дополнительного флага переноса AF отображается битом 4, состояние флага четности PF отображается битом 2, и состояние флага переноса CF отображается битом 0. Биты 5, 3 и 1 однобайтового регистра AH каким-либо флагам не соответствуют. Бит 1 всегда устанавливается в состояние логической единицы, биты 5 и 3 сбрасываются в нуль.
|
|
Код |
Пример |
|
|
9F |
LAHF |
7.03-50 |
LDS – загрузка регистра DS |
|
Команда LDS (Load address into DS) выполняет загрузку полного адреса из памяти, причем сегментный адрес загружается в регистр DS, а смещение – в другой регистр, указываемый в качестве первого операнда. Второй операнд команды LDS задает смещение, указывающее на ячейку памяти, откуда должен быть считан первый байт загружаемого полного адреса. Байты 2 и 1 полного адреса определяют смещение, байты 4 и 3 – сегментный адрес. Состояния флагов команда LDS не изменяет.
– 282 –
Глава 7: Ассемблерные команды отладчика Debug.exe
1-й байт |
2-й байт |
Байты данных |
Пример |
C5 |
(1,5,9)(8-F) |
0-2 |
LDS bx,[bp+si+ffff] |
Примечание 1: отладчик DEBUG.EXE ошибочно дизассемблирует как команду
LDS коды "C5 (C-F)(0-F)".
Примечание 2 по умолчанию пара регистров DS:SI считается определяющей адрес источника данных, и потому в качестве первого операнда команды LDS (вместо bx) наиболее часто указывают регистр SI.
Примечание 3: и сегментный адрес в регистре DS:, и смещение могут быть использованы для адресации и перезагружены в одной операции; например, вполне допустима команда DS: LDS SI,[SI].
7.03-51 LEA – вычисление смещения
Команда LEA (Load Effective Address) вычисляет выражение в квадратных скобках, которое задано в качестве второго операнда и определяет некоторое смещение. Результат вычисления загружается в регистр, указанный в качестве первого операнда. Состояния флагов команда LEA не изменяет.
1й байт |
2-й байт |
Байты данных |
Пример |
8D |
(0-B)(0-F) |
0-2 |
LEA bx,[bp+si+ffff] |
7.03-52 LES – загрузка регистра ES
Команда LES (Load address into ES) выполняет загрузку полного адреса из памяти, причем сегментный адрес загружается в регистр ES, а смещение – в другой регистр, указываемый в качестве первого операнда. Второй операнд команды LES задает смещение, указывающее на ячейку памяти, откуда должен быть считан первый байт загружаемого полного адреса. Байты 2 и 1 полного адреса определяют смещение, байты 4 и 3 – сегментный адрес. Состояния флагов команда LES не изменяет.
|
1-й байт |
2-й байт |
Байты данных |
|
Пример |
|
|
C4 |
(1,5,9)(8-F) |
0-2 |
|
LES bx,[bp+si+ffff] |
|
Примечание 1: отладчик DEBUG.EXE ошибочно |
дизассемблирует как команду |
LES коды "C4 (C-F)(0-F)".
Примечание 2: по умолчанию пара регистров ES:DI считается определяющей адрес назначения, и потому в качестве первого операнда команды LES (вместо bx) наиболее часто указывают регистр DI.
– 283 –
Глава 7: Ассемблерные команды отладчика Debug.exe
Примечание 3: и сегментный адрес в регистре ES:, и смещение могут быть использованы для адресации и перезагружены в одной операции; например, вполне допустима команда ES: LES DI,[DI].
7.03-53 LODSB – считывание байта
Команда LODSB (LOaD String of Bytes) считывает из памяти в однобайтовый регистр AL один байт, на который указывает полный адрес, заранее записанный в пару регистров DS:SI. После считывания смещение в регистре SI увеличивается или уменьшается на единицу: это зависит от состояния флага направления DF, которое следует заранее задать командой CLD (счет вверх, 7.03-11) или командой STD (счет вниз, 7.03-85). Состояния флагов команда LODSB не изменяет.
Команде LODSB может предшествовать префикс смены сегмента (7.02-01); он
позволит адресовать считываемый байт через другой сегментный регистр вместо принимаемого по умолчанию сегментного регистра DS.
|
Код |
Пример |
|
AC |
LODSB |
7.03-54 LODSW – считывание слова |
|
Команда LODSW (LOaD String of Words) считывает в регистр AX одно двухбайтовое слово и изменяет смещение в регистре SI на 2, подготавливая тем самым адрес для считывания следующего слова. Под действием префикса 66h смены разрядности операнда (7.02-06) команда LODSW считывает в регистр EAX 4-байтовое слово (типа Dword) и изменяет смещение в регистре SI на 4. Остальные особенности команды LODSW такие же, как у команды LODSB (7.03-53).
|
Код |
Пример |
|
AD |
LODSW |
7.03-55 LOOP – организация цикла |
|
Команда LOOP сначала уменьшает число в регистре CX на единицу, а потом проверяет, не равен ли остаток нулю. Пока он не равен нулю, будет выполняться "короткий" переход в пределах ±7Fh путем прибавления байта данных к смещению в регистре IP. А когда станет CX = 0, процессор перейдет к исполнению следующей команды. Состояния флагов команда LOOP не изменяет.
– 284 –
Глава 7: Ассемблерные команды отладчика Debug.exe
Счет циклов в регистре CX исходит из предположения, что команда LOOP следует за телом цикла. В этом случае тело цикла будет исполнено один раз, прежде чем условие вхождения в цикл будет проверено командой LOOP. Чтобы предотвратить исполнение тела цикла до проверки, можно перед телом цикла поставить команду JCXZ (7.03-34). Другое решение состоит в вынесении тела цикла из основной последовательности команд. В последнем случае число, заранее записываемое в регистр CX, должно быть на единицу больше требуемого числа актов исполнения цикла.
1-й байт |
2-й байт |
Байты данных |
Пример |
E2 |
|
1 |
LOOP aaaa |
7.03-56 LOOPNZ – возврат в цикл, если не нуль
Команда LOOPNZ (LOOP if Not Zero) сначала уменьшает число в регистре CX на единицу, а затем проверяет два условия: отличается ли остаток в регистре CX от нуля и сброшен ли флаг нуля ZF в состояние NZ. Когда оба условия выполнены, происходит "короткий" переход в пределах ±7Fh путем прибавления байта данных к смещению в регистре IP. Если же хотя бы одно условие не удовлетворяется, то процессор просто переходит к исполнению следующей команды. Особенности организации циклов командой LOOPNZ такие же, как у команды LOOP (7.03-55). Состояния флагов команда LOOPNZ не изменяет.
Отладчик DEBUG.EXE принимает команду LOOPNZ также под именем LOOPNE (LOOP, if Not Equal = цикл, если не равно), но тем не менее дизассемблирует код E0h всегда как команду LOOPNZ.
1-й байт |
2-й байт |
Байты данных |
Пример |
E0 |
|
1 |
LOOPNZ aaaa |
7.03-57 LOOPZ – возврат в цикл, если нуль
Команда LOOPZ (LOOP if Zero) сначала уменьшает число в регистре CX на единицу, а затем проверяет два условия: отличается ли остаток в регистре CX от нуля и установлен ли флаг нуля ZF в состояние ZR. Когда оба условия выполнены, происходит "короткий" переход в пределах ±7Fh путем прибавления байта данных к смещению в регистре IP. Если же хотя бы одно условие не удовлетворяется, то процессор просто перейдет к исполнению следующей команды. Особенности организации циклов командой LOOPZ такие же, как у команды LOOP (7.03-55). Состояния флагов команда LOOPZ не изменяет.
– 285 –
Глава 7: Ассемблерные команды отладчика Debug.exe
Отладчик DEBUG.EXE принимает команду LOOPZ также под именем LOOPE (LOOP, if Equal = цикл, если равно), но тем не менее дизассемблирует код E1h всегда как команду LOOPZ.
|
1-й байт |
2-й байт |
Байты данных |
Пример |
|
|
E1 |
|
|
1 |
LOOPZ aaaa |
7.03-58 |
MOV – копирование данных |
|
Команда MOV копирует байт или слово данных, определяемых прямо или косвенно вторым операндом, в регистр или в ячейку памяти, задаваемые первым операндом. Явное указание размера копируемых данных – байт или слово – требуется только когда в качестве операнда не указан регистр процессора. Обычные формы команды MOV состояния флагов не изменяют; исключение составляют только обращения к управляющим, отладочным и тестовым регистрам, показанные ниже в примечании 1 (после них состояния флагов OF, SF, ZF, AF, PF, CF могут не сохраняться).
1-й байт |
2-й байт |
Байты |
Примеры |
|
данных |
||||
|
|
|
||
88 |
(0-B)(0-5, 7-F) |
0-2 |
MOV [bp+si+ffff],bl |
|
88 |
(C-F)(0-F) |
|
MOV bl,bl |
|
89 |
(0-B)(0-5, 7-F) |
0-2 |
MOV [bp+si+ffff],bx |
|
89 |
(C-F)(0-F) |
|
MOV bx,bx |
|
8A |
(0-B)(0-5, 7-F) |
0-2 |
MOV bl,[bp+si+ffff] |
|
8B |
(0-B)(0-5, 7-F) |
0-2 |
MOV bx,[bp+si+ffff] |
|
8C |
(0,1,4,5,8,9)(0-F) |
0-2 |
MOV [bp+si+ffff],ss |
|
8C |
(C,D,E)(0-F) |
|
MOV bx,ss |
|
8E |
(0,1,4,5,8,9)(0-F) |
0-2 |
MOV ss,[bp+si+ffff] |
|
8E |
(C,D,E)(0-F) |
|
MOV ss,bx |
|
A0 |
|
2 |
MOV AL,[ffff] |
|
A1 |
|
2 |
MOV AX,[ffff] |
|
A2 |
|
2 |
MOV [ffff],AL |
|
A3 |
|
2 |
MOV [ffff],AX |
|
B(0-7) |
|
1 |
MOV bl,ff |
|
B(8-F) |
|
2 |
MOV bx,ffff |
|
C6 |
(0,4,8)(0-7) |
1-3 |
MOV byte ptr [bp+si+ffff],ff |
|
C7 |
(0,4,8)(0-7) |
2-4 |
MOV word ptr [bp+si+ffff],ffff |
Примечание 1: отладчик DEBUG.EXE "не знает" команд обращения к управляющим и отладочным регистрам 32-разрядных процессоров,
но коды этих команд можно вводить как данные с помощью
– 286 –
Глава 7: Ассемблерные команды отладчика Debug.exe
инструкции DB (7.01-01). Такие команды копирования – трехбайтовые, начинаются с байта 0Fh; второй байт определяет исполнение копирования:
20h – из управляющего регистра (CR0, CR2 – CR4) 21h – из отладочного регистра (DR0 – DR3, DR6, DR7) 22h – в управляющий регистр (CR0, CR2 – CR4)
23h – в отладочный регистр (DR0 – DR3, DR6, DR7)
Третий байт в таких командах указывает на конкретные регистры: C0h – на CR0 или DR0, например, 0F 20 C0 = MOV EAX,CR0 C8h – на DR1, например, 0F 23 C8 = MOV DR1,EAX D0h – на CR2 или DR2, например, 0F 20 D0 = MOV EAX,CR2 D8h – на CR3 или DR3, например, 0F 20 D8 = MOV EAX,CR3
E0h – на CR4, |
например, 0F 22 E0 = MOV CR4,EAX |
F0h – на DR6, |
например, 0F 21 F0 = MOV EAX,DR6 |
F8h – на DR7, |
например, 0F 23 F8 = MOV DR7,EAX |
Чтобы вместо EAX задействовать какой-либо иной регистр, нужно к 3-му байту прибавить номер этого регистра (от 00h до 07h) в
следующем перечне: EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI,
например:
0F 20 C3 = MOV EBX,CR0
Отладчик DEBUG.EXE неспособен дизассемблировать эти коды, но не препятствует отладке программ, которые такие коды содержат, при условии работы на компьютере с 32-разрядным процессором.
Префикс смены разрядности операнда перед такими командами не требуется.
Примечание 2: отладчик DEBUG.EXE "не знает" команд обращения к сегментным регистрам GS: и FS:, имеющимся в 32-разрядных процессорах, но
коды этих команд можно вводить как данные с помощью инструкции DB (7.01-01). Такие команды копирования – двухбайтовые:
8C E0 = MOV AX,FS
8C E8 = MOV AX,GS
8E E0 = MOV FS,AX
8E E8 = MOV GS,AX
Чтобы вместо AX задействовать какой-либо иной регистр, нужно ко 2-му байту прибавить номер этого регистра (от 00h до 07h) в перечне, приведенном во 2-й строке таблицы 7.00, например:
8E E3 = MOV FS,BX
Отладчик DEBUG.EXE ошибочно дизассемблирует такие коды как относящиеся к регистрам CS: и ES:, но не препятствует правильной отладке программ, которые такие коды содержат, при условии работы на компьютере с 32-разрядным процессором.
– 287 –
Глава 7: Ассемблерные команды отладчика Debug.exe
Примечание 3: команду MOV нельзя использовать для записи данных в регистр CS:, это можно делать только посредством команд перехода или команд передачи управления (CALL, JMP, RETF и т.п.).
Примечание 4: команда копирования слова данных в регистр SS вызывает
аппаратное блокирование внешних прерываний на время исполнения одной следующей команды, которой должна быть команда обновления указателя в регистре SP. Только такой порядок их исполнения исключает сбои из-за возникновения прерываний в моменты переходов на другой стек.
Примечание 5: отладчик DEBUG.EXE дизассемблирует как команду MOV коды
"8(A,B) (C-F)(0-F)", "8(C,E) (2,3,6,7,A,B,F)(0-F)" и "C(6,7) (C-F)(0-F)".
7.03-59 MOVSB – копирование байта
Команда MOVSB (MOVe a String of Bytes) копирует один байт из адреса источника в адрес назначения. Оба адреса должны быть подготовлены заранее: адрес источника – в паре регистров DS:SI, адрес назначения – в паре регистров ES:DI. После копирования оба смещения – смещение источника в регистре SI и смещение назначения в регистре DI – увеличиваются на единицу или уменьшаются на единицу: это зависит от состояния флага направления DF, которое следует заранее задать командой CLD (счет вверх, 7.03-11) или командой STD (счет вниз, 7.03-85). Автоматическое изменение смещений в индексных регистрах
подготавливает условия для копирования следующего байта в следующую ячейку памяти. Состояния флагов команда MOVSB не изменяет.
Перед командой MOVSB часто ставится префикс повторения REPNZ (7.02-03) или REPZ (7.02-04), что позволяет исполнять команду MOVSB несколько раз и таким образом копировать сразу строку байтов. Также перед командой MOVSB можно ставить один из префиксов смены сегмента (7.02-01); это позволяет
отсчитывать адрес источника относительно другого сегментного регистра вместо принимаемого по умолчанию сегментного регистра DS:. Сегментный регистр адреса назначения (ES:) посредством префикса смены сегмента изменить нельзя.
|
Код |
|
Пример |
|
A4 |
|
MOVSB |
7.03-60 MOVSW – копирование слова |
|
Команда MOVSW (MOVe a String of Words) копирует двухбайтовое слово и затем изменяет смещение в адресах источника и назначения на 2, подготавливая их
– 288 –