В.Г. Баула - Введение в архитектуру ЭВМ и системы программирования (975817), страница 12
Текст из файла (страница 12)
IP := [m16]
Здесь на регистр IP заносится число, содержащееся в двух байтах памяти по адресу m16, т.е. это близкий длинный абсолютный косвенный переход.
Таким образом, каждый переход можно классифицировать по его свойствам: близкий – дальний, относительный – абсолютный, короткий – длинный, прямой – косвенный. Разумеется, не все из этих переходов реализуются в компьютере, так, мы уже знаем, что короткими или длинными бывают только относительные переходы, а относительные переходы бывают только прямыми.
7.6. Команды переходов
Изучим сначала команды переходов. Эти команды предназначены только для передачи управления в другое место программы, они не меняют никаких флагов.
7.6.1. Команды безусловного перехода
Рассмотрим сначала команды безусловного перехода, которые всегда передают управление в указанную в них точку программы. На языке Ассемблера все эти команды записываются в виде
jmp op1
Здесь op1 может иметь следующие форматы:
op1 | Способ выполнения | Вид перехода |
i8 | IP := (IP + i8)mod 216 | Близкий относительный короткий |
i16 | IP := (IP + i16)mod 216 | Близкий относительный длинный |
r16 | IP := [r16] | Близкий абсолютный косвенный |
m16 | IP := [m16] | Близкий абсолютный косвенный |
m32 | IP := [m32], CS := [m32+2] | Дальний абсолютный косвенный |
seg:off | IP := off, CS := seg | Дальний абсолютный прямой |
Здесь seg:off – это мнемоническое обозначение двух операндов в формате i16, разделённых двоеточием. Как видно из этой таблицы, многие потенциально возможные виды безусловного перехода (например, близкие абсолютные прямые, близкие абсолютные короткие и др.) не реализованы в нашей архитектуре. Это сделано исключительно для упрощения центрального процессора (не нужно реализовывать в нём эти команды) и для уменьшения размера программы (чтобы длина поля кода операции в командах не была слишком большой).
Рассмотрим теперь, как на языке Ассемблера задаются эти операнды команд безусловного перехода. Для указания близкого относительного перехода в команде обычно записывается метка команды, на которую необходимо выполнить переход, например:
jmp L; Перейти на команду, помеченную меткой L
Напомним, что вслед за меткой команды, в отличие от метки области памяти, ставится двоеточие. Так как значением метки является её смещение в том сегменте, где эта метка описана, то программе Ассемблера приходится самой вычислять необходимое смещение i8 или i16, которое необходимо записать на место операнда в команде на машинном языке 17, например:
L: add bx,bx ; <─┐
. . . │
. . . │ i8 или i16 (со знаком !)
. . . │
jmp L; L = i8 или i16 <─┘
Здесь формат операнда (i8 или i16) выбирается программой Ассемблера автоматически, в зависимости от расстояния в программе между командой перехода и меткой. Если же метка L располагается в программе после команды перехода, то Ассемблер, ещё не зная истинного расстояния до этой метки, "на всякий случай" заменяет эту метку на операнд размера i16. Поэтому для тех программистов, которые знают, что смещение должно быть формата i8 и хотят сэкономить один байт памяти, Ассемблер предоставляет возможность задать размер операнда в явном виде:
jmp short L
Ясно, что это нужно делать только при острой нехватке оперативной памяти для программы. 18 Для явного указания дальнего перехода программист должен использовать оператор far ptr, например:
jmp far ptr L
Приведём фрагмент программы с различными видами командам безусловного перехода, в этом фрагменте описаны два кодовых сегмента (для иллюстрации дальних переходов) и один сегмент данных:
data segment
A1 dw L2; Смещение команды с меткой L2 в своём сегменте
A2 dd Code1:L1; Это seg:off
. . .
data ends
code1 segment
. . .
L1: mov ax,bx
. . .
code1 ends
code2 segment
assume cs:code2, ds:data
start:mov ax,data
mov ds,ax ; загрузка сегментного регистра DS
L2: jmp far ptr L1; дальний прямой абсолютный переход, op1=seg:off
. . .
jmp L1; ошибка т.к. без far ptr
jmp L2; близкий относительный переход, op1=i8 или i16
jmp A1; близкий абсолютный косвенный переход, op1=m16
jmp A2; дальний абсолютный косвенный переход, op1=m32
jmp bx; близкий абсолютный косвенный переход, op1=r16
jmp [bx]; ошибка, нет выбора: op1=m16 или m32 ?
mov bx,A2
jmp dword ptr [bx]; дальний абсолютный косвенный переход op1=m32
. . .
code2 ends
Отметим одно важное преимущество относительных переходов перед абсолютными. Значение i8 или i16 в команде относительного перехода зависит только от расстояния в байтах между командой перехода и точкой, в которую производится переход. При любом изменении в сегменте кода вне этого диапазона команд значения i8 или i16 не меняются.
Как видим, архитектура нашего компьютера обеспечивает большой спектр команд безусловного перехода. Напомним, что в нашей учебной машине УМ-3 была только одна команда безусловного перехода. На этом мы закончим наше краткое рассмотрение команд безусловного перехода. Напомним, что для усвоения материала по курсу Вам необходимо изучить соответствующий раздел учебника по Ассемблеру.
7.6.2. Команды условного перехода
Все команды условного перехода выполняются по схеме
if <условие перехода> then goto L
и производят близкий короткий относительный переход, если выполнено некоторое условие перехода, в противном случае продолжается последовательное выполнение команд программы. На Паскале условие перехода чаще всего задают в виде условного оператора
if op1 <отношение> op2 then goto L
где отношение – один из знаков операции отношения = (равно), <> (не равно), > (больше), < (меньше), <= (меньше или равно), >= (больше или равно). Если обозначить rez=op1–op2, то оператор условного перехода можно записать в эквивалентном виде сравнения с нулём
if rez <отношение> 0 then goto L
Все машинные команды условного перехода, кроме одной, вычисляют условие перехода, анализируя один, два или три флага из регистра флагов, и лишь одна команда условного перехода вычисляет условие перехода, анализируя значение регистра CX. Команда условного перехода в языке Ассемблер имеет вид
j<мнемоника перехода> i8; IP := (IP + i8)mod 216
Мнемоника перехода (это от одной до трёх букв) связана со значением анализируемых флагов (или регистра CX), либо со способом формирования этих флагов. Чаще всего программисты формируют флаги, проверяя отношение между двумя операндами op1 <отношение> op2, для чего выполняется команда вычитания или команда сравнения. Команда сравнения имеет мнемонический код операции cmp и такой же формат, как и команда вычитания:
cmp op1,op2
Она и выполняется точно так же, как команда вычитания за исключением того, что разность не записывается на место первого операнда. Таким образом, единственным результатом команды сравнения является формирование флагов, которые устанавливаются так же, как и при выполнении команды вычитания. Вспомним, что программист может трактовать результат вычитания (сравнения) как производимый над знаковыми или же беззнаковыми числами. Как мы уже знаем, от этой трактовки зависит и то, будет ли один операнд больше другого или же нет. Так, например, рассмотрим два коротких целых числа 0FFh и 01h. Как знаковые числа 0FFh = -1 < 01h = 1, а как беззнаковые числа 0FFh = 255 > 01h = 1.
Исходя из этого, принята следующая терминология: при сравнении знаковых целых чисел первый операнд может быть больше (greater) или меньше (less) второго операнда. При сравнении же беззнаковых чисел будем говорить, что первый операнд выше (above) или ниже (below) второго. Ясно, что действию "выполнить переход, если первый операнд больше второго" будут соответствовать разные машинные команды, если трактовать операнды как знаковые или же беззнаковые целые числа. Это учитывается в различных мнемониках этих команд.
Ниже в Таблице 7.1 приведены мнемоники команд условного перехода. Некоторые команды имеют разную мнемонику, но выполняются одинаково (переводятся программой Ассемблера в одну и ту же машинную команду), такие команды указаны в одной строке таблицы.
Таблица 7.1. Мнемоника команд условного перехода | ||
КОП | Условие перехода | |
Логическое условие перехода | Результат (rez) команды вычитания или cоотношение операндов op1 и op2 команды сравнения | |
je jz | ZF = 1 | Rez = 0 или op1 = op2 (результат = 0, операнды равны) |
jne jnz | ZF = 0 | rez <> 0 или op1 <> op2 Результат <> 0, операнды не равны |
jg jnle | (SF=OF) and (ZF=0) | rez > 0 или op1 > op2 Знаковый результат > 0, op1 больше op2 |
jge jnl | SF = OF | rez >= 0 или op1 >= op2 Знаковый результат >= 0, т.е. op1 больше или равен (не меньше) op2 |
jl jnge | SF <> OF | rez < 0 или op1 < op2 Знаковый результат < 0, т.е. op1 меньше (не больше или равен) op2 |
jle jng | (SF<>OF) or (ZF=1) | rez <= 0 или op1 <= op2 Знаковый результат <= 0, т.е. op1 меньше или равен(не больше) op2 |
ja jnbe | (CF=0) and (ZF=0) | rez > 0 или op1 > op2 Беззнаковый результат > 0, т.е. op1 выше (не ниже или равен) op2 |
jae jnb jnc | CF = 0 | rez >= 0 или op1 >= op2 Беззнаковый результат >= 0, т.е. op1 выше или равен (не ниже) op2 |
jb jnae jc | CF = 1 | rez < 0 или op1 < op2 Беззнаковый результат < 0, т.е. op1 ниже (не выше или равен) op2 |
jbe jna | (CF=1) or (ZF=1) | rez >= 0 или op1 >= op2 Беззнаковый результат >= 0, т.е. op1 ниже или равен (не выше) op2 |
js | SF = 1 | Знаковый бит разультата (7-й или 15-ый, в зависимости от размера) равен единице |
jns | SF = 0 | Знаковый бит разультата (7-й или 15-ый, в зависимости от размера) равен нулю |
jo | OF = 1 | Флаг переполнения равен единице |
jno | OF = 0 | Флаг переполнения равен нулю |
jp jpe | PF = 1 | Флаг чётности 19 равен единице |
jnp jpo | PF = 0 | Флаг чётности равен единице |
jcxz | CX = 0 | Значение регистра CX равно нулю |
В качестве примера рассмотрим, почему условному переходу jl/jnge соответствует логическое условие перехода SF<>OF. При выполнении команды сравнения cmp op1,op2 или команды вычитания sub op1,op2 нас будет интересовать трактовка операндов как знаковых целых чисел, поэтому возможны два случая, когда первый операнд меньше второго. Во-первых, если при выполнении операции вычитания op1-op2 результат получился правильным, т.е. не было переполнения (OF=0), то бит знака у правильного результата равен единице (SF=1). Во-вторых, при вычитании мог получиться неправильный результат, т.е. было переполнение (OF=0), но в этом случае знаковый бит результата будет неправильным, т.е. равным нулю. Видно, что в обоих случаях эти два флага не равны друг другу, т.е. должно выполняться условие SF<>OF, что и указано в нашей таблице. Для тренировки разберите правила формирования и других условий переходов.