Ассемблер Часть 1
Как создать проект с ASM-кодом
Структура программы на ассемблере
Структура программы на ассемблере
Основные типы данных
Задание числовых переменных
Задание символьных строк
Задание массивов
Структура команды
Операнды
Операнды в оперативной памяти
Ограничения на операнды
Основные флаги регистра EFLAGS
Команды пересылки
Команды работы со стеком
Арифметические команды
Арифметические команды
Арифметические команды
Логические команды
Сдвиговые команды
Сдвиговые команды
Команды преобразования типов
Команды установки единичного бита
Команды управления флагами
Оператор переопределения типа
Оператор получения сегмента и смещения
Операторы определения длины
Консольный ввод/вывод
Консольный ввод/вывод
Встроенный (inline) ассемблер
471.00K
Category: programmingprogramming

Ассемблер

1. Ассемблер Часть 1

Смирнов Александр Валерьевич
Кафедра теоретической информатики

2. Как создать проект с ASM-кодом

1. Создаём консольное приложение Win32.
2. Заходим в «Настройки построения» проекта и ставим флажок
«masm (.targets, .props)».
3. Заходим в «Свойства» проекта и в поле «Свойства
конфигурации > Компоновщик > Включить инкрементную
компоновку» ставим «Нет».
4. Добавляем необходимые файлы исходного кода в проект.
Файлам, полностью написанным на ассемблере,
устанавливаем расширение .asm.
5. Заходим в «Свойства» всех файлов с расширением .asm и
устанавливаем тип элемента «Microsoft Macro Assembler».

3. Структура программы на ассемблере

Пример:
Общий синтаксис:
<набор команд ЦП>
.MODEL <модель памяти>
.STACK <сегмент стека>
.DATA
<сегмент данных>
.CODE
<метка процедуры>:
<команды>
RET
END <метка процедуры>
.686P
.MODEL FLAT, C
.STACK 4096
.DATA
a DW 5
.CODE
MAIN:
MOV AX, a
INC AX
PUSH AX
SUB AX, 2
MOV a, AX
POP AX
ADD AX, a
MOV a, AX
RET
END MAIN

4. Структура программы на ассемблере

.686P ; 686 — набор команд P6 (Pentium II), P — защищённый режим
.MODEL FLAT, C
; плоская модель памяти, вызов как в языке C
.STACK 4096
; устанавливаем размер стека
.DATA
; начало сегмента данных
a DW 5
; переменная a типа «слово», a = 5
.CODE
; начало сегмента кода
MAIN:
; начало основной процедуры
MOV AX, a
; переместить значение a в регистр AX
INC AX
; увеличить AX на 1
PUSH AX
; положить AX в стек
SUB AX, 2
; вычесть из AX 2
MOV a, AX
; переместить значение из AX в a
POP AX
; извлечь в AX значение из стека
ADD AX, a
; сложить AX и a
MOV a, AX
; переместить значение из AX в a
RET
; выйти из процедуры
END MAIN
; конец процедуры MAIN

5. Основные типы данных

Форматы:
• DB — байт;
• DW — слово;
• DD — двойное слово;
• DQ — учетверённое слово;
• DT — 10 байт.
Целые числа: DB, DW, DD, DQ.
Числа с плавающей точкой: DD, DQ, DT.
Символьные строки: DB.

6. Задание числовых переменных

Переменные определяются в сегменте данных.
Синтаксис:
<идентификатор> <тип данных> <значение> ; комментарий
Модификатор d (или отсутствие модификатора) задаёт
десятичное число, h — шестнадцатеричное, b — двоичное,
q — восьмеричное:
a DB 14
a DB 0Eh
a DB 00001110b
a DB 16q
Неопределённое значение обозначается с помощью
вопросительного знака:
a DB ?

7. Задание символьных строк

Символьные строки задаются в одинарных или двойных
кавычках, либо в виде кодов символов, перечисленных через
запятую.
13 — возврат строки, 10 — перевод каретки, 0 — конец строки.
Синтаксис:
<идентификатор> DB <строка> ; комментарий
Примеры:
STR1 DB 'Первая строка', 0
STR2 DB "Вторая строка", 13, 10, 0

8. Задание массивов

