Команды переходов

Машинные команды выполняются в порядке расположения их в памяти. Но естественный порядок нередко приходиться нарушать, чтобы следующей выполнялась не очередная команда программы, а иная. Такую возможность обеспечивают команды перехода. Переходы различают условные и безусловные. Если переход делается при выполнении некоторого условия, такой переход называется условным, а если независимо от условий, то это безусловный переход. Флаги команды перехода не изменяют.

Команда безусловного перехода JMPвыполняет безусловный ближний (внутрисегментный) и дальний (межсегментный) переход по указанному адресу (табл. 47). Ближние переходы осуществляются с применением относительной (с 8- или 16-разрядным отклонением) и косвенной адресации, дальние – с применением прямой и косвенной адресации.

 

 

Табл. 47. Команда JMP.

Код Инструкция Описание
EB cb JMP rel8 Безусловный короткий переход.
E9 cw JMP rel16 Безусловный ближний переход.
FF /4 JMP r/m16 Безусловный ближний косвенный переход.
EA cd JMP ptr16:16 Безусловный дальний переход.
FF /5 JMP m16:16 Безусловный дальний косвенный переход.

 

 

Операнд указывает адрес перехода, т.е. адрес команды, которая должна быть выполнена следующей. Обычно указывается метка команды, на которую следует передать управление. Непосредственный операнд указывать нельзя. Пример прямого перехода:

 

JMP L ; следующей будет выполняться команда с меткой L

...

L:...

 

Регистр указателя команд IP хранит адрес команды, которая должна быть выполнена следующей. Поэтому переход по некоторому адресу означает запись данного адреса в регистр IP. Однако команда прямого перехода устроена так, что в ней указывается не этот адрес, а разность между ним и адресом команды перехода. Действие команды перехода заключается в прибавлении этой величины к текущему значению регистра IP.

Выгода от указывания не адреса перехода, а расстояния от команды перехода заключается в экономии памяти. Если в команде указывать сам адрес перехода, то на него придется всегда отводить слово. В большинстве случаев переходы делаются на команды, расположенные недалеко от команд перехода, поэтому разность между адресами двух команд, как правило, небольшая, и достаточно одного байта.

Существуют две команды прямого перехода. В первой команде относительный адрес перехода задается в виде байта (короткий переход), а в другой – в виде слова (длинный переход). В каждой из этих команд операнд рассматривается как целое со знаком, поэтому при сложении его с IP значение регистра может, как увеличиться, так и уменьшиться, т.е. возможен переход по ссылке вперед, и переход по ссылке назад.

Встречая команду перехода, ассемблер вычисляет разность между адресом метки и адресом команды перехода, и оценивает величину этой разности. Если она укладывается в байт, ассемблер формирует машинную команду короткого перехода (1 байт), иначе – формирует команду длинного перехода (2 байта). Однако сделать такой выбор ассемблер в состоянии, если метка была описана до команды перехода, т.е. имеет место переход по ссылке назад.

Если в команде перехода указана ссылка вперед, то ассемблер не сможет оценить величину разности. В результате ассемблер не определит, какой переход – короткий или длинный, а потому на всякий случай сформирует команду длинного перехода.

Такой способ трансляции переходов не всегда выгоден: если метка окажется близко расположенной, то будет потерян один байт. Для указания короткого перехода существует оператор SHORT, который ставится в команде перехода перед меткой. В этом случае ассемблер формирует машинную команду короткого перехода:

 

JMP L ; длинный переход

JMP SHORT L ; короткий переход

 

Если указан оператор SHORT, но переход оказался длинным, ассемблер зафиксирует ошибку. При указании оператора перед меткой, описанной ранее, ассемблер проигнорирует его.

Косвенный переход является разновидностью безусловного. Он используются, когда адрес перехода известен только во время исполнения. В этом случае в команде перехода указывается не адрес перехода, а место, где он находится. Адрес может находиться в регистре общего назначения или занимать слово памяти. Полученный адрес рассматривается как «настоящий», а не отсчитанный от команды перехода. Примеры косвенных переходов:

 

