Как формируется машинный код команды безусловного перехода ассемблера
Перейти к содержимому

Как формируется машинный код команды безусловного перехода ассемблера

  • автор:

 

Команда безусловного перехода

Безусловный переход в программе на Ассемблере производится по команде JMP. Полный формат команды следующий:

JMP[модификатор]адрес_перехода.

Адрес перехода может быть либо меткой, либо адресом области памяти, в которую предварительно помещен указатель перехода.

В системе команд микропроцессора существуют несколько кодов машинных команд безусловного перехода. Их различия определяются дальностью перехода и способом задания целевого адреса. Дальность перехода определяется местоположением операнда адрес_перехода. Этот адрес может находиться в текущем сегменте кода или в некотором другом сегменте. В первом случае переход называется внутрисегментным или близким, а во втором случае – межсегментным или дальним.

Внутрисегментный переход предполагает, что изменяется только содержимое регистра IP. Можно выделить три варианта внутрисегментного перехода:

Прямой короткий внутрисегментный переход применяется, когда расстояние от команды JMPдо адреса перехода не более чем –128: +127 байтов. В этом случае транслятор языка формирует машинную команду безусловного перехода длиной 2 байта 1 байт – код операции, 2-ой байт – смещение. В коде операции заложена информация о том, что 2-ой байт интерпретируется как смещение. Здесь нужно отметить одну особенность транслятора Ассемблера – он является однопроходным, иными словами, машинный код программы получается за один просмотр мнемокоманд от начала до конца. В связи с этим обстоятельством, если безусловный переход должен происходить на адрес до командыJMP, то транслятор может легко вычислить смещение. Если же переход короткий, но на метку после командыJMP, то транслятору нужно подсказать, что он должен сформировать команду безусловного короткого перехода. С этой целью в командеJMPиспользуется модификаторSHORTPTR(полностью -SHORTPOINTERили короткий указатель):

JMP SHORT PTR M1

. . . . . . не более 35-40 команд

Прямой внутрисегментный переход отличается от короткого тем, что длина машинной команды составляет 3 байта, в которой 2 последних байта интерпретируются как смещение. Нетрудно определить, что в этом варианте можно осуществлять переход в пределах 64 Кбайт памяти относительно следующей за JMPкоманды.

В приведенном в параграфе “команды условного перехода” фрагменте программы, наряду с командами условного перехода, присутствуют команды безусловного перехода, которые правильно надо было бы писать как

JMP SHORT PTR K.

Приведу этот фрагмент программы полностью с комментариями.

MOV AL,A ;сторону треугольника а записать в AL

MOV BL,B ;сторону треугольника в записать в ВL

MOV СL,С ;сторону треугольника с записать в СL

CMP AL,BL ;сравнить стороны а и b

JNE NOT_EQABC ;если стороны не равны, перейти к NOT_EQABC

CMP BL,CL ;если а=b, сравнить b и c

JNE NOT_EQABC ;если стороны не равны, перейти к NOT_EQABC

здесь поместить команды выдачи сообщения “треугольник равносторонний”

JMP SHORT PTR K ; переход на метку K

NOT_EQABC: CMP BL,CL ;а не равно b, сравнить b и c

JE EQUAL ; если стороны равны, перейти к EQUAL

CMP AL,CL ; если b не равно c,сравнить а и с

JE EQUAL ; если стороны равны, перейти к EQUAL

здесь поместить команды выдачи сообщения “треугольник обычный”

JMP SHORT PTR K ; переход на метку K

здесь поместить команды выдачи сообщения “треугольник равносторонний”

Если приведенный фрагмент сравнить с предыдущим, то можно видеть, что после метки NOT_EQABCпропущена проверка сторонаив, поскольку на эту команду мы попадем в том случае, если а не равно в.

Косвенный внутрисегментный переход означает, что в команде JMPуказывается не сам адрес перехода, а место, где этот адрес записан. Например:

DSEG SEGMENT PARA PUBLIC ‘DATA’

CSEG SEGMENT PARA PUBLIC ‘CODE’

ASSUME CS:CSEG, DS:DSEG, SS:STACK

