Учебник Ассемблер для начинающих
Этот курс показывает, что происходит «под капотом» любой программы: как процессор хранит числа в регистрах, читает команды из памяти и шаг за шагом их исполняет. Мы пишем на ассемблере x86-64 в синтаксисе NASM под Linux, разбираем дополнительный код, систему команд, переходы, стек и соглашения вызова System V, делаем системные вызовы напрямую и смотрим, во что компилятор превращает обычный код на C. Курс для тех, кто уже знаком с любым языком высокого уровня и хочет понять машину по-настоящему: не чтобы писать на ассемблере каждый день, а чтобы перестать бояться слов «регистр», «стек» и «дизассемблер».
Курс «Ассемблер: как процессор исполняет код» состоит из 6 разделов и 23 уроков: Что такое ассемблер и зачем он нужен, Регистры, флаги и память, Представление чисел, Система команд, Управление потоком и функции и Память, ввод-вывод и связь с C. Уроки идут по порядку — от основ к более сложным темам, в каждом есть объяснение с примерами, а в конце — вопросы для самопроверки. К урокам привязаны задачи с автоматической проверкой: прочитали тему — сразу закрепили её кодом.
Программа курса
1 Что такое ассемблер и зачем он нужен
- Машинный код, ассемблер и язык высокого уровня
Чем машинный код отличается от ассемблера и от Python: три уровня одной программы и место ассемблера между ними.
- Архитектура x86-64 и цикл исполнения
Как устроен процессор x86-64: регистры, АЛУ, шина памяти и цикл fetch-decode-execute на простом примере.
- Первая программа: структура файла NASM
Секции .data, .bss и .text, метка _start и точка входа: из чего состоит минимальная программа на NASM под Linux.
- Машинный код, ассемблер и язык высокого уровня
2 Регистры, флаги и память
- Регистры общего назначения и их части
16 регистров x86-64, их 64/32/16/8-битные части (rax/eax/ax/al) и зачем такая матрёшка.
- Регистр флагов: ноль, знак, перенос
Флаги ZF, SF, CF, OF в RFLAGS: как операции их выставляют и зачем они нужны для условий.
- Память и режимы адресации
Как обращаться к памяти в ассемблере: квадратные скобки, базовый адрес, индекс, масштаб и смещение.
- Регистры общего назначения и их части
3 Представление чисел
- Двоичная и шестнадцатеричная системы
Биты, байты, степени двойки и удобство hex: как одни и те же числа выглядят в разных системах счисления.
- Дополнительный код: отрицательные числа
Как процессор хранит отрицательные числа в дополнительном коде и почему одно и то же сложение работает для плюса и минуса.
- Знаковые и беззнаковые операции
Почему процессор различает знаковые и беззнаковые числа: movzx/movsx, переполнение и выбор переходов.
- Двоичная и шестнадцатеричная системы
4 Система команд
- Пересылка данных: mov, lea, обмен
Команды mov, lea и xchg: как класть значения в регистры, вычислять адреса и обмениваться данными.
- Арифметика: add, sub, mul, div
Целочисленная арифметика в ассемблере: сложение, вычитание, умножение и деление с участием rax/rdx.
- Логика: and, or, xor, not
Битовые логические операции в ассемблере: маски, проверка и установка флагов, идиома xor для обнуления.
- Битовые сдвиги: shl, shr, sar
Сдвиги влево и вправо в ассемблере: умножение и деление на степени двойки, логический и арифметический сдвиг.
- Пересылка данных: mov, lea, обмен
5 Управление потоком и функции
- Метки и безусловный переход jmp
Метки как адреса и команда jmp: как менять порядок исполнения и почему линейный код это иллюзия.
- Условные переходы и ветвления
cmp плюс je/jne/jg/jl: как собрать if-else из сравнения и условного перехода в ассемблере.
- Циклы на ассемблере
Как собрать цикл for и while из метки, счётчика, cmp и условного перехода; команда loop.
- Стек: push и pop
Как устроен стек в памяти, как работают push и pop и почему стек растёт вниз по адресам.
- Вызов функций: call и ret
Как call сохраняет адрес возврата на стеке, а ret его забирает: механика вызова функции в ассемблере.
- Кадр функции и соглашение System V
Пролог/эпилог, кадр стека через rbp и передача аргументов в rdi/rsi/rdx по соглашению System V.
- Метки и безусловный переход jmp
6 Память, ввод-вывод и связь с C
- Массивы и строки в памяти
Как массивы и строки лежат в памяти, обход по индексу, нуль-терминированные строки в стиле C.
- Системные вызовы: syscall в Linux
Как делать ввод-вывод через syscall в Linux: номер вызова в rax, аргументы в регистрах, вывод строки и exit.
- Как C компилируется в ассемблер
Что компилятор делает с кодом на C: пролог/эпилог, godbolt, оптимизации и чтение сгенерированного ассемблера.
- SIMD-обзор и отладка в gdb
Что такое SIMD и регистры xmm, как gdb помогает шагать по командам, смотреть регистры и дизассемблировать код.
- Массивы и строки в памяти