Assembler - язык неограниченных возможностей

         

Команды передачи управления




  • Команда:
  • JMP операнд
  • Назначение:
  • Безусловный переход
  • Процессор:
  • 8086

    JMP передает управление в другую точку программы, не сохраняя какой-либо информации для возврата. Операндом может быть непосредственный адрес для перехода (в программах используют имя метки, установленной перед командой, на которую выполняется переход), а также регистр или переменная, содержащая адрес.

    В зависимости от типа перехода различают:

  • переход типа short (короткий переход) — если адрес перехода находится в пределах от -127 до +128 байт от команды JMP;
  • переход типа near (ближний переход) — если адрес перехода находится в том же сегменте памяти, что и команда JMP;
  • переход типа far (дальний переход) — если адрес перехода находится в другом сегменте. Дальний переход может выполняться и в тот же самый сегмент, если в сегментной части операнда указано число, совпадающее с текущим значением CS;
  • переход с переключением задачи — передача управления другой задаче в многозадачной среде. Этот вариант будет рассмотрен в главе, посвященной защищенному режиму.
  • При выполнении переходов типа short и near команда JMP фактически изменяет значение регистра EIP (или IP), изменяя тем самым смещение следующей исполняемой команды относительно начала сегмента кода. Если операнд — регистр или переменная в памяти, то его значение просто копируется в EIP, как если бы это была команда MOV. Если операнд для JMP — непосредственно указанное число, то его значение суммируется с содержимым EIP, приводя к относительному переходу. В ассемблерных программах в качестве операнда обычно указывают имена меток, но на уровне исполнимого кода ассемблер вычисляет и записывает именно относительные смещения.

    Выполняя дальний переход в реальном режиме, виртуальном режиме и в защищенном режиме (при переходе в сегмент с теми же привилегиями), команда JMP просто загружает новое значение в EIP и новый селектор сегмента кода в CS, используя старшие 16 бит операнда как новое значение для CS и младшие 16 или 32 — как значение IP или EIP.

  • Команда:
  • Jcc метка
  • Назначение:
  • Условный переход
  • Процессор:
  • 8086
    <
    /p> Это набор команд, каждая из которых выполняет переход (типа short или near), если удовлетворяется соответствующее условие. Условием в каждом случае реально является состояние тех или иных флагов, но, если команда из набора Jcc используется сразу после СМР, условия приобретают формулировки, соответствующие отношениям между операндами СМР (см. табл. 7). Например, если операнды СМР были равны, то команда JE, выполненная сразу после этого СМР, осуществит переход. Операнд для всех команд из набора Jcc — 8-битное или 32-битное смешение относительно текущей команды.

    Слова «выше» и «ниже» в таблице относятся к сравнению чисел без знака, слова «больше» и «меньше» учитывают знак.

    Таблица 7. Варианты команды Jcc

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

    cmp ах,0 jne local_1 jmp far_label ; переход, если АХ = 0 lосаl_1:

  • Команда:
  • JCXZ метка
  • Назначение:
  • Переход, если СХ = 0
  • Процессор:
  • 8086
  • Команда:
  • JECXZ метка
  • Назначение:
  • Переход, если EСХ = 0
  • Процессор:
  • 80386
    <


    /p> Выполняет ближний переход на указанную метку, если регистр CX или ECX (для JCXZ и JECXZ соответственно) равен нулю. Так же как и команды из серии Jcc, JCXZ и JECXZ не могут выполнять дальних переходов. Проверка равенства СХ нулю, например, может потребоваться в начале цикла, организованного командой LOOPNE, — если в него войти с СХ = 0, то он будет выполнен 65 535 раз.

  • Команда:
  • LOOP метка
  • Назначение:
  • Цикл
  • Процессор:
  • 8086
    Уменьшает регистр ЕСХ на 1 и выполняет переход типа short на метку (которая не может быть дальше, чем на расстоянии от -128 до +127 байт от команды LOOP), если ЕСХ не равен нулю. Эта команда используется для организации циклов, в которых регистр ЕСХ (или СХ при 16-битной адресации) играет роль счетчика. Так, в следующем фрагменте команда ADD выполнится 10 раз:

    mov cx,0Ah loop_start: add ax,cx loop loop_start

    Команда LOOP полностью эквивалентна паре команд

    dec ecx jz метка

    Но LOOP короче этих двух команд на один байт и не изменяет значения флагов.

  • Команда:
  • LOOPE метка
  • Назначение:
  • Цикл, пока равно
  • Команда:
  • LOOPZ метка
  • Назначение:
  • Цикл, пока ноль
  • Команда:
  • LOOPNE метка
  • Назначение:
  • Цикл, пока не равно
  • Команда:
  • LOOPNZ метка
  • Назначение:
  • Цикл, пока не ноль
  • Процессор:
  • 8086
    Все эти команды уменьшают регистр ЕСХ на один, после чего выполняют переход типа short, если ЕСХ не равен нулю и если выполняется условие. Для команд LOOPE и LOOPZ условием является равенство единице флага ZF, для команд LOOPNE и LOOPNZ — равенство флага ZF нулю. Сами команды LOOPcc не изменяют значений флагов, так что ZF должен быть установлен (или сброшен) предшествующей командой. Например, следующий фрагмент копирует строку из DS:SI в строку в ES:DI (см. описание команд работы со строками), пока не кончится строка (СХ = 0) или пока не встретится символ с ASCII-кодом 13 (конец строки):

    mov cx,str_length move_loop: stosb lodsb cmp al,13 loopnz move_loop

  • Команда:
  • CALL операнд
  • Назначение:
  • Вызов процедуры
  • Процессор:
  • 8086
    <


    /p> Сохраняет текущий адрес в стеке и передает управление по адресу, указанному в операнде. Операндом может быть непосредственное значение адреса (метка в ассемблерных программах), регистр или переменная, содержащие адрес перехода. Если в качестве адреса перехода указано только смещение, считается, что адрес расположен в том же сегменте, что и команда CALL. При этом, так же как и в случае с JMP, выполняется ближний вызов процедуры. Процессор помещает значение регистра EIP (IP при 16-битной адресации), соответствующее следующей за CALL команде, в стек и загружает в EIP новое значение, осуществляя тем самым передачу управления. Если операнд CALL — регистр или переменная, то его значение рассматривается как абсолютное смещение, если операнд — метка в программе, то ассемблер указывает ее относительное смещение. Чтобы осуществить дальний CALL в реальном режиме, режиме V86 или в защищенном режиме при переходе в сегмент с теми же привилегиями, процессор помещает в стек значения регистров CS и EIP (IP при 16-битной адресации) и выполняет дальний переход аналогично команде JMP.

  • Команда:
  • RET число
    RETN число
    RETF число
  • Назначение:
  • Возврат из процедуры
  • Процессор:
  • 8086
    RETN считывает из стека слово (или двойное слово, в зависимости от режима адресации) и загружает его в IP (или EIP), выполняя тем самым действия, обратные ближнему вызову процедуры командой, CALL. RETF соответственно загружает из стека IP (EIP) и CS, возвращаясь из дальней процедуры. Если в ассемблерной программе указана команда RET, ассемблер заменит ее на RETN или RETF в зависимости от того, как была описана процедура, которую эта команда завершает. Операнд для RET необязателен, но, если он присутствует, после считывания адреса возврата из стека будет удалено указанное количество байт — это бывает нужно, если при вызове процедуры ей передавались параметры через стек.

  • Команда:
  • INT число
  • Назначение:
  • Вызов прерывания
  • Процессор:
  • 8086
    INT помещает в стек содержимое регистров EFLAGS, CS и EIP, после чего передает управление программе, называемой «обработчик прерывания» с указанным в качестве операнда номером (число от 0 до 0FFh), аналогично команде CALL. В реальном режиме адреса обработчиков прерываний считываются из таблицы, начинающейся в памяти по адресу 0000h:0000h. Адрес каждого обработчика занимает 4 байта, так что, например, адрес обработчика прерывания 10h находится в памяти по адресу 0000h:0040h. В защищенном режиме адреса обработчиков прерываний находятся в таблице IDT и обычно недоступны для прямого чтения или записи, так что для установки собственного обработчика программа должна обращаться к операционной системе. В DOS вызовы прерываний используются для выполнения большинства системных функций — работы с файлами, вводом/выводом и т.д. Например, следующий фрагмент кода завершает выполнение программы и возвращает управление DOS:

    mov ax,4C01h int 21h



  • Команда:
  • IRET
    IRETD
  • Назначение:
  • Возврат из обработчика прерывания
  • Процессор:
  • 8086
    Возврат управления из обработчика прерывания или исключения. IRЕТ загружает из стека значения IP, CS и FLAGS, a IRETD — EIP, CS и EFLAGS соответственно. Единственное отличие IRET от RETF состоит в том, что восстанавливается значение регистра флагов, из-за чего многим обработчикам прерываний приходится изменять значение EFLAGS, находящегося в стеке, чтобы, например, вернуть флаг CF установленным в случае ошибки.

  • Команда:
  • INT3
  • Назначение:
  • Вызов прерывания 3
  • Процессор:
  • 8086
    Размер этой команды — один байт (код 0CCh), что делает ее удобной для отладки программ отладчиками, работающими в реальном режиме. Такие отладчики записывают этот байт вместо первого байта команды, перед которой требуется точка останова, и переопределяют адрес обработчика прерывания 3 на соответствующую процедуру внутри отладчика.

  • Команда:
  • INTO
  • Назначение:
  • Вызов прерывания 4 при переполнении
  • Процессор:
  • 8086
    INTO — еще одна специальная форма команды INT. Эта команда вызывает обработчик прерывания 4, если флаг OF установлен в 1.

  • Команда:
  • BOUND индекс, границы
  • Назначение:
  • Проверка выхода за границы массива
  • Процессор:
  • 80186
    BOUND проверяет, не выходит ли значение первого операнда (регистр), взятое как число со знаком, за границы, указанные во втором операнде (переменная). Границы — два слова или двойных слова (в зависимости от разрядности операндов), рассматриваемые как целые со знаком, расположенные в памяти подряд. Первая граница считается нижней, вторая — верхней. Если индекс меньше нижней границы или больше верхней, вызывается прерывание 5 (или исключение #BR), причем адрес возврата указывает не на следующую команду, а на BOUND, так что обработчик должен исправить значение индекса или границ, прежде чем выполнять команду IRET.

  • Команда:
  • ENTER размер, уровень
  • Назначение:
  • Вход в процедуру
  • Процессор:
  • 80186
    <


    /p> Команда ENTER создает стековый кадр заданного размера и уровня вложенности (оба операнда — числа; уровень вложенности может принимать значения только от 0 до 31) для вызова процедуры, использующей динамическое распределение памяти в стеке для своих локальных переменных. Так, команда

    enter 2048,3

    помещает в стек указатели на стековый кадр текущей процедуры и той, из которой вызывалась текущая, создает стековый кадр размером 2 килобайта для вызываемой процедуры и помещает в ЕВР адрес начала кадра. Пусть процедура MAIN имеет уровень вложенности 0, процедура PROCA запускается из MAIN и имеет уровень вложенности 1, и PROCB запускается из PROCA с уровнем вложенности 2. Тогда стек при входе в процедуру MAIN имеет вид, показанный на рис. 10.



    Рис. 10. Стековый кадр процедуры 0-го уровня (MAIN)

    Теперь процедура MAIN может определять свои локальные переменные в памяти, используя текущее значение ЕВР.

    На первом уровне вложенности процедура PROCA, как показано на рис. 11, может создавать свои локальные переменные, используя текущее значение EBP, и получает доступ к локальным переменным процедуры MAIN, используя значение ЕВР для MAIN, помещенное в стек командой ENTER.



    Рис. 11. Стековый кадр процедуры 1-го уровня (PROCA)

    Процедура PROCB на втором уровне вложенности (рис. 12) получает доступ как к локальным переменным процедуры PROCA, используя значение ЕВР для PROCA, так и к локальным переменным процедуры МАIN, используя значение ЕВР для MAIN.



    Рис. 12. Стековый кадр процедуры 2-го уровня (PROCB)

  • Команда:
  • LEAVE
  • Назначение:
  • Выход из процедуры
  • Процессор:
  • 80186
    Команда LEAVE выполняет действия, обратные команде ENTER. Фактически эта команда только копирует содержимое ЕВР в ESP, тем самым выбрасывая из стека весь кадр, созданный последней выполненной командой ENTER, и считывает из стека ЕВР для предыдущей процедуры, что одновременно восстанавливает и значение, которое имел ESP до вызова последней команды ENTER.


    Содержание раздела