Команды передачи управления
Эти команды нарушают естественный порядок выполнения команд посредством загрузки в командный счетчик адреса команды, к которой осуществляют переход. Решение о том, какая команда должна выполняться следующей может быть:
1) безусловным – из данной точки программы необходимо передать управление не следующей команде, а другой, которая находится на некотором удалении т текущей;
2) условным – решение о том, какая команда будет выполняться следующей, принимается на основе анализа некоторых условий или данных.
Безусловные переходы.
Безусловные переходы связаны с использованием команды безусловного перехода и команд обращений к процедурам.
Команда безусловного перехода
Формат команды
JMP [Модификатор] адрес_перехода
Этой командой задаются внутрисегментные и межсегментные переходы.
Описание команды безусловного перехода для внутрисегментных переходов представлено в таблице 4.10.
Таблица 4.10 – Формат команды для внутрисегментных переходов
Вариант внутрисегментного перехода | Мнемоника и формат команды | Описание действия |
Прямой короткий переход (расстояние от команды JMP до адреса перехода не превышает -128 или 127 байт) | JMP SHORT OPR | (IP) (IP) + 8- битное смещение, определяемое OPR |
Прямой переход (на расстояние от 128 байт до 64 Кбайт) | JMP [NEAR] OPR | (IP) (IP) + 16- битное смещение, определяемое OPR |
Косвенный переход (в команде указывается не сам адрес перехода, а место, где он находится) | JMP OPR | (IP) (EA), где EA- эффективный адрес, определяемый OPR |
Формат команды для межсегментных переходов описан в таблице 4.11.
Таблица 4.11 – Формат команды для межсегментных переходов
Вариант межсегментного перехода | Мнемоника и формат команды | Описание действия |
Прямой переход | JMP FAR PTR OPR | (CS) начальный адрес сегмента, определяемого OPR (IP) смещение в сегменте из OPR |
Косвенный переход | JMP OPR | (IP) (EA), где EA- эффективный адрес, определяемый OPR (CS) (EA + 2), где EA- эффективный адрес из OPR |
Тип перехода определяется типом операнда. Межсегментные передачи управления реализуются только командами безусловных переходов. Не модифицируются все флажки условий. Что касается режимов адресации, то во внутрисегментных прямых переходах применяется относительный режим, в межсегментных прямых переходах - прямой режим. В косвенных переходах не допускается непосредственный режим, а в межсегментных косвенных переходах должна адресоваться память.
Обращение к процедурам
Процедура (подпрограмма) – это группа команд для решения конкретной подзадачи, обладающая средствами получения управления из точки вызова задачи более высокого уровня и возврата управления в эту точку.
Другими словами, это правильным образом оформленная совокупность команд, которая, будучи однократно описана, при необходимости может быть вызвана в любом месте программы.
Описание процедуры состоит из заголовка, тела и конца процедуры:
имя_процедуры PROC [расстояние] – заголовок процедуры
…
команды, директивы ассемблера - тело процедуры
…
ret
имя_процедуры ENDP - конец процедуры
Имя процедуры – это идентификатор (метка), по которому происходит обращение к процедуре из основной программы или другой процедуры. Необязательный параметр [расстояние] характеризует возможность обращения к процедуре из другого сегмента кода. Моет принимать значения: NEAR – для процедур ближнего вызова (описание процедуры находится в том же самом сегменте кода, что и основная программа) и FAR – для процедур дальнего вызова (описание процедуры находится в другом сегменте кода). По умолчанию этот параметр равен NEAR.
Процедура может размещаться в любом месте программы, но так, чтобы на нее случайным образом не попало управление. В этом случае процессор воспринимает процедуру как часть исполняемого потока команд и начинает их выполнять. Процедура может размещаться:
1) в начале программы (до первой исполняемой команды);
c_s segment
assume cs:c_s
Pr1 proc near
…
Ret
P1 endp
begin: ;начало программы
…
end begin
2) в конце программы (после команды корректного завершения работы и возвращения управления операционной системе- ОС);
c_s segment
assume cs:c_s
begin:
…
mov ah, 4ch
int 21h ;корректное завершение работы и передача управления ОС
P1 proc near
…
Ret
P1 endp
c_s ends
end begin
3) внутри тела программы или другой процедуры (должен быть предусмотрен обход процедуры с помощью оператора JMP);
c_s segment
assume cs:c_s
begin:
…
jmp m1
P1 proc near
…
Ret
P1 endp
m1: …
mov ah, 4ch
int 21h ;корректное завершение работы и передача управления ОС
c_s ends
end begin
4) в другом модуле – часто используемы процедуры выносятся в отдельный файл, который оформляется как обычный файл ассемблера, а затем подвергается трансляции для получения объектного кода. Впоследствии этот объектный файл с помощью компоновщика можно объединить с файлом, в котором все или некоторые данные процедуры используются.
Специальный механизм вызова процедур, который поддерживается командами CALL и RET, позволяет сохранять информацию о состоянии программы в точке вызова процедуры. Команда CALL осуществляет вызов процедуры, сохраняя предварительно в стеке адрес возврата – адрес команды, следующей после команды CALL. При выполнении команды CALL осуществляется передача управления по адресу с символическим именем имя_процедуры.
Формат команды CALL:
CALL [Модификатор] имя_процедуры
Модификатор может принимать значения NEAR или FAR, для обращения к процедурам ближнего или дальнего вызовов, соответственно.
Команда RET считывает из стека адрес возврата и загружает его в регистр IP/EIP или регистры CS и IP/EIP, возвращая тем самым управление на команду, следующую в программе или другой процедуре за командой CALL.
Для процедур ближнего вызова адрес возврата полностью определяется содержимым регистра IP/EIP, а для процедур дальнего вызовы – содержимым дух регистров: CS и IP/EIP. При этом команда CALL запоминает в стеке сначала значение регистра CS, а затем значение регистра IP/EIP. Важно также отметить, что одна и та же процедура не может быть одновременно и процедурой ближнего вызова, и процедурой дальнего вызова.
Примечание:при использовании процедур программа должна обязательно содержать сегмент стека для обеспечения корректной обработки процедур. Тогда, в общем случае, программа будет иметь три сегмента: сегмент стека, сегмент данных и сегмент кода.
Условные переходы
В этих командах, также как и в командах безусловного перехода, нарушается естественный порядок выполнения команд. Но в условном переходе замена содержимого программного счетчика зависит от условия или от состояния флагов (без AF). Команды условно перехода, проверяющие некоторое условие, используются только совместно с командой сравнения CMP, рассмотренной выше, которая задает значение условия перехода. Команды условного перехода, работающие с флагами условий, могут использоваться как совместно с командой CMP (некоторые), которая модифицирует флаги, так и с другими командами, изменяющими флаги (все).
Команды условного перехода и их формат представлены в таблице 4.12.
Таблица 4.12 – Формат команд условного перехода
Название команды | Мнемоника и формат команды | Критерий условного перехода (в CMP) | Значение флагов для перехода |
Перейти, если равно | JE OPR | OPR1 = OPR2 | ZF = 1 |
Перейти, если не равно | JNE OPR | OPR1 <> OPR2 | ZF = 0 |
Перейти, если ниже (меньше)/ не выше или равно (без знака) | JB/ JNAE OPR | OPR1 < OPR2 | CF = 1 |
Перейти, если не ниже (меньше)/ выше или равно (без знака) | JNB/ JAE OPR | OPR1 >= OPR 2 | CF = 0 |
Перейти, если ниже или равно/ не выше (без знака) | JBE/ JNA OPR | OPR1 <= OPR2 | CF = 1 или ZF = 1 |
Перейти, если не ниже или равно/ выше (больше) (без знака) | JNBE/ JA OPR | OPR1 > OPR2 | CF = 0 и ZF = 0 |
Перейти, если меньше/ не больше (со знаком) | JL/ JNGE OPR | OPR1 < OPR2 | SF <> OF |
Перейти, если не меньше/ больше или равно (со знаком) | JNL/ JGE OPR | OPR1 => OPR2 | SF = OF |
Перейти, если меньше или равно/ не больше (со знаком) | JLE/ JNG OPR | OPR1 <= OPR2 | SF <> OF или ZF = 1 |
Перейти, если не меньше или равно/ больше (со знаком) | JNLE/ JG OPR | OPR1 > OPR2 | SF = OF и ZF=0 |
Продолжение таблицы 4.12 | |||
Перейти, если ноль | JZ OPR | [OPR1 = OPR2] | ZF = 1 |
Перейти, если не ноль | JNZ OPR | [OPR1 <> OPR2] | ZF = 0 |
Перейти, если знак установлен | JS OPR | [OPR1 < OPR2] | SF = 1 |
Перейти, если знак сброшен | JNS OPR | [OPR1 > OPR2] | SF = 0 |
Перейти, если есть переполнение | JO OPR | - | OF = 1 |
Перейти, если нет переполнения | JNO OPR | - | OF = 0 |
Перейти, если паритет установлен | JP OPR | - | PF = 1 |
Перейти, если паритет сброшен | JNP OPR | - | PF = 0 |
Перейти, если перенос установлен | JC OPR | - | CF = 1 |
Перейти, если перенос сброшен | JNC | - | CF = 0 |
Если проверочное условие удовлетворяется, то действие этих команд заключается в следующем:
(IP) (IP)+ 8-битное смещение с расширением знака.
В противном случае программный счетчик не изменяется, и программа продолжается в естественном порядке. Не модифицируются флажки условий. Режимы адресации - относительно программного счетчика (IP). Операнд OPR должен быть в пределах от-128 до127 байт от команды, находящейся за командой перехода.
Команды циклов
Циклы организуются для многократного повторения одной или нескольких команд программы или процедуры. Цикл можно организовать, используя команды условного и безусловного переходов, рассмотренных выше, а можно с помощью специальных команд. Формат команд представлен в таблице 4.13.
Команда LOOP и ее расширения позволяют организовывать циклы, подобные циклам for в языках высокого уровня.
Таблица 4.13 – Формат команд циклов
Название команды | Мнемоника и формат команды | Проверяемое условие |
Зациклить | LOOP OPR | (ECX/ CX) <> 0 |
Зациклить, пока ноль или равно | LOOPZ/ LOOPE OPR | (ECX/ CX) <> 0 или ZF = 0 |
Зациклить, по не ноль или не равно | LOOPNZ/ LOOPNE OPR | (ECX/ CX) <> 0 или ZF=1 |
Переход по CX | JCXZ OPR | (ECX/ CX) = 0 |
За исключением команды JCXZ, которая не изменяет (ECX/ CX), производится (ECX/ CX)(ECX/ CX)-1, затем, если проверяемое условие удовлетворяется, (EIP/ IP)(EIP/ IP)+D8 с расширением знака; в противном случае (IP) не изменяется и программа продолжается в естественном порядке.
Не модифицируются все флажки условий. Режимы адресации - относительно IP. Операнд OPR должен быть меткой, которая находится в диапазоне от -128 до127 байт от команды, следующей за командой цикла.
Стековые команды
Организация стека
Стек – это область памяти, специально выделяемая для временного хранения данных программы. Для стека в структуре программы предусмотрен отдельный сегмент. Регистры процессора для работы со стеком были рассмотрены выше (в разделе 4.8).
Размер стека зависит от режима работы процессора и ограничивается значением 64 Кбайт в обычном режиме (или 4 Гбайт в защищенном режиме). В каждый момент времени доступен только один стек, начальный адрес сегмента которого содержится в регистре SS. Для перехода к другому стеку необходимо загрузить в SS его адрес. Запись и чтение данных в стеке осуществляется в соответствии с принципом LIFO (Last Input First Output - Последним Пришел Первым Ушел). По мере записи данных в стек он растет в сторону младших адресов памяти.
Концептуальная схема организации стека представлена на рисунке 4.2. Регистры SS, ESP/ SP и EBP/ BP используются комплексно, каждый из них имеет свое функциональное назначение. Регистр ESP/ SP всегда указывает на вершину стека, то есть содержит смещение относительно начала стека, по которому в стек был записан последний элемент. Для доступа к элементам не в вершине, а внутри стека используется регистр EBP/ BP – указатель базы кадра стека. Например, при входе в процедуру выполняется передача нужных параметров путем записи их в стек. Если процедура также использует стек, то доступ к этим параметрам становится проблематичным. Выход заключается в том, чтобы после записи параметров в регистр EBP/ BP записать адрес вершины стека ESP/ SP. Значение регистра ESP/ SP в дальнейшем будет изменяться, однако в регистре EBP/ BP хранится адрес, используя который , можно получить доступ к переданным параметрам.
Рисунок 4.2 – Схема организации стека
Когда стек пуст, то значение регистра ESP/ SP равно адресу последнего байта сегмента (самому старшему адресу ячейки памяти в сегменте), выделенного под стек. Когда стек заполнен, то значение регистра ESP/ SP становится равным значению регистра SS, и дальнейшее добавление элементов невозможно. При помещении элементов в стек адрес вершины стека (содержимое регистра ESP/ SP) уменьшается (смещается в сторону меньших адресов), а при извлечении элементов из стека – увеличивается (смещается в сторону больших адресов).
Для работы со стеком предусмотрены специальные команды, формат которых представлен в таблице 4.14.
Таблица 4.14 – Формат стековых команд
Название команды | Мнемоника и формат команды | Описание действия |
Включить в стек | PUSH SRC | (SP) (SP) – 2 ((SP + 1):SP) (SRC) |
Извлечь из стека | POP DST | (DST) ((SP + 1):SP) (SP) (SP) + 2 |
Команда PUSH сначала уменьшает значение SP на 2, а затем по адресу (SP+1):SP записывает содержимое источника.
Команда POP сначала записывает содержимое из вершины стека (по адресу (SP+1):SP) по месту, указанному в DST, а затем увеличивает SP на 2.
В качестве операнда- источника SRC и в качестве операнда- приемника DST используются только регистры, кроме однобайтных и регистра CS.