- •Nasm help v0.2
- •1. Основы
- •1.1 Секции
- •1.3 _Start
- •1.4 Регистры
- •1.5 Разыменование
- •2. Синтаксис nasm
- •2.1 Базовые команды
- •2.3 Организация подпрограмм
- •2.4 Метки в подпрограммах
- •2.5 Сохранение регистров
- •2.6 Передача аргументов подпрограмме
- •2.2 Вызовы ядра
- •3. Основные логические структуры в переложении на ассемблер.
- •3.1 Условие
- •3.2 Цикл
- •4. Заключение
1.5 Разыменование
Разыменование - это получение объекта по ссылке.
Ссылка — это объект, указывающий на определенные данные, но не хранящий их
(в частности переменная хранящая адрес объекта).
Когда мы(программисты на ассемблере) обращаемся к регистру или константе, то пишем их имена просто так, обращаясь же к выделенной области оперативной памяти (в секции .data или .bss) мы пишем имя метки в квадратных скобках, но на самом деле, проводим операцию разыменования по отношению к данному адресу.
Объясню на примере, допустим у нас есть массив в секции .data:
section .data
mass: db 4, 8, 15, 16, 23, 42
И мы хотим использовать пятое число из этого массива, тогда пишем [mass+4] или byte [mass+4]. Разберём эту запись по шагам.
Итак, метка mass содержит адрес нулевого элемента массива (или говорят: указывает на нулевой элемент массива), но не является самим элементом — это ссылка.
Прибавляя к метке mass число 4 мы добились того, что общее выражение mass+4 теперь указывает на элемент массива с номером 4 (5 элемент).
Затем мы проводим операцию разыменования, то есть сообщаем ассемблеру, что всё находящееся между квадратными скобками является адресом и нам нужно значение лежащее в памяти по этому адресу.
Тогда значение [mass+4] или byte [mass+4] будет равно 23.
Именно здесь, если попытаться перейти по адресу, к которому нет доступа (в нашем примере это [mass+6] и большие значения: +7, +8 и т.д.) программа выдаёт ошибку Segmentation fault.
Затем, зачем нужны все эти приписки: byte, word, dword? Ответ прост. Если разыменование используется в команде где явно обозначен размер операнда (Как пример mov al, [mass+4]) уточнение размера не требуется, но в некоторых командах (или просто чтобы уменьшить вероятность ошибки) указывается размер данных, которые лежат по адресу, в нашем случае там лежит байт, поэтому byte [mass+4]
Ещё один подводный камень заключается в том, что смещение (то есть эту «циферку с плюсом или минусом») нужно умножать на размер элементов массива.
В случае выше это был байт ((5-1)*1=4) и запись была такой - byte [mass+4] (=23),
Но если бы было так:
section .data
mass: dd 4, 8, 15, 16, 23, 42
То доступ к пятому элементу был бы оформлен исходя из размера в 4 байта ((5-1)*4=16), и запись была бы такой -
dword [mass+16] (=23).
2. Синтаксис nasm
2.1 Базовые команды
1) mov <операнд1>,<операнд2>
Помещает содержимое <операнд2> в <операнд1>
2) add <операнд1>,<операнд2>
Помещает значение суммы операндов в <операнд1>
3) inc <операнд1>
Эквивалентно add <операнд1>,1
4) sub <операнд1>,<операнд2>
Вычитает из <операнд1> <операнд2> и помещает разность в <операнд1>
5) dec <операнд1>
Эквивалентно sub <операнд1>,1
6) mul <операнд1>
Умножает значение регистра A на <операнд1>, и кладёт результат в A(D:A). Размер A (и наличие D) зависит от размера <операнд1>:
6.1) размер <операнд1> = 1 байт
Умножает al на <операнд1>
Кладёт результат в ax (ah:al если быть точным)
6.2) размер <операнд1> = 2 байт
Умножает ax на <операнд1>
Кладёт результат в dx:ax
6.3) размер <операнд1> = 4 байт
Умножает eax на <операнд1>
Кладёт результат в edx:eax
7) div <операнд1>
Делит значение регистра(ов) A(D:A) на <операнд1>, и кладёт результат в A(D:A). Размер A и наличие D зависят от размера <операнд1>:
7.1) размер <операнд1> = 1 байт
Делит ax(ah:al) на <операнд1>
Кладёт результат деления в al
Кладёт остаток от деления в ah
7.2) размер <операнд1> = 2 байт
Делит dx:ax на <операнд1>
Кладёт результат деления в ax
Кладёт остаток от деления в dx
7.3) размер <операнд1> = 4 байт
Делит edx:eax на <операнд1>
Кладёт результат деления в eax
Кладёт остаток от деления в edx
8) not <операнд1>
Инвертирует все биты <операнд1>
9) neg <операнд1>
Умножает <операнд1> на -1
Эквивалентно: not <операнд1> | inc <операнд1>
10) and <операнд1>,<операнд2>
Конъюнктирует побитово <операнд1> и <операнд2>
Кладёт результат в <операнд1>
11) or <операнд1>,<операнд2>
Дизъюнктирует побитово <операнд1> и <операнд2>
Кладёт результат в <операнд1>
12) xor <операнд1>,<операнд2>
Складывает по модулю 2 побитово <операнд1> и <операнд2>. Кладёт результат в <операнд1>. Чаще всего используется как замена mov <операнд1>,0 т.к. Размер последнего после компиляции 5 байт, а размер xor'а 2 байта.
13) push <операнд1>
Помещает <операнд1> в стек
14) pop <операнд1>
Забирает верхушку стека и кладёт в <операнд1>
15) pushad
Сохраняет все регистры в стеке
16) popad
Восстанавливает все регистры в стеке
17) cmp <операнд1>,<операнд2>
Сравнивает <операнд1> и <операнд2>
18) jmp <метка>
Безусловный переход на метку
19) j<усл> <метка>
Условный переход на метку
<усл> задаёт условие (для результата последней операции cmp)
1) e — равно (ne — не равно)
2) a — больше (na, ae — не больше, меньше или равно)
3) b — меньше (nb, be — не меньше, больше или равно)
4) g — больше (ng, ge - не больше, меньше или равно)
5) l — меньше (nl, le - не меньше, больше или равно)
2,3 — для беззнаковых целых
4,5 — для знаковых целых