Синтаксис:
<идентификатор> <тип данных> <значения> ; комментарий
<идентификатор> <тип данных> <размер> DUP(<значение>)
Примеры:
ARR1 DB 0,1,2,3,4,5,6,7,8,9
ARR2 DB 0,1,2,3
DB 4,5,6,7
DB 8,9
ARR3 DB 200 DUP (0)
ARR4 DB 200 DUP (?)
ARR5 DB 10 DUP(20 DUP (?))
N EQU 10
ARR6 DW N DUP(?)
В последнем примере с помощью команды EQU мы определили
константу.

9. Структура команды

<метка>: <команда> <операнд(ы)> ; комментарий
Обязательной частью является только сама команда.
Задаётся 0, 1 или 2 операнда.

10. Операнды

Операнд, заданный на микропрограммном уровне, в команде не
указывается; он подставляется неявно:
MUL EBX ; EAX = EAX * EBX
Непосредственный операнд (константа) в команде может стоять
только на втором месте:
ADD EAX, 320
Регистровый операнд задаётся именем регистра:
• 32-разрядные регистры: ЕАХ, ЕВХ, ЕСХ, EDX, ESI, EDI, ESP, EBP;
• 16-разрядные регистры: АХ, ВХ, СХ, DX, SI, DI, SP, ВР;
• 8-разрядные регистры: АН, AL, BH, BL, CH, CL, DH, DL;
• сегментные регистры: CS, DS, SS, ES, FS, GS.

11. Операнды в оперативной памяти

Прямая адресация — по имени операнда:
ADD EAX, var1
Косвенная базовая адресация — адрес находится в одном из РОН,
кроме ESP и EBP, тогда обращение происходит по типу [<регистр>]:
ADD EAX, [EBX]
Косвенная базовая адресация со смещением — [<регистр> + <число>]:
ADD EAX, [EBX + 4]
Косвенная индексная адресация — <имя>[<индекс>*<масштаб>]:
ADD EAX, arr[ESI]
ADD EAX, arr[ESI * 4]
Косвенная базовая индексная адресация — [<регистр>][<индекс>]:
ADD EAX, [EBX][ESI]

12. Ограничения на операнды

1. Нельзя в одной команде оперировать двумя областями памяти
одновременно.
2. Нельзя оперировать сегментным регистром и значением
непосредственно из памяти.
3. Нельзя оперировать двумя сегментными регистрами.
4. Нельзя использовать сегментный регистр CS в качестве операндаприёмника.
5. Операнды команды, если это не оговаривается дополнительно в
описании команды, должны быть одного размера.
В случае необходимости выполнить действие из пп. 1-3 следует
использовать свободный регистр общего назначения или стек
в качестве промежуточного буфера.

13. Основные флаги регистра EFLAGS

CF — бит переноса. Этот флаг показывает состояние переполнения
для беззнаковых целочисленных арифметических действий.
PF — бит чётности: устанавливается в 1, если результат последней
операции имеет чётное число единиц.
AF — бит вспомогательного переноса: устанавливается в 1, если
арифметическая операция генерирует перенос из младшей тетрады
битов (из 3 бита в 4), сбрасывается в 0 в противном случае. Этот флаг
используется в двоично-десятичной арифметике.
ZF — бит нулевого значения: устанавливается в 1, если результат
нулевой, сбрасывается в 0 в противном случае.
SF — знаковый бит: устанавливается равным старшему биту
результата, который определяет знак в знаковых целочисленных
операциях (0 – положительное число, 1 – отрицательное число).
OF — бит переполнения: устанавливается в 1, если целочисленный
результат выходит за пределы разрядной сетки.

14. Команды пересылки

Пересылка операндов:
MOV dest, src
Обмен операндов:
XCHG op1, op2
Загрузка эффективного адреса в указанный регистр:
LEA reg, mem
Загрузка в сегментный регистр и указанный РОН сегмента и
эффективного адреса элемента:
LDS reg, mem
LSS reg, mem
LES reg, mem
LFS reg, mem
LGS reg, mem

15. Команды работы со стеком

