PS
Решил поделиться своими заметками по разным тематикам. Сразу предупреждаю, что они могут быть малого объёма и не раскрывать тему полностью (какие-то базовые/начальные вещи). Я писал их для себя, чтобы быстрее въехать в какой-либо материал, либо когда понадобиться - открыть и вспомнить, что и как (короче, использую как шпаргалки).
Для первой статьи в таком жанре выбрал заметки по языку Assembler (языку АссемблерАААА, я привык просто Ассемблер).
Assembler
Это машинно-ориентированный язык программирования низкого уровня. Если вам необходимо углубиться в него, то существует большое количество книг, статей и видеоуроков.
Структура программы
.586 ; размещены команды начиная с версии 586
.MODEL FLAT, STDCALL ; плоская модель памяти, отчистка стэка
;PUBLIC fn ; вставляется при работе с С++
.DATA ; (var)
.CODE ; блок программы, содержащий код
START: ; метка
OPERATORS
;fn ENDP
END START
Подключение к C++
В файле <name>.с\.cpp после (это не тег, а знак решетки)#include.
extern "C" тип_возвращаемого_значения __stdcall fn(переменные);
Если в ассемблер передаются переменные, то их нужно вытащить из стэка командой pop.
Например: в С++ (fn(a);) в asm (pop EAX)
Регистры
- EAX - аккумулятор !
- EBX - база ! регистры общего назначения
- ECX - счетчик ! могут хранить любую информацию
- EDX - регистр данных !
- EBP - указатель базы
- ESP - указатель стека (самое верхнее значение)
- ESI - индекс источника
- EDI - индекс приемника
- EIP - указатель текущей команды
- EFLAGS - регистр флагов
Флаги
- O - флаг переполнения
- A - доп. флаг переноса
- P - флаг четности (1 - когда четное количество 1 в двоичном числе)
- Z - флаг нуля (если вернул ноль, то флаг = 1)
- S - флаг знака (отрицательное - s = 1)
- C - флаг переноса (было ff, прибавили 1, флаг стал = 1)
Команды
(Нельзя оформить двухуровневый список, поэтому таким образом)
- ADD - сумма
ADC - с переносом
XADD - например, XADD EAX(значение = 9),ECX(значение = 1) тогда будет EAX=A, ECX=9, то есть обмен + сложение
- SUB - вычитание
SBB - с переносом
- MUL - умножение
IMUL - со знаком
- DIV - деление
IDIV - со знаком
- MOV - копирование значения (2 в 1)
MOVSX, MOVZX - копируют значения 2го (например, размер 4) в 1ое (размер 8) и заполняет левую сторону (F-отриц или 0-положит)/(0)
- LEA - копирование адреса (первый операнд - это регистр общего назначения, а второй - адрес ячейки памяти)
- NEG - изменение знака
- PUSH - помещение в стек (PUSH [401008] - помещение в стек содержимого ячейки в памяти по адресу 401008, но в обратном порядке)
PUSHAD = PUSH EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI
PUSHA = PUSH AX,...
- POP - извлечение из стека
POPAD = POP EDI, ESI, EBP, ESP, EBX, EDX, ECX, EAX
POPA = POP DI,...
- LOOP - управление циклом с ECX
- INC - инкремент
- DEC - декремент
- CMP - сравнение двух операторов (например, CMP EAX, ECX и если они равны то активируется флаг Z, если не равны, то S=1 когда ECX>EAX)
- SHL - сдвиг влево
- SHR - сдвиг вправо
- NOP - no operation
Логические инструкции
- AND (AND EAX,ECX) - побитное "и"
- OR
- XOR
- NOT
Переходы
Все инструкции переходов принимают один операнд, задающий адрес, на который должна перейти программа.
- JMP – переход
- JE, JZ – переход, если равно нулю
- JNE, JNZ – переход, если не равно нулю
- JS – переход, если знак отрицателен
- JNS – переход, если знак не отрицателен
- JP, JPE – переход, если чётно
- JNP, JOP – переход, если нечётно
- JO – переход, если произошло переполнение
- JNO – переход, если переполнения не произошло
- JB, JNAE – переход, если ниже
- JNB, JAE – переход, если выше или равно
- JBE, JNA – переход, если ниже или равно
- JNBE, JA – переход, если выше
- JL, JNGE – переход, если меньше
- JNL, JGE – переход, если больше или равно
- JLE, JNG – переход, если меньше или равно
- JNLE, JG – переход, если больше
- CALL address - вызывает функцию по адресу
- RET (RETN) - возвращает нас на следующую строку после CALL
Циклы
перед началом цикла
XOR ECX,ECX ; обнуляем
ADD ECX,15 ; записываем количество итераций в счетчик
цикл на простых командах:
DEC ECX ; декремент счетчика
; тело цикла
TEST ECX,ECX ; проверка на ноль, если не ноль, то z=0
JNE метка_начала_цикла ; если z=0, то прыграет на начала цикла (на dec)
цикл на LOOP:
LOOP метка_начала_цикла
Существуют некоторые вариации инструкции LOOP:
LOOPZ, LOOPE Цикл повторяется пока флаг Z установлен
LOOPNZ, LOOPNE Цикл повторяется пока флаг Z сброшен
Обе вариации работают как обычный LOOP, т.е. повторяют тело цикла пока счётчик не достигнет нуля, уменьшая на 1 значение счётчика при каждом повторе. В добавок, LOOPZ и LOOPNZ ещё проверяют значение флага Z и прерывают цикл если Z сброшен или установлен соответственно. Таким образом, цикл можно прервать досрочно (до того как ECX достигнет нуля), используя флаг Z.
Цепочечные инструкции
MOVS - Данная инструкция копирует данные из одного адреса в другой. Адрес источника хранится в регистре ESI, адрес приёмника - в EDI. Предварительно инициализируем ESI адресом ячейки, содержимое которой нужно скопировать (источник), и EDI - адресом ячейки, в которую нужно осуществить копирование (проёмник). MOVS копирует 4x-байтные значения = MOVSD. Существуют ещё инструкции MOVSW и MOVSB, копирующие 2 байта (WORD) и 1 байт (BYTE) соответственно.
REP - Это префикс, который можно использовать перед некоторыми инструкциями, в частности MOVS. Данный префикс указывает, что текущую инструкцию нужно выполнить ECX количество раз.
LODS - Данная инструкция загружает данные из источника (ESI) в аккумулятор (EAX). Есть ещё инструкции LODSW и LODSB для загрузки 2-байтовых (WORD) и 1-байтных (BYTE) значений соответственно.
STOS - Сохраняет значение аккумулятора (EAX) по адресу приёмника EDI. Можно использовать префикс REP для автоповторения и существуют 2-байтовая и 1-байтная версии: STOSW и STOSB.
CMPS - Осуществляет сравнение ячеек, указанных в источнике (ESI) и приёмнике (EDI). Сравнение кроет за собой арифметическую операцию вычитания и, если значения равны, то в результате мы получаем ноль, а это значит, что флаг Z будет установлен.
Способы адресации
1. Прямая адресация:
MOV dword ptr [00513450], ecx
MOV ax, word ptr [00510A25]
MOV al, byte ptr [00402811]
CALL 452200
JMP 421000
2. Косвенная адресация:
MOV dword ptr [eax], ecx
CALL EAX
JMP [ebx + 4]