Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Arkhitektura_EVM_uchebnoe_posobie

.pdf
Скачиваний:
57
Добавлен:
13.04.2015
Размер:
2 Mб
Скачать

Команда логического ИЛИ OR

OR <операнд1>, <операнд2>

OR выполняет поразрядную дизъюнкцию (логическое ИЛИ) двух операндов и помещает результат в первый операнд. Каждый бит результата устанавливается в 0, если оба соответствующих бита операндов равны 0, в противном случае – в 1.

Команда логического исключающего ИЛИ XOR

XOR <операнд1>, <операнд2>

XOR выполняет для двух операндов исключающее ИЛИ и помещает результат в первый операнд. Каждый бит результата устанавливается в 0, если соответствующие биты операндов различны, в противном случае – в 1.

Команда логического отрицания NOT

NOT <операнд>

NOT поразрядно инвертирует операнд

Команды сдвигов SAL (SHL), SAR (SHR)

SAL <операнд1>, 1

SAL <операнд1>, CL

SAR <операнд1>, 1

SAR <операнд1>, CL

SAL (синоним – SHL) сдвигает биты операнда влево. Старший бит сдвигается в флаг CF, а младший очищается. SAR и SHR сдвигает биты вправо. Младший бит сдвигается в флаг CF. Сдвиг повторяется столько раз, сколько задает второй операнд, который может указываться непосредственно в команде или находиться в регистре CL.

Команды циклических сдвигов RCL, RCR, ROL, ROR

RCL <операнд1>, 1

RCL <операнд1>, CL

RCR <операнд1>, 1

RCR <операнд1>, CL

ROL <операнд1>, 1

ROL <операнд1>, CL

ROR <операнд1>, 1

ROR <операнд1>, CL

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

Для команд RCL и RCR флаг переноса рассматривается как часть сдвигаемого значения. RCL сдвигает флаг переноса в младший бит, а старший бит – во флаг переноса. RCR сдвигает флаг переноса в старший бит, а младший бит – во флаг переноса. Команды ROL и ROR при сдвиге не используют флаг переноса в

80

качестве дополнительного бита, но CF получает копию бита, который был передвинут с одного конца на другой.

Сдвиг повторяется столько раз, сколько задает второй операнд, который может указываться непосредственно или в регистре CL.

Флаг переполнения определен только для одношаговых форм команд (второй операнд – 1). Во всех остальных случаях его значение не определено. Для получения значения OF, при циклическом сдвиге влево выполняется операция (CF после сдвига) XOR (старший бит результата), а при циклическом сдвиге вправо выполняется операция XOR над двумя старшими битами результата.

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

Команда безусловного перехода JMP

JMP <операнд>

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

Если в качестве операнда указано двухбайтовое смещение, то оно прибавляется к адресу команды, следующей за командой JMP, для определения адреса приемника.

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

Форма команды JMP сегмент:смещение использует четырехбайтовый длинный указатель на адрес перехода.

Команды переходов по условию Jxxx

JA <смещение> JAE <смещение> JB <смещение> JBE <смещение> JC <смещение> JE <смещение> JZ <смещение> JG <смещение> JGE <смещение> JL <смещение> JLE <смещение> JO <смещение> JP <смещение> JPE <смещение> JPO <смещение> JS <смещение> JCXZ <смещение>

JNA <смещение> JNAE <смещение> JNB <смещение> JNBE <смещение> JNC <смещение> JNE <смещение> JNZ <смещение> JNG <смещение> JNGE <смещение> JNL <смещение> JNLE <смещение> JNO <смещение> JNP <смещение> JNPE <смещение> JNPO <смещение> JNS <смещение>

Команды условных переходов (кроме JCXZ/JECXZ) проверяют флаги, установленные предыдущими операциями. Флаги, проверяемые такой командой, кодируются в ее мнемонике, например: JC – переход, если установлен CF. Сокращения «L» (less – меньше) и «G» (greater – больше) применяются для целых со знаком, a «A» (above – над) и «В» (below – под) для целых без знака.

81

Если условие выполняется, происходит переход по смещению, указанному в качестве операнда, причем этот адрес должен находиться в том же кодовом сегменте и на расстоянии, не превышающем -128…+127 байт от первого байта следующей команды. Когда адрес условного перехода находится в другом сегменте, необходимо использовать противоположную форму команды перехода в комбинации с командой безусловного перехода. Например, если нельзя применить

JZ FarLabel,

то комбинация

JNZ NearLabel

JMP FarLabel

NearLabel:

позволяет достичь нужного результата.

JCXZ отличается от других команд условного перехода, тем, что она проверяет содержимое регистра СХ, а не флагов. Эту команду лучше всего применять в начале условного цикла, чтобы предотвратить вхождение в цикл, если СХ = 0.

Команда организации цикла со счетчиком СХ

LOOP <смещение>

LOOPE <смещение>

LOOPZ <смещение>

LOOPNE <смещение>

LOOPNZ <смещение>

LOOP уменьшает счетчик в регистре СХ без изменения каких-либо флагов. Если условие, указанное в мнемонике команды, истинно, выполняется переход на заданную операндом метку, которая должна быть в пределах 128 байт до или 127 байт после данной команды.

Для использования LOOP необходимо поместить в регистр СХ целое значение числа циклов, а в конце последовательности команд, которую необходимо повторять, поставить команду LOOP, операнд которой будет являться меткой, указывающей на начало цикла.

Команда вызова процедуры CALL

CALL <операнд>

Команда CALL передает управление процедуре, адрес которой задан операндом. После завершения процедуры (выполнения команды возврата из процедуры) выполнение продолжается с команды, следующей за CALL.

Команда возврата из процедуры RET

RET передает управление по адресу возврата, находящемуся в стеке. Адрес обычно помещается в стек командой CALL, поэтому возврат осуществляется на команду, следующую за CALL.

Команда вызова программного прерывания INT

INT <n>

82

Команда генерирует программный вызов обработчика прерываний. Непосредственный операнд (от 0 до 255) задает индекс адреса программы прерывания в таблице векторов прерываний.

Команда выхода из программного прерывания IRET

Команда IRET восстанавливает IP, CS и флаговый регистр из стека и завершает подпрограмму обработки прерывания.

Управляющие команды

Команда сброса флага переноса CLC

CLC устанавливает значение флага CF, равное 0. Все остальные флаги и регистры остаются неизменными.

Команда инвертирования флага переноса CMC

CMC изменяет значение флага CF на противоположное. Другие флаги остаются без изменений.

Команда установки флага переноса STC

STC устанавливает флаг переноса в 1.

Команда сброса флага направления CLD

CLD очищает флаг направления. Все остальные флаги и регистры остаются неизменными. После выполнения CLD используемые строковые операции будут увеличивать индексный регистр (SI или DI).

Команда установки флага направления STD

STD устанавливает флаг направления в 1, что заставляет все последующие строковые операции уменьшать при их выполнении индексный регистр SI и/или DI.

Команда запрещения внешних прерываний CLI

CLI очищает флаг прерываний, в результате чего процессор не распознает внешние маскируемые прерывания.

Команда разрешения внешних прерываний STI

STI устанавливает флаг разрешения прерываний в 1. После этого при завершении работы следующей команды процессор может выполнять обработку внешних прерываний, если эта команда снова не сбросила флаг прерываний.

Команда ожидания прерывания HLT

HLT приостанавливает выполнение и переводит процессор в состояние HALT. Продолжить выполнение могут только разрешенное прерывание, немаскируемое прерывание (NMI) или общий сброс (сигнал RESET). Если прерывание (включая NMI) используется для продолжения выполнения после HLT, сохраненное значение CS:IP указывает на команду, следующую за HLT.

Команда NOP

NOP не выполняет никаких операций. NOP – это однобайтная команда, которая занимает место, но не вносит никаких изменений в машинный контекст, кроме изменения счетчика команд (IP).

83

Команды работы со строками

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

Если флаг направления перед выполнением команды строковой обработки установлен в 0 (выполнена команда CLD), значение в индексном регистре увеличивается, если в 1 (выполнена STD) – уменьшается. Регистры уменьшаются или увеличиваются на 1, если команда работает с байтами, на 2 – если со словами.

