Изменения

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

Навигация