В командах косвенного внутрисегментного перехода рекомендуется применять модификатор NEAR, т.к. при косвенном переходе не всегда транслятору удается определить, находится адрес перехода в текущем сегменте кода или нет.

Команда прямого межсегментного перехода имеет длину 5 байт, из которых 2 байта составляет смещение адреса перехода, а другие 2 байта – значение сегментной составляющей (CS) того кодового сегмента, где находится адрес перехода. Например:

SEG1 SEGMENT PARA PUBLIC ‘CODE’

ASSUME CS:SEG1, DS:DSEG1, SS:STACK

SEG2 SEGMENT PARA PUBLIC ‘CODE’

ASSUME CS:SEG2, DS:DSEG2, SS:STACK

Во втором случае FARнеобязательно, но если модификатор примените, то ошибки не будет. Необязательность объясняется тем, что метка находится раньше команды перехода и транслятор может самостоятельно определить, что переход является межсегментным.

Команда косвенного межсегментного перехода в качестве операнда имеет адрес области памяти, в которой содержится смещение и сегментная часть целевого адреса перехода.

DSEG SEGMENT PARA PUBLIC ‘DATA’

CSEG SEGMENT PARA PUBLIC ‘CODE’

ASSUME CS:CSEG, DS:DSEG, SS:STACK

CS1 SEGMENT PARA PUBLIC ‘CODE’

ASSUME CS:CS1, DS:DS1, SS:ST1

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

DSEG SEGMENT PARA PUBLIC ‘DATA’

CSEG SEGMENT PARA PUBLIC ‘CODE’

ASSUME CS:CSEG, DS:DSEG, SS:STACK

JMP DWORD PTR [BX]

CS1 SEGMENT PARA PUBLIC ‘CODE’

ASSUME CS:CS1, DS:DS1, SS:ST1

В двойное слово ADDRпомещается смещение адреса и начало сегмента кода, включающего меткуM1, в нашем случае, начало сегментаCS1.

Т.о. модификаторы SHORTPTR,NEARPTRиWORDPTRприменяют при организации внутрисегментных переходов, аFARPTRиDWORDPTR– при межсегментных переходах.

FasmWorld Программирование на ассемблере FASM для начинающих и не только

Учебный курс. Часть 16. Условные и безусловные переходы

Автор: xrnd | Рубрика: Учебный курс | 27-04-2010 | Распечатать запись

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

Безусловные переходы

Безусловный переход — это переход, который выполняется всегда. Безусловный переход осуществляется с помощью команды JMP. У этой команды один операнд, который может быть непосредственным адресом (меткой), регистром или ячейкой памяти, содержащей адрес. Существуют также «дальние» переходы — между сегментами, однако здесь мы их рассматривать не будем. Примеры безусловных переходов:

 

jmp metka ;Переход на метку jmp bx ;Переход по адресу в BX jmp word[bx] ;Переход по адресу, содержащемуся в памяти по адресу в BX

Условные переходы

Условный переход осуществляется, если выполняется определённое условие, заданное флагами процессора (кроме одной команды, которая проверяет CX на равенство нулю). Как вы помните, состояние флагов изменяется после выполнения арифметических, логических и некоторых других команд. Если условие не выполняется, то управление переходит к следующей команде.

Существует много команд для различных условных переходов. Также для некоторых команд есть синонимы (например, JZ и JE — это одно и то же). Для наглядности все команды условных переходов приведены в таблице:

Команда Переход, если Условие перехода
JZ/JE нуль или равно ZF=1
JNZ/JNE не нуль или не равно ZF=0
JC/JNAE/JB есть переполнение/не выше и не равно/ниже CF=1
JNC/JAE/JNB нет переполнения/выше или равно/не ниже CF=0
JP число единичных бит чётное PF=1
JNP число единичных бит нечётное PF=0
JS знак равен 1 SF=1
JNS знак равен 0 SF=0
JO есть переполнение OF=1
JNO нет переполнения OF=0
JA/JNBE выше/не ниже и не равно CF=0 и ZF=0
JNA/JBE не выше/ниже или равно CF=1 или ZF=1
JG/JNLE больше/не меньше и не равно ZF=0 и SF=OF
JGE/JNL больше или равно/не меньше SF=OF
JL/JNGE меньше/не больше и не равно SF≠OF
JLE/JNG меньше или равно/не больше ZF=1 или SF≠OF
JCXZ содержимое CX равно нулю CX=0

