## Архитектура - 64-битная (процессоры Intel / AMD) - Ассемблер: `NASM` - OC: Linux - Размеры данных: - `byte` - `word` (два байта) - `dword` (4 байта) - `qword` (8 байт) ## Регистры общего назначения Все 64-битные регистры начинаются с `R`. Их младшие части можно прочитать отдельно #### База - `RAX` (Accumulator) - аккумулятор, возвращаются результаты функций и номера сисколлов - `RBX` (Base) - обычная переменная - `RCX` (Counter) - счетчик циклов, 4-й аргумент функции, уничтожается сисколлом - `RDX` (Data) - данные, 3-й аргумент функции, второе возвращаемое значение, хранит остаток при делении #### Индексы и указатели - `RDI` (Destination Index) - 1-й аргумент функции - `RSI` (Source Index) - 2-й аргумент фукнции - `RSP` (Stack Pointer) - указатель вершины стека - `RBP` (Base Pointer) - указатель базы стекового кадра #### Новые регистры - `R8, R9` - 5-й и 6-й аргументы функций - `R10, R11` - временные - `R12-R15` - свободные переменные #### Имена частей регистров | *64 бита (qword)* | *32 бита (dword)* | *16 бит (word)* | *8 бит (byte)* | | :---------------: | :---------------: | :-------------: | :------------: | | `rax` | `eax` | `ax` | `al` | | `rbx` | `ebx` | `bx` | `bl` | | `rcx` | `ecx` | `cx` | `cl` | | `rdx` | `edx` | `dx` | `dl` | | `rdi` | `edi` | `di` | `dil` | | `rsi` | `esi` | `si` | `sil` | | `rsp` | `esp` | `sp` | `spl` | | `rbp` | `ebp` | `bp` | `bpl` | | `r8..15` | `r8..15d` | `r8..15w` | `r8..15b` | ## Соглашение о вызовах 1. Аргументы: `RDI`, `RSI`, `RDX`, `RCX`, `R8`, `R9` 2. Возврат значения: `RAX` и `RDX` 3. Сохранность регистров - *Caller-saved* (портятся при вызове `call`): `RAX`, `RCX`, `RDX`, `RSI`, `RDI`, `R8-R11`. Обязанность запоминать их - на вызывающем - *Callee-saved* (обязаны остаться неизменными): `RBX`, `RBP`, `RSP`, `R12-R15`. Обязанность вернуть их в исходное состояние - на функции 4. Выравнивание стека - В момент `call` значение регистра `RSP` должно быть кратно 16 - При входе в функцию стек сдвинут адресом возврата, поэтому RSP % 16 == 8. Перед внутренним call нужно выровнять стек (сделать push или sub rsp, 8) ## Самые нужные сисколлы Все сисколлы [тут](https://gitlab.se.ifmo.ru/programming-languages/cse-programming-languages-fall-2026/main/-/blob/master/docs/system-calls.md) | Назначение | RAX | RDI (fd) | RSI (buffer) | RDX (size) | Возврат в RAX | | :----------------------- | :--- | :----------- | :------------- | :---------- | :--------------------------------------------- | | **Чтение (`sys_read`)** | `0` | `0` (stdin) | Адрес в памяти | Кол-во байт | Кол-во прочитанных байт (0 = EOF, <0 = ошибка) | | **Запись (`sys_write`)** | `1` | `1` (stdout) | Адрес в памяти | Кол-во байт | Кол-во записанных байт | | **Выход (`sys_exit`)** | `60` | Код возврата | - | - | Процесс завершается | ## Самые нужные инструкции #### Перемещение данных - `mov A, B` - скопировать B в A - `movzx` - скопировать байт B в регистр A и заполнить старшие биты нулями #### Математика - `add A, B` / `sub A, B` - сложение / вычитание `A = A +/- B` - `inc A` / `dec A` - инкремент / декремент - `neg A` - `A = -A` - `imul A, B` - знаковое умножение `A = A * B` - `mul B` - беззнаковое умножение, умножает `RAX` на B. Старшая часть результата в `RDX`, младшая - в `RAX` (результат - `RDX:RAX`) - `div B` - беззнаковое деление. Делит `RDX:RAX` на B. Частное в `RAX`, остаток в `RDX` #### Логика - `and`, `or`, `not` - побитовое И, ИЛИ, НЕ - `xor A, B` - исключающее ИЛИ (`xor rax, rax` - быстрый способ обнулить регистр) - `test A, B` - побитовое И без сохранения результата (только ставит флаги) - лучший способ проверить регистр на ноль #### Ветвление и переходы - `cmp A, B` - сравнивает A и B, ставит флаги - `jmp метка` - безусловный переход - `je` / `jne` (или `jz` / `jnz`) - прыжок, если `Z = 1` / `Z = 0` - Дли знаковых чисел - `jl` / `jle` (Less / Less or Equal) - меньше / меньше или равно - `jg` / `jge` (Greater / Greater or Equal) - больше / больше или равно - `js` / `jns` (Sign) - отрицательное / положительное (флаг `S`) - Для беззнаковых чисел: - `jb` / `jbe` (Below / Below or Equal) - меньше / меньше или равно - `ja / jae` (Above / Above or Equal) - больше / больше или равно - Для переполнений - `jc` / `jnc` (Carry) - `jo` / `joc` (Overflow) #### Работа со стеком Растет как в БЭВМ (в сторону уменьшения адресов) - `push A` - кладет 8 байт на стек (`rsp -= 8, [rsp] = A`) - `pop A` - достает 8 байт со стека (`A = [rsp], rsp += 8`) - `sub rsp, 24` - выделить буфер на 24 байта - `add rsp, 24` - освободить буфер