Эти команды часто используются с однобайтными префиксами, которые обеспечивают многократное автоматическое повторение выполнения команды.

Команда пересылки данных из строки в строку

MOVS <операнд1>, <операнд2>

MOVS копирует байт или слово, находящееся по адресу SI, в байт или слово по адресу ES:DI. Операнд приемника должен адресоваться относительно регистра ES, перекрытие этого сегмента невозможно. Переопределение сегмента может использоваться для сегмента приемника (по умолчанию – DS).

Адреса источника и приемника определяются содержимым SI и D1, поэтому перед использованием MOVS необходимо записать в них правильное значение индекса.

MOVS может использоваться с префиксом REP для операции пересылки блоков из CX байтов или слов.

Команда загрузки строкового операнда

LODS <операнд>

LODS загружает один из регистров AL или АХ байтом или словом, находящимся в памяти, на который указывает регистр индекса источника.

В качестве индексного регистра используется SI. Адрес данных источника определяется только содержимым этого регистра, поэтому перед выполнением команды LODS необходимо поместить в SI правильное значение.

Команда сохранения строкового операнда

STOS <операнд>

STOS пересылает содержимое регистров AL или АХ в байт или слово, находящееся в памяти, на которые указывает смещение в индексном регистре DI относительно сегмента ES. Переопределение сегмента ES не допускается.

Адрес данных источника определяется только содержимым регистра приемника, а не операндом STOS. Этот операнд используется только для правильной адресации сегмента ES и определения типа данных.

STOS может иметь префикс REP для заполнения блока данных количеством СХ байтов или слов.

84

Команда сравнения строк

CMPS <операнд1>, <операнд2>

CMPS выполняет сравнение строки байтов или слов, на которую указывает смещение в индексном регистре SI (источник) со строкой байтов или слов, на которую указывает смещение в индексном регистре DI (приемник). Перед использование» CMPS необходимо загрузить правильным значением индексные регистры SI и DI Сравнение выполняется вычитанием операнда, индексированного регистром DI, из операнда, индексированного регистром SI.

Вычитание, выполняемое CMPS, происходит как [SI] – [DI], т.е. левый операнд – источник, а правый – приемник, что является исключением из соглашений фирмы Intel, в которых левый операнд – приемник, а правый – источник.

Результат вычитания никуда не записывается, а лишь отражается в изменении флагов. Для первого операнда, [SI], используется регистр DS, если не задано переопределение сегмента. Второй операнд, [DI], для адресации приемника должен использоваться с регистром ES, и для него переопределение сегмента невозможно.

CMPS может иметь префикс REPE или REPNE для блокового сравнения СХ строк байтов или слов.

Команда поиска в строке

SCAS <операнд>

SCAS вычитает байт или слово строки из регистра AL или АХ. Результат никуда не записывается, происходит только установка флагов. Операнд должен адресоваться индексным регистром DI относительно регистра ES, переопределение сегмента не допускается.

Адрес памяти, по которому находится строка, определяется только содержимым индексного регистра приемника, а не операндом SCAS. Операнд проверяет правильность адресации сегмента ES и определяет тип данных. Поэтому перед использованием SCAS необходимо загрузить регистр DI правильным значением индекса.

SCAS может иметь префикс REPE или REPNE для блокового сравнения СХ байтов или слов.

Префиксы повторения строковых команд

REP, REPE (повторять, пока равны) и REPNE (повторять, пока не равны) – это префиксы, которые применяются к строковым операциям. Каждый префикс приводит к тому, что команда, следующая за ним, будет повторяться либо определенное число раз (указывается в регистре СХ), либо (для REPE и REPNE) до тех пор, пока условие, отражаемое флагом ZF, больше не встретится.

Синонимы для REPE и REPNE – REPZ и REPNZ соответственно. Префикс REP относится только к выполнению одной строковой команды. Для повторения блока команд используется LOOP или другая конструкция организации цикла.

На каждом этапе цикла выполняются следующие действия.

85

1.Проверка СХ. Если он равен 0 – выход из цикла и переход к следующей команде.

2.Подтверждение любых возникающих прерываний.

3.Выполнение указанной строковой операции.

4.Уменьшение СХ на 1, флаги при этом не изменяются.

5.Проверка флага ZF, если выполняется строковая операция SCAS или CMPS. Если условие повторения цикла не выполняется – выход из цикла и переход к следующей команде. Выход из цикла, если префиксом является REPE и ZF = 0 (последнее сравнение не совпало) или используется префикс REPNE и ZF = 1 (последнее сравнение совпало).

6.Возврат на 1 для выполнения следующего этапа цикла.

3.6. Ассемблер

Ассемблер – это программа, которая переводит текст с языка, понятного программисту, в язык, понятный процессору, то есть, она переводит язык Ассемблера в машинный код.

Программа на языке Ассемблера состоит из строк, имеющих следующий

вид:

[метка] [команда/директива] [операнды] [; комментарий]

Метка может быть любой комбинацией букв английского алфавита, цифр и символов _, $, @, ?, но цифра не может быть первым символом метки. Во втором поле, поле команды, может располагаться команда процессора, которая транслируется в исполняемый код, или директива, которая не приводит к появлению нового кода, а управляет работой самого Ассемблера. В поле операндов располагаются требуемые командой или директивой операнды. В поле комментариев, начало которого отмечается символом «;», можно написать все что угодно – текст от символа «;» до конца строки не анализируется Ассемблером.

Если метка располагается перед командой процессора, сразу после нее всегда ставится символ «:», который указывает Ассемблеру, что надо создать переменную с этим именем, содержащую адрес текущей команды:

some_loop:

 

; cчитать слово из строки,

lodsw

ax,7

cmp

; если это 7 - выйти из цикла

loopne

some_loop

 

Когда метка стоит перед директивой Ассемблера, она обычно оказывается одним из операндов этой директивы и двоеточие не ставится. Рассмотрим директивы, работающие напрямую с метками и их значениями, – LABEL, EQU и =.

Директива LABEL определяет метку и задает ее тип:

метка label тип

Тип может быть: BYTE (байт), WORD (слово), DWORD (двойное слово), FWORD (6 байт), QWORD (учетверенное слово), TBYTE (10 байт), NEAR (ближняя метка), FAR (дальняя метка). Метка получает значение, равное адресу

86

следующей команды или следующих данных, и тип, указанный явно. В зависимости от типа команда

mov метка, 0

запишет в память байт (слово, двойное слово и т.д.), заполненный нулями, а команда

call метка

выполнит ближний или дальний вызов подпрограммы.

С помощью директивы LABEL удобно организовывать доступ к одним и тем же данным, как к байтам, так и к словам, определив перед данными две метки с разными типами.

Директива EQU присваивает метке значение, которое определяется как результат целочисленного выражения в правой части:

метка equ выражение

Результатом этого выражения может быть целое число, адрес или любая строка символов.

Директива «=» эквивалентна EQU, но определяемая ею метка может принимать только целочисленные значения. Кроме того, метка, указанная этой директивой, может быть переопределена.

Псевдокоманда – это директива Ассемблера, которая приводит к включению данных или кода в программу, хотя сама она никакой команде процессора не соответствует. Псевдокоманды определения переменных указывают Ассемблеру, что в соответствующем месте программы располагается переменная, определяют тип переменной (байт, слово, вещественное число и т.д.), задают ее начальное значение и ставят в соответствие переменной метку, которая будет использоваться для обращения к этим данным. Псевдокоманды определения данных записываются в общем виде следующим образом:

имя_переменной d* значение

где D* — одна из нижеприведенных псевдокоманд (директив): DB – определить байт;

DW – определить слово (2 байта);

DD – определить двойное слово (4 байта);

DF – определить 6 байт (адрес в формате 16-битный селектор: 32-битное смещение);

DQ – определить учетверенное слово (8 байт); DT – определить 10 байт (80-битные типы данных).

Поле значения может содержать одно или несколько чисел, строк символов (взятых в одиночные или двойные кавычки), операторов ? и DUP, разделенных запятыми. Все установленные таким образом данные окажутся в выходном файле, а имя переменной будет соответствовать адресу первого из указанных значений. Например, набор директив

87

text_string

db

'Hello world!'

number

dw

7

table

db

1,2,3,4,5,6,7,8,9,0Ah,0Bh,0Ch,0Dh,0Eh,0Fh

float_number

dd

3.5e7

заполняет данными 33 байта. Первые 12 байт содержат ASCII-коды символов строки «Hello world!», и переменная text_string указывает на первую букву в этой строке, так что команда

mov al, text_string

считает в регистр AL число 48h (код латинской буквы «H»). Если вместо точного значения указан знак «?», переменная считается неинициализированной и ее значение на момент запуска программы может оказаться любым.

Синтаксис поля значение отличается для разных директив и должен соответствовать типу директивы.

Значением инициализации в директиве DB могут быть:

выражение-константа, имеющая значение в пределах от -128 до 255 (байт со знаком – от -128 до +127, байт без знака – от 0 до 255);

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

В директиве DW значение инициализации может быть:

выражением-константой, имеющей значение и диапазоне от -32768 до 65535 (слово со знаком – в диапазоне от -32768 до 32767, слово без знака – в диапазоне от 0 до 65535);

выражением над каким-то адресом с размером результата 16 или 8 бит (в том числе смещение в 16-битовом сегменте, а также адрес сегмента или группы);

одноили двухбайтной строкой, заключенной в кавычки;

Директива DD воспринимает в качестве значения инициализации:

выражение-константу, имеющей значение в диапазоне от –2147483648

до 4294967295;

адресное выражение с размером результата 32 бита;

выражение с относительным адресом, состоящее из значений 16битового сегмента и 16-битового смещения;

строку длиной до 4 байт, заключенную в кавычки;

короткое (32 бита) число с плавающей точкой.

Для директивы DQ в качестве значения инициализации допускаются:

константы со знаком, имеющие значение в диапазоне от -263 до 264 – 1 (при наличии знака «–» в диапазоне от -263 до 263 -1; без знака – в диапазоне от

0до 264 - 1);

строка длиной до 8 байт, заключенная в кавычки;

длинное (64 бита) число с плавающей точкой.

Значениями инициализации для директив DF и DP могут быть:

константы со знаком, имеющие значение в диапазоне от -247 до 248 – 1

88

(при наличии знака «–» в диапазоне от -247 до 247 – 1; без знака – в диапазоне от 0 до 248 – 1);

строка длиной до 6 байт, заключенная в кавычки.

Для директивы DT значением инициализации могут быть:

константы со знаком, имеющие значение в диапазоне от -279 до 280 - 1 (при наличии знака "-" в диапазоне от -279 до 279 - 1; без знака – в диапазоне от

0до 280 -1);

10-байтное вещественное число с плавающей точкой;

строка длиной до 10 байтов, заключенная в кавычки;

упакованная десятичная константа в диапазоне от 0 до

99999999999999999999.

Данные всегда размещаются в памяти в порядке, при котором сначала идет младшая часть значения, а затем – старшая. Например, слово в памяти представляется в виде младшего байта, за которым следует старший, двойное слово

– в виде последовательности: последний (самый младший) байт, предпоследний байт (образуют младшее слово двойного слова), второй байт, первый (самый старший) байт (образуют старшее слово двойного слова) и т.д.

Внекоторых случаях числовые и строковые константы при указании их в качестве значений инициализации отличаются от используемых в выражениях констант. Например, при указании в директивах DB, DP, DQ или DT строки, заключенной в кавычки, ее длина может быть больше, чем длина строки для выражения, описывающего данные такого же типа.

Вдирективах DD, DQ и DT допускаются значения инициализации в виде чисел с плавающей точкой, например:

DD 1.0Е30

DT 2.56Е-21

DQ 1.28Е+5

DT 0.02S.

Если нужно заполнить участок памяти повторяющимися данными, используется специальный оператор DUP, имеющий формат:

счетчик DUP (значение).

Например, вот такое определение: table_512w dw 512 dup(?)

создает массив из 512 неинициализированных слов, на первое из которых указывает переменная table_512w. В качестве аргумента в операторе DUP могут выступать несколько значений, разделенных запятыми, и даже дополнительные вложенные операторы DUP.

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

Оператор < > – часть выражения, заключенная в угловые скобки, не вычисляется, а применяется как строка символов, например:

89