Регистр SP (ЕSP). Указатель стека. Стеком называется свободная область памяти, предназначенная для временного хранения данных с целью их дальнейшего использования.
Регистр ВР (ЕВР). Используется для доступа к параметрам, значения которых передаются с помощью сохранения данных в стеке.
Регистр SI (ЕSI). Является указателем источника. Применяется в строковых операциях, при которых связан с регистром сегмента данных DS.
Регистр DI (ЕDI). Является указателем приемника. В строковых операциях связан с дополнительным регистром сегмента данных ES.
Сегментные регистры.
Физический адрес любой ячейки памяти состоит из 16-битного значения адреса сегмента и 16-битного смещения внутри сегмента. Каждый сегментный регистр используется для адресации определенного типа. Имеется четыре сегментных регистра: CS, DS, ES, SS. Микропроцессоры фирмы Intel, начиная с 486, имеют еще два новых дополнительных сегментных регистра – FS и GS.
Регистр CS. Определяет сегмент кода – сегмент программы, содержащей выполняемые команды. Устанавливается при загрузке программы автоматически.
Регистр DS. Определяет сегмент данных. В строковых операциях связан с регистром источника SI.
Регистр ES. Определяет дополнительный сегмент данных и применяется в тех случаях, когда требуется обратиться к произвольному сегменту памяти. В строковых операциях связан с регистром приемника DI.
Регистр SS. Регистр сегмента стека, связан с регистром SP. Содержит начальный адрес сегмента стека, в то время как SP устанавливается на конец стека. Регистры SS и SP при загрузке программы устанавливаются автоматически.
Регистры состояния и управления.
В микропроцессоре присутствуют несколько регистров, содержащих информацию о состоянии микропроцессора и программы, команды которой находятся в очереди команд (загружены на конвейер). К этим регистрам относятся счетчик команд IP (EIP), регистр флагов FL (EFL) и системные регистры.
Счетчик команд IP (EIP). Называется также командным указателем. Он связан с регистром сегмента кодов CS и содержит смещение команды, которая должна быть выполнена. При выполнении команды значение счетчика увеличивается за исключением тех случаев, когда команда относится к командам управления – перехода, цикла, вызова подпрограммы.
Регистр флагов FL (EFL). Содержит 16 (32) бит. Отдельные биты имеют определенное функциональное назначение и называются флагами. Различаются три типа флагов:
-
системные флаги – отражают текущее состояние компьютера в целом и используется ОС, а не программами пользователя;
-
флаги состояния – изменяются после каждой команды;
-
флаги управления.
Вопросы:
-
Что называется регистром?
-
Перечислить регистры общего назначения.
-
Какова роль регистров общего назначения в работе МП?
-
Перечислить сегментные регистры.
-
Какова роль сегментных регистров в работе МП?
-
Перечислить регистры состояния и управления.
-
Для чего используются регистры состояния и управления?
Семинар 8.
Синтаксис Ассемблера.
Представление данных в памяти. Представление команд в памяти.
Формат машинной команды.
Программа на ассемблере представляет собой совокупность блоков памяти, называемых сегментами памяти. Программа может состоять из одного или нескольких таких блоков-сегментов. Каждый сегмент содержит совокупность предложений языка, каждое из которых занимает отдельную строку кода программы.
Предложения ассемблера бывают четырех типов:
-
команды, или инструкции, представляющие собой символические аналоги машинных команд. В процессе трансляции инструкции ассемблера преобразуются в соответствующие команды МП
-
макрокоманды – оформляемые определенным образом предложения текста программы, замещаемые во время трансляции другими предложениями.
-
директивы, являющиеся указанием транслятору ассемблера на выполнения некоторых действий. У директив нет аналогов в машинном представлении
-
строки комментариев, содержащие любые символы, в том числе и буквы русского алфавита. Комментарии игнорируются транслятором.
Машинная команда состоит из нескольких байт, содержащих поле кода операции и поля операндов. Количество операндов может быть равно 0, 1 или 2. Команда может содержать также префикс, модифицирующий ее действие. Архитектура микропроцессора не позволяет манипулировать двумя операндами, находящимися в памяти. Поскольку в команде может участвовать не более одного операнда из памяти, то команда, имеющая два операнда, адресует их одним из следующих способов:
-
регистр – регистр;
-
регистр – память;
-
память – регистр;
-
число – регистр;
-
число – память.
Рассмотрим формат команды ассемблера:
[Метка:] Мнемокод [операнд] [;комментарий]
Обязательным здесь является только мнемокод. В зависимости от команды может не быть операндов, может быть один или два операнда.
***** Метка – служит для присвоения имени команде. На эту метку можно будет ссылаться из любой части программы. Она может содержать до 31 символа и заканчиваться двоеточием и содержать символы алфавита от a до Z. и от a до z, цифры от 0 до 9 и символы ?, ., @,, _, $. Метка не должна начинаться с цифры. Если используется «.», то она должна быть первым символом метки. Имя метки не должно совпадать с названием команд. В метку не должны вставляться пробелы.
***** Комментарии – должны быть отделены от команд ;. Это комментарии к команде, программе и блоку команд.
***** Мнемокод – это имя команды МП. Поле операндов – в поле операндов может быть 0, 1 или 2 операнда в зависимости от типа команды. Операнд – часть команды, макрокоманды или директивы ассемблера, обозначающие объекты, над которыми производятся действия. Операнды ассемблера описываются выражениями с числовыми и текстовыми константами, метками и идентификаторами переменных с использованием знаков операций и некоторых зарезервированных слов.
Если в команде 2 операнда, то первый операнд называется приемником, а второй источником. Например:
MOV AX, CX ; содержимое регистра cx перемещается в ax
Для работы с данными их помещают в сегмент данных. Описание сегмента данных осуществляется с помощью директивы.
Классификация операндов.
1- Постоянные и непосредственные операнды- число, строка, имя или выражение, имеющие некоторое фиксированное значение.
MOV ax,5
2- Адресные операнды- задают физическое расположение операнда в памяти с помощью указания двух составляющих адреса: сегмента и смещения .
MOV AX,0000H
MOV DS,AX
MOV AX,DS:0000H ; адресный операнд
3- Перемещаемые операнды – любые символьные имена, представляющие некоторые адреса памяти.
.data
a db 10
.code
…..
lea si,a ; a – перемещаемый операнд
4- Счетчик адреса – специфический вид операнда. Он обозначается $. Когда транслятор ассемблера встречает $ в исходной программе этот символ то подставляет вместо него текущее значение счетчика адреса. Значение счетчика адреса, или как его иногда называют счетчика размещения, представляет собой смещение текущей машинной команды
относительно начала сегмента кода.
Jmp $+3 ; переход на mov
cld
mov al,1
5- Регистровый операнд – это просто имя регистра.
6- Базовый и индексный операнды – используется для косвенной адресации
7- Структурные операнды – используется для доступа к конкретному элементу сложного типа данных, называемых структурой.
-
Записи – используется для доступа к битовому полю некоторой записи.
Команды пересылки данных
Эти команды осуществляют обмен данными и адресами между регистрами и ячейками памяти или портами ввода-вывода.
К этой группе относятся следующие команды:
MOV <операнд-приемник>,<операнд-источник>
Существуют ограничения на использования данной команды:
-
Нельзя осуществлять пересылку из одной области памяти в другую. Если возникает такая необходимость, то нужно использовать в качестве промежуточного буфера любой доступный в данный момент регистр общего назначения нельзя загрузить в сегментный регистр значение непосредственно из памяти.
-
Нельзя пересылать содержимое одного регистра в другой сегментный регистр. Это объясняется тем, что в системе команд нет соответствующего кода операции. Выполнить такую операцию можно через регистр общего назначения.
mov ax,ds
mov es,ax
-
Нельзя использовать сегментный регистр cs в качестве операнда-приемника. Это объясняется тем, что в паре регистров cs:ip всегда содержится адрес команды, которая должна выполняться следующей. Изменение данного регистра означает фактически операцию перехода, а не команду пересылки.
Для организации работы со стеком используются следующие команды.
Стек – память организованная по принципу «первым пришел последним ушел». Чаще всего стек используется при вызовах процедуры при использовании команды CALL. В этом случае адрес возврата, который извлекается после выполнения процедуры.
Стек имеет следующую структуру:
Адрес стека находится в указателе стека sp. Адрес, который содержится в sp называется вершиной стека. Стек «растет» по направлению к младшим адресам (к ячейке 0), т.е. первое слово помещенное в стек имеет наибольший адрес, следующее на 2 байта ниже.
Если нам необходимо получить доступ к элементам не на вершине, а внутри стека, то в этом случае необходимо использовать регистр ebp- это регистр указателя базы кадра стека, где можно записать необходимый адрес стека.
-
PUSH источник - запись значения источника в вершину стека. В этом случае если необходимо сохранить необходимый адрес
-
POP приемник - запись значения из вершины стека по месту, указанному операндом приемником. Значение при этом «снимается» с вершины стека.
-
PUSHA и PUSHAW– команда групповой записи в стек. По этой команде в стек последовательно записываются регистры ax, cx, dx, bx, sp, bp, si, di. Разница этих двуух команд в разрядности используемых регистров (16 или 32 разрядных регистров)
-
POPA, POPAW – групповое извлечение из стека, обратная предыдущим операция.
-
PUSH – сохранения регистров флагов в стеке.
-
PUSHFW – сохраняет в стеке регистр флагов flags или eflags
-
POPF и POPFW – обратная предыдущим операция извлечения регистра флагов из стека.
Команда обмена XCHG
Двунаправленная пересылка данных. Команда меняет между собой значения двух регистров или регистра и ячейки памяти.
XCHG ax,bx
XCHG al,bl
Работа с адресами и указателями
-
lea приемник, источник - загрузка исполнительного адреса. Удобна для работы со строками. В отличие от команды mov с операцией OFFSET операнд источник может быть индексированным.
Например:
mov di, 5
lea bx, tab[di]
Команда Lea похожа на команду mov тем, что также производит пересылку. Однако эта команда производит пересылку не данных, а эффективного адреса (т.е. смещения данных относительно начала сегмента данных) в регистр, указанный операндом назначения.
-
lds приемник, источник - регистр указателя в регистр сегмента данных ds. Это загрузка указателя и регистра сегмента данных( загрузка указателя с использованием регистра ds)
Например:
h_f dd here
……
lds bx, h_f
аналогично операции
mov bx, offset h_f
mov ax,seg here
mov ds, ax
где SEG - операция, которая возвращает номер блока адреса переменной.
В этой операции исключается использование дополнительного третьего регистра.
-
les приемник, источник -загрузка указателя в регистр дополнительного сегмента данных es
-
lgs приемник, источник – загрузка указателя в регистр дополнительного сегмента данных gs.
-
lfs приемник, источник - . загрузка указателя в регистр дополнительного сегмента данных fs.
-
lss приемник, источник - . загрузка указателя в регистр сегмента стека ss.
Использование Borland Pascal с языком ассемблера
Встроенный ассемблер Borland Pascal позволяет вам непосредственно в
программах Паскаля записывать код ассемблера процессоров 8087/8087 и 80286/80287.
Если требуется чередовать код Паскаля и ассемблера, можно преобразовать код
ассемблера в машинные инструкции вручную и воспользоваться затем операторами inline, либо выполнять компоновку с файлами .OBJ, которые содержат внешние процедуры и
функции (external). Встроенные операторы ассемблера представляют собой большое подмножество синтаксиса, поддерживаемого Турбо Ассемблером и Макроассемблером фирмы Microsoft. Встроенный ассемблер поддерживает все коды операций процессором
8086/8087 и 80286/80287 и некоторые из операций, используемых в выражениях Турбо
Ассемблера За исключением директив DB (определить байт), DW (определить слово) и DD (определить двойное слово) никакие другие директивы
Турбо Ассемблера, типа EQU, STRUC, SEGMENT или MACRO, встроенным ассемблером не поддерживаются. Однако, операции, реализуемые с помощью директив Турбо Ассемблера, близко соответствуют конструкциям Borland Pascal.
Например, большинство директив EQU соответствуют описаниям Borland Pascal const,
var и type, директива PROC – описаниям procedure и function,
а директива STRUC - типам record Borland Pascal.
Фактически, встроенный ассемблер Borland Pascal можно рассматривать, как компилятор языка ассемблера, использующий для всех описаний синтаксис Паскаля.
Оператор asm
Встроенный ассемблер становится доступным с помощью операторов asm.
Оператор asm имеет следующий синтаксис:
asm
оператор_ассемблера < разделитель оператор_ассемблера >
end,
где "оператор_ассемблера" представляет собой оператор ассемблера, а "разделитель " - это точка с запятой, новая строка или комментарий Паскаля. Приведем некоторые примеры операторов asm:
asm
mov ah,0 { считать с клавиатуры код функции }
int 16H { для чтения клавиши вызвать BIOS }
mov CharCode,al { сохранить код ASCII }
mov ScanCode,ah { сохранить код опроса }
end;
asm
push ds { сохранить DS }
lds si,Source { загрузить указатель источника }
les di,Dest { загрузить указатель приемника }
mov cx,Count { загрузить размер блока }
cld { переместить }
rep movsb { скопировать блок }
pop ds { восстановить DS }
end;
Заметим, что на одной строке можно разместить несколько операторов ассемблера разделив их точками с запятой. Кроме того следует отметить, что если операторы
ассемблера размещаются на разных строках, разделять их точками с запятой не требуется.
Заметим также, что точка с запятой не говорит о том, что остальная часть строки представляет собой комментарий.
Комментарии следует записывать, используя синтаксис Паскаля:
с помощью { и } или (* и *).
Команды ассемблера
Арифметические операции - ADD, SUB, MUL, DIV. Многие опкоды делают вычисления. Вы можете узнать многие из них по их названиям: add (addition - добавление), sub (substraction - вычитание), mul (multiply - умножение), div (divide - деление).
Опкод add имеет следующий синтаксис:
add приемник, источник
Выполняет вычисление: приемник = приемник + источник.
Имеются также другие формы:
приемник
|
источник
|
пример
|
регистр
|
регистр
|
add ecx, edx
|
регистр
|
память
|
add ecx, dword ptr [104h] / add ecx, [edx]
|
регистр
|
значение
|
add eax, 102
|
память
|
значение
|
add dword ptr [401231h], 80
|
память
|
регистр
|
add dword ptr [401231h], edx
|
Эта команда очень проста. Она добавляет значение источника к значение приемника и помещает результат в приемник. Другие математические команды:
sub приемник, источник (приемник = приемник - источник)
mul множимое, множитель (множимое = множимое * множитель)
div делитель (eax = eax / делитель, edx = остаток)
******** Вообще все арифметические операции в ассемблере производятся между регистром и аккумулятором, то есть регистром EAX. В операторах MUL и DIV только один параметр, потому что ассемблер сразу знает, что второе число хранится в EAX.
Поскольку регистры могут содержать только целочисленные значения (то есть числа, не, с плавающей запятой), результат деления разбит на частное и остаток. Теперь, в зависимости от размера источника, частное сохраняется в eax, а остаток в edx:
размер источника
|
деление
|
частное в...
|
остаток в...
|
BYTE (8-bits)
|
ax / делитель
|
AL
|
AH
|
WORD (16-bits)
|
dx:ax* / делитель
|
AX
|
DX
|
DWORD (32-bits)
|
edx:eax* / делитель
|
EAX
|
EDX
|
* = Например: если dx = 2030h, а ax = 0040h, dx: ax = 20300040h. Dx:ax - значение dword, где dx представляет старшее word, а ax - младшее. Edx:eax - значение quadword (64 бита), где старшее dword в edx и младшее в eax.
Источник операции деления может быть:
-
8-бит регистр (al, ah, cl,...)
-
16-бит регистр (ax, dx, ...)
-
32-бит регистр (eax, edx, ecx...)
-
8-бит значение из памяти (byte ptr [xxxx])
-
16-бит значение из памяти (word ptr [xxxx])
-
6a 32-бит значение памяти (dword ptr [xxxx])
Источник не может быть непосредственным значением, потому что тогда процессор не сможет определить размер исходного операнда.
Логические операции с битами - OR, XOR, AND, NOT. Эти команды работают с приемником и источником, исключение команда 'NOT'. Каждый бит в приемнике сравнивается с тем же самым битом в источнике, и в зависимости от команды, 0 или 1 помещается в бит приемника:
команда
|
AND
|
OR
|
XOR
|
NOT
|
Бит источника
|
0
|
0
|
1
|
1
|
0
|
0
|
1
|
1
|
0
|
0
|
1
|
1
|
0
|
1
|
Бит приемника
|
0
|
1
|
0
|
1
|
0
|
1
|
0
|
1
|
0
|
1
|
0
|
1
|
X
|
X
|
Бит результата
|
0
|
0
|
0
|
1
|
0
|
1
|
1
|
1
|
0
|
1
|
1
|
0
|
1
|
0
|
AND (логическое И) устанавливает бит результата в 1, если оба бита, бит источника и бит приемника установлены в 1.
OR (логическое ИЛИ) устанавливает бит результата в 1, если один из битов, бит источника или бит приемника установлен в 1.
XOR (НЕ ИЛИ) устанавливает бит результата в 1, если бит источника отличается от бита приемника.
NOT инвертирует бит источника.
Пример:
mov ax, 3406d
mov dx, 13EAh
xor ax, dx
ax = 3406 (десятичное), в двоичном - 0000110101001110.
dx = 13EA (шестнадцатиричное), в двоичном - 0001001111101010.
Выполнение операции XOR на этими битами:
Источник = 0001001111101010 (dx)
Приемник = 0000110101001110 (ax)
Результат = 0001111010100101 (новое значение в ax)
Увеличение/Уменьшение - INC/DEC. Есть 2 очень простые команды, DEC и INC. Эти команды увеличивают или уменьшают содержимое памяти или регистра на единицу. Просто поместите:
inc регистр ; регистр = регистр + 1
dec регистр ; регистр = регистр - 1
inc dword ptr [103405] ; значение в [103405] будет увеличено на 1.
dec dword ptr [103405] ; значение в [103405] будет уменьшено на 1.
Ещё одна команда сравнения - test. Команда Test выполняет операцию AND (логическое И) с двумя операндами и в зависимости от результата устанавливает или сбрасывает соответствующие флаги. Результат не сохраняется. Test используется для проверки бит, например в регистре:
test eax, 100b
jnz смещение
Команда jnz выполнит переход, если в регистре eax третий бит справа - установлен. Очень часто комманду test используют для проверки, равен ли регистр нулю:
test ecx, ecx
jz смещение
Команда jz выполнит переход, если ecx = 0.
Новое значение в ax, после выполнения команды - 0001111010100101 (7845 - в десятичном, 1EA5 - в шестнадцатиричном).
Для организации работы со стеком используются следующие команды:
Стек – это память организованная по принципу «первым пришел последним ушел». Чаще всего стек используется при вызовах процедуры при использовании команды CALL. В этом случае адрес возврата, который извлекается после выполнения процедуры.
Стек имеет следующую структуру:
Адрес стека находится в указателе стека SP. Адрес, который содержится в SP, называется вершиной стека. Стек «растет» по направлению к младшим адресам (к ячейке 0), т.е. первое слово, помещенное в стек имеет наибольший адрес, следующее на 2 байта ниже.
Если нам необходимо получить доступ к элементам не на вершине, а внутри стека, то в этом случае необходимо использовать регистр EBP- это регистр указателя базы кадра стека, где можно записать необходимый адрес стека.
PUSH источник - запись значения источника в вершину стека. В этом случае если необходимо сохранить необходимый адрес
POP приемник - запись значения из вершины стека по месту, указанному операндом приемником. Значение при этом «снимается» с вершины стека.
PUSHA и PUSHAW– команда групповой записи в стек. По этой команде в стек последовательно записываются регистры AX, CX, DX, BX, SP, BP, SI, DI. Разница этих двух команд в разрядности используемых регистров (16 или 32 разрядных регистров)
POPA, POPAW – групповое извлечение из стека, обратная предыдущим операция.
Команда обмена XCHG - двунаправленная пересылка данных. Команда меняет между собой значения двух регистров или
регистра и ячейки памяти.
XCHG AX, BX
XCHG AL, BL
Работа с адресами и указателями
LEA приемник, источник - загрузка исполнительного адреса. Удобна для работы со строками. В отличие от команды MOV с операцией OFFSET операнд источник может быть индексированным.
Например,
MOV DI, 5
LEA BX, TAB[DI]
LDS приемник, источник - регистр указателя в регистр сегмента данных DS. Это загрузка указателя и регистра сегмента данных (загрузка указателя с использованием регистра DS)
Например,
H_F DD HERE
……
LDS BX, H_F
аналогично операции
MOV BX, OFFSET H_F
MOV AX, SEG HERE
MOV DS, AX
где SEG - операция, которая возвращает номер блока адреса переменной. В этой операции исключается использование дополнительного третьего регистра.
LES приемник, источник - загрузка указателя в регистр дополнительного сегмента данных
ES/ LGS приемник, источник – загрузка указателя в регистр дополнительного сегмента данных GS.
LFS приемник, источник - загрузка указателя в регистр дополнительного сегмента данных FS.
Команда обмена XCHG - двунаправленная пересылка данных. Команда меняет между собой значения двух регистров или регистра и ячейки памяти.
XCHG AX, BX
XCHG AL, BL
Команды ввода-вывода в порт.
В этом случае ввод-вывод осуществляется на уровне BIOS напрямую с оборудованием.
IN аккумулятор, порт
OUT порт, аккумулятор,
где аккумулятор – регистр AL при обмене байтами или регистр AX при обмене словами.
порт - десятичное значение от 0 до 256
В качестве операнда «порт» можно использовать регистр DX.
Команды манипулирования битами
Все команды манипулирования битами делятся три типа:
-
Логические команды
-
Команды сдвига
-
Команды логического сдвига.
Логические команды
AND источник, приемник – операция логического умножения. Команда выполняет поразрядное логическую операцию И (конъюнкция) Результат записывается в приемник.
OR источник, приемник – операция логического сложения. Команда выполняет поразрядное логическую операцию ИЛИ (дизъюнкция) Результат записывается в приемник.
XOR источник, приемник – операция логического исключающего сложения. Команда выполняет поразрядное логическую операцию исключающего сложения Результат записывается в приемник.
0 XOR 0 =0
1 XOR 0 =1
0 XOR 1 =1
0 XOR 0 =0
XOR AX,AX ; AX=0
TEST источник, приемник –. операция проверить. Команда выполняет поразрядное логическую операцию И. Результат никуда не записывается. Изменяется состояние флагов ZF, SF и CF.
NOT операнд – операция логического отрицания. Поразрядное инвертирование каждого бита операнда. Результат записывается в операнд.
Логические операции с битами - OR, XOR, AND, NOT. Эти команды работают с приемником и источником, исключение команда 'NOT'. Каждый бит в приемнике сравнивается с тем же самым битом в источнике, и в зависимости от команды, 0 или 1 помещается в бит приемника:
команда
|
AND
|
OR
|
XOR
|
NOT
|
Бит источника
|
0
|
0
|
1
|
1
|
0
|
0
|
1
|
1
|
0
|
0
|
1
|
1
|
0
|
1
|
Бит приемника
|
0
|
1
|
0
|
1
|
0
|
1
|
0
|
1
|
0
|
1
|
0
|
1
|
X
|
X
|
Бит результата
|
0
|
0
|
0
|
1
|
0
|
1
|
1
|
1
|
0
|
1
|
1
|
0
|
1
|
0
|
AND (логическое И) устанавливает бит результата в 1, если оба бита, бит источника и бит приемника установлены в 1.
OR (логическое ИЛИ) устанавливает бит результата в 1, если один из битов, бит источника или бит приемника установлен в 1.
XOR (НЕ ИЛИ) устанавливает бит результата в 1, если бит источника отличается от бита приемника.
NOT инвертирует бит источника.
Пример:
MOV AX, 3406D
MOV DX, 13EAH
XOR AX, DX
AX = 3406 (десятичное), в двоичном - 0000110101001110.
DX = 13EA (шестнадцатеричное), в двоичном - 0001001111101010.
Выполнение операции XOR на этими битами:
Источник = 0001001111101010 (DX)
Приемник = 0000110101001110 (AX)
Результат = 0001111010100101 (новое значение в AX)
Новое значение в ax, после выполнения команды - 0001111010100101 (7845 - в десятичном, 1EA5 - в шестнадцатиричном).
Другой пример:
MOV ECX, FFFF0000H
NOT ECX
FFFF0000 в двоичном это - 11111111111111110000000000000000
Если вы выполните инверсию каждого бита, то получите:
00000000000000001111111111111111 , в шестнадцатиричном это 0000FFFF
Значит после операции NOT, ECX будет содержать 0000FFFFh.
Увеличение/Уменьшение - INC/DEC. Есть 2 очень простые команды, DEC и INC. Эти команды увеличивают или уменьшают содержимое памяти или регистра на единицу. Просто поместите:
INC РЕГИСТР ; регистр = регистр + 1
DEC РЕГИСТР ; регистр = регистр - 1
INC DWORD PTR [103405] ; значение в [103405] будет увеличено на 1.
DEC DWORD PTR [103405] ; значение в [103405] будет уменьшено на 1.
Ещё одна команда сравнения - TEST. Команда TEST выполняет операцию AND (логическое И) с двумя операндами и в зависимости от результата устанавливает или сбрасывает соответствующие флаги. Результат не сохраняется. TEST используется для проверки бит, например в регистре:
TEST EAX, 100B
JNZ СМЕЩЕНИЕ
Команда JNZ выполнит переход, если в регистре EAX третий бит справа - установлен. Очень часто команду TEST используют для проверки, равен ли регистр нулю:
TEST ECX, ECX
JZ СМЕЩЕНИЕ
Команда JZ выполнит переход, если ECX = 0.
Для организации в ассемблере ветвлений, циклов и подпрограмм используются команды управления. Рассмотрим некоторые из них:
-
JMP метка - команда безусловного перехода. Метка определяет очередную команду.
-
JZ метка ≈ условный переход на команду, определяемую меткой. Условие перехода ≈равенство нулю результата предыдущей команды (бит z=l). Если условие ложно (бит z=0), тогда выполняется следующая команда программы.
-
JE метка - Такой же смысл имеет команда JZ метка.
-
JG метка ≈ переход по условию "результат не меньше 0", (бит s=0).
-
JL метка ≈ переход по условию "результат < 0".
-
JNZ метка ≈ переход по условию "результат не равен О"
Команды сдвига
Общий формат этих команд:
КОП операнд, счетчик_сдвигов
Команды этой группы обеспечивают манипуляции над отдельными битами операндов, но иным способом, чем логически команды, рассмотренные выше. Все команды сдвига помещают биты в поле операнда влево или вправо, в зависимости кода операции.
Все команды сдвига делятся на команды:
Линейный сдвиг
Осуществляется сдвиг по следующей схеме:
-
Очередной «выдвигаемый» бит устанавливается флаг CF
-
бит, вводимый в операнд с другого конца, имеет значение 0
-
при сдвиге очередного бита он переходит во флаг CF, при этом значение предыдущего сдвинутого бита теряется.
Команды линейного делятся на:
-
команды логического сдвига
-
команды арифметического сдвига.
К командам логического сдвига относятся:
SHL операнд, счетчик_сдвигов – логический сдвиг влево. Содержимое операнда сдвигается влево на количество битов, определяемое значением счетчика_сдвигов. Справа (в позицию младшего бита) вписываются нули.
SHR операнд, счетчик_сдвигов – логический сдвиг вправо. Содержимое операнда сдвигается вправо на количество битов, определяемое значением счетчика_сдвигов. Слева (в позицию старшего бита) вписываются нули.
SHL AH, 4
Команды арифметического линейного сдвига отличаются от команд логического сдвига тем, что они особым образом работают со знаковым разрядом операнда:
SAL операнд, счетчик_сдвигов – арифметический сдвиг влево. Содержимое операнда сдвигается влево на количество битов, определяемое значением счетчика_сдвигов. Справа (в позицию
младшего бита) вписываются нули. Команда SAL не сохраняет знака, но устанавливает флаг CF в случае смены знака очередным выдвигаемым битом.
Семинар 9.
Команды ввода/вывода. Команды работы со строками.
Дополнительные команды.
Строковые операции
Строковые команды рассчитаны на обработку строк. Замечу, что термин «строка» здесь отнюдь не эквивалентен аналогичному термину Турбо Паскаля и означает произвольную цепочку байт или слов длиной до 64 Кбайт. Эти команды оперируют пятью примитивами, каждый из которых обрабатывает лишь один байт или одно слово за раз. Перед примитивом обычно указывается префикс повторения REP/REPE/REPNE, заставляющий выполняться примитив до тех пор, пока не обнулится счетчик повторений СХ или не будет нарушено соответствующее условие.
При использовании строковых команд важно помнить два обстоятельства:
-
Во-первых, эти команды всегда берут адрес строки-источника из пары DS:SI, а строки-приемника - из пары ES:DI. Таким образом, перед исполнением строковой команды необходимо инициировать сегментные регистры нужным образом.
-
Во-вторых, строковые команды используют индексную адресацию с автоматическим изменением смещения в SI/DI после однократного исполнения примитива. Содержимое этих регистров изменяется на 1 при обработке байтов и на 2 при обработке слов, причем наращивается, если флаг направления DF сброшен, и уменьшается, если он равен 1.
Все команды для работы со строками считают, что:
-
строка-источник находится по адресу DS:SI (или DS:ESI), то есть в сегменте памяти, указанном в DS со смещением в SI,
-
строка-приемник — соответственно в ES:DI (или ES:EDI).
-
Кроме того, все строковые команды работают только с одним элементом строки (байтом, словом или двойным словом) за один раз.
-
Для того чтобы команда выполнялась над всей строкой, необходим один из префиксов повторения операций.
Префикс:
|
REP
|
Назначение:
|
Повторять
|
Префикс:
|
REPE
|
Назначение:
|
Повторять, пока равно
|
Префикс:
|
REPNE
|
Назначение:
|
Повторять, пока не равно
|
Префикс:
|
REPZ
|
Назначение:
|
Повторять, пока ноль
|
Префикс:
|
REPNZ
|
Назначение:
|
Повторять, пока не ноль
|
Процессор:
|
8086
|
Все эти команды — префиксы для операций над строками.
******** Любой из префиксов выполняет следующую за ним команду строковой обработки столько раз, сколько указано в регистре ЕСХ (или СХ, в зависимости от разрядности адреса), уменьшая его при каждом выполнении команды на 1.
******** Кроме того, префиксы REPZ и REPE прекращают повторения команды, если флаг ZF сброшен в 0, и префиксы REPNZ и REPNE прекращают повторения, если флаг ZF установлен в 1.
******** Префикс REP обычно используется с командами INS, OUTS, MOVS, LODS, STOS, а префиксы REPE, REPNE, REPZ и REPNZ — с командами CMPS и SCAS. Поведение префиксов не с командами строковой обработки не определено.
Команда:
|
MOVS приемник, источник
|
Назначение:
|
Копирование строки
|
Процессор:
|
8086
|
Команда:
|
MOVSB
|
Назначение:
|
Копирование строки байт
|
Процессор:
|
8086
|
Команда:
|
MOVSW
|
Назначение:
|
Копирование строки слов
|
Процессор:
|
8086
|
Команда:
|
MOVSD
|
Назначение:
|
Копирование строки двойных слов
|
Процессор:
|
80386
|
Копирует один байт (MOVSB), слово (MOVSW) или двойное слово (MOVSD) из памяти по адресу DS:ESI (или DS:SI, в зависимости от разрядности адреса) в память по адресу ES:EDI (или ES:DI).
При использовании формы записи MOVS ассемблер сам определяет из типа указанных операндов (принято указывать имена копируемых строк, но можно использовать любые два операнда подходящего типа), какую из трех форм этой команды (MOVSB, MOVSW или MOVSD) выбрать.
Используя MOVS с операндами, можно заменить регистр DS на другой с помощью префикса замены сегмента (ES:, GS:, FS:, CS:, SS:), регистр ES заменить нельзя. После выполнения команды регистры ESI (SI) и EDI (DI) увеличиваются на 1, 2 или 4 (если копируются байты, слова или двойные слова), если флаг DF = 0, и уменьшаются, если DF = 1. При использовании с префиксом REP команда MOVS выполняет копирование строки длиной в ЕСХ (или СХ) байт, слов или двойных слов.
Команда:
|
CMPS приемник, источник
|
Назначение:
|
Сравнение строк
|
Процессор:
|
8086
|
Команда:
|
CMPSB
|
Назначение:
|
Сравнение строк байт
|
Процессор:
|
8086
|
Команда:
|
CMPSW
|
Назначение:
|
Сравнение строк слов
|
Процессор:
|
8086
|
Команда:
|
CMPSD
|
Назначение:
|
Сравнение строк двойных слов
|
Процессор:
|
80386
|
******** Сравнивает один байт (CMPSB), слово (CMPSW) или двойное слово (CMPSD) из памяти по адресу DS:ESI (или DS:SI, в зависимости от разрядности адреса) с байтом, словом или двойным словом по адресу ES:EDI (или ES:DI) и устанавливает флаги аналогично команде СМР. При использовании формы записи CMPS ассемблер сам определяет из типа указанных операндов (принято указывать имена сравниваемых строк, но можно использовать любые два операнда подходящего типа), какую из трех форм этой команды (CMPSB, CMPSW или CMPSD) выбрать.
******** Используя CMPS с операндами, можно заменить регистр DS на другой, применяя префикс замены сегмента (ES:, GS:, FS:, CS:, SS:), регистр ES заменить нельзя. После выполнения команды регистры ESI (SI) и EDI (DI) увеличиваются на 1, 2 или 4 (если сравниваются байты, слова или двойные слова), если флаг DF = 0, и уменьшаются, если DF = 1.
******** При использовании с префиксом REP команда CMPS выполняет сравнение строки длиной в ЕСХ (или СХ) байт, слов или двойных слов, но чаще ее используют с префиксами REPNE/REPNZ или REPE/REPZ. В первом случае сравнение продолжается до первого несовпадения в сравниваемых строках, а во втором — до первого совпадения.
Команда:
|
SCAS приемник
|
Назначение:
|
Сканирование строки
|
Процессор:
|
8086
|
Команда:
|
SCASB
|
Назначение:
|
Сканирование строки байт
|
Процессор:
|
8086
|
Команда:
|
SCASW
|
Назначение:
|
Сканирование строки слов
|
Процессор:
|
8086
|
Команда:
|
SCASD
|
Назначение:
|
Сканирование строки двойных слов
|
Процессор:
|
80386
|
******** Сравнивает содержимое регистра AL (SCASB), AX (SCASW) или ЕАХ (SCASD) с байтом, словом или двойным словом из памяти по адресу ES:EDI (или ES:DI, в зависимости от разрядности адреса) и устанавливает флаги аналогично команде СМР. При использовании формы записи SCAS ассемблер сам определяет из типа указанного операнда (принято указывать имя сканируемой строки, но можно использовать любой операнд подходящего типа), какую из трех форм этой команды (SCASB, SCASW или SCASD) выбрать. После выполнения команды регистр EDI (DI) увеличивается на 1, 2 или 4 (если сканируются байты, слова или двойные слова), если флаг DF = 0, и уменьшается, если DF = 1.
******** При использовании с префиксом REP команда SCAS выполняет сканирование строки длиной в ЕСХ (или СХ) байт, слов или двойных слов, но чаще ее используют с префиксами REPNE/REPNZ или REPE/REPZ. В первом случае сканирование продолжается до первого элемента строки, отличного от содержимого аккумулятора, а во втором — до первого совпадающего.
Команда:
|
LODS источник
|
Назначение:
|
Чтение из строки
|
Процессор:
|
8086
|
Команда:
|
LODSB
|
Назначение:
|
Чтение байта из строки
|
Процессор:
|
8086
|
Команда:
|
LODSW
|
Назначение:
|
Чтение слова из строки
|
Процессор:
|
8086
|
Команда:
|
LODSD
|
Назначение:
|
Чтение двойного слова из строки
|
Процессор:
|
80386
|
******** Копирует один байт (LODSB), слово (LODSW) или двойное слово (LODSD) из памяти по адресу DS:ESI (или DS:SI, в зависимости от разрядности адреса) в регистр AL, АХ или ЕАХ соответственно. При использовании формы записи LODS ассемблер сам определяет из типа указанного операнда (принято указывать имя строки, но можно использовать любой операнд подходящего типа), какую из трех форм этой команды (LODSB, LODSW или LODSD) выбрать. Используя LODS с операндом, можно заменить регистр DS на другой с помощью префикса замены сегмента (ES:, GS:, FS:, CS:, SS:). После выполнения команды регистр ESI (SI) увеличивается на 1, 2 или 4 (если считывается байт, слово или двойное слово), если флаг DF = 0, и уменьшается, если DF = 1.
******** При использовании с префиксом REP команда LODS выполнит копирование строки длиной в ЕСХ (или СХ), что приведет к тому, что в аккумуляторе окажется последний элемент строки. На самом деле эту команду используют без префиксов, часто внутри цикла в паре с командой STOS, так что LODS считывает число, другие команды выполняют над ним какие-нибудь действия, а затем STOS записывает измененное число в то же место в памяти.
Команда:
|
STOS приемник
|
Назначение:
|
Запись в строку
|
Процессор:
|
8086
|
Команда:
|
STOSB
|
Назначение:
|
Запись байта в строку
|
Процессор:
|
8086
|
Команда:
|
STOSW
|
Назначение:
|
Запись слова в строку
|
Процессор:
|
8086
|
Команда:
|
STOSD
|
Назначение:
|
Запись двойного слова в строку
|
Процессор:
|
80386
|
******** Копирует регистр AL (STOSB), AX (STOSW) или ЕАХ (STOSD) в память по адресу ES:EDI (или ES:DI, в зависимости от разрядности адреса). При использовании формы записи STOS ассемблер сам определяет из типа указанного операнда (принято указывать имя строки, но можно использовать любой операнд подходящего типа), какую из трех форм этой команды (STOSB, STOSW или STOSD) выбрать. После выполнения команды регистр EDI (DI) увеличивается на 1, 2 или 4 (если копируется байт, слово или двойное слово), если флаг DF = 0, и уменьшается, если DF = 1. При использовании с префиксом REP команда STOS заполнит строку длиной в ЕСХ (или СХ) числом, находящимся в аккумуляторе.
Команда:
|
INS источник, DX
|
Назначение:
|
Чтение строки из порта
|
Процессор:
|
80186
|
Команда:
|
INSB
|
Назначение:
|
Чтение строки байт из порта
|
Процессор:
|
80186
|
Команда:
|
INSW
|
Назначение:
|
Чтение строки слов из порта
|
Процессор:
|
80186
|
Команда:
|
INSD
|
Назначение:
|
Чтение строки двойных слов из порта
|
Процессор:
|
80386
|
******** Считывает из порта ввода-вывода, номер которого указан в регистре DX, байт (INSB), слово (INSW) или двойное слово (INSD) в память по адресу ES:EDI (или ES:DI, в зависимости от разрядности адреса). При использовании формы записи INS ассемблер определяет из типа указанного операнда, какую из трех форм этой команды (INSB, INSW или INSD) употребить. После выполнения команды регистр EDI (DI) увеличивается на 1, 2 или 4 (если считывается байт, слово или двойное слово), если флаг DF = 0, и уменьшается, если DF = 1. При использовании с префиксом REP команда INS считывает блок данных из порта длиной в ЕСХ (или СХ) байт, слов или двойных слов.
Команда:
|
OUTS DX, приемник
|
Назначение:
|
Запись строки в порт
|
Процессор:
|
80186
|
Команда:
|
OUTSB
|
Назначение:
|
Запись строки байт в порт
|
Процессор:
|
80186
|
Команда:
|
OUTSW
|
Назначение:
|
Запись строки слов в порт
|
Процессор:
|
80186
|
Команда:
|
OUTSD
|
Назначение:
|
Запись строки двойных слов в порт
|
Процессор:
|
80386
|
******** Записывает в порт ввода-вывода, номер которого указан в регистре DX, байт (OUTSB), слово (OUTSW) или двойное слово (OUTSD) из памяти по адресу DS:ESI (или DS:SI, в зависимости от разрядности адреса). При использовании формы записи OUTS ассемблер определяет из типа указанного операнда, какую из трех форм этой команды (OUTSB, OUTSW или OUTSD) употребить. Используя OUTS с операндами, также можно заменить регистр DS на другой с помощью префикса замены сегмента (ES:, GS:, FS:, CS:, SS:). После выполнения команды регистр ESI (SI) увеличивается на 1, 2 или 4 (если считывается байт, слово или двойное слово), если флаг DF = 0, и уменьшается, если DF = 1. При использовании с префиксом REP команда OUTS записывает блок данных размером в ЕСХ (или СХ) байт, слов или двойных слов в указанный порт. Все процессоры вплоть до Pentium не проверяли готовность порта принять новые данные в ходе выполнения команды REP OUTS, так что, если порт не успевал обрабатывать информацию с той скоростью, с которой ее поставляла эта команда, часть данных терялась.
Закрепление:
Цикл LOOP
Во время изучения логики работы команд обработки блоков данных во
избежание ошибок реализуйте программу сначала без циклов, чтобы можно
было бы проконтролировать процесс выполнения по шагам.
Для решения задачи заполнения переменной типа string заданным количеством одинаковых символов, запишите несколько строк с командой STOSB, и только убедившись в правильности алгоритма, реализуйте цикл (REP STOSB):
var
S : string; C : char; N : byte;
begin
S := ''; // строка для заполнения
C := 'A'; // символ для заполнения строки
N := 3; // количество символов в строке
ASM
LEA EDI, S // адрес строки
XOR CX,CX // очистка счетчика CX = 0
MOV CL,N // в счетчик занести количество повторений
MOV AL,C // символ для заполнения поместить в AL
MOV [EDI],CL // заполнить S[0] – количество символов в строке
INC EDI // символы записывать, начиная с S[1]
CLD // установить инкремент адреса
STOSB // записать три раза по одному символу
STOSB
STOSB
END;
end.
При необходимости использования цикла в цикле можно использовать
цикл LOOP, но при выполнении вложенного цикла не забывайте сохранять
значение регистра CX (счетчик внешнего цикла), например, в стеке:
Label L1,L2;
begin
ASM
MOV CX,2
L1: PUSH CX
MOV CX,3
L2: NOP
LOOP L2
POP CX
LOOP L1
END;
end.
Директивы определения переменных. Директивы определения сегментов. Директивы ассемблера
Достарыңызбен бөлісу: |