A DW L

JMP A ; goto [A] = goto L

MOV DX, A ; DX = L

JMP DX ; goto [DX] = goto L

 

Команды условного перехода реализуют переход в два этапа. Сначала сравниваются некоторые величины, в результате чего формируются флаги, а затем в зависимости от их значений выполняется переход. Сравнение двух операндов осуществляет команда CMP(табл. 48).

Команда эквивалентна команде SUB op1, op2, т.е. сравнение выполняется путём вычитания значения второго операнда из значения первого операнда. Результат вычитания теряется, однако на его основании устанавливаются флаги. При выполнении операции над 16-разрядным первым операндом и 8-разрядным вторым (код операции 83) перед операцией производится расширение знака второго операнда.

 

 

Табл. 48. Команда CMP.

Код Инструкция Описание
38 /r CMP r/m8, r8 Сравнение r/m8 и r8.
39 /r CMP r/m16, r16 Сравнение r/m16 и r16.
3A /r CMP r8, r/m8 Сравнение r8 и r/m8.
3B /r CMP r16, r/m16 Сравнение r16 и r/m8.
3C ib CMP AL, imm8 Сравнение AL и imm8.
3D iw CMP AX, imm16 Сравнение AX и imm16.
80 /7 ib CMP r/m8, imm8 Сравнение r/m8 и imm8.
81 /7 iw CMP r/m16, imm16 Сравнение r/m16 и imm16.
83 /7 ib CMP r/m16, imm8 Сравнение r/m16 и imm8.

Команд условного перехода много, но все они записываются единообразно (табл. 49). Операнд указывает метку, на которую следует сделать переход в случае выполнения некоторого условия. Мнемокод начинается с буквы J, за которой следует одна или несколько букв, описывающих условие. Существует три группы команд условного перехода.

 

 

Табл. 49. Команда Jxx.

Код Инструкция Описание
77 cb JA rel8 Переход, если выше (CF=0 и ZF=0).
73 cb JAE rel8 Переход, если выше или равно (CF=0).
72 cb JB rel8 Переход, если ниже (CF=1).
76 cb JBE rel8 Переход, если ниже или равно (CF=1 или ZF=1).
72 cb JC rel8 Переход, если есть перенос (CF=1).
E3 cb JCXZ rel8 Переход, если регистр CX содержит 0.
74 cb JE rel8 Переход, если равно (ZF=1).
7F cb JG rel8 Переход, если больше (ZF=0 и SF=OF).
7D cb JGE rel8 Переход, если больше или равно (SF=OF).
7C cb JL rel8 Переход, если меньше (SF≠OF).
7E cb JLE rel8 Переход, если меньше или равно (ZF=1 или SF≠OF).
76 cb JNA rel8 Переход, если не выше (CF=1 или ZF=1).
72 cb JNAE rel8 Переход, если не выше или равно (CF=1).
73 cb JNB rel8 Переход, если не ниже (CF=0).
77 cb JNBE rel8 Переход, если не ниже или равно (CF=0 и ZF=0).
73 cb JNC rel8 Переход, если переноса нет (CF=0).
75 cb JNE rel8 Переход, если не равно (ZF=0).
7E cb JNG rel8 Переход, если не больше (ZF=1 или SF≠OF).
7C cb JNGE rel8 Переход, если не больше или равно (SF≠OF).
7D cb JNL rel8 Переход, если не меньше (SF=OF).
7F cb JNLE rel8 Переход, если не меньше или равно (ZF=0 и SF=OF).
71 cb JNO rel8 Переход, если переполнения нет (OF=0).
7B cb JNP rel8 Переход, если результат нечётный (PF=0).
79 cb JNS rel8 Переход, если знака нет (SF=0).
75 cb JNZ rel8 Переход, если не нуль (ZF=0).
70 cb JO rel8 Переход, если есть переполнение (OF=1).
7A cb JP rel8 Переход, если результат чётный (PF=1).
7A cb JPE rel8 Переход, если результат чётный (PF=1).
7B cb JPO rel8 Переход, если результат нечётный (PF=0).
78 cb JS rel8 Переход, если есть знак (SF=1).
74 cb JZ rel8 Переход, если нуль (ZF=1).