У всех этих команд один операнд — имя метки для перехода. Обратите внимание, что некоторые команды применяются для беззнаковых чисел, а другие — для чисел со знаком. Сравнения «выше» и «ниже» относятся к беззнаковым числам, а «больше» и «меньше» — к числам со знаком. Для беззнаковых чисел признаком переполнения будет флаг CF, а соответствующими командами перехода JC и JNC. Для чисел со знаком о переполнении можно судить по состоянию флага OF, поэтому им соответствуют команды перехода JO и JNO. Команды переходов не изменяют значения флагов.

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

use16 ;Генерировать 16-битный код org 100h ;Программа начинается с адреса 100h mov al,[x] ;AL = x add al,[y] ;AL = x + y jo error ;Переход, если переполнение mov ah,09h ;\ mov dx,ok_msg ; > Вывод строки ‘OK’ int 21h ;/ exit: mov ah,09h ;\ mov dx,pak ; > Вывод строки ‘Press any key. ‘ int 21h ;/ mov ah,08h ;\ int 21h ;/ Ввод символа mov ax,4C00h ;\ int 21h ;/ Завершение программы error: mov ah,09h ;\ mov dx,err_msg ; > Вывод сообщения об ошибке int 21h ;/ jmp exit ;Переход на метку exit ;———————————————————- x db -89 y db -55 err_msg db ‘Error: overflow detected.’,13,10,’$’ ok_msg db ‘OK’,13,10,’$’ pak db ‘Press any key. $’

Команды CMP и TEST

Часто для формирования условий переходов используются команды CMP и TEST. Команда CMP предназначена для сравнения чисел. Она выполняется аналогично команде SUB: из первого операнда вычитается второй, но результат не записывается на место первого операнда, изменяются только значения флагов. Например:

cmp al,5 ;Сравнение AL и 5 jl c1 ;Переход, если AL < 5 (числа со знаком)

cmp al,5 ;Сравнение AL и 5 jb c1 ;Переход, если AL < 5 (числа без знака)

Команда TEST работает аналогично команде AND, но также результат не сохраняется, изменяются только флаги. С помощью этой команды можно проверить состояние различных битов операнда. Например:

test bl,00000100b ;Проверить состояние 2-го бита BL jz c2 ;Переход, если 2-й бит равен 0

Пример программы

Простая программка, которая выводит меню и предлагает пользователю сделать выбор. Для ввода символа используется функция DOS 01h (при вводе символ отображается на экране). В зависимости от введённого символа осуществляется переход на нужный кусок кода. Для разнообразия, я поместил данные в начале программы, а не в конце (кстати, обычно так и делают). Чтобы данные не выполнились как код, перед ними стоит команда безусловного перехода.

use16 ;Генерировать 16-битный код org 100h ;Программа начинается с адреса 100h jmp start ;Безусловный переход на метку start ;———————————————————- menu db ‘1 — Print hello’,13,10 db ‘2 — Print go away’,13,10 db ‘0 — Exit’,13,10,’$’ select db 13,10,’Select>$’ hello db 13,10,’Hello!’,13,10,13,10,’$’ go_away db 13,10,’Go away!’,13,10,13,10,’$’ ;———————————————————- start: mov ah,09h ;\ mov dx,menu ; > Вывод меню int 21h ;/ select_loop: mov ah,09h ;\ mov dx,select ; > Вывод строки ‘Select>’ int 21h ;/ mov ah,01h ;Функция DOS 01h — ввод символа int 21h ;Введённый символ помещается в AL cmp al,’1′ ;Сравнение введённого символа с ‘1’ je c1 ;Переход, если равно cmp al,’2′ ;Сравнение введённого символа с ‘2’ je c2 ;Переход, если равно cmp al,’0′ ;Сравнение введённого символа с ‘0’ je exit ;Переход, если равно jmp select_loop ;Безусловный переход c1: mov ah,09h ;\ mov dx,hello ; > Вывод строки ‘Hello’ int 21h ;/ jmp start ;Безусловный переход c2: mov ah,09h ;\ mov dx,go_away ; > Вывод строки ‘Go away’ int 21h ;/ jmp start ;Безусловный переход exit: mov ax,4C00h ;\ int 21h ;/ Завершение программы

