ВУЗ: Не указан

Категория: Не указан

Дисциплина: Не указана

Добавлен: 18.06.2021

Просмотров: 131

Скачиваний: 2

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.

FAR PTR — прямой переход на метку в другом сегменте кода, при этом адрес перехода задается в виде непосредственного операнда или адреса (метки) и состоит из 16-разрядного селектора и 16/32-разрядного смещения, которые загружаются, соответственно, в регистры CS и EIP/IP;

WORD PTR — косвенный переход на метку внутри текущего сегмента кода, при этом модифицируется (значением смещения размером 16 или 32 бита из памяти по указанному в команде адресу или из регистра) только регистр EIP/IP;

DWORD PTR — косвенный переход на метку в другом сегменте кода, при этом модифицируются (значением из памяти — и только из памяти, из регистра нельзя) оба регистра, CS и EIP/IP (первое слово/двойное слово адреса перехода, представляющее собой смещение, загружается в EIP/IP; второе/третье слово — в CS).

Синтаксис команды безусловного перехода без сохранения информации о точке возврата:

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

Здесь адрес_перехода представляет метку или адрес области памяти, в которой находится указатель перехода.

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

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

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

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

В системе команд процессора IA-32 есть большая группа команд, призванных самостоятельно принимать решение о том, какая команда должна выполняться следующей. Решение принимается в зависимости от определенных условий, определяемых конкретной командой перехода. Процессор поддерживает 18 команд условного перехода, позволяющих проверить:

отношение между операндами) со знаком (больше или меньше);

отношение между операндами без знака (выше или ниже);

состояниями арифметических флагов ZF, SF, CF, OF, PF (но не AF).

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

jcc метка_перехода

Для того чтобы принять решение о том, куда будет передано управление командой условного перехода, предварительно должно быть сформировано условие, на основании которого должно приниматься решение. Источниками такого условия могут быть:

любая команда, изменяющая состояние арифметических флагов;

команда СМР, сравнивающая значения двух операндов;

состояние регистра ЕСХ/СХ.

Команда сравнения СМР (СоМРаrе) имеет следующий принцип работы. Команда СМР так же, как и команда SUB, выполняет вычитание операндов и по результатам сравнения устанавливает флаги. При этом записи результата вычитания на место первого операнда не происходит.


Синтаксис команды СМР:

cmp операнд_1,операнд__2

В листинге 1 приведен пример программы, производящей в строке символов длиной п байт замену строчных букв английского алфавита прописными. Строчные и прописные буквы в таблице ASCII упорядочены по алфавиту. Строчным буквам соответствует диапазон кодов 61h-7ah, прописным — 41h-5ah. Для того чтобы понять идею, лежащую в основе алгоритма преобразования, достаточно сравнить представления соответствующих прописных и строчных букв в двоичном виде:

а - 0110 0001..z – 0111 1010

А - 0100 0001...Z – 0101 1010.

Как видно из приведенного двоичного представления, для выполнения преобразования между строчными и прописными буквами достаточно всего лишь инвертировать 5-й бит.

Листинг 1. Смена регистра символов

<1>

;

model small

.stack 100h

.data

n equ 10

stroka db 'acvfgrndup'

.code

start:

mov ax,@data

mov ds,ax

xor ax,ax

mov cx,n

lea bx,stroka ;адрес stroka в bx

m1: mov al,[bx] ;очередной символ из stroka в al

cmp al,61h ;проверить, что код символа не меньше 61h

jb next ;если меньше, то не обрабатывать и на следующий символ

cmp al,7ah ;проверить, что код символа не больше 7аh

ja next ;если больше, то не обрабатывать и на следующий символ

and al,11011111b ;инвертировать 5-й бит

mov [bx],al ;символ на место в stroka

next:

inc bx ;адресовать следующий символ

dec cx ;уменьшить значение счетчика в cx

jnz m1 ;если cx не 0, то переход на m1

exit:

mov ax,4c00h

int 21h ;возврат управления операционной системе

end start

<2>

<3>

<4>

<5>

<6>

<7>

<8>

<9>

<10>

<11>

<12>

<13>

<14>

<15>

<16>

<16>

<18>

<19>

<20>

<21>

<22>

<23>

<24>

<25>

<26>

<27>

<28>

<29>

<30>


В строке 25 команда DEC уменьшает значение регистра СХ на 1. Когда это значение станет равным 0, процессор по результату операции декремента установит флаг ZF. Команда в строке 26 анализирует состояние этого флага и, пока он не равен 1, передает управление на метку ml. Причем на место этой команды можно было бы поставить команду JNE. Но для анализа регистра СХ в системе команд процессора есть специальная команда, которая рассматривается в дальнейшем.

Команды условного перехода и регистр ЕСХ/СХ

Регистр ЕСХ/СХ в архитектуре процессора имеет определенное функциональное назначение — он выполняет функции счетчика в командах управления циклами и при работе с цепочками символов. Возможно, что функционально команды условного перехода, связанные с регистром ЕСХ/СХ, правильнее было бы отнести к этой группе команд.

Синтаксис команд JCXZ (Jump if ex is Zero — переход, если СХ ноль) и JECXZ (Gump Equal ecx Zero — переход, если ЕСХ ноль) таков:

jcxz/jecxz метка_перехода

Эти команды используются при организации цикла и при работе с цепочками символов. В отличие от других команд условной передачи управления, команды JCXZ/JECXZ могут адресовать только короткие переходы — на -128 байт или на +127 байт от следующей за ней команды.


Установка байта по условию

При рассмотрении команд условного перехода логично упомянуть еще об одной команде — SETcc. Данная команда впервые появилась в процессоре i386. Ее формат: SETcc операнд1.

Команда устанавливает байт операнд1 после проверки модификатора ее, задающего условие, аналогично тому, как это делается в командах условного перехода. Фактически, модификатор «сс» обозначает флаг, который нужно проверить. В качестве операнда используется либо один из 8-разрядных регистров (AL, АН, BL, BH, CL, CH, DL, DH), либо адрес ячейки памяти размером в байт. Алгоритм работы команды заключается в том, что значение операнда устанавливается по результатам проверки условия, заданного модификатором «сс»:

операнд1 = 0 — если условие ложно;

операнд1 = 1 — если условие истинно.

Организация циклов

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

Например, подсчет количества нулевых байтов в области mas (листинг 2).

Листинг 2. Подсчет числа нулевых элементов


<1>

;

model small

.stack 100h

.data

len equ 10 ;количество элементов в mas

mas db 1,0,9,8,0,7,8,0,2,0

.code

start:

mov ax,@data

mov ds,ax

mov cx,len ;длину поля mas в cx

xor ax,ax

xor si,si

cycl:

jcxz exit ;проверка cx на 0, если 0, то на выход

cmp mas[si],0 ;сравнить очередной элемент mas с 0

jne m1 ;если не равно, то на m1

inc al ;в al счетчик нулевых элементов

m1:

inc si ;перейти к следующему элементу

dec cx ;уменьшить cx на 1;

jmp cycl

exit:

mov ax,4c00h

int 21h ;возврат управления операционной системе

end start

<2>

<3>

<4>

<5>

<6>

<7>

<8>

<9>

<10>

<11>

<12>

<13>

<14>

<15>

<16>

<16>

<18>

<19>

<20>

<21>

<22>

<23>

<24>

<25>

<26>


Цикл в листинге 2 организован тремя командами, JCXZ, DEC и JMP (строки 15, 21 и 22).

Команда JCXZ выполняет здесь две функции: предотвращает выполнение «пустого» цикла (когда счетчик цикла в СХ равен нулю) и отслеживает окончание цикла после обработки всех элементов поля mas.

Команда DEC после каждой итерации цикла уменьшает значение счетчика в регистре СХ на 1. При такой организации цикла все операции по его организации выполняются «вручную». Но, учитывая важность такого алгоритмического элемента, как цикл, разработчики процессора ввели в систему команд группу из трех команд, облегчающую программирование циклов. Эти команды также используют регистр ЕСХ/СХ как счетчик цикла.

К числу таких команд относится команда LOOP, которая позволяет организовать циклы (loops), подобные циклам for в языках высокого уровня с автоматическим уменьшением счетчика цикла. Синтаксис команды:

loop метка_перехода

Команда реализует следующие действия:


  1. Декремент регистра ЕСХ/СХ.

  2. Сравнение регистра ЕСХ/СХ с нулем:

если (ЕСХ/СХ) > 0, то управление передается на метку перехода;

если (ЕСХ/СХ) = 0, то управление передается на следующую после LOOP команду.

Команды LOOPE и LOOPZ (Loop still сх <> 0 or Zero flag = 0 — повторить цикл пока СХ <> 0 или ZF = 0) — абсолютные синонимы.

Синтаксис команд:

loope/loopz метка_перехода

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

  1. Декремент регистра ЕСХ/СХ.

  2. Сравнение регистра ЕСХ/СХ с нулем и анализ состояния флага нуля ZF:

если (ЕСХ/СХ) > 0 и ZF = 1, управление передается на метку перехода;

если (ЕСХ/СХ) = 0 и ZF = 0, управление предается на слудующую после LOOP команду.

Команды LOOPE/LOOPZ и LOOPNE/LOOPNZ по принципу своей работы являются взаимообратными. Они расширяют действие команды LOOP тем, что дополнительно анализируют флаг ZF. Это дает возможность организовать досрочный выход из цикла, используя этот флаг в качестве индикатора. Типичное применение этих команд связано с операцией поиска определенного значения в последовательности или со сравнением двух чисел.