Первая группа команд условного перехода содержат операнды, которые ставятся после команды сравнения. В их мнемокодах с помощью букв вписывается исход сравнения, при котором следует выполнить переход. Перечислим все обозначения:

- E - equal (равно);

- N - not (не, отрицание);

- Е - greater (больше) для чисел со знаком;

- L - less (меньше) для чисел со знаком;

- A - above (выше, больше) для чисел без знака;

- В - below (ниже, меньше) для чисел без знака.

В табл. 50 приведены названия команд условного перехода, используемых, после команды сравнения. Для условий «меньше» и «больше» введены две системы обозначений. Это связано с тем, что после сравнения чисел со знаком и сравнения чисел без знака нужно реагировать на разные флаги.

В командах, предназначенных для переходов по результатам сравнения чисел со знаком, анализируются флаги SF и OF, а в командах для беззнаковых сравнений – флаг CF. В любом случае равенство или неравенство чисел отражается состоянием флага ZF.

Заметим, что одна и та же команда условного перехода может иметь несколько названий-синонимов. Например, условие «меньше» в то же время является условием «не верно, что больше или равно», поэтому переход «по меньше» для знаковых чисел обозначается и как JL, и как JNGE.

 

 

Табл. 50. Мнемокоды сравнения по команде CMP.

Мнемокод Условия для перехода после CMP op1, op2 Состояние флагов для перехода
Для любых чисел
JE op1 = op2 ZF=1
JNE op1 <> op2 ZF=0
Для знаковых чисел
JL/JNGE op1 < op2 SF<>OF
JLE/JNG op1 <= op2 SF<>OF или ZF=1
JG/JNLE op1 > op2 SF=OF и ZF=0
JGE/JNL op1 >= op2 SF=OF
Для беззнаковых чисел
JB/JNAE op1 < op2 CF=1
JBE/JNA op1 <= op2 CF=1 или ZF=1
JA/JNBE op1 > op2 CF=0 и ZF=0
JAE/JNB op1 >= op2 CF=0

 

 

Рассмотрим пример совместного применения команды сравнения CMP и условного перехода. Пусть необходимо разместить в памяти два числа в порядке возрастания. Для определенности допустим, что числа беззнаковые, размером слово, а смещения их адресов в сегменте данных расположены в регистрах SI и DI.

 

MOV AX, [SI] ; загрузить в AX первое число

CMP AX, [DI] ; сравнить числа

JBE L ; переход, если первое число меньше либо равно второму

XCHG AX, [DI] ; иначе поменять их местами

MOV [SI], AX ; записать число из AX в ячейку памяти

L:...

 

Вторая группа команд условного перехода состоит из команд, которые реагируют на значение определенного флага. В мнемокодах команд указывается первый символ проверяемого флага, если переход должен быть выполнен при значении 1 у флага, либо этот символ указывается с символом N (not), если переход требуется сделать при нулевом значении флага (табл. 51). Легко заметить, что следующие пары мнемокодов эквиваленты: JE и JZ, JNE и JNZ, JB и JC, JNB и JNC.

 

 

Табл. 51. Мнемокоды сравнения по регистру флагов.

Мнемокод Условие перехода
J(N)Z ZF=1(0)
J(N)S SF=1(0)
J(N)C CF=1(0)
J(N)O OF=1(0)
J(N)P PF=1(0)

 

 

Третья группа команд условного перехода содержит всего одну команду, реагирующую на нулевое значение регистра СХ:

 

JCXZ <метка>

 

Действие команды JCXZ (jump if CX is zero):

 

if CX = 0 then goto <метка>

 

Инструкция JCXZ является единственной командой условного перехода, которая не проверяет состояние флага или группы флагов. Вместо этого она проверяет содержимое регистра CX.

