Разработано AKSION-ом

1.

16-разрядные регистры общего назначения (POH) процессора (АХ, ВХ, СХ, DX, SI, DI, SP, ВР).


AX (аккумулятор) [Accumulator eXchange],

BX (база) [Base eXchange],

CX (счетчик) [Counter eXchange],

DX (регистр данных) [Data eXchange],

SI (индекс источника) [Source Index],

DI (индекс приемника) [Destination Index],

BP (указатель базы) [Base Pointer],

SP (указатель стека) [Stack Pointer].


Назначение и использование.

Могут использоваться без ограничений для любых целей — временного хранения данных, аргументов или результатов различных операций.

Специальное назначение регистров.

AX - применяется для всех операций ввода-вывода, некоторых операций над строками и некоторыми арифметическими операциями. Например команды умножения, деления и сдвига предполагают использование регистра AX. Некоторые команды генерируют более эффективный код если они имеют ссылки на регистр AX. AX: | AH | AL |

BX - единственный регистр общего назначения, который может использоваться в качестве "индекса" для расширенной адресации. BX: | BH | BL |

CX - необходим для управления числом повторений циклов и для операций сдвига влево или вправо. CX: | CH | CL |

DX - Он применяется для некоторых операций ввода-вывода и тех операций умножения и деления над большими числами, которые используют регистровую пару DX:AX. DX: | DH | DL |

SP - обеспечивает использование стека в памяти, позволяет временно хранить адреса и иногда данные. Этот регистр связан с регистром SS для адресации стека.

BP - облегчает доступ к параметрам (данным и адресам, переданным через стек).

SI - применяется для некоторых операций над строками.

DI - применяется также для строковых операций.

8-битные регистры: *H - старшие (High) байты регистров, *L – соответственно младшие (Low).
2.

Регистр флагов.

Регистр флагов FLAGS, 16 бит, в этом регистре каждый бит является флагом, то есть устанавливается в 1 при определенных условиях или установка его в 1 изменяет поведение процессора.

Основные флаги (CF, OF, AF, SF, ZF, IF, DF).

CF — флаг переноса (Carry Flag). Устанавливается в 1, если результат предыдущей операции не уместился в приемнике и произошел перенос из старшего бита или если требуется заем (при вычитании), иначе устанавливается в 0. Например, после сложения слова 0FFFFh и 1, если регистр, в который надо поместить результат, — слово, в него будет записано 0000h и флаг CF = 1.

OF — флаг переполнения (Overflow Flag). Этот флаг устанавливается в 1, если результат предыдущей арифметической операции над числами со знаком выходит за допустимые для них пределы. Например, если при сложении двух положительных чисел получается число со старшим битом, равным единице (то есть отрицательное) и наоборот.

AF — флаг полупереноса или вспомогательного переноса (Auxiliary carry Flag). Устанавливается в 1, если в результате предыдущей операции произошел перенос (или заем) из третьего бита в четвертый. Этот флаг используется автоматически командами двоично-десятичной коррекции.

SF — флаг знака (Sign Flag). Этот флаг всегда равен старшему биту результата.

ZF — флаг нуля (Zero Flag). Устанавливается в 1, если результат предыдущей команды — ноль.

IF — флаг прерываний (Interrupt enable Flag). Установка этого флага в 1 приводит к тому, что процессор перестает обрабатывать прерывания от внешних устройств. Обычно его устанавливают на короткое время для выполнения критических участков кода.

DF — флаг направления (Direction Flag). Этот флаг контролирует поведение команд обработки строк — когда он установлен в 1, строки обрабатываются в сторону уменьшения адресов, а когда DF = 0 — наоборот.

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

STC –[SeT Carry]Установить флаг переноса. Устанавливает флаг CF в 1.

CLC – [CLear Carry] Сбросить флаг переноса. Сбрасывает флаг CF в 0.

CMC – [CoMplement Carry] Инвертировать флаг переноса. Инвертирует флаг СF.

STD[SeT Direction]Установить флаг направления. Устанавливает флаг DF в 1, так что при последующих строковых операциях регистры DI и SI будут уменьшаться.

CLD -[CLear Direction] Сбросить флаг направления. Сбрасывает флаг DF в 0, так что при последующих строковых операциях регистры DI и SI будут увеличиваться.

LAHF – [Load Flags into AH]Загрузить флаги состояния в АН. Копирует младший байт регистра FLAGS в АН, включая флаги SF (7 бит), ZF (6 бит), AF (4 бит), PF (2 бит) и CF (0 бит). Бит 1 устанавливается в 1, биты 3 и 5 - в 0.

SAHF– [Store AH into Flags] Загрузить флаги состояния из АН. Загружает флаги SF, ZF, AF, PF и CF из регистра АН значениями бит 7, 6, 4, 2 и 0 соответственно. Зарезервированные биты 1, 3 и 5 регистра флагов не изменяются.

CLI – [CLear Interrupt]Запретить прерывания. Сбрасывает флаг IF в 0. После выполнения этой команды процессор игнорирует все прерывания от внешних устройств.

STI – [SeT Interrupt]Разрешить прерывания. Устанавливает флаг IF в 1, отменяя тем самым действие команды CLI.

Использование флагов.

При программировании на ассемблере наиболее часто используются флаги OF, SF, ZF и CF для арифметических операций и операций сравнения, а флаг DF для обозначения направления в операциях над строками.

Команды ассемблера PUSHF и POPF.

PUSHF– [PUSH Flags]Эти команды копируют содержание регистра FLAGS в стек (уменьшая SP на 2).

POPF– [POP Flags]Считывает из вершины стека слово (POPF) и помещает в регистр FLAGS (увеличивает SP на 2).


3.

Понятие сегментной адресации.

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

Определение сегмента в ассемблере (директивы SEGMENT и ENDS).

Сегмент программы описывается директивами SEGMENT и ENDS.

имя_сегмента segment readonly выравн. тип разряд 'класс' ...имя_сегмента ends

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

Все пять операндов директивы SEGMENT необязательны.

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

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

BYTE — с любого адреса;

WORD — с четного адреса;

DWORD — с адреса, кратного 4;

PARA — с адреса, кратного 16 (граница параграфа);

PAGE — с адреса, кратного 256.

По умолчанию используется выравнивание по границе параграфа.

Тип. Выбирает один из возможных типов комбинирования сегментов:

- тип PUBLIC (иногда используется синоним MEMORY) означает, что все такие сегменты с одинаковым именем, но разными классами будут объединены в один;

- тип STACK — то же самое, что и PUBLIC, но должен использоваться для сегментов стека, потому что при загрузке программы сегмент, полученный объединением всех сегментов типа STACK, будет использоваться как стек;

- сегменты типа COMMON с одинаковым именем также объединяются в один, но не последовательно, а по одному и тому же адресу, следовательно, длина суммарного сегмента будет равна не сумме длин объединяемых сегментов, как в случае PUBLIC и STACK, а длине максимального;

- тип AT — выражение указывает, что сегмент должен располагаться по фиксированному абсолютному адресу в памяти. Результат выражения, использующегося в качестве операнда для AT, равен этому адресу, деленному на 16. Например: segment at 40h — сегмент, начинающийся по абсолютному адресу 0400h. Такие сегменты обычно содержат только метки, указывающие на области памяти, которые могут потребоваться программе;

- PRIVATE (значение по умолчанию) — сегмент такого типа не объединяется с другими сегментами.

Разрядность. Этот операнд может принимать значения USE16 и USE32. Размер сегмента, описанного как USE16, не может превышать 64 Кб, и все команды и адреса в этом сегменте считаются 16-битными. В этих сегментах все равно можно применять команды, использующие 32-битные регистры или ссылающиеся на данные в 32-битных сегментах, но они будут использовать префикс изменения разрядности операнда или адреса и окажутся длиннее и медленнее. Сегменты USE32 могут занимать до 4 Гб, и все команды и адреса в них по умолчанию 32-битные. Если разрядность сегмента не указана, по умолчанию используется USE16 при условии, что перед директивой .MODEL не применялась директива задания допустимого набора команд .386 или старше.

Класс — это любая метка, взятая в одинарные кавычки. Все сегменты с одинаковым классом, даже сегменты типа PRIVATE, будут расположены в исполняемом файле непосредственно друг за другом.

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

Сегментные регистры (CS, DS, SS, ES, FS, GS). Их назначение.

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

DS,ES,GS,FS – Называются регистрами сегментов данных, процессор использует их для обычного доступа к данным.

CS – [Code Segment] Сегмент кода содержит программу, исполняющуюся в данный момент, так что запись нового селектора в этот регистр приводит к тому, что далее будет исполнена не следующая по тексту программы команда, а команда из кода, находящегося в другом сегменте, с тем же смещением. Все команды передачи управления — перехода, условного перехода, цикла, вызова подпрограммы и т.п. — и осуществляют эту самую запись в CS.

SS – [Stack Segment] Сегмент стека.

Директива ASSUME.

assume регистр:связь...

Директива ASSUME указывает ассемблеру, с каким сегментом или группой сегментов связан тот или иной сегментный регистр. В качестве операнда «связь» могут использоваться имена сегментов, имена групп, выражения с оператором SEG или слово «NOTHING», означающее отмену действия предыдущей ASSUME для данного регистра. Эта директива не изменяет значений сегментных регистров, а только позволяет ассемблеру проверять допустимость ссылок и самостоятельно вставлять при необходимости префиксы переопределения сегментов, если они необходимы.

Директива GROUP.

имя_группы group имя_сегмента...

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


4.

Способы задания операндов в командах (виды адресации).[Адресация в 16 битных процессорах]

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

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

mov ax,bx

Непосредственная адресация. Некоторые команды (все арифметические команды, кроме деления) позволяют указывать один из операндов непосредственно в тексте программы, например команда

mov ax,2помещает в регистр AX число 2.Прямая адресация. Если известен адрес операнда, располагающегося в памяти, можно использовать этот адрес. Если операнд — слово, находящееся в сегменте, на который указывает ES, со смещением от начала сегмента 0001, то команда mov ax,es:0001 поместит это слово в регистр AX. В реальных программах обычно для задания статических переменных используют директивы определения данных, которые позволяют ссылаться на статические переменные не по адресу, а по имени. Тогда, если в сегменте, указанном в ES, была описана переменная word_var размером в слово, можно записать ту же команду как mov ax,es:word_var В таком случае ассемблер сам заменит слово «word_var» на соответствующий адрес. Если селектор сегмента данных находится в DS, имя сегментного регистра при прямой адресации можно не указывать, DS используется по умолчанию. Прямая адресация иногда называется адресацией по смещению.

Косвенная адресация. По аналогии с регистровыми и непосредственными операндами адрес операнда в памяти также можно не указывать непосредственно, а хранить в любом регистре. Например, следующая команда помещает в регистр AX слово из ячейки памяти, селектор сегмента которой находится в DS, а смещение — в BX: mov ax,[bx] (можно использовать только BX, SI, DI и BP)

Адресация по базе со сдвигом. Теперь скомбинируем два предыдущих метода адресации: следующая команда mov ax,[bx+2] | mov ax,[bp]+2 | mov ax,2[bp] помещает в регистр AX слово, находящееся в сегменте, указанном в DS, со смещением на 2 большим, чем число, находящееся в BX. (можно использовать только BX, BP, SI, DI и сдвиг может быть только байтом или словом (со знаком))

Адресация по базе с индексированием. В этом методе адресации смещение операнда в памяти вычисляется как сумма чисел, содержащихся в двух регистрах, и смещения, если оно указано. Все следующие команды — это разные формы записи одного и того же действия: mov ax,[bx+si+2] | mov ax,[bx][si]+2 | mov ax,[bx+2][si] | mov ax,[bx][si+2] | mov ax,2[bx][si] В регистр AX помещается слово из ячейки памяти со смещением, равным сумме чисел, содержащихся в BX и SI, и числа 2. Из шестнадцатибитных регистров так можно складывать только BX + SI, BX + DI, BP + SI и BP + DI. Так же как и для прямой адресации, вместо непосредственного указания числа можно использовать имя переменной, заданной одной из директив определения данных.


5.

Понятие программного счетчика.

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

Директивы работы с программным счетчиком (ORG, ALIGN EVEN).

org выражение

Устанавливает значение программного счетчика. Директива ORG с операндом 100h обязательно используется при написании файлов типа COM, которые загружаются в память после блока параметров размером 100h.

align значение

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

even

