2015. Таблица - справочник по командам NASM (1110694), страница 2
Текст из файла (страница 2)
ИМХО: Стек стоит представлять в голове как подвешенные к потолку грузики. Каждый новый грузик подвешивается, естественно, за низ самого нижнего из уже висящих.
esp указывает на вершину стека (самый низковисящий грузик).
esp + smth – движемся вглубь стека (к потолку).
esp – smth – свободное место между стеком и кучей.
Над стековым фреймом функции:
аргументы, передаваемые фикции f из вызывающей функции |
Стековый фрейм функции:
ret | ибо был произведен CALL (в некоторых учебниках не включается в фрейм) |
ebp | Стандартный пролог функции: push ebp mov ebp, esp |
Сохраненные регистры (ebx, esi, edi) | |
Локальные переменные + аргументы для вызова функцией следующей функции | |
…. | |
Стандартный эпилог функции: mov esp, ebp; чтобы вернуться в то положение стека, в котором были при вызове функции pop ebp; мало ли вызывающей функции это значение пригодится ret ------------- эквивалентно: leave ret |
*каждая «строка» в таблице весит 4 байта
//рекурсивные вызовы подчиняются правилу last in - first out => для выделения памяти и работы с ней логично использовать стек.
Возвращаемое значение по CDECL:
my_type f(…)
sizeof(my_type) | Возвращаемой функцией f значение будет храниться в: |
4 (2, 1) | EAX (AX, AL) |
8 | EDX:EAX |
my_type – это структура | Первым (неявным) параметром, переданным в функцию f из вызывающей функции, будет адрес начала фрагмента памяти, в который нужно записать структуру |
fastcall:
arg1->ecx
arg2->edx;
arg3...argn -> stack
stdcall:
Вызываемая функция сама снимает со стека свои аргументы (подробнее – см. операцию ret op1 в табл. выше).
fomit-frame-pointer (англ. omit – упускать):
Все обращения к содержимому стека выполняются только через регистр ESP.
С точки зрения эффективности такой подход дает два преимущества:
-
исчезает необходимость сохранять и восстанавливать EBP в прологе и эпилоге функции;
-
у компилятора появляется дополнительный регистр для организации вычислений.
Регистр EFLAGS
Выполнение арифметических операций сопровождается выработкой флагов регистра EFLAGS:
Флаги статуса:
-
SF – знак результата (иными словами, значение крайнего левого бита) – sign flag;
-
ZF – результат равен нулю – zero flag;
-
OF – переполнение (в знаковой трактовке числа – (перенос на знаковый бит) xor CF) – overflow flag;
-
CF – перенос за разрядную сетку (переполнение числа в беззнаковой трактовке – перенос за знаковый бит) – carry flag;
-
PF – четность числа единиц в младшем байте результата – parity flag.
Флаг направления:
-
DF - флаг направления. Управляет направлением обработки строк данных, поведением цепочных инструкций (MOVS, CMPS, SCAS, LODS, STOS):
DF=0 — от младших адресов к старшим,
DF=1 — от старших адресов к младшим (для специальных строковых команд).
Когда флаг сброшен, при выполнении цепочечной команды происходит автоинкремент адресов источника и приемника. Когда флаг установлен — автодекремент (подробнее – см. ниже табл. "Строковые инструкции").
Разметка регистра EFLAGS:
OF | SF | ZF | PF | CF | |
ADD, SUB, NEG | M | M | M | M | M |
INC, DEC | M | M | M | M | |
IMUL, MUL | M | – | – | – | M |
IDIV, DIV | – | – | – | – | – |
CBW, CWD, CDQ | |||||
MOV, MOVSX, MOVZX | |||||
CMP | M | M | M | M | M |
TEST | 0 | M | M | M | 0 |
«M» инструкция обновляет флаг (сбрасывает или устанавливает); «–» влияние инструкции на флаг не определено ; « » инструкция на флаг не влияет; «0» инструкция сбрасывает флаг.
Некоторые из флагов могут быть изменены специально предназначенными для этой цели инструкциями. Для изменения или проверки группы флагов можно воспользоваться командами:
LAHF / SAHF | загрузка / сохранение младших 8 битов регистра флагов в регистре AH. (Load / Save) |
PUSHF / POPF | помещение / извлечение из стека младших 16 битов регистра флагов |
PUSHFD / POPFD | помещение / извлечение из стека 32-битного регистра EFLAGS |
PUSHAD / POPAD | PUSHAD выгружает все основные регистры на стек, POPAD загружает назад. На значения флагов не влияет. |
CLC / STC / CMC | Сбросить CF в 0 / установить CF в 1 / инвертировать CF |
CLD / STD | Сбросить DF / установить DF |
Условные переходы (условная передача управления)
•JMP –r/m/imm 32 - безусловный переход
•Jcc –imm32 - условный переход. Ниже таблица условий.
Jcc | Описание (Переход, если…) | Условие перехода | Комментарий | ||||||||||||
J[буква флага: Z, S, O, C, P] | Переход, если флаг взведен |
| |||||||||||||
JN[буква флага: Z, S, O, C, P] | Переход, если флаг не взведен | ||||||||||||||
JE / JZ | Нуль или равно | ZF (т.е. ZF = 1) | Zero; Equal | ||||||||||||
JNE / JNZ | не нуль или не равно | ~ZF (т.е. ZF = 0) | Not zero; Not equal | ||||||||||||
JG / JNLE | Больше (знаковые числа) | ~(SF^OF)&~ZF | Greater | ||||||||||||
JGE / JNL | Больше либо равно (знаковые числа) | ~(SF^OF) | Greater or equal | ||||||||||||
JL / JNGE | Меньше (знаковые числа) | (SF^OF) | Lower | ||||||||||||
JLE / JNG | Меньше либо равно (знаковые числа) | (SF^OF)|ZF | Lower or equal | ||||||||||||
JA / JNBE | Больше / не меньше и не равно (числа без знака) | ~CF&~ZF | Above / Not (below or equal) | ||||||||||||
JNA / JBE | Не больше / меньше или равно(числа без знака) | ||||||||||||||
JB | Меньше (числа без знака) | CF | Below
| ||||||||||||
JCXZ / JECXZ | Содержимое CX / ECX равно нулю | CX = 0 / ECX = 0 | jump (if) cx / ecx (is) zero |
КОМАНДА | ОПИСАНИЕ | СИНТАКСИС | Комментарий |
LOOP .mark | Декрементирует регистр регистр ECX и после этого сравнивает его с нулем. Если не равен нулю — переход след. итерацию (на метку .mark), если равен нулю — идем по коду дальше. | т.е. присваиваются значения True / False Команды LOOP/LOOPcc являются макросам и в этом их главная проблема: Условный переход может быть только в пределах [ –128, 127] байтов от текущей позиции в коде. Закодировать цикл с достаточно объемным телом не получится | |
LOOPZ / LOOPE ( LOOPNZ / LOOPNE) | Переход выполняется, если значение регистра ECX не равно нулю и флаг ZF установлен (сброшен). |
Условная передача данных
КОМАНДА | ОПИСАНИЕ | СИНТАКСИС | Комментарий |
SETcc op1 | Помещает в свой единственный операнд либо 0, либо 1, в зависимости от выполнения условия, указанного в суффиксе кода операции. | - op1 = r/m 8 | т.е. присваиваются значения True / False |
CMOVcc op1, op2 | if (cc){ mov op1, op2; } | CMOVcc r / m, r / m (Нельзя константу перемещать. Нельзя память-память) | CMOV - Condition MOV |
Строковые инструкции
КОМАНДА | ОПИСАНИЕ | СИНТАКСИС | Комментарий |
cmps{b, w, d} | compare [esi] and [edi] | eSi – source eDi - destination | |
lods{b, w, d} | {AL, AX, EAX} := [esi] esi += sizeof( {b, w, d} ) | ||
movs/movs{b, w, d} | Пересылка данных память-память. Конкретнее: пересылка элементов двух последовательностей (цепочек) - строк байтов/слов/двойных слов - в памяти. [edi] := [esi] | movs приемник, источник movsb movsw movsd | (MOVe String Byte/Word/Double word) выполнение команды не влияет на флаги |
scas{b, w, d} | compare {AL, AX, EAX} and [edi] | ||
stos{b, w, d} | [edi] := {AL, AX, EAX} edi += sizeof( {b, w, d} ) | ||
cld std | cld => DF := 0 std => DF := 1 | esi = esi + delta edi = edi + delta delta = +/- {1, 2, 4} DF = 0 => + (просмотр строки слева-направо) DF = 1 => - (просмотр строки в обратном порядке (справа-налево) ) | |
rep op1 repe (<=> repz) op1 repne (<=> repnz) op1 | (REPeat string operation) - Повторить цепочечную операцию Алгоритм работы зависит от конкретного префикса. Префиксы rep, repe и repz на самом деле имеют одинаковый код операции, их действия зависят от той цепочечной команды, которую они предваряют:
op1 dec cx }
op1 dec cx //не влияет на флаги? }
что проверяют zf на противоположное условие: op1 dec cx //не влияет на флаги? }
| - op1 – команда NASM | Состояние флагов после выполнения команды: 06 ZF r Применение: Команды rep, repe, repz, repne и repnz в силу специфики своей работы называются префиксами. Они имеют смысл только при использовании цепочечных операций, заставляя их циклически выполняться и тем самым без организации внешнего цикла обрабатывать последовательности элементов фиксированной длины. Большинство применяемых префиксов являются условными, то есть они прекращают работу цепочечной команды при выполнении определенных условий. |
Алгоритм работы:
-
выполнить копирование байта, слова или двойного слова из операнда источника в операнд приемник, при этом адреса элементов предварительно должны быть загружены:
-
адрес источника — в пару регистров ds:esi/si (ds по умолчанию, допускается замена сегмента);
-
адрес приемника — в пару регистров es:edi/di (замена сегмента не допускается);
-
в зависимости от состояния флага df изменить значение регистров esi/si и edi/di:
-
если df=0, то увеличить содержимое этих регистров на длину структурного элемента последовательности;
-
если df=1, то уменьшить содержимое этих регистров на длину структурного элемента последовательности;
если есть префикс повторения, то выполнить определяемые им действия (см. команду rep).
Применение: