6. Инструкции передачи управления
Последовательность выполнения инструкций программы процессором 8086/8088 определяется содержимым регистров CS и IP. Регистр CS содержит базовый адрес текущего сегмента кода, т. е. 64-килобайтной области памяти, из которой выбираются инструкции. Содержимое регистра IP используется как смещение от начала сегмента кода. Комбинация регистров CS и IP указывает на позицию памяти, из которой должна быть выбрана очередная инструкция (обычно, впрочем, следующая инструкция уже выбрана и ожидает в очереди инструкций CPU, что обеспечивается наличием раздельных механизмов выборки и исполнения инструкций процессора 8086/8088).
Описываемые в этом разделе инструкции передачи управления оперируют с содержимым регистров CS и IP, что нарушает нормальную последовательность выполнения. При передаче управления очередь не содержит корректной инструкции, и BIU получает следующую инструкцию из памяти, используя содержимое CS и IP, после чего передаёт инструкцию непосредственно EU и начинает формировать очередь, начиная с нового адреса.
Процессор 8086/8088 имеет 4 группы инструкций передачи управления: инструкции безусловной и условной передачи управления, итерации и прерывания. Только последняя группа влияет на состояние флагов процессора. Однако выполнение многих инструкций передачи управления зависит от значений флагов.
6.1. Безусловный переход
Инструкции этого типа обеспечивают безусловный переход и могут передавать управление как внутри текущего сегмента кода (внутрисегментная передача управления), так и за его пределы (межсегментная передача управления). Тип передачи управления может быть задан ассемблеру предшествующим адресу перехода ключевым словом NEAR (внутрисегментная) или FAR (межсегментная).
Описания инструкций безусловного перехода приведены ниже.
CALL имя-процедуры ВЫЗОВ ПРОЦЕДУРЫ
Инструкция CALL активизирует указанную процедуру, сохраняя в стеке адрес следующей за CALL инструкции. Ассемблер генерирует инструкцию CALL разных типов в зависимости от того, с каким описателем объявлено имя-процедуры: NEAR или FAR. Для корректного возврата из процедуры тип инструкции CALL должен соответствовать типу инструкции RET, выполняющей этот возврат. Потенциальная возможность несоответствия имеет место, когда инструкция CALL и сама процедура находятся в раздельно транслируемых частях программы. Обычно ассемблер сам следит за соответствием вызовов и возвратов. Дополнительно об этом см. «Система программирования на макроассемблере MS-DOS. Часть 3. Директивы языка ассемблера», п. 3.2.
Различные формы CALL позволяют получать адрес процедуры из самой инструкции (прямая CALL) или из области памяти или регистра, на которые ссылается CALL (непрямая CALL). Следует помнить, что процессор автоматически устанавливает регистр IP указывающим на следующую инструкцию до сохранения его в стеке.
Для внутрисегментной прямой CALL содержимое регистра SP уменьшается на 2, и в стек помещается содержимое регистра IP. Затем к содержимому IP добавляется относительное смещение адреса процедуры, изменяющееся в пределах от –32К до +32К. Эта форма CALL является самоотносительной и динамически переместимой (CALL и процедура находятся в одном сегменте и перемещаются вместе) и может поэтому использоваться в адресно независимых программах.
Внутрисегментная непрямая CALL может функционировать через память или через регистр. Содержимое SP уменьшается на 2, и в стек помещается содержимое IP. Смещение процедуры извлекается из специфицированных в инструкции слова памяти или 16-битового регистра и заносится в IP.
Для межсегментной прямой CALL содержимое SP уменьшается на 2, и в стек помещается содержимое регистра CS. В CS заносится полученное из инструкции слово сегмента. SP снова уменьшается на 2, и в стек помещается содержимое IP, а в сам IP заносится слово смещения из инструкции.
В случае межсегментной непрямой CALL, которая может функционировать только через память, содержимое SP уменьшается на 2, в стек заносится регистр CS, в который затем копируется 2-е слово из адресуемого инструкцией 4-байтного указателя. SP снова уменьшается на 2, и в стек помещается содержимое регистра IP, куда затем заносится 1-е слово указателя.
RET число ВОЗВРАТ ИЗ ПРОЦЕДУРЫ
Инструкция RET передаёт управление из процедуры на инструкцию, непосредственно следующую за вызвавшей процедуру инструкцией CALL. Ассемблер генерирует внутрисегментную RET, если программист определил NEAR-процедуру, и межсегментную RET в случае FAR-процедуры. Инструкция RET извлекает из адресуемой регистром SP вершины стека слово, помещая его в регистр IP, и увеличивает содержимое SP на 2. В случае межсегментной RET из новой вершины стека извлекается и помещается в регистр CS еще одно слово, а содержимое SP увеличивается ещё на 2. Если в инструкции RET указано число (оно может отсутствовать), это значение добавляется в SP. Эта возможность может быть использована для удаления помещённых в стек параметров процедуры.
JMP адрес БЕЗУСЛОВНЫЙ ПЕРЕХОД
По этой инструкции управление безусловно передаётся по указанному адресу. В отличие от CALL инструкция JMP не помещает в стек никакой информации, и возврата к следующей за JMP инструкции не обеспечивается. Подобно CALL адрес получающей управление инструкции может быть получен из самой JMP (прямая JMP) или из ячейки памяти или регистра, специфицированных в JMP (непрямая JMP). С другой стороны, передача управления может быть как внутрисегментной, так и межсегментной.
Внутрисегментная прямая JMP изменяет содержимое регистра IP, добавляя туда смещение целевой инструкции относительно себя. Если ассемблер обнаружит, что эта инструкция отстоит от JMP не более, чем на 127 байтов, он автоматически генерирует двухбайтную форму инструкции (короткая JMP); в противном случае формируется ближний JMP, который может адресовать цель в пределах от -32К до +32К. Эти формы JMP являются самоотносительными и динамически переместимыми (JMP и целевая инструкция находятся в одном сегменте и перемещаются вместе) и могут поэтому использоваться в адресно независимых программах.
Внутрисегментная непрямая JMP может функционировать через память или через регистр. В первом случае содержимое адресуемого инструкцией слова памяти помещается в регистр IP. Во втором новое значение IP выбирается из указанного 16-битового регистра.
Межсегментная прямая JMP помещает в регистры IP и CS значения, специфицированные инструкцией.
Межсегментная непрямая JMP может функционировать только через память. Первое слово из адресуемого инструкцией 4-байтного указателя помещается в регистр IP, второе - в CS.
6.2. Условный переход
Инструкции условного перехода организуют передачу управления задаваемой инструкции при выполнении специфичных для каждой инструкции этого типа условий. Эти условия определяются текущими состояниями флагов процессора. Каждая из этих 18 инструкций (им соответствуют 30 мнемонических кодов операций) проверяет определённую комбинацию флагов. Если условие выполняется, происходит переход по указанному адресу; в противном случае управление передается на следующую инструкцию программы.
Все условные переходы являются короткими, т. е. целевая инструкция должна отстоять не далее, чем на –128 или +127 байтов от первого байта следующей инструкции (JMP 00h обеспечивает переход к следующей инструкции).
Поскольку переход осуществляется добавлением к содержимому регистра IP относительного смещения цели, все инструкции условного перехода являются самоотносительными и могут поэтому использоваться при написании адресно независимых программ.
Инструкции условной передачи управления и проверяемые при их выполнении условия приведены в таблице 6.1.
Таблица 6.1. Инструкции условной передачи управления
Мнемокод
|
Условие перехода
|
Флаги
|
Пояснение
|
JA/JNBE
|
(CF or ZF)=0
|
выше/не ниже и не равно
|
JAE/JNB
|
CF=0
|
выше или равно/не ниже
|
JB/JNAE
|
CF=1
|
ниже/не выше и не равно
|
JBE/JNA
|
(CF or ZF)=1
|
ниже или равно/не выше
|
JC
|
CF=1
|
перенос
|
JE/JZ
|
ZF=1
|
равно/нуль
|
JG/JNLE
|
((SF xor OF) or ZF)=0
|
больше/ не меньше и не равно
|
JGE/JNL
|
(SF xor OF)=0
|
больше или равно/не меньше
|
JL/JNGE
|
(SF xor OF)=1
|
меньше/не больше и не равно
|
JLE/JNG
|
((SF xor OF) or ZF)=1
|
меньше или равно/ не больше
|
JNC
|
CF=0
|
нет переноса
|
JNE/JNZ
|
ZF=0
|
не равно/не нуль
|
JNO
|
OF=0
|
нет переполнения
|
JNP/JPO
|
PF=0
|
нет паритета/
паритет нечетный
|
JNS
|
SF=0
|
знак +
|
JO
|
OF=1
|
переполнение
|
JP/JPE
|
PF=1
|
есть паритет/ паритет чётный
|
JS
|
SF=1
|
знак –
|
Примечания:
1. Термины «выше» и «ниже» применимы для сравнения беззнаковых величин (адресов).
2. Термины «больше» и «меньше» используются при учёте знака числа.
3. Слова xor и or обозначают соответствующие логические операции.
6.3. Итерации
Инструкции управления итерациями могут быть использованы для регулирования повторений программных циклов. Они используют содержимое регистра CX как счётчик повторений. Подобно условным переходам инструкции этой группы являются самоотносительными и могут осуществлять только короткие передачи управления, т. е. в пределах от –128 до +127.
LOOP короткая-метка ЦИКЛ
Инструкция LOOP уменьшает содержимое регистра CX на 1 и передаёт управление по указанному адресу, если в CX не 0; в противном случае выполняется следующая за LOOP инструкция.
LOOPE/LOOPZ короткая-метка ЦИКЛ, ПОКА РАВНО/НУЛЬ
Эти два обозначения являются различными мнемониками одной инструкции, по которой содержимое регистра CX уменьшается на 1, и управление передаётся по указанному адресу, если в CX не 0 и флаг ZF равен 1; в противном случае выполняется следующая инструкция.
LOOPNE/LOOPNZ короткая-метка ЦИКЛ, ПОКА НЕ РАВНО/НЕ НУЛЬ
Эти два обозначения являются различными мнемониками одной инструкции, по которой содержимое регистра CX уменьшается на 1, и управление передаётся по указанному адресу, если в CX не 0 и флаг ZF равен 0; в противном случае выполняется следующая инструкция.
JCXZ короткая-метка ПЕРЕХОД, ЕСЛИ В CX 0
Инструкция JCXZ передаёт управление по указанному адресу, если регистр CX содержит 0; в противном случае выполняется следующая за JCXZ инструкция. Инструкция JCXZ может использоваться в начале цикла для распознавания ситуации, когда CX уже содержит 0.
6.4. Прерывания
Инструкции этой группы позволяют использовать в программах сервисные функции, обеспечиваемые через аппарат прерываний операционной системы. С этой целью генерируется программное прерывание, эффект которого подобен эффекту аппаратных прерываний. Однако процессор не выполняет цикл передачи подтверждения прерывания, если прерывание инициировано программой или связано с NMI.
Инструкции прерываний каждая по-своему влияют на состояния флагов процессора.
INT номер-прерывания ПРЕРЫВАНИЕ
Инструкция INT активизирует процедуру, предусмотренную для обработки прерывания с указанным номером. Указатель стека SP уменьшается на 2, в стек помещаются флаги (в формате инструкции PUSHF) и флаги TF и IF устанавливаютя в 0 (для запрета пошагового режима и маскируемых прерываний). Затем SP уменьшается еще на 2, и в стек заносится содержимое регистра CS. Адрес указателя прерывания (т. е. местонахождение адреса программы обработки прерывания) вычисляется путём умножения указанного в инструкции INT номера на 4: второе слово указателя замещает значение регистра CS. SP снова уменьшается на 2, и в стек помещается содержимое регистра IP, а в сам IP заносится первое слово указателя.
Если указан номер прерывания 3, ассемблер генерирует короткую (1 байт) форму инструкции, известную как прерывание по достижении точки выхода.
Программные прерывания могут использоваться как «вызовы супервизора», т. е. для запроса сервиса операционной системы, в частности, процедур, написанных для обработки аппаратных прерываний.
INTO ПРЕРЫВАНИЕ, ЕСЛИ ЕСТЬ ПЕРЕПОЛНЕНИЕ
По инструкции INTO генерируется программное прерывание, если установлен в 1 флаг OF; в противном случае управление передается следующей инструкции без активизации процедуры обработки прерывания. Инструкция INTO обращается к требуемой процедуре (номер прерывания – 4) через указатель прерывания, расположенный по 16-ричному адресу 10, устанавливает в 0 флаги TF и IF и в остальном работает также, как INT. Инструкция INTO может использоваться после арифметических или логических операций для обработки возможных переполнений.
INT3 ТОЧКА ВЫХОДА
Выполнение этой инструкции эквивалентно прерыванию с номером 3 («достигнута точка выхода»). Ассемблер генерирует короткую, 1-байтную машинную инструкцию.
IRET ВОЗВРАТ ИЗ ПРЕРЫВАНИЯ
По инструкции IRET управление возвращается в точку прерывания путём восстановления из стека содержимого регистров IP и CS и значений флагов, помещённых туда при возникновении прерывания. Эта инструкция используется для выхода как из программных, так и из аппаратных прерываний.
|