Скриншот работы программы:

Упражнение

Упражнение простое. Напишите программу для сравнения двух переменных со знаком a и b. В зависимости от результатов сравнения выведите «a < b», «a > b» или «a = b». Проверьте работу программы в отладчике. Результаты можете выкладывать в комментариях.

Как формируется машинный код команды безусловного перехода ассемблера

Команда безусловного перехода имеет следующий синтаксис:

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

Прямой переход

Если в команде перехода указывается метка команды, на которую надо перейти, то переход называется прямым.

Косвенный переход

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

Команды условного перехода

В системе команд процессора архитектуры x86 не предусмотрена поддержка условных логических структур, характерных для языков высокого уровня. Однако на языке ассемблера с помощью набора команд сравнения и условного перехода вы можете реализовать логическую структуру любой сложности. В языке высокого уровня любой условный оператор выполняется в два этапа. Сначала вычисляется значение условного выражения, а затем, в зависимости от его результата, выполняются те или иные действия. Проводя аналогию с языком ассемблера, можно сказать, что сначала выполняются такие команды, как CMP , AND или SUB , влияющие на флаги состояния процессора. Затем выполняется команда условного перехода, которая анализирует значение нужных флагов, и в случае если они установлены, выполняют переход по указанному адресу.

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

Все команды условного перехода можно разделить на три группы.

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

Условие перехода после команды CMP op1, op2

Команды условных и безусловных переходов

Нарушение естественного порядка следования команд, когда адрес следующей выполняемой команды автоматически вычисляется программным счетчиком, осуществляется путем загрузки в программный счетчик и, при необходимости, в сегментный регистр CS новых адресов. Эти действия выполняются при помощи команд условных и безусловных переходов. Мнемоника этих команд начинается с символа J (jump).

Команды безусловного перехода имеют одну и ту же мнемонику JMP и дополнительную уточняющую информацию, определяющую дальность перехода. В командах безусловного перехода адрес новой команды может формироваться двумя способами. В первом способе в самой команде указывается смещение относительно текущей команды, которое может быть как положительным, так и отрицательным. Адрес, загружаемый в программный счетчик, образуется путем сложения с его текущим содержимым этого смещения, или его вычитания. Смещение может быть задано как однобайтным числом, так и двухбайтным. В первом случае переход называется коротким (SHORT), отстоящим от текущего адреса не более, чем на 127, во втором случае – близким (NEAR), т.е. находящимся в одном сегменте с текущим адресом, напомним, что объем одного сегмента – 216 = 64 Кбайт.

Во втором способе адрес новой исполняемой команды непосредственно загружается в программный счетчик. При этом он может быть взят из команды в виде двухбайтного числа, или из ячейки памяти, адрес которой указан в команде всеми возможными режимами адресации. Второй способ обеспечивает переход не только внутри текущего сегмента программы, но и в любой другой. Для этого новый адрес загружается не только в программный счетчик, но и в сегментный регистр CS. Он может быть задан либо вторым двухбайтным словом, содержащимся в команде, либо содержимым двух ячеек ОЗУ, находящихся следом за ячейками с внутрисегментным адресом для программного счетчика. Такой переход называют далеким (FAR).

При транслировании команд с языка Ассемблер в машинные коды дальность перехода и тип определяются либо дополнительной информацией – SHORT, NEAR или FAR, либо размером адреса (одно-, двух-, четырехбайтный). Очень часто в качестве адреса в команде дается ссылка на метку, которой помечена команда, к которой осуществляется переход:

JMP SHORT NEXT.

По этой команде адрес следующей исполняемой команды определится как сумма текущего с однобайтным смещением. Расчет смещения выполняет ассемблирующая программа по отстоянию текущей команды от команды, помеченной меткой NEXT:

JMP FAR [DI]+100.

Эта команда определяет межсегментный переход. Адреса, загружаемые в программный счетчик и регистр CS, содержатся в четырех соседних ячейках ОЗУ. Адрес первой из них определяется как содержимое регистра DI плюс смещение 100.