Недостаток команд организации цикла LOOP, LOOPE/LOOPZ и LOOPNE/LOOPNZ заключается в том, что они реализуют только короткие переходы (от -128 до +127 байт). Для работы с длинными циклами используются команды условного перехода и команда JMP (листинг 2).

Рассмотрим несколько примеров организации циклов с помощью команд LOOP, LOOPE/LOOPZ и LOOPNE/LOOPNZ.



4. Цепочечные команды



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

8 битов, то есть байт;

16 битов, то есть слово;

32 бита, то есть двойное слово.

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

Операции-примитивы обработки цепочек и реализующие их команды ассемблера.

Пересылка цепочки:

MOVS адрес_приемника,адрес_источника;

MOVSB;

MOVSW;

MOVSD.

Сравнение цепочек:

CMPS адрес_приемника,адрес_источника;

CMPSB;

CMPSW;

CMPSD.

Сканирование цепочки:

SCASадрес_приемника;

SCASB;

SCASW;

SCASD.

Загрузка элемента из цепочки:

LODS адрес_источника;

LODSB;

LODSW;

LODSD.

Сохранение элемента в цепочке:

STOS адрес_приемника;

STOSB;

STOSW;

STOSD.

Получение элементов цепочки из порта ввода-вывода:

INS адрес_приемника,номер_порта;

INSB;

INSW;

INSD.

Вывод элементов цепочки в порт ввода-вывода:

OUTS номер_порта,адрес_источника;

OUTBS;

OUTWS;

OUTDS.

Логически к этим командам нужно отнести и так называемые префиксы повторения. Один из возможных типов префиксов — это префиксы повторения. Они предназначены для использования цепочечными командами. Префиксы повторения имеют свои мнемонические обозначения:


REP;

REPE, или REPZ;

REPNE, или REPNZ.

Эти префиксы повторения указываются перед нужной цепочечной командой в поле метки. Цепочечная команда без префикса выполняется один раз. Размещение префикса перед цепочечной командой заставляет ее выполняться в цикле. Различия приведенных префиксов — в основании, по которому принимается решение о циклическом выполнении цепочечной команды: по состоянию регистра ЕСХ/СХ или по флагу нуля ZF.

Префикс повторения REP (REPeat) используется с командами, реализующими операции-примитивы пересылки и сохранения элементов цепочек, — соответственно, MOVS и STOS. Префикс REP заставляет данные команды выполняться, пока содержимое в ЕСХ/СХ не станет равным 0. При этом цепочечная команда, перед которой стоит префикс, автоматически уменьшает содержимое ЕСХ/СХ на единицу. Та же команда, но без префикса, этого не делает.

Префиксы повторения REPE (REPeat while Equal) и REPZ (REPeat while Zero) являются абсолютными синонимами. Они заставляют цепочечную команду выполняться до тех пор, пока содержимое ЕСХ/CX не равно 0 или флаг ZF равен 1. Как только одно из этих условий нарушается, управление передается следующей команде программы. Благодаря возможности анализа флага ZF наиболее эффективно эти префиксы можно использовать с командами CMPS и SCAS для поиска различающихся элементов цепочек.

Префиксы повторения REPNE (REPeat while Not Equal) и REPNZ (REPeat while Not Zero) также являются абсолютными синонимами. Их действие на цепочечную команду несколько отличается от действий префиксов REPE/REPZ. Префиксы REPNE/REPNZ заставляют цепочечную команду циклически выполняться до тех пор, пока содержимое ЕСХ/СХ не равно нулю или флаг ZF равен нулю. При нарушении одного из этих условий работа команды прекращается. Данные префиксы также можно использовать с командами CMPS и SCAS, но для поиска совпадающих элементов цепочек.

Следующий важный момент, связанный с цепочечными командами, заключается в особенностях формирования физического адреса операндов адрес_источника и адрес_приемника. Цепочка-источник, адресуемая операндом адрес_источника, может находиться в текущем сегменте данных, определяемом регистром DS. Цепочка-приемник, адресуемая операндом адрес_приемника, должна быть в дополнительном сегменте данных, адресуемом сегментным регистром ES. Причем допускается замена (с помощью префикса замены сегмента) только регистра DS, регистр ES подменять нельзя. Вторые части адресов (смещения цепочек) также находятся в строго определенных местах. Для цепочки-источника это регистр ESI/SI (Source Index register — индексный регистр источника). Для цепочки-получателя это регистр EDI/DI (Destination Index register — индексный регистр приемника). Таким образом, полные физические адреса для операндов цепочечных команд следующие:

адрес_источника — пара ds:esi/si;

адрес_приемника — пара es:edi/di.

Команды LDS и LES позволяют получить полный указатель (сегмент плюс смещение) на ячейку памяти. Применение их в данном случае очень удобно в силу жесткой регламентации использования регистров для адресации операндов источника и приемника в цепочечных командах.