Поместить операнд в вершину стека:
PUSH src
Извлечь значение из вершины стека, поместить в операнд:
POP dest
Поместить в стек регистры EAX, EBX, ECX, EDX, ESI, EDI, EBP, ESP:
PUSHA
Извлечь из стека регистры EAX, EBX, ECX, EDX, ESI, EDI, EBP, ESP:
POPA
Поместить в стек регистр EFLAGS:
PUSHF
Извлечь из стека регистр EFLAGS:
POPF

16. Арифметические команды

Сложение двух операндов:
ADD dest, src
Сложение двух операндов и регистра CF:
ADC dest, src
Вычитание из первого операнда второго:
SUB dest, src
Вычитание из первого операнда второго и регистра CF:
SBB dest, src
Увеличение/ уменьшение на 1:
INC dest
DEC dest
Смена знака числа:
NEG dest

17. Арифметические команды

Беззнаковое умножение:
MUL src
Первый операнд задан неявно — это регистр AL, AX или EAX.
Результат помещается в AH:AL, DX:AX или EDX:EAX соответственно.
Знаковое умножение:
IMUL src
IMUL dest, src
Первый вариант работает так же, как в беззнаковом случае.
Во втором варианте результат помещается в первый операнд.
Последний операнд может быть непосредственным 8-битным
операндом.

18. Арифметические команды

Беззнаковое деление:
DIV src
Первый операнд задан неявно — это регистры AH:AL, DX:AX или
EDX:EAX.
Частное помещается в AL, AX или EAX соответственно.
Остаток помещается в AH, DX или EDX соответственно.
Знаковое деление:
IDIV src
Сравнение целых чисел:
CMP op1, op2
Вычитает второй операнд из первого и не сохраняет результат, а
устанавливает биты OF, SF, ZF, AF, PF, CF регистра признаков EFLAGS
в соответствии с результатом.
Обычно предшествует команде условного перехода.

19. Логические команды

Побитовая конъюнкция:
AND dest, src
Побитовая дизъюнкция:
OR dest, src
Побитовая инверсия:
NOT dest
Побитовое сложение по модулю 2:
XOR dest, src

20. Сдвиговые команды

Логический сдвиг вправо (заполнение нулями):
SHR dest, steps
SHR dest
Арифметический сдвиг вправо (деление на 2steps):
SAR dest, steps
SAR dest
Логический сдвиг влево (заполнение нулями):
SHL dest, steps
SHL dest
Арифметический сдвиг влево (умножение на 2steps):
SAL dest, steps
SAL dest
Если параметр один, steps = 1 неявно.
В качестве второго параметра указывается константа или регистр CL.

21. Сдвиговые команды

Циклический сдвиг вправо:
ROR dest, steps
ROR dest
Циклический сдвиг вправо через перенос:
RCR dest, steps
RCR dest
Циклический сдвиг влево:
ROL dest, steps
ROL dest
Циклический сдвиг влево через перенос:
RCL dest, steps
RCL dest
Если параметр один, steps = 1 неявно.
В качестве второго параметра указывается константа или регистр CL.

22. Команды преобразования типов

Команды расширяют данные, хранящиеся в AL, AX или EAX.
Расширение AL до AX:
CBW
Расширение AX до EAX:
CWDE
Расширение AX до DX:AX:
CWD
Расширение EAX до EDX:EAX:
CDQ

23. Команды установки единичного бита

Операнд — 8-битный регистр или переменная; проверяется условие
на флаги, если оно выполнено, младший бит устанавливается в 1,
иначе — в 0.
Общий синтаксис (вместо <f> подставляется нужная комбинация):
SET<f> dest
Оператор
SETA, SETNBE
Условие
Оператор
Условие
CF = 0 & ZF = 0
SETLE, SETNG
SF != OF | ZF = 1
CF = 0
SETNE, SETNZ
ZF = 0
CF = 1
SETNO
OF = 0
SETBE, SETNA
CF = 1 | ZF = 1
SETNP, SETPO
PF = 0
SETE, SETZ
ZF = 1
SETNS
SF = 0
SETG, SETNLE
ZF = 0 & SF = OF
SETO
OF = 1
SETGE, SETNL
SF = OF
SETP, SETPE
PF = 1
SETL, SETNGE
SF != OF
SETS
SF = 1
SETAE, SETNB,
SETNC
SETB, SETC,
SETNAE

24. Команды управления флагами

Сброс флага CF (CF = 0):
CLC
Установка флага CF (CF = 1):
CMC
Инверсия флага CF (CF = ¬CF):
STC

25. Оператор переопределения типа

Оператор переопределения типа PTR применяется для
переопределения или уточнения типа метки или переменной,
определяемых выражением.
<тип> PTR <выражение>
Типы:
• BYTE — 1 байт;
• WORD — 2 байта;
• DWORD — 4 байта;
• QWORD — 8 байт;
• TWORD — 10 байт;
• NEAR — ближний указатель на функцию;
• FAR — дальний указатель на функцию
Примеры:
MOV AX, WORD PTR a
MOV BYTE PTR [esi], 18

26. Оператор получения сегмента и смещения

Оператор получения сегментной составляющей адреса выражения
SEG возвращает физический адрес сегмента для выражения, в
качестве которого могут выступать метка, переменная, имя сегмента,
имя группы или некоторое символическое имя.
Оператор получения смещения выражения OFFSET позволяет
получить значение смещения выражения в байтах относительно
начала того сегмента, в котором выражение определено.
Пример:
MOV
MOV
ADD
ADD
ESI, OFFSET arr1
EAX, [ESI]
EAX, [ESI + 4]
EAX, 8[ESI]

27. Операторы определения длины

Оператор определения длины массива LENGTH возвращает число
элементов, определённых операндом DUP. Если операнд DUP
отсутствует, то оператор LENGTH возвращает значение 1.
Оператор TYPE возвращает число байтов, соответствующее
определению указанной переменной.
Оператор SIZE возвращает произведение длины LENGTH и типа TYPE
и используется при ссылках на переменную с операндом DUP.
Пример:
MOV EAX, SIZE arr1

28. Консольный ввод/вывод

Консольный вывод в DOS:
.DATA
STR1 DB "Console Output",0
.CODE
MAIN:
LEA DX, STR1
MOV AH, 9
INT 21h
END MAIN

29. Консольный ввод/вывод

Консольный вывод в Windows:
.686P
;плоская модель памяти
.MODEL FLAT, stdcall
;константы
STD_OUTPUT_HANDLE equ -11
;прототипы внешних процедур
EXTERN GetStdHandle@4:NEAR
EXTERN WriteConsoleA@20:NEAR
EXTERN ExitProcess@4:NEAR
;директивы компоновщику для подключения библиотек
includelib c:\masm32\lib\user32.lib
includelib c:\masm32\lib\kernel32.lib
;-----------------------------------------------;сегмент данных
_DATA SEGMENT
;строка в OEM-кодировке
STR1 DB "Console Output",0
LENS DD ? ;количество выведенных символов
RES DD ?
_DATA ENDS
;сегмент кода
_TEXT SEGMENT
START:
;получить HANDLE вывода
PUSH STD_OUTPUT_HANDLE
CALL GetStdHandle@4
;длина строки
PUSH OFFSET STR1
CALL LENSTR
;вывести строку
PUSH OFFSET RES ; резерв
PUSH OFFSET LENS ; выведено символов
PUSH EBX ; длина строки
PUSH OFFSET STR1 ; адрес строки
PUSH EAX ; дескриптор вывода
CALL WriteConsoleA@20
PUSH 0
CALL ExitProcess@4
;строка - [EBP+08H]
;длина в EBX
LENSTR PROC
PUSH EBP
MOV EBP,ESP
PUSH EAX
PUSH EDI
;-------------------CLD
MOV EDI,DWORD PTR [EBP+08H]
MOV EBX,EDI
MOV ECX,100 ; ограничить длину строки
XOR AL,AL
REPNE SCASB ; найти символ 0
SUB EDI,EBX ; длина строки, включая 0
MOV EBX,EDI
DEC EBX
;-------------------POP EDI
POP EAX
POP EBP
RET 4
LENSTR ENDP
_TEXT ENDS
END START

30. Встроенный (inline) ассемблер

Определяется директивой __asm в коде на языке C.
Использует данные и стек основной процедуры на языке C.
Однострочная ассемблерная вставка:
__asm <команда> ; комментарий
Многострочная ассемблерная вставка:
__asm
{
<команды>
}
English     Русский Rules