Команды условных переходов имеют только один способ определения адреса перехода – как смещение, не более чем ±127 относительно текущего адреса. В этих командах осуществляется проверка различных условий выполнения перехода. Порядок действия МП при выполнении команды условного перехода следующий: если условие, заданное в команде, выполняется, то следующий адрес вычисляется путем сложения (вычитания) текущего содержимого программного счетчика со смещением; если же условие не выполняется, то автоматически сформированный адрес и есть адрес следующей команды. Таким образом, сохраняется естественный порядок следования команд и следующая команда стоит непосредственно за командой условного перехода.

Мнемоника команд условного перехода начинается с символа J. Затем идут символы, определяющие проверяемое условие. Проверка условий осуществляется путем анализа различных флажков – битов регистра слова состояния процессора, хранящих признаки результата предыдущей операции. Таким образом, непосредственно перед командой условного перехода обязательно должна стоять команда, с помощью которой формируются признаки результата. У одной части команд осуществляется анализ только одного признака результата – одного бита регистра флажков, у другой двух или трех битов.

Приведем мнемоники некоторых команд с их наименованиями и необходимыми пояснениями.

JZ "Перейти, если ноль" – переход осуществляется, если результат предыдущей операции равен нулю.

JNZ – "Перейти, если не ноль" – команда противоположна команде JZ

JS – "Перейти, если знаковый бит равен 1" – переход выполняется, если результат вычитания двух операндов отрицателен.

JNS – "Перейти, если знаковый бит равен 0" – переход выполняется, если результат вычитания положителен.

В следующих четырех командах осуществляется проверка условий, соответствующих математическим операторам отношений <, >, >, <. Эти команды предназначены для использования после команды сравнения СМР, в которой второй операнд вычитается из первого, а результат операции не сохраняется.

JL "Перейти, если меньше".

JNL "Перейти, если больше".

JLE "Перейти, если меньше или равно".

JNLE – "Перейти, если больше или равно".

Команды условного перехода обычно имеют следующий обобщенный вид:

Мнемоника Метка, например JLE NEXT.

В данном примере NEXT – это метка команды, которую следует выполнить в случае выполнения условия. Она должна находиться не далее чем на ±127 относительно команды условного перехода. При трансляции ассемблирующая программа вычислит соответствующее смещение и поместит его в машинную команду. Если команда, которой следует передать управление, находится дальше или в другом сегменте, то используют конструкцию из двух команд: условного и безусловного перехода. Сначала проверяется условие с помощью команды условного перехода, которая дает ссылку на команду безусловного перехода, находящуюся вблизи ее. Затем по команде безусловного перехода осуществляется переход к нужному участку программы в любую точку памяти.

Команды ввода-вывода. Все внешние устройства рассматриваются микропроцессором как внешние регистры или порты ввода-вывода. Для передачи данных между МП и ВУ имеются две команды: IN ввод и OUT– вывод. Весь процесс обмена ведется через регистр АХ или его отдельные половины. Он является как бы "почтовым ящиком". Через него осуществляются пересылки данных из МП в ВУ и в него же данные принимаются. Обобщенный вид команд можно представить в следующем виде:

Мнемоника Приемник, Источник.

В команде IN в качестве приемника может выступать регистр АХ (АН, AL). В качестве источника должен выступать адрес регистра ВУ, который может быть задан либо однобайтной константой (от 0 до 255), либо косвенно, путем указания регистра DX. В этом случае в этот регистр должен быть занесен двухбайтный адрес регистра ВУ. В команде OUT регистр АХ теперь выступает уже в качестве источника, а адрес регистра ВУ должен быть помещен на место приемника. Он может быть задан так же, как и в команде IN.

В команде IN АХ, 40 приемником является АХ, а источником – регистр с адресом 40.

В команде OUT DX, AL приемником является регистр с адресом, содержащимся в DX, а источником – регистр AL.

Кроме рассмотренных команд в МП Intel 8086 имеются команды для работы со стеком – записи в стек и извлечения из стека; команды для организации циклических программ; команды для установки и сброса отдельных признаков результата – флажков; команды, обеспечивающие управление микропроцессором.

 

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *