Партнерка на США и Канаду по недвижимости, выплаты в крипто
- 30% recurring commission
- Выплаты в USDT
- Вывод каждую неделю
- Комиссия до 5 лет за каждого referral
Организация циклов.
Иногда надо организовать цикл, т. е. совершить повторение количество раз, которое указано в регистре ECX. Следовательно, надо у теле цикла уменьшать значение ECX. Именно для этого предназначена команда loop. Он проверяет, равен ли регистр ECX нулю, если он не равен нулю, то значение регистра ECX уменьшается на 1 и совершается ближний прыжок на смещение указанное в операнде.
Mov ecx, 023h
repeat:
::..; обязательно ближнее расстояние
Loop repeat
Тело цикла выполнится 23h раза.
Команда loope делает то же самое, но перед прыжком проверяет, установлен ли флаг ZF, если он установлен, то прыжок совершается. Точно тоже самое делает команда loopz. Команды loopne и loopnz делают то же сомое что и loope, но прыгают, если флаг ZF сброшен.
С переходами разобрались. Разобрались не только с переходами, но и с циклами.
Урок 8
Арифметические операции - ADD, SUB, MUL, DIV. Многие опкоды делают вычисления. Вы можете узнать многие из них по их названиям: add (addition - добавление), sub (substraction - вычитание), mul (multiply - умножение), div (divide - деление).
Опкод add имеет следующий синтаксис:
add приемник, источник
Выполняет вычисление : приемник = приемник + источник.
Имеются также другие формы:
приемник | источник | пример |
регистр | регистр | add ecx, edx |
регистр | память | add ecx, dword ptr [104h] / add ecx, [edx] |
регистр | значение | add eax, 102 |
память | значение | add dword ptr [401231h], 80 |
память | регистр | add dword ptr [401231h], edx |
Эта команда очень проста. Она добавляет значение источника к значение приемника и помещает результат в приемник. Другие математические команды:
sub приемник, источник (приемник = приемник - источник)
mul множимое, множитель (множимое = множимое * множитель)
div делитель (eax = eax / делитель, edx = остаток)
Поскольку регистры могут содержать только целочисленные значения (то есть числа, не, с плавающей запятой), результат деления разбит на частное и остаток. Теперь, в зависимости от размера источника, частное сохраняется в eax, а остаток в edx:
размер источника | деление | частное в... | остаток в... |
BYTE (8-bits) | ax / делитель | AL | AH |
WORD (16-bits) | dx:ax* / делитель | AX | DX |
DWORD (32-bits) | edx:eax* / делитель | EAX | EDX |
* = Например: если dx = 2030h, а ax = 0040h, dx: ax = h. Dx:ax - значение dword, где dx представляет старшее word, а ax - младшее. Edx:eax - значение quadword (64 бита), где старшее dword в edx и младшее в eax.
Источник операции деления может быть:
8-бит регистр (al, ah, cl,.бит регистр (ax, dx, .бит регистр (eax, edx, ecx...) 8-бит значение из памяти (byte ptr [xxxx]) 16-бит значение из памяти (word ptr [xxxx]) a 32-бит значение памяти (dword ptr [xxxx])Источник не может быть непосредственным значением, потому что тогда процессор не сможет определить размер исходного операнда.
Логические операции с битами - OR, XOR, AND, NOT. Эти команды работают с приемником и источником, исключение команда 'NOT'. Каждый бит в приемнике сравнивается с тем же самым битом в источнике, и в зависимости от команды, 0 или 1 помещается в бит приемника:
команда | AND | OR | XOR | NOT | ||||||||||
Бит источника | 0 | 0 | 1 | 1 | 0 | 0 | 1 | 1 | 0 | 0 | 1 | 1 | 0 | 1 |
Бит приемника | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | X | X |
Бит результата | 0 | 0 | 0 | 1 | 0 | 1 | 1 | 1 | 0 | 1 | 1 | 0 | 1 | 0 |
AND (логическое И) устанавливает бит результата в 1, если оба бита, бит источника и бит приемника установлены в 1.
OR (логическое ИЛИ) устанавливает бит результата в 1, если один из битов, бит источника или бит приемника установлен в 1.
XOR (НЕ ИЛИ) устанавливает бит результата в 1, если бит источника отличается от бита приемника.
NOT инвертирует бит источника.
Пример:
mov ax, 3406d
mov dx, 13EAh
xor ax, dx
ax = 3406 (десятичное), в двоичном - .
dx = 13EA (шестнадцатиричное), в двоичном - .
Выполнение операции XOR на этими битами:
Источник = (dx)
Приемник = (ax)
Результат = (новое значение в ax)
Новое значение в ax, после выполнения команды - в десятичном, 1EA5 - в шестнадцатиричном).
Другой пример:
mov ecx, FFFF0000h
not ecx
FFFF0000 в двоичном это -
Если вы выполните инверсию каждого бита, то получите:
, в шестнадцатиричном это 0000FFFF
Значит после операции NOT, ecx будет содержать 0000FFFFh.
Увеличение/Уменьшение - INC/DEC. Есть 2 очень простые команды, DEC и INC. Эти команды увеличивают или уменьшают содержимое памяти или регистра на единицу.
Просто поместите:
inc регистр ; регистр = регистр + 1
dec регистр ; регистр = регистр - 1
inc dword ptr [103405] ; значение в [103405] будет увеличено на 1.
dec dword ptr [103405] ; значение в [103405] будет уменьшено на 1.
Ещё одна команда сравнения - test. Команда Test выполняет операцию AND (логическое И) с двумя операндами и в зависимости от результата устанавливает или сбрасывает соответствующие флаги. Результат не сохраняется. Test используется для проверки бит, например в регистре:
test eax, 100b
jnz смещение
Команда jnz выполнит переход, если в регистре eax третий бит справа - установлен. Очень часто комманду test используют для проверки, равен ли регистр нулю:
test ecx, ecx
jz смещение
Команда jz выполнит переход, если ecx = 0.
Ничего не делающая команда - nop. Эта команда не делает абсолютно ничего (пустая команда). Она только занимает пространство и время. Используется для резервирования места в сегменте кода или организации программной задержки.
Обмен значениями - XCHG. Команда XCHG также весьма проста. Назначение: обмен двух значений между регистрами или между регистрами и памятью:
mov eax, 237h
mov ecx, 978h
xchg eax, ecx
в результате:
eax = 978h
ecx = 237h
Урок 9
На этом уроке я вам расскажу про подпрограммы и структуры. Подпрограмма по-простому это процедура (или функция: без разницы, язык Pascal дал этим терминам разные определения), а структура это запись.
Подпрограммы.
Подпрограммы удобны, когда некоторое действие повторяется несколько раз в программе. Процедуры делают программу более читабельной и надёжнее, в такой программе легче устранять ошибки и улучшать.
Процедуры задаются директивами proc и endp. Proc обозначает начало процедуры, а endp конец процедуры. Вот пример объявления процедуры:
SameProc proc
...more code...
Ret ; обязательно
SameProc endp
Вызов процедуры
...
Call SameProc
...
Если вызывающий использует, какие либо регистры и подпрограмме нельзя изменять их то для этого эти регистры надо сохранять в стеке.
SameProc proc
Push ebx
Push edi
...more code...
Mov esi, edx
:изменяем сохранённые регистры:.
Pop edi
Pop ebx
Ret
SameProc endp
Специально для этого создана директива uses.
SameProc proc uses ebx, esi
...more code...
Mov esi, edx
...изменяем сохранённые регистры...
Ret ; обязательно
SameProc endp
И всё теперь вместо всяких "пушев" и "попов" ставите ret, TASM сделает всё за вас: в начале поставит "пуши" вместо ret поставит "попы" (извините за выражение) и ret.
Имя процедуры становится обычной меткой. Можно получать значение, на которое она указывает (обычно это значение равно опкоду первой инструкции процедуры), но изменить его получится, поскольку секция кода доступна только для чтения.
Структуры.
Структура это набор переменных (данных). Структура задаётся с помощью директивы struct и ends.
SOMESTRUCTURE STRUCT
dword1 dd?
dword2 dd?
some_word dw?
abyte db?
anotherbyte db?
SOMESTRUCTURE ENDS
(имя структуры не должно содержать прописных букв).
Вы также можете объявить ваши переменные как в секции с инициализированными данными, так и в секции с неинициализированными данными, со знаком вопроса.
MYSTRUCT struc
dword1 dd?
dword2 dd?
some_word dw?
abyte db?
anotherbyte db?
MYSTRUCT ends
.data
msg MYSTRUCT <?>
или
MYSTRUCT struc
dword1 dd?
dword2 dd?
some_word dw?
abyte db?
anotherbyte db?
MYSTRUCT ends
.data?
msg MYSTRUCT <?>
одинаковый результат, но во втором случае размер файла будет меньше.
Для того чтобы получить доступ к записи надо указать метку переменной, которой она обозначена и через точку указать имя поля.
mov [msg. dword1], 45h
xor eax, eax
mov eax, [msg. dword1] ; eax = 45
при этом запись msg. dword1 считается обычной меткой данных: берётся смещение метки msg плюс смещение поля dword1 в структуре, размер данных по умолчанию равен размеру директивы указанной после метки поля. Также можно пользоваться обращением к полю при обращении к записи через регистр:
mov [msg. dword2], 45h
xor eax, eax
lea ebx, msg
mov eax, [ebx].dword2 ; eax = 45
в данном случае к смещению, которое указано в ebx прибавляется смещение dword2 в своей структуре. Так как имя поля не гарантирует уникальности то лучше использовать такой тип использования записи так:
mov [msg. dword2], 45h
xor eax, eax
lea ebx, msg
mov eax, [ebx].MYSTRUCT. dword2 ; eax = 45
это безопаснее. Для того, что бы окончательно разобраться с записями приведу ещё один пример, в котором используется доступ к полю записи в лоб:
mov [msg. abyte], 45h
xor eax, eax
lea ebx, msg
mov al, [ebx+10d] ; al = 45
к ebx я прибавил 10d, потому что смещение поля abyte в структуре равно 10d.
Урок 10
Главной альтернативой секции .const является простое объявление символьной константы. Всё гениальное просто (слишком сильно сказано):
CONST_VALUE = 678h
.data
Dd CONST_VALUE
.code
...more code...
Mov edi, CONST_VALUE
Xor eax, CONST_VALUE
Вторая не менее важная альтернатива это определение "макросимвола" (я это сам придумал, а по научному абсолютный символ или "прозвище"). Он задаётся через директиву equ.
примеры
CONST1 equ 0123h
CONST2 equ 14d*15h
CONST3 equ "slovo"
CONST4 equ 56-45
CONST5 equ (offset metka1)
CONST6 equ (offset metka2+offset metka3)
CONST7 equ (CONST2+10b)
CONST8 equ CONST7/2
CONST9 equ (offset metka1-offse metka5)
CONST10 equ (offset metka4+CONST4)
CONST11 equ add edx, edi
... и так далее до посинения...
Директива equ используется в там же, где определяются символьные константы. Это ещё не все возможности этой директивы. О ней можно говорить очень много. Я вам объяснил, как надо объявлять численные константы, но также можно дать прозвище некоторой команде, например:
Command1 equ mov eax, esi.
После этого при каждом упоминании command1 будет подразумеваться команда move eax, esi.
Пример
Mov eax, CONST1
Add edi, CONST2
Xor ebp, CONST7
CONST11
Sub edx, CONST8
Объявлять equ надо в начале файла там же где объявляются структуры и константы.
Макрос - это набор команд. С помощью equ мы могли создавать "прозвище" только для одной команды, а с помощью макросов можно создавать "прозвище" для нескольких команд. Для создания макроса надо использовать директивы macro и соответственно endm.
Firstmacro macro
Sub ebp, esp
Mov eax, ebp
Endm
Теперь если компилятор встречает слово Firstmacro, то он автоматически заменяет его на тело макроса. Также макросу можно передавать параметры.
Secondmacro macro param1, param2
Add edi, param1
Sub esi, param2
endm
.code ; использование
..........
Secondmacro 55h, edx
У макросов очень много возможностей. Я объяснил самые важные из них, а на объяснение всех возможностей этого урока не хватит. Макросы очень часто используются в MASM.
Иногда надоедает (особенно при создании оконных приложений) объявлять в каждой программе одни и те же структуры и константы. Хотелось бы один раз их задать, а потом их использовать в каждой своей программе как в Си или Паскале. Для этого предназначены включаемые файлы *.inc. В них можно задать структуры, константы, макросы. Для включения такого файла надо использовать директиву include. После этой директивы надо указать путь к включаемому файлу абсолютный или относительный. При написании такого файла просто думайте, что вы находитесь после директивы. model и до. data.
Пример:
Файл sample. asm
;=======[CUT HERE]========
.386
.model flat, stdcall
include sample. inc
extrn MessageBoxA:PROC
.data
Msg db "First ASSEMBLER program",0h
Ttl db 'Hello, World!!!!',0h
RCTNGL RECT?
.code
start:
call MessageBoxA,0,offset Msg, offset Ttl, MB_OKCANCEL
call ExitProcess, 0
end start
;=====[CUT HERE]==========
Файл sample. inc
;=======[CUT HERE]========
extrn ExitProcess:PROC
UINT EQU <dd> ; 32 bits for WIN32
|
Из за большого объема этот материал размещен на нескольких страницах:
1 2 3 4 5 |