Общая особенность команд условного перехода заключается в том, что команды используют относительную адресацию с 8-разрядным отклонением, что ограничивает длину перехода 127 байтами вперёд и 128 байтами назад относительно адреса команды, следующей за инструкцией перехода (примерно 30-40 команд; в среднем одна команда занимает 3-4 байта). Использовать в командах условного перехода оператор SHORT не имеет смысла, т.к. все переходы короткие.

Для выполнения длинных условных переходов (на расстояние более 127 байтов от команды перехода, а также межсегментных) следует использовать команду длинного безусловного перехода. Например, при длинной метке М оператор:

 

if AX = BX then goto M

 

следует реализовывать так:

 

if AX<>BX then goto L; { короткий переход }

goto M; { длинный переход }

L:...

 

Ассемблер транслирует ее в следующий код:

 

CMP АХ, ВХ

JNE L

JMP М

L:...

M:...

 

Дальние переходы. Все описанные переходы являются ближними. При выполнении ближнего перехода операнд команды содержит новое значение указателя команд IP (смещение следующей выполняемой команды в текущем сегменте кода). Однако в общем случае в программе может быть много команд, и в результате они не поместятся в один сегмент памяти (суммарный размер команд превосходит 64 Кб).

При выполнении дальнего (межсегментного) перехода адрес следующей команды занимает два слова памяти: в первом хранится смещение, во втором – адрес сегмента. Таким образом, команда дальнего перехода загружает регистровую пару CS:IP.

Рассмотрим следующие два сегмента:

 

C1 SEGMENT

ASSUME CS: C1

START: MOV AX, 0

...

JMP FAR PTR L

C1 ENDS

 

C2 SEGMENT

ASSUME CS: C2

L: INC BX

...

C2 ENDS

 

Переход из сегмента C1 на метку L сегмента C2 будет дальним. При таких переходах меняется значение регистра CS и регистра IP: регистр CS настраивается на начало сегмента с меткой CS:=C2, а в регистр IP записывается смещение метки внутри сегмента IP:=OFFSET L.

В системе команд предусмотрены команды, реализующие дальние переходы, причем все они являются только безусловными прямыми или косвенными. В языке ассемблера в этих командах указывается также мнемокод JMP, но с дополнительными операторами. Флаги команды дальнего перехода не меняют:

 

JMP FAR PTR <метка>

 

Оператор FARуказывает ассемблеру, что метка дальняя и находится в другом сегменте. По этой команде регистр CS устанавливается на начало того сегмента, в котором находится метка, а в регистр IP записывается смещение метки внутри данного сегмента:

 

S:=seg <метка:> ; IP:=offset <метка:>

 

При дальнем косвенном переходе в команде указывается адрес двойного слова, в котором находится адрес перехода в виде адресной пары seg:disp, записанной в обратном порядке: смещение disp должно быть записано по адресу m32, а номер сегмента seg - по адресу m32+2:

 

JMP m32

 

Следует заметить, что если X является ссылкой вперед, существуют разновидности команды безусловного перехода:

 

JMP X ; близкий прямой длинный

JMP SHORT X ; близкий прямой короткий

JMP FAR PTR X ; дальний прямой

JMP WORD PTR X ; близкий косвенный

JMP DWORD PTR X ; дальний косвенный

 

Такие уточнения требуются и для команды JMP, если указана косвенная ссылка, например JMP [BX]. По умолчанию ассемблер рассматривает подобного рода команду как близкий косвенный переход. Если X – ссылка назад, то вид перехода обязательно следует уточнять только при дальнем прямом переходе. Ассемблер, зная, что X – метка из другого сегмента команд, все равно не будет рассматривать команду JMP X как дальний переход.

Встречая любую метку, ассемблер автоматически приписывает ей тип NEAR(близкий). Операторы NEAR и FAR являются именами стандартных констант со значениями соответственно -1 (0FFFFh) и -2 (0FFFEh).