Умножение беззнаковых чисел
MUL OP2; (OP2)*(AL) Ú (AX) Ú (EAX) ® AX Ú DX:AX Ú EDX:EAX.
Содержимое ОР2 умножается на содержимое AL, AX, EAX в зависимости от типа операнда и пересылается в них же соответственно.
Умножение знаковых чисел.
IMUL OP2; аналогично MUL
IMUL OP1, OP2 ;i386 и >
Содержимое первого операнда умножается на содержимое второго и результат записывается в первый операнд.
IMUL op1, op2, op3 ; i186 и >
Содержимое второго умножается на содержимое третьего и результат в первый.
OP1 всегда регистр, OP2 – непосредственный операнд, регистр или память.
При умножении результат имеет удвоенный формат по отношению к сомножителям. Иногда мы точно знаем, что результат может уместиться в формат сомножителей, тогда мы извлекаем его из AL, AX, EAX.
Размер результата можно выяснить с помощью флагов OF и CF.
Если OF = CF = 1, то результат занимает двойной формат, и OF = СF = 0 , результат умещается в формат сомножителей.
Остальные флаги не изменяются.
Деление беззнаковых чисел: Деление знаковых чисел.
DIV OP2; OP2 = r Ú m IDIV OP2; OP2 = r Ú m
(AX) Ú (DX:AX) Ú (EDX:EAX) делится на указанный операнд и результат помещается в AL Ú AX Ú EAX, остаток помещается в AH Ú DX Ú EDX.
Значение флагов не меняется, но может наступить деление на 0 или переполнение, если 1) op2 = 0, 2) частное не умещается в отведенное ему место. Например:
MOV AX, 600
MOV BH, 2
DIV BH; 600 div 2 = 300 - не умещается в AL.
При использовании арифметических операций необходимо следить за размером операндов. При необходимости их нужно расширять.
Пример:
Необходимо цифры целого беззнакового байтового числа N записать в байты памяти, начиная с адреса D как символы. N - (abc)
c = N mod 10
b = (N div 10) mod 10
a = (N div 10) div 10
Перевод в символы: код(i) = код (‘0’) + i
---------------------
N DB ?
D DB 3 Dup (?)
------------------
MOV BL, 10; делитель
MOV AL, N; делимое
MOV AH, 0; расширяем делимое до слова
; или CBW AH конвертируем до слова
DIV BL; A L= ab, AH = c
ADD AH, ‘0’
MOV D+2, AH
MOV AH, 0
DIV BL; AL = a, AH = b
ADD AL, ‘0’
MOV D, AL
ADD AH, ‘0’
MOV D+1, AH
----------------------
7) Основные элементы языка Ассемблера: имена, константы, переменные, выражения.
Алфавит из 26 латинских букв и цифр. Прописные и строчные буквы не различаются.
Символические имена в Ассемблере могут состоять из строчных и прописных букв латинского алфавита, цифр от 0 до 9 и некоторых символов ‘_’, ‘.’, ‘?’, . Могут состоять из произвольного количества символов, но значащими будут считаться только первые 31.
Константы – неизменные в процессе программы величины. Ассемблер может работать с именованными и неименованными. В программе на Ассемблере могут использоваться константы пяти типов: целые двоичные, десятичные, шестнадцатеричные, действительные с плавающей точкой, символьные.
Целые двоичные – это последовательности 0 и 1 со следующим за ними символом ‘b’, например, 10101010b или 11000011b.
Целые десятичные - это обычные десятичные числа, возможно заканчивающиеся буквой d, например, – 125 или 78d.
Целые шестнадцатеричные числа – должны начинаться с цифры и заканчиваются всегда ‘h’, если первый символ – ‘A’, ‘B’, ‘C’, ‘D’, ‘E’, ‘F’, то перед ним необходимо поставить 0, иначе они будут восприниматься как символические имена.
Числа действительные с плавающей точкой представляются в виде мантиссы и порядка, например, – 34.751е+02 – это 3475.1 или 0.547е-2 – это 0.00547.
Символьные данные – это последовательности символов, заключенные в апострофы или двойные кавычки, например,
'abcd', 'a1b2c3', ‘567'.
Также, как и в языках высокого уровня, в Ассемблере могут использоваться именованные константы. Для этого существует специальная директива EQU. Например,
M EQU 27; директива EQU присваивает имени М значение 27.
Переменные в Ассемблере определяются с помощью директив определения данных и памяти, например,
V1 DB ?
V2 DW 34
или с помощью директивы ‘ = ’
v3 = 100
v3 = v3+1
Константы в основном используются в директивах определения или как непосредственные операнды в командах.
Выражения в Ассемблере строятся из операндов, операторов и скобок. Вычисляются слева направо с учетом приоритета операций и скобок. Операнды – это константы или переменные, выражения в скобках. Операторы – это знаки операций (арифметических, логических, отношений и некоторых специальных)
Арифметические операции: ‘+’, ‘-‘, ‘*’, ‘/’, mod.
Логические операции: NOT, AND, OR, XOR (исключ. или).
Операции отношений: LT(<), LE(£), EQ(=), NE(¹), GT(>), GE(³).
Операции сдвига: сдвиг влево (SHL), сдвиг вправо (SHR)
Специальные операции: offset и PTR
offset <имя> - ее значением является смещение операнда, а операндом может быть метка или переменная;
PTR – определяет тип операнда:
BYTE = 1 байт,
WORD = 2 байт,
DWORD = 4 байт,
FWORD = 6 байт,
QWORD = 8 байт,
TWORD = 10 байт;
или тип вызова: NEAR – ближний, FAR – дальний.
Примеры выражений: 1) 10010101b + 37d 2) OP1 LT OP2
3) (OP3 GE OP4) AND (OP5 LT OP6) 4) 27 SHL 3 ;
Выражения чаще всего используются непосредственно в операндах или в директивах определения данных памяти.
Директивы определения
Общий вид директивы определения следующий
[<имя>] DX <операнды> <; комментарии>,
где Х это B, W, D, F, Q или T.
В поле операндов может быть ‘?’, одна или несколько констант, разделенных запятой, определяющие содержимое выделенных ячеек памяти. Знак вопроса говорит о том, что выделенная область ничем не заполняется. Имя, если оно есть, определяет адрес первого байта выделяемой области. Директивой выделяется указанное количество байтов ОП и указанные операнды пересылаются в эти поля памяти. Если операнд – это ‘?’, то в соответствующее поле ничего не заносится.
Пример:
R1 DB 0, 0, 0; выделено 3 поля, заполненных 0.
R1
R1+1
R2 DB ?, ?, ? R2 (дорис) R1+2
R2+1
R2+2
1) Если операндом является символическое имя IM1, которое соответствует смещению в сегменте 03АС1h, то после выполнения
M DD IM1
будет выделено 4 байта памяти. Адрес – М. Значение - 03АС1h.
2) Если необходимо выделить 100 байтов памяти и заполнить 1, то это можно сделать с помощью специального повторителя DUP.
D DB 100 DUP (1)
3) Определение одномерного массива слов, адрес первого
элемента массива – имя MAS,значение его 1.
MAS DW 1, 7, 35, 75, 84
4) Определение двумерного массива:
Arr DB 7, 94, 11, -5
DB 5, 0, 1, 2
DB -5, 0, 15, 24
5)Const EQU 100
D DB Const DUP (?); выделить 100 байтов памяти. В директиве определения байта (слова) максимально допустимая константа – 255 (65535).
С помощью директивы определения байта можно определить символьную константу длинной 255 символов, а с помощью определения слова можно определить символьную константу, которая может содержать не более двух символов.
23) Команды безусловной передачи управления, обращения к подпрограмме и возврата из программы.
Команды управления позволяют изменить ход вычислительного процесса.
К ним относятся команды безусловной передачи управления, команды условной передачи управления, команды организации циклов.
Команды безусловной передачи управления имеют вид
JMP <имя>,
где имя определяет метку команды, которая будет выполняться следующей за этой командой. Эта команда может располагаться в том же кодовом сегменте, что и команда JMP или в другом сегменте.
JMP M1; по умолчанию М1 имеет тип NEAR
Если метка содержится в другом сегменте, то в том сегменте, в который передается управление, должно быть Public M1, а из которого –
EXTRN M1: FAR.
Кроме того, передачу можно осуществлять с использованием прямой адресации (JMP M1) или с использованием косвенной адресации (JMP [BX]).
Команда, осуществляющая близкую передачу, занимает 3 байта, а дальняя – 5 байтов. А если передача осуществляется не далее как на -128 или 127 байтов, то можно использовать команду безусловной передачи данных, занимающую 1 байт.
ADD AX, BX
JMP Short M1
M2: ------/-------
M1: MOV AX, CX
----------/-----------
К командам безусловной передачи данных относятся команды обращения к подпрограммам, процедурам, и возврат из них. После безусловной передачи следующая команда должна иметь метку.
Процедура обязательно имеет тип дальности и по умолчанию тип NEAR, а FAR необходимо указывать.
PP Proc FAR
------/-------
PP endp
Процедура типа NEAR может быть вызвана только из того кодового сегмента, в котором содержится ее описание. Процедура типа FAR может быть вызвана из любого сегмента. Поэтому тип вызова функции (дальность) определяется следующим образом: главная программа всегда имеет тип FAR, т.к. обращаются к ней из ОС или отладчика, если процедур несколько и они содержатся в одном кодовом сегменте, то все остальные, кроме главной, имеют тип NEAR. Если процедура описана в кодовом сегменте с другим именем, то у нее должен быть тип FAR.
1) Cseg segment….
assume …..
p1 proc far
-------------------------
call p2
m: mov AX, BX
--------------------------
ret
p1 endp
p2 proc near
m1: mov CX, DX
---------------------------
ret
p2 endp
Cseg ends