Ассемблер
Ассемблер — это программа, транслирующая язык ассемблера в машинный код.
Язык ассемблера — это низкоуровневый язык, предоставляющий более прямой доступ к аппаратным ресурсам компьютера по сравнению с высокоуровневыми языками. Каждая инструкция в языке ассемблера обычно соответствует одной машинной инструкции, что делает его близким к языку машинного кода.
Синтаксис
В этой статье используется синтаксис Intel на примере архитектуры x86-64.
Разновидности синтаксиса
Существует две основные разновидности синтаксиса для языка ассемблера: Intel и AT&T. Они различаются в основном в способе записи операндов и некоторых других деталях.
Синтаксис Intel чаще встречается при работе IBM-совместимыми архитектурами (например, x86 и x86-64), при использовании компиляторов от Intel и Microsoft.
Синтаксис AT&T чаще ассоциируется с миром UNIX-подобных систем. Например, он используется в ассемблерных программах в исходных текстах Linux.
Инструкция формируется из мнепоники (иногда называют опкод, от operation code) и какого-то количества операндов.
Например: mov eax, 5; здесь mov это мнемоника, а eax и 5 — операнды.
Эта запись означает "поместить значение 5 в регистр eax".
Одной мнемонике могут соответствовать несколько машинных команд. После компиляции они будут иметь разные машинные кода и, зачастую, разный размер.
Операнды могут быть трёх типов:
- непосредственный: значение, которое указано прямо в комадне
- регистровый: название регистра
- адресный: адрес ячейки (в т.ч. начало области памяти)
Адресный операнд всегда указывается в квадратных скобках [].
Команды
Рассматривать все команды смысла нет, далее рассмотрены только основные.
Перемещение данных
mov <dst> <src>(move)
Арифметические операции
-
add <dst> <src>— складывает два операнда и сохраняет результат в целевом операнде (dst); эквивалентноdst = dst + src -
sub <dst> <src>(subtract) — вычитает второй операнд из первого и сохраняет результат в целевом операнде; эквивалентноdst = dst - src -
inc <dst>(increment) — увеличивает значение операнда на 1, эквивалентноdst = dst + 1 -
dec <dst>(decrement) — уменьшает значение операнда на 1, эквивалентноdst = dst - 1 -
neg <dst>(negate) — изменяет знак операнда; эквивалентноdst = -dst -
mul(multiply) -
div(divide)
Логические операции
andиtest– побитовое "и"or– побитовое "или"xor– побитовое исключающее "или"cmp(compare) – сравнение
Переходы
Безусловный переход обозначается командой jump и имеет один операнд — метку,
к которой нужно перейти (под меткой понимается адрес инструкции).
Команд для переходов с условием значительно больше, но все они однотипны. Они также имеют один адресный операнд, но переход происходит только если выполнилось условие.
Эти команды выполняются в связке с другими (например cmp). Предыдущие
команды каким-либо образом меняют флаговые регистры, на основе которых затем
происходит проверка истинности условия.
Например
cmp rax, rcx
jl label
читается так: сравнить значения в регистрах rax и rcx; если сравнение
дало результат "первый операнд меньше второго", перейти к метке label.
Ниже список мнемоник с пояснениями:
je– jump if equaljz– jump if zerojl– jump if lowerjg– jump if greaterjle– jump if less or equaljge– jump if greater of equaljne– jump if not equaljnz– jump if not zerojnl– jump if not lessjng– jump if not greaterjnle– jump if not less or equaljnge– jump if not greater or equal
Стек
callret(return)pushpop
Другое
lea <dst> <addr>(load effective address)