Директива EVEN делает текущее значение счетчика кратным двум, вставляя команду NOP, если оно было нечетным. Это увеличивает скорость работы программы, так как для доступа к слову, начинающемуся с нечетного адреса, процессор должен считать два слова из памяти. Если при описании сегмента не использовалось выравнивание типа BYTE, счетчик в начале сегмента всегда четный.

Регистры CS и IP.

Регистры CS [Code Segment] отвечает за сегмент кода. Сегмент кода содержит программу, исполняющуюся в данный момент, так что запись нового селектора в этот регистр приводит к тому, что далее будет исполнена не следующая по тексту программы команда, а команда из кода, находящегося в другом сегменте, с тем же смещением.

Регистр IP [Instruction Pointer] хранит в себе смещение следующей выполняемой команды (указатель инструкции), запись в который также приведет к тому, что следующей будет исполнена какая-нибудь другая команда. Все команды передачи управления — перехода, условного перехода, цикла, вызова подпрограммы и т.п. — осуществляют эту самую запись в CS и IP.


6.

Директива определения модели.

Модели памяти задаются директивой .MODEL

.model модель, язык, модификатор

где модель — одно из следующих слов:

>TINY [крошечный] — код, данные и стек размещаются в одном и том же сегменте размером до 64 Кб. Эта модель памяти чаще всего используется при написании на ассемблере небольших программ;

>SMALL [маленький] — код размещается в одном сегменте, а данные и стек — в другом (для их описания могут применяться разные сегменты, но объединенные в одну группу). Эту модель памяти также удобно использовать для создания программ на ассемблере;

>COMPACT [компактный] — код размещается в одном сегменте, а для хранения данных могут использоваться несколько сегментов, так что для обращения к данным требуется указывать сегмент и смещение (данные дальнего типа);

>MEDIUM [середина] — код размещается в нескольких сегментах, а все данные — в одном, поэтому для доступа к данным используется только смещение, а вызовы подпрограмм применяют команды дальнего вызова процедуры;

>LARGE и HUGE [большой и громадный] — и код, и данные могут занимать несколько сегментов;

>FLAT [распростертый] — то же, что и TINY, но используются 32-битные сегменты, так что максимальный размер сегмента, содержащего и данные, и код, и стек, — 4 Мб.

Язык — необязательный операнд, принимающий значения C, PASCAL, BASIC, FORTRAN, SYSCALL и STDCALL. Если он указан, подразумевается, что процедуры рассчитаны на вызов из программ на соответствующем языке высокого уровня.

Модификатор — необязательный операнд, принимающий значения NEARSTACK (по умолчанию) или FARSTACK. Во втором случае сегмент стека не будет объединяться в одну группу с сегментами данных.

Директивы упрощенной сегментации. Связь директив упрощенной сегментации с определением сегментов.

После того как модель памяти установлена, вступают в силу упрощенные директивы определения сегментов, объединяющие действия директив SEGMENT и ASSUME. Кроме того, сегменты, объявленные упрощенными директивами, не требуется закрывать директивой ENDS — они закрываются автоматически, как только ассемблер обнаруживает новую директиву определения сегмента или конец программы.

Директива .CODE описывает основной сегмент кода

.code имя_сегмента

эквивалентно

_TEXT segment word public ’CODE’

для моделей TINY, SMALL и COMPACT и

name_TEXT segment word public ’CODE’

для моделей MEDIUM, HUGE и LARGE (name — имя модуля, в котором описан данный сегмент). В этих моделях директива .CODE также допускает необязательный операнд — имя определяемого сегмента, но все сегменты кода, описанные так в одном и том же модуле, объединяются в один сегмент с именем NAME_TEXT.

.stack размер

Директива .STACK описывает сегмент стека и эквивалентна директиве

STACK segment para public ’stack’

Необязательный параметр указывает размер стека. По умолчанию он равен 1 Кб.

.data

Описывает обычный сегмент данных и соответствует директиве

_DATA segment word public ’DATA’ .data?

Описывает сегмент неинициализированных данных:

_BSS segment word public ’BSS’

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

.const

Описывает сегмент неизменяемых данных:

CONST segment word public ’CONST’

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

.fardata имя_сегмента

Сегмент дальних данных:

имя_сегмента segment para private ’FAR_DATA’

Доступ к данным, описанным в этом сегменте, потребует загрузки сегментного регистра. Если не указан операнд, в качестве имени сегмента используется FAR_DATA.

.fardata? имя_сегмента

Сегмент дальних неинициализированных данных:

имя_сегмента segment para private ’FAR_BSS’

Как и в случае с FARDATA, доступ к данным из этого сегмента потребует загрузки сегментного регистра. Если имя сегмента не указано, используется FAR_BSS.

Во всех моделях памяти сегменты, представленные директивами .DATA, .DATA?, .CONST, .FARDATA и .FARDATA?, а также сегмент, описанный директивой .STACK, если не был указан модификатор FARSTACK, и сегмент .CODE в модели TINY автоматически объединяются в группу с именем FLAT — для модели памяти FLAT или DGROUP — для всех остальных моделей. При этом сегментный регистр DS (и SS, если не было FARSTACK, и CS в модели TINY) настраивается на всю эту группу, как если бы была выполнена команда ASSUME.


7.

Директивы определения данных. Инициализация данных различных типов.

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

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

где D* — одна из нижеприведенных псевдокоманд:

DB — определить байт;

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

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

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

DQ — определить учетверенное слово (8 байт);

DT — определить 10 байт (80-битные типы данных, используемые FPU).

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

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

table_512w dw 512 dup(?)

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

Хранение строк и отрицательных чисел.

text_string db 'Hello world!'

Первые 12 байт содержат ASCII-коды символов строки «Hello world!», и переменная text_string указывает на первую букву в этой строке, так что команда mov al,text_string считает в регистр AL число 48h (код латинской буквы H).

 

Упакованные десятичные числа сопроцессора имеют бит знака в старшем байте. Упакованное десятичное число хранится в десятичном коде, причем старший бит 10-байтного поля содержит знак (0 - положительно, 1 - отрицательно). Для описания упакованного десяточного числа используется оператор определения десятибайтового поля DT. Чтобы задать упакованное десятичное число в этом поле, необходимо использовать шестнадцатеричную запись. Если в поле операнда окажется целое число, ассемблер преобразует его в дополнительный двоичный код, а не в упакованное десятичное число. К счастью, преобразовать десятичное число в необходимую шестнадцатеричную форму легко. Просто запишите нужное число в десятичной форме, а затем добавьте букву H, показывающую, что это - шестнадцатеричное число. Изобразить отрицательное число труднее. Если вы напишите перед десятичным числом знак "-", ассемблер преобразует его в двоичный дополнительный код, даже если есть буква H. Поэтому в этом случае нужно подсчитать десятичные цифры и удлинить число до 20 цифр. первые две цифры должны быть 80, чтобы показать, что число отрицательно. То есть, чтобы изобразить -1234 в упакованном десятичном формате, надо записать:

number DT 80000000000000001234H

 

 


8.

Понятие строк с терминатором (ASCIIZ-строки) и строки со счетчиком.

String_ASCIIZ db “Hello World”,’0’

String_ASCII_with_ counter db ’11’,“Hello World”

Необходимость подобного представления строк.

D

Достоинства и недостатки каждого метода.

D


9.

Структуры, объединения, записи и перечисления. Директивы их описания в языке ассемблер. Работа с ними.

Структура.

Директива STRUC позволяет определить структуру данных аналогично структурам в языках высокого уровня. Последовательность директив

имя struc поляимя ends

где поля — любой набор псевдокоманд определения переменных или структур, устанавливает, но не инициализирует структуру данных. В дальнейшем для ее создания в памяти используют имя структуры как псевдокоманду:

метка имя <значения>

И наконец, для чтения или записи в элемент структуры используется оператор «.» (точка). Например:

point struc ; Определение структурыx dw 0 ; Три слова со значениямиy dw 0 ; по умолчанию 0,0,0z dw 0color db 3 dup(?) ; и три байтаpoint endscur_point point <1,1,1,255,255,255> ; Инициализация mov ax,cur_point.x ; Обращение к слову "x"

Если была определена вложенная структура, доступ к ее элементам осуществляется через еще один оператор «.» (точка).

color struc ; Определить структуру color.red db ?green db ?blue db ?color endspoint strucx dw 0y dw 0z dw 0clr color <>point ends cur_point point <> mov cur_point.clr.red,al ; Обращение к красной компоненте ; цвета точки cur_point.

Объединения.

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

имя union поляимя ends

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

Записи.

Это структурный тип данных, состоящий из фиксированного числа элементов длинной от одного до нескольких бит. Суммарный размер записи определяется суммой размеров её полей и не может быть более 8, 16 или 32 бит. Если суммарный размер записи меньше указанных значений, то все поля записи «прижимаются» к младшим разрядам.

имя RECORD описание_элементов

описание_элементов – представляет собой последовательность описаний отдельных элементов записи согласно правилу: имя_поля : размер = значение [,имя_поля : размер = значение]

Перечисления.


10.

Операторы ассемблера.

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

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

Например: 2 + 2 — выражение, состоящее из двух чисел (2 и 2) и оператора +. Каждое выражение имеет значение, которое определяется как результат действия операторов. Так, значение выражения 2 + 2 — число 4.

Операторы присваивания, арифметические, логические, сдвигов, сравнения.

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

message1 equ <foobar>

Оператор () (круглые скобки). Часть выражения, заключенная в круглые скобки, вычисляется в первую очередь. mov al, 2*(3+4) ; mov al,14

Арифметические операторы: + (плюс), – (минус), * (умножение), / (целочисленное деление), MOD (остаток от деления). Они выполняют соответствующие арифметические действия. mov al,90 mod 7 ; mov al,6

Кроме того, к арифметическим операторам относится унарный минус — минус, который ставят перед отрицательным числом.

Логические операторы: AND (И), NOT (НЕ), OR (ИЛИ), XOR (исключающее ИЛИ), SHL (сдвиг влево), SHR (сдвиг вправо). Эти операторы выполняют соответствующие логические действия.

mov ax,1234h AND 4321h ; mov ax,0220h

Операторы сравнения: EQ (равно), GE (больше или равно), GT (больше), LE (меньше или равно), LT (меньше), NE (не равно). Результат действия каждого из этих операторов — единица, если условие выполняется, и ноль — если не выполняется. .errnz $ gt 65535 ; Если адрес больше 64 Кб – ошибка

Операторы адресации:

SEG выражение — сегментный адрес;

OFFSET выражение — смещение;

THIS тип — текущий адрес (MASM и TASM);

Тип PTR выражение — переопределение типа;

LARGE выражение — 32-битное смещение (TASM и WASM);

SMALL выражение — 16-битное смещение (TASM и WASM);

SHORT выражение — 8-битное смещение.

SEG и OFFSET возвращают соответствующую часть адреса своего аргумента:

mov dx, offset msg ; Занести в DX смещение переменной msg

THIS создает операнд, адресом которого является текущее значение счетчика:

mov al, this byte-1 ; Занести в AX последний байт кода предыдущей команды.

PTR создает аргумент, адресом которого является значение выражения, а тип указан явно:

mov dword ptr [si],0 ; Записать 4 байта нулей по адресу DS:SI

LARGE, SMALL и SHORT используются с командами передачи управления, если возникают двусмысленности при косвенных переходах:

jmp large dword ptr old_address ; Переменная old_address содержит 32-битное смещениеjmp small dword ptr old_address ; Переменная old_address содержит 16-битный сегментный адрес и 16-битное смещение.jmp short short_label ; Метка short_label находится ближе, чем +128/-127 байт от этой команды, так что можно использовать короткую форму команды JMP.

Другие операторы:

. (точка) — ссылка на элемент структуры;

: (двоеточие) — переопределение сегмента;

[] (прямые скобки) — косвенная адресация;

? — неинициализированное значение;

число DUP (значение) — повторяющееся значение.

LENGTH метка – число элементов данныхtable dw 0,1,2,3,4,5,6,7 ; Определить таблицу из 8 слов.table_count = length table ; table_count = 8SIZE метка – размер данныхtable_size = size table ; table_size = 16

Отличия операторов от команд ассемблера.

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


11.

Команды перемещения данных (MOV, XCHG, LEA, LDS, LSS, LES, LFS, LGS, XLATB, PUSH, POP, IN, OUT, CBW, CWD). Назначение, ограничения.

MOV приемник, источник ; Назначение: Пересылка данных.

Базовая команда пересылки данных. Копирует содержимое источника в приемник, источник не изменяется. Команда MOV действует аналогично операторам присваивания из языков высокого уровня, то есть команда mov ax,bx эквивалентна выражению ах = bх; языка С, за исключением того, что команда ассемблера позволяет работать не только с переменными в памяти, но и со всеми регистрами процессора. В качестве источника для MOV могут использоваться: число (непосредственный операнд), регистр общего назначения, сегментный регистр или переменная (то есть операнд, находящийся в памяти). В качестве приемника — регистр общего назначения, сегментный регистр (кроме CS) или переменная. Оба операнда должны быть одного и того же размера — байт, слово или двойное слово. Нельзя выполнять пересылку данных с помощью MOV из одной переменной в другую, из одного сегментного регистра в другой и нельзя помещать в сегментный регистр непосредственный операнд — эти операции выполняют двумя командами MOV (из сегментного регистра в обычный и уже из него в другой сегментный) или парой команд PUSH/POP.

XCHG операнд1, операнд2 ; Назначение: Обмен операндов между собой.

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

xchg eax,ebx ; то же, что три команды на языке С: ; temp = eax; eax = ebx; ebx = temp; xchg al,al ; а эта команда не делает ничегоLEA приемник, источник ; Назначение: Вычисление эффективного адреса.Команда lea похожа на команду mov тем, что она также производит пересылку. Однако, обратите внимание, команда lea производит пересылку не данных, а эффективного адреса данных (то есть смещения данных относительно начала сегмента данных) в регистр, указанный операндом назначение.lds назначение,источник ; Назначение: загрузка указателя в регистр сегмента данных ds; lss назначение,источник ; Назначение: загрузка указателя в регистр сегмента стека ss.les назначение,источник ; Назначение: загрузка указателя в регистр дополнительного сегмента данных es; lfs назначение,источник ; Назначение: загрузка указателя в регистр дополнительного сегмента данных fs;lgs назначение,источник ; Назначение: загрузка указателя в регистр дополнительного сегмента данных gs; Все команды этой группы позволяют получить в паре регистров такой полный указатель на операнд в памяти. При этом имя сегментного регистра, в который помещается сегментная составляющая адреса, определяется кодом операции. Соответственно, смещение помещается в регистр общего назначения, указанный операндом назначение. Но не все так просто с операндом источник. На самом деле, в команде в качестве источника нельзя указывать непосредственно имя операнда в памяти, на который мы бы хотели получить указатель. Предварительно необходимо получить само значение полного указателя в некоторой области памяти и указать в команде получения полного адреса имя этой области.XLATB ; Трансляция в соответствии с таблицейПомещает в AL байт из таблицы в памяти по адресу ES:BX со смещением относительно начала таблицы, равным AL. В качестве примера использования XLATB можно написать следующий вариант преобразования шестнадцатеричного числа в ASCII-код соответствующего ему символа:

mov al,0Ch

mov bx, offset htable

xlatb

если в сегменте данных, на который указывает регистр ES, было записано

htable db "0123456789ABCDEF"

то теперь AL содержит не число 0Сh, а ASCII-код буквы «С». Разумеется, это преобразование можно выполнить, используя гораздо более компактный код всего из трех арифметических команд, который будет рассмотрен в описании команды DAS, но с XLAT можно выполнять любые преобразования такого рода.

PUSH источник ; Назначение: Поместить данные в стек.

Помещает содержимое источника в стек. Источником может быть регистр, сегментный регистр, непосредственный операнд или переменная. Фактически эта команда копирует содержимое источника в память по адресу SS:[SP] и уменьшает SP на размер источника в байтах (2 или 4).

POP приемник ; Назначение: Считать данные из стека.

Помещает в приемник слово или двойное слово, находящееся в вершине стека, увеличивая SP на 2 или 4 соответственно. POP выполняет действие, полностью обратное PUSH. Приемником может быть регистр общего назначения, сегментный регистр, кроме CS (чтобы загрузить CS из стека, надо воспользоваться командой RET), или переменная.

IN приемник, источник Назначение: Считать данные из порта.

Копирует число из порта ввода-вывода, номер которого указан в источнике, в приемник. Приемником может быть только AL, АХ или ЕАХ. Источник — или непосредственный операнд, или DX, причем можно указывать только номера портов не больше 255.

OUT приемник, источник Назначение: Записать данные в порт.

Копирует число из источника (AL, АХ) в порт ввода-вывода, номер которого указан в приемнике. Приемник может быть либо непосредственным номером порта, либо регистром DX.

CBW ; Назначение: Конвертирование байта в слово.

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

mov al,0F5h ; AL = 0F5h = 245 = -11

cbw ; теперь АХ = 0FFF5h = 65 525 = -11

CWD; Назначение: Конвертирование слова в двойное слово.

Команда CWD превращает слово в AХ в двойное слово, младшая половина которого (биты 0 – 15) остается в АХ, а старшая (биты 16 – 31) располагается в DX. Эта команда всего лишь устанавливает все биты регистра DX в значение, равное значению старшего бита регистра АХ, сохраняя таким образом его знак.


12.

Арифметические команды (ADD, ADC, SUB, SBB, CMP, MUL, IMUL, DIV, IDIV, NEG). Назначение, устанавливаемые флаги.

Все команды арифметические команды, кроме команд деления и умножения, изменяют флаги OF, SF, ZF, AF, CF, PF в соответствии с назначением каждого из этих флагов.

ADD приемник, источник – Сложение.

Команда выполняет арифметическое сложение приемника и источника, помещает сумму в приемник, не изменяя содержимое источника. Приемник может быть регистром или переменной, источник может быть числом, регистром или переменной, но нельзя использовать переменную одновременно и для источника, и для приемника. Команда ADD никак не различает числа со знаком и без знака, но, употребляя значения флагов CF (перенос при сложении чисел без знака), OF (перенос при сложении чисел со знаком) и SF (знак результата), можно использовать ее и для тех, и для других.

ADC приемник, источник – Сложение с переносом.

Эта команда во всем аналогична ADD, кроме того, что она выполняет арифметическое сложение приемника, источника и флага СF.

SUB приемник, источник – Вычитание.

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

SBB приемник, источник – Вычитание с займом.

Эта команда во всем аналогична SUB, кроме того, что она вычитает из приемника значение источника и дополнительно вычитает значение флага CF.

CMP приемник, источник – Сравнение.

Сравнивает приемник и источник и устанавливает флаги. Сравнение осуществляется путем вычитания источника (число, регистр или переменная) из приемника (регистр или переменная; приемник и источник не могут быть переменными одновременно), причем результат вычитания никуда не записывается, единственным результатом работы этой команды оказывается изменение флагов CF, OF, SF, ZF, AF и PF.

MUL источник - Умножение чисел без знака.

Выполняет умножение содержимого источника (регистр или переменная) и регистра AL, АХ, (в зависимости от размера источника) и помещает результат в АХ, DX:AX, соответственно. Если старшая половина результата (АН, DX) содержит только нули (результат целиком поместился в младшую половину), флаги CF и OF устанавливаются в 0, иначе — в 1. Значение остальных флагов (SF, ZF, AF и PF) не определено.

IMUL источник – Умножение чисел со знаком.

IMUL приемник, источник

IMUL приемник, источник1, источник2

Эта команда имеет три формы, различающиеся числом операндов:

>IMUL источник: источник (регистр или переменная) умножается на AL, АХ (в зависимости от размера операнда), и результат располагается в АХ, DX:AX соответственно.

>IMUL приемник, источник: источник (число, регистр или переменная) умножается на приемник (регистр), и результат заносится в приемник.

>IMUL приемник,источник1,источник2: источник 1 (регистр или переменная) умножается на источник 2 (число), и результат заносится в приемник (регистр).

Во всех трех вариантах считается, что результат может занимать в два раза больше места, чем размер источника. В первом случае приемник автоматически оказывается достаточно большим, но во втором и третьем случаях могут произойти переполнение и потеря старших бит результата. Флаги OF и CF будут равны единице, если это произошло, и нулю, если результат умножения поместился целиком в приемник (во втором и третьем случаях) или в младшую половину приемника (в первом случае). Значения флагов SF, ZF, AF и PF после команды IMUL не определены.

DIV источник – Целочисленное деление без знака.

Выполняет целочисленное деление без знака AL, АХ (в зависимости от размера источника) на источник (регистр или переменная) и помещает результат в AL, АХ, а остаток — в АН, DX соответственно. Результат всегда округляется в сторону нуля, абсолютное значение остатка всегда меньше абсолютного значения делителя. Значения флагов CF, OF, SF, ZF, AF и PF после этой команды не определены, а переполнение или деление на ноль вызывает исключение #DE (ошибка при делении) в защищенном режиме и прерывание 0 — в реальном.

IDIV источник – Целочисленное деление со знаком.

Выполняет целочисленное деление со знаком AL, АХ (в зависимости от размера источника) на источник (регистр или переменная) и помещает результат в AL, АХ, а остаток — в АН, DX соответственно. Результат всегда округляется в сторону нуля, знак остатка всегда совпадает со знаком делимого, абсолютное значение остатка всегда меньше абсолютного значения делителя. Значения флагов CF, OF, SF, ZF, AF и PF после этой команды не определены, а переполнение или деление на ноль вызывает исключение #DE (ошибка при делении) в защищенном режиме и прерывание 0 — в реальном.

NEG приемник – Изменение знака.

Выполняет над числом, содержащимся в приемнике (регистр или переменная), операцию дополнения до двух. Эта операция эквивалентна обращению знака операнда, если рассматривать его как число со знаком. Если приемник равен нулю, флаг CF устанавливается в 0, иначе — в 1. Остальные флаги (OF, SF, ZF, AF, PF) устанавливаются в соответствии с результатом операции.


13.

Логические команды (AND, OR, XOR, NOT, TEST). Назначение, устанавливаемые флаги.

AND приемник, источник – Логическое И.

Команда выполняет побитовое «логическое И» над приемником (регистр или переменная) и источником (число, регистр или переменная; источник и приемник не могут быть переменными одновременно) и помещает результат в приемник. Любой бит результата равен 1, только если соответствующие биты обоих операндов были равны 1, и равен 0 в остальных случаях. Наиболее часто AND применяют для выборочного обнуления отдельных бит, например, команда

and al,00001111b

обнулит старшие четыре бита регистра AL, сохранив неизменными четыре младших. Флаги OF и CF обнуляются, SF, ZF и PF устанавливаются в соответствии с результатом, AF не определен.

OR приемник, источник – Логическое ИЛИ.

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

or al,00001111b

приведет к тому, что младшие четыре бита регистра AL будут установлены в 1. При выполнении команды OR флаги OF и CF обнуляются, SF, ZF и PF устанавливаются в соответствии с результатом, AF не определен.

XOR приемник, источник – Логическое исключающее ИЛИ.

Выполняет побитовое «логическое исключающее ИЛИ» над приемником (регистр или переменная) и источником (число, регистр или переменная; источник и приемник не могут быть переменными одновременно) и помещает результат в приемник. Любой бит результата равен 1, если соответствующие биты операндов различны, и нулю, если одинаковы. XOR используется для самых разных операций, например:

xor ах,ах ; обнуление регистра АХ

или

xor ах,bх

xor bх,ах

xor ах,bх ; меняет местами содержимое АХ и ВХ

Оба этих примера могут выполняться быстрее, чем соответствующие очевидные команды

mov ax,0

или

xchg ax,bx

NOT приемник – Инверсия.

Каждый бит приемника (регистр или переменная), равный нулю, устанавливается в 1, и каждый бит, равный 1, сбрасывается в 0. Флаги не затрагиваются.

TEST приемник, источник – Логическое сравнение.

Вычисляет результат действия побитового «логического И» над приемником (регистр или переменная) и источником (число, регистр или переменная; источник и приемник не могут быть переменными одновременно) и устанавливает флаги SF, ZF и PF в соответствии с полученным результатом, не сохраняя результат (флаги OF и CF обнуляются, значение AF не определено). TEST, так же как и СМР, используется в основном в сочетании с командами условного перехода (Jcc), условной пересылки данных (CMOVcc) и условной установки байт (SETcc).


14.

Команды сдвигов (SHL, SHR, SAL, SAR, RCL, RCR, ROL, ROR). Назначение, устанавливаемые флаги.

SHL приемник, счетчик - Логический сдвиг влево;

SHR приемник, счетчик - Логический сдвиг вправо;

SAL приемник, счетчик - Арифметический сдвиг влево;

SAR приемник, счетчик - Арифметический сдвиг вправо.

Эти четыре команды выполняют двоичный сдвиг приемника (регистр или переменная) вправо (в сторону старшего бита) или влево (в сторону младшего бита) на значение счетчика (число или регистр CL, из которого учитываются только младшие пять бит, которые могут принимать значения от 0 до 31), Операция сдвига на 1 эквивалентна умножению (сдвиг влево) или делению (сдвиг вправо) на 2. Так, число 0010b (2) после сдвига на 1 влево превращается в 0100b (4). Команды SAL и SHL выполняют одну и ту же операцию (на самом деле это одна и та же команда) — на каждый шаг сдвига старший бит заносится в CF, все биты сдвигаются влево на одну позицию, и младший бит обнуляется. Команда SHR выполняет прямо противоположную операцию: младший бит заносится в CF, все биты сдвигаются на 1 вправо, старший бит обнуляется. Эта команда эквивалентна беззнаковому целочисленному делению на 2. Команда SAR действует по аналогии с SHR, только старший бит не обнуляется, а сохраняет предыдущее значение, так что, например, число 11111100b (-4) перейдет в 11111110b (-2). SAR, таким образом, эквивалентна знаковому делению на 2, но, в отличие от IDIV, округление происходит не в сторону нуля, а в сторону отрицательной бесконечности. Так, если разделить -9 на 4 с помощью IDIV, результат будет -2 (и остаток -1), а если выполнить арифметический сдвиг вправо числа -9 на 2, результат будет -3. Сдвиги больше чем на 1 эквивалентны соответствующим сдвигам на 1, выполненным последовательно.

Сдвиги на 1 изменяют значение флага OF: SAL/SHL устанавливают его в 1, если после сдвига старший бит изменился (то есть старшие два бита исходного числа не были одинаковыми), и в 0, если старший бит остался тем же. SAR устанавливает OF в 0, и SHR устанавливает OF в значение старшего бита исходного числа. Для сдвигов на несколько бит значение OF не определено. Флаги SF, ZF, PF устанавливаются всеми сдвигами в соответствии с результатом, значение AF не определено (кроме случая, если счетчик сдвига равен нулю, в котором ничего не происходит и флаги не изменяются).

В процессорах 8086 непосредственно можно было задавать в качестве второго операнда только число 1 и при использовании CL учитывать все биты, а не только младшие 5, но уже начиная с 80186 эти команды приняли свой окончательный вид.

RCL приемник, счетчик – Циклический сдвиг влево через флаг переноса;

RCR приемник, счетчик – Циклический сдвиг вправо через флаг переноса;

ROL приемник, счетчик – Циклический сдвиг влево;

ROR приемник, счетчик – Циклический сдвиг вправо.

Эти команды осуществляют циклический сдвиг приемника (регистр или переменная) на число бит, указанное в счетчике (число или регистр CL, из которого учитываются только младшие пять бит, принимающие значения от 0 до 31). При выполнении циклического сдвига на 1 команды ROR (ROL) сдвигают каждый бит приемника вправо (влево) на одну позицию, за исключением самого младшего (старшего), который записывается в позицию самого старшего (младшего) бита. Команды RCR и RCL выполняют аналогичное действие, но включают флаг CF в цикл, как если бы он был дополнительным битом в приемнике.

 


15.

Команды работы с двоично-десятичными числами (ААА, DAA, AAS, DAS, AAD, ААМ). Назначение, принцип их работы.

AAA –ASCII-коррекция после сложения.

Корректирует сумму двух неупакованных двоично-десятичных чисел в AL. Если коррекция приводит к десятичному переносу, АН увеличивается на 1. Эта команда имеет смысл сразу после команды сложения двух таких чисел. Например, если при сложении 05 и 06 в АХ окажется число 000Bh, то команда ААА скорректирует его в 0101h (неупакованное десятичное 11). Флаги CF и OF устанавливаются в 1, если произошел перенос из AL в АН, иначе они равны нулю. Значения флагов OF, SF, ZF и PF не определены.

DAA –BCD-коррекция после сложения. [BCD=Binary-Coded Decimal=двоично-десятичный код]

Если эта команда выполняется сразу после ADD (ADC, INC или XADD) и в регистре AL находится сумма двух упакованных двоично-десятичных чисел, то в результате в AL записывается упакованное двоично-десятичное число, которое должно было быть результатом сложения. Например, если AL содержит число 19h, последовательность команд

inc al

daa

приведет к тому, что в AL окажется 20h (а не 1Ah, как было бы после INC). Флаги AF и CF устанавливаются, если в ходе коррекции происходил перенос из первой или второй цифры соответственно, SF, ZF и PF устанавливаются в соответствии с результатом, флаг OF не определен.

AAS –ASCII-коррекция после вычитания.

Корректирует разность двух неупакованных двоично-десятичных чисел в AL сразу после команды SUB или SBB. Если коррекция приводит к займу, АН уменьшается на 1. Флаги CF и OF устанавливаются в 1, если произошел заем из AL в АН, и в ноль — в противном случае. Значения флагов OF, SF, ZF и PF не определены.

DAS –BCD-коррекция после вычитания.

Если эта команда выполняется сразу после SUB (SBB или DEC) и в регистре AL находится разность двух упакованных двоично-десятичных чисел, то в результате в AL записывается упакованное двоично-десятичное число, которое должно было быть результатом вычитания. Например, если AL содержит число 20h, последовательность команд

dec al

das

приведет к тому, что в AL окажется 19h (а не 1Fh, как было бы после DEC).

Флаги AF и CF устанавливаются, если в ходе коррекции происходил заем из первой или второй цифры соответственно, SF, ZF и PF устанавливаются в соответствии с результатом, флаг OF не определен.

AAD -ASCII-коррекция перед делением.

Выполняет коррекцию неупакованного двоично-десятичного числа, находящегося в регистре АХ, так, чтобы последующее деление привело к корректному десятичному результату. Например, разделим десятичное 25 на 5:

mov ax,0205h ; 25 в неупакованном формате

mov bl,5

aad ; теперь в АХ находится 19h

div bl ; АХ = 0005

Флаги SF, ZF и PF устанавливаются в соответствии с результатом, OF, AF и CF не определены.

AAM –ASCII-коррекция после умножения.

Корректирует результат умножения неупакованных двоично-десятичных чисел, находящийся в АХ после выполнения команды MUL, преобразовывая полученный результат в пару неупакованных двоично-десятичных чисел (в АН и AL). Например:

mov al,5

mov bl,5 ; умножить 5 на 5

mul bl ; результат в АХ - 0019h

aam ; теперь АХ содержит 0205h

ААМ устанавливает флаги SF, ZF и PF в соответствии с результатом и оставляет OF, AF и CF неопределенными.


16.

Команды переходов.Условный (Jcc) и безусловный (JMP) переход.Ограничения на дальность перехода.Короткий, близкий и дальний переход.

JMP операнд – Безусловный переход.

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

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

>переход типа short (короткий переход) — если адрес перехода находится в пределах от -127 до +128 байт от команды JMP;

>переход типа near (ближний переход) — если адрес перехода находится в том же сегменте памяти, что и команда JMP;

>переход типа far (дальний переход) — если адрес перехода находится в другом сегменте. Дальний переход может выполняться и в тот же самый сегмент, если в сегментной части операнда указано число, совпадающее с текущим значением CS;

>переход с переключением задачи — передача управления другой задаче в многозадачной среде. Этот вариант будет рассмотрен в главе, посвященной защищенному режиму.

При выполнении переходов типа short и near команда JMP фактически изменяет значение регистра IP, изменяя тем самым смещение следующей исполняемой команды относительно начала сегмента кода. Если операнд — регистр или переменная в памяти, то его значение просто копируется в IP, как если бы это была команда MOV. Если операнд для JMP — непосредственно указанное число, то его значение суммируется с содержимым IP, приводя к относительному переходу. В ассемблерных программах в качестве операнда обычно указывают имена меток, но на уровне исполнимого кода ассемблер вычисляет и записывает именно относительные смещения.

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

Jcc метка – Условный переход.

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

Команды Jcc не поддерживают дальних переходов, так что, если требуется выполнить условный переход на дальнюю метку, необходимо использовать команду из набора Jcc с обратным условием и дальний JMP, как, например:

cmp ах,0 jne local_1 jmp far_label ; переход, если АХ = 0lосаl_1:Косвенный переход.Косвенный ближний (внутрисегментный) переход. В отличие от команд прямых переходов, команды косвенных переходов могут использовать различные способы адресации и, соответственно, иметь много разных вариантов. Общим для них яштястся то, что адрес перехода не указывается явным образом в виде метки, а содержится либо в ячейке памяти, либо в одном из регистров. Это позволяет при необходимости модифицировать адрес перехода, а также осуществлять переход по известному абсолютному адресу. Рассмотрим случай, когда адрес перехода хранится в ячейке сегмента данных. Если переход ближний, то ячейка с адресом состоит из одного слова и содержит только смещение к точке перехода. code segment … jmp DS:go_addr ;Код FF 26 dddd … go: ; Точка перехода … code ends data segment … go_addr dw go ;Адрес перехода (слово) … data ends Косвенный дальний (межсегментный) переход. Как и в случае ближнего перехода, переход осуществляется по адресу, который содержится в ячейке памяти, однако эта ячейка имеет размер 2 слова, и в ней содержится полный (сегмент плюс смещение) адрес точки перехода. Программа в этом случае должна включать по меньшей мере два сегмента команд. Структура программы с использованием косвенного дальнего перехода может выглядеть следующим образом: codel segment assume CS:codel,DS:data … jmp DS:go_addr ; Код FF 2E dddd … codel ends code2 segment assume CS:code2 … go: ;Точка перехода в другом сегменте команд … code2 ends data segment … go_addr dd go ;Двухсловный адрес точки перехода … data ends Директива LOCALS для локализации меток.Метки считаются глобальными. Но обычно, на языках высокого уровня, мы ожидаем, что они будут местными. TASM позволяет нам использовать "@@" приставку к названиям меток, если мы сначала используем директиву LOCALS. Это должно находиться наверху программы, около MODEL и STACK директивы. Тогда, если мы определяем метки в пределах процедуры, они являются местными к этой процедуре, и они могут использоваться в другом месте без конфликта.
17.Команда организации циклов (LOOP). Алгоритм работы. LOOP метка – ЦиклУменьшает регистр СХ на 1 и выполняет переход типа short на метку (которая не может быть дальше, чем на расстоянии от -128 до +127 байт от команды LOOP), если СХ не равен нулю. Эта команда используется для организации циклов, в которых регистр СХ играет роль счетчика. Так, в следующем фрагменте команда ADD выполнится 10 раз:

mov cx,0Ah

loop_start: add ax,cx

loop loop_start

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

dec ecx

jz метка

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

Команды организации циклов с условием (LOOPE/LOOPZ и LOOPNE/LOOPNZ).LOOPE метка - Цикл, пока равноLOOPZ метка - Цикл, пока нольLOOPNE метка - Цикл, пока не равноLOOPNZ метка - Цикл, пока не нольВсе эти команды уменьшают регистр СХ на один, после чего выполняют переход типа short, если СХ не равен нулю и если выполняется условие. Для команд LOOPE и LOOPZ условием является равенство единице флага ZF, для команд LOOPNE и LOOPNZ — равенство флага ZF нулю. Сами команды LOOPcc не изменяют значений флагов, так что ZF должен быть установлен (или сброшен) предшествующей командой. Например, следующий фрагмент копирует строку из DS:SI в строку в ES:DI (см. описание команд работы со строками), пока не кончится строка (СХ = 0) или пока не встретится символ с ASCII-кодом 13 (конец строки): mov cx,str_lengthmove_loop: stosb lodsb cmp al,13 loopnz move_loopКоманда JCXZ.JCXZ метка - Переход, если СХ = 0Выполняет ближний переход на указанную метку, если регистр CX равен нулю. Команды не может выполнять дальних переходов. Проверка равенства СХ нулю, например, может потребоваться в начале цикла, организованного командой LOOPNE, — если в него войти с СХ = 0, то он будет выполнен 65 535 раз.
18.

Команды вызова (CALL) процедур и возврата (RET) из них. Алгоритм их работы.

CALL операнд - Вызов процедуры.

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

RET число - Возврат из процедуры.

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

Определение процедур в ассемблере (директивы PROC и ENDP).

Процедурой в ассемблере является все то, что в других языках называют подпрограммами, функциями, процедурами и т.д. Ассемблер не накладывает на процедуры никаких ограничений — на любой адрес программы можно передать управление командой CALL, и оно вернется к вызвавшей процедуре, как только встретится команда RET. Такая свобода выражения легко может приводить к трудночитаемым программам, и в язык ассемблера были включены директивы логического оформления процедур.