Архитектура x86-64 и цикл исполнения

Урок собирает общую картину: из чего состоит процессор и как команды превращаются в действия.

Архитектура набора команд (ISA) — это «контракт» между железом и программистом: список команд, регистров и правил, на которые можно опираться.

Из чего состоит процессор для нас

Чтобы писать на ассемблере, не нужно знать транзисторы. Достаточно модели из нескольких блоков:

  • Регистры — крошечные сверхбыстрые ячейки внутри процессора (rax, rbx и др.). Их единицы, и в них идёт вся работа.
  • АЛУ (арифметико-логическое устройство) — складывает, вычитает, сравнивает, делает and/or.
  • Память (RAM) — огромный массив байтов снаружи процессора, медленнее регистров.
  • Регистр флагов RFLAGS — хранит результат последнего сравнения (был ли ноль, перенос, знак).

Почему регистры, а не сразу память

Регистр читается за доли наносекунды, обращение к RAM — в десятки раз дольше. Поэтому философия ассемблера такая: загрузи данные из памяти в регистры, обработай в регистрах, выгрузи результат обратно. Почти каждая арифметическая команда работает с регистрами, а не напрямую с памятью.

Цикл исполнения на примере

Возьмём программу из трёх команд и проследим состояние регистра rax:

mov rax, 10     ; шаг 1
add rax, 5      ; шаг 2
sub rax, 3      ; шаг 3

Изменение значения шаг за шагом:

ШагКомандаrax после
1mov rax, 1010
2add rax, 515
3sub rax, 312

На каждом шаге процессор выбирает команду по адресу RIP, декодирует её, выполняет в АЛУ и сдвигает RIP дальше. Эту же модель удобно проверять на Python, имитируя регистр обычной переменной.

rax = 10
print("start :", rax)
rax = rax + 5   # add rax, 5
print("add 5 :", rax)
rax = rax - 3   # sub rax, 3
print("sub 3 :", rax)

Вывод:

start : 10
add 5 : 15
sub 3 : 12

Как работает под капотом

Между процессором и RAM стоят несколько уровней кэша (L1, L2, L3). Когда вы делаете mov rax, [адрес], процессор сначала ищет данные в L1; если не нашёл — спускается ниже, вплоть до RAM. Поэтому обращения к памяти бывают «дешёвыми» и «дорогими», хотя в ассемблере выглядят одинаково. Это объясняет, почему один и тот же алгоритм с другим порядком доступа к памяти может работать в разы быстрее.

Частые ошибки

  • Считать память и регистры одним и тем же. Регистров мало и они быстры; память велика и медленна. Команды работают по-разному с тем и другим.
  • Игнорировать флаги. После арифметики и сравнений RFLAGS меняется автоматически — именно от него зависят условные переходы.
  • Ждать «оператора цикла». В процессоре нет while — цикл собирается вручную из сравнения и перехода (об этом будет отдельный раздел).

Итог

  • Процессор для нас — это регистры, АЛУ, флаги и память снаружи.
  • Работа идёт в регистрах, потому что они в десятки раз быстрее RAM.
  • Команды исполняются в цикле fetch–decode–execute, RIP ведёт указатель.
  • RFLAGS хранит результат последней операции и управляет переходами.
Проверьте себя
1. Почему данные перед обработкой загружают в регистры?
AРегистры в десятки раз быстрее оперативной памяти
BВ памяти нельзя хранить числа
CРегистры больше по объёму, чем RAM
DТак требует синтаксис NASM, без причины
2. Что хранит регистр RFLAGS?
AАдрес следующей команды
BРезультат последней операции: ноль, перенос, знак
CТекст исходной программы
DСодержимое всей памяти
3. Что такое ISA (архитектура набора команд)?
AКонкретная модель процессора Intel
BЯзык программирования высокого уровня
CКонтракт между железом и программистом: команды, регистры, правила
DПрограмма-отладчик