Изменения
→Арифметические команды: так читабельнее
Регистры -- основная — память в ассемблерепроцессора.
Регистры '''общего назначения:''' (в скобках — изначальное предназначение)
eax (accumulator)
ebx (base)
ecx (counter)
edx (data)
ebp ...(stack base pointer) esp (stack pointer) трогать <s>нежелательно</s> аккуратно, стек ПЫЩЬ esi ...(source) edi ...(destination)
То, что вторые буквы -- — первые четыре буквы лат. латинского алфавита -- — случайность. Это видно в том числе и по тому, что их естественный порядок виден при переносе на стек: eax, edx, ecx, ebx...
Ещё регистры:
eip (instruction pointer)
eflags: куча битов, которые означают флаги. пример:
zf -- — 1, если последняя операция вернула 0, 1 otherwise cf -- — знак переноса (если результат последней операции не влезает в нужное кол-во битов и один переносится) sf -- — знаковый бит. 0 -- — полож., 1 -- — отриц.
df -- — направление выполнения строковых операций.Регистры 32-битны. На 64-битных системах действует следующие наименования: e*x ____^____ / \ 32 | 16 | 8 | 8 *h *l \______ ______/ v r*x
Регистры e** 32-битны. На 64-битных системах действует следующие наименования:
<tex>
\underbrace {\fbox{32 \quad\quad\quad\quad}
\overbrace{\fbox{16 \quad\quad}
\overbrace{
\underbrace{\fbox{8 \quad}}_{*h}
\underbrace{\fbox{8 \quad}}_{*l}
}^{*x}
}^{e*x}
}_{r*x}
</tex>
Собственно, этимология названий: буква '''e''' (extended) появилась в названиях регистров с 386 процессором и 32-битным режимом работы. '''h''' и '''l''' пошли от high и low соответственно (старший и младший байты)
= Обзор команд =
== Команды загрузки ==
mov -- команда загрузки.register|memory, register|memory|immediate ; записать значение второго операнда в первый, размер данных должен совпадать mov al, 5 -- ; загрузить в al 5Обычно первый аргумент команды -- то, что меняется. mov cx, di -- ; скопировать значения значение di в cx в di. Размер копируемых данных должен совпадать. movzx -- размер игнорируется; то, что осталось, заполняется нулями movcx -- размер игнорируется; то, что осталось, заполняется знаковым (старшем) битом mov(cc): cc -- условие. если cc, то mov, ничего otherwise xchg -- обмен значений регистров
movzx register, register|memory ; копирование значений меньшей разрядности в регистр большей разрядности, недостающие биты заполняются нулями movsx register, register|memory ; копирование значений меньшей разрядности в регистр большей разрядности, недостающие биты заполняются знаковым битом cmov(cc) register, register|memory ; cc — условие, команда выполняется только если условие верно xchg register|memory, register|memory ; обмен значений bswap -- register ; меняет порядок байт в регистре на обратный (little в big, big в little)
Уточнение про порядок байт:
//31...15...7...0
//
//процессоры: x86 -- — little-endian, при обмене данными по сети -- — big-endian
Обращаться можно и к памяти:
mov eax,[ebx] -- ; загрузка в eax того, что находится по адресу ebx. (в C выглядело бы как eax = *ebx. ) [] - косвенная адресация. не более одних скобок за раз, ** недопустимы. может Может использоваться как для левого, так и правого аргумента mov. по правилам в В команде <= 1 может быть не больше одного обращения к памяти. сказать, что " <s>mov [eax],[ebx]" разрешено == всё равно, что выгнать себя с экзамена)</s> ; так делать нельзя!
Оперативную память попортить нельзя, она разделена между процессами.
В квадратных скобках при использовании 16-битных регистров можно писать три опциональные части:
bx (bp) si + si (di) +(/-) offset (16-битное число) bp di
В квадратных скобках при использовании 32-битных регистров позволено писать довольно много разных вещей:
== Работа со стеком ==
push eax -- register|memory|immediate ; положить eax значение на стек.
Сишный псевдокод:
pop eax -- запихать вершину register|memory ; записать значение верхнего элемента стека в eaxрегистр/память
Как это выглядит на ассемблере:
Стек-пойнтеру (sp) в 16-битном режиме довольно желательно бы быть чётным, в 32-битном -- — кратным четырём: всё будет работать существенно быстрее.Стек -- — хорошее быстрое временное хранилище. не Не слишком большое (1-2 мб).//malloc и free -- — системные функции, их можно свободно использовать в любом языке (и в Си, и здесь, и в дельфи)
pusha(d) -- ; сохранить в стек все 8 регистров общего назначения popa(d) -- ; вытащить их из стека
(push|pop)ad работают с 32-битными регистрами, (push|pop)a - — c 16-битными.при При восстановлении не меняется esp (логично, дабы с esp не произошло трешака).
//"Вас никто не заставляет делать разумные вещи. Если вы хотите делать безумные вещи, вы можете это делать совершенно свободно!"
imul / idiv
mul OP -- — после этой команды в edx:eax 64 бита -- — результат умножения eax на аргументOP div OP -- — после этой команды в edx edx:eax / ebx
в eax же eds:eax % ebx
//в документации указана обработка всего этого в 8- и 16-битных случаях
imul и idiv -- — аналогично mul и div, НО: работают со знаковыми числами
кроме того, у imul есть такие формы записи:
== Команды логики ==
and, or, xor, not. Все, кроме not -- унарныеимеют два аргумента.
xor eax, eax -- — быстрое обнуление регистра
команда mov anything, 0 имеет смысл, но редко. когда:
Команды cmp/test аналогичны командам (sub/and). результаты не пишут никуда (!!!), но ставят флаги.
test eax,eax -- — самый короткий способ проверить, 0 ли регистр
== Команды сдвига ==
Во всех сдвигах последний сдвигаемый бит идёт в cf
shr/shl -- — сишные сдвиги (>>, <<). второй аргумент команды -- — либо константа, либо cl. деление на степени двойки -- — самое быстрые, ибо сдвиги, которые гораздо более быстрее, нежели "реальное" деление. sar -- — сдвиг справо со знаком. Сишное >> компилируется в зависимости от "знаковости" переменной в shr/sar. shl, очевидно, == sal.
shrd/shld принимают три аргумента.
shrd eax,ebx,3:
ebx,eax двигаются на 3 вправо (О_О). первые k (где k -- — третий аргумент) битов того, что указано в первом аргументе == последние k того, что указано во втором.
=== Команды вращения (о_О) ===
v-------------------------------->
Аналогично rol/ror'у, но флаг cf -- — часть того, что сдвигается (т.о., сдвигаются 33 бита)
== Команды передачи управления ==
jmp метка (jmp eax)
фактически -- — mov eip, smth
Так же есть условия, зависящие от флагов:
j(cc)
ex.: jz -- — условный переход, если флаг нуля установлен. jnz -- — переход, если флаг нуля не установлен. jc, jnc -- — аналогично для флага переноса, и так далее... тысячи их!
ja, jb, jae, jbe, jl, jg, jle, jge (к каждой можно устроить отрицание(
ja -- — above (если больше, без знака) jb -- — below (если меньше, без знака) jae -- — above/equal (больше или равно без знака) jbe -- — below/equal (меньше или равно без знака)
jg \
jl |} -- — аналогично вышеуказанным, jge |} -- — но с учётом знаков.
jle /
те же самые условия используеются в командах условной загрузки (mov(cc))
call -- — аналогично jmp, НО.
call x ~=
| push eip
| pop eip
У ret есть опциональный параметр -- — число.
ret x ~=
pop eip
//пара команд, которые все любят
nop -- — Команда, Которая Ничего Не Делает ud2 -- — Команда, Которой Не Существует. Если она выполняется, программа падает с ошибкой. И БУДЕТ ПАДАТЬ. ВСЕГДА. И НЫНЕ. И ПРИСНО. ВО ВЕКИ. ВЕКОВ