Ключевую роль в обработке данных в процессоре играют специальные ячейки, известные как регистры. Регистры в процессоре x86-64 можно разделить на четыре категории: регистры общего назначения, специальные регистры для приложений, сегментные регистры и специальные регистры режима ядра. Здесь нас будут интересовать прежде всего регистры общего назначения (general-purpose registers), которые в основном и используются в приложениях на ассемблере.
Начнем с того, что процессор архитектуры x86 имел восемь 32-битных регистров общего назначения, регистр флагов и указатель инструкций. Регистры общего назначения:
EAX (Accumulator): для арифметических операций
ECX (Counter): для хранения счетчика цикла
EDX (Data): для арифметических операций и операций ввода-вывода
EBX (Base): указатель на данные
ESP (Stack pointer): указатель на верхушку стека
EBP (Base pointer): указатель на базу стека внутри функции
ESI (Source index): указатель на источник при операциях с массивом
EDI (Destination index): указатель на место назначения в операциях с массивами
EIP: указатель адреса следующей инструкции для выполнения
EFLAGS: регистр флагов, содержит биты состояния процессора
Можно получить доступ к частям 32-битных регистров с меньшей разрядностью. Например, младшие 16 бит 32-битного регистра EAX обозначаются как AX. К регистру AX можно обращаться как к отдельным байтам, используя имена AH (старший байт) и AL (младший байт).
В архитектуре х64 эти регистры были расширены до 64 бит, а новые расширенные регистры получили имена, которые начинаются с буквы R, например,
RAX
, RBX
и т.д. Кроме того, были добавлены 8 новых 64-битных регистров R8 - R15
Для обращения к 32-, 16- и 8-битной части 64-разрядных регистров используются стандартные для архитектуры x86 имена регистров. Для доступа к подрегистрам новых 64-битных регистров R8 - R15 применяется соответствующий суффикс:
D: для получения младших 32 бит регистра, например, R11D
W: для получения младших 16 бит регистра, например, R11W
B: для получения младших 8 бит регистра, например, R11B
Таким образом, в архитектуре x86-64 мы можем использовать следующие регистры общего пользования:
Шестнадцать 64-разрядных регистров RAX, RBX, RCX, RDX, RSI, RDI, RBP, RSP, R8, R9, R10, R11, R12, R13, R14 и R15
Шестнадцать 32-разрядных регистров EAX, EBX, ECX, EDX, ESI, EDI, EBP, ESP, R8D, R9D, R10D, R11D, R12D, R13D, R14D и R15D
Шестнадцать 16-разрядных регистров AX, BX, CX, DX, SI, DI, BP, SP, R8W, R9W, R10W, R11W, R12W, R13W, R14W и R15W
Шестнадцать 8-разрядных регистров AL, AH, BL, BH, CL, CH, DL, DH, DIL, SIL, BPL, SPL, R8B, R9B, R10B, R11B, R12B, R13B, R14B и R15B
Например, запись в часть 64-битного регистра, например в регистр AL, влияет только на биты этой части. В случае AL загрузка 8-битного значения изменяет младшие 8 битов RAX, оставляя остальные 48 бит без изменений.
Хотя эти регистры и называются общего назначения, но это не значит, что их можно использовать для любых целей. Все регистры x86-64 имеют свое особое назначение, которое ограничивает их использование в определенных контекстах.
Регистр флагов RFLAGS, содержит биты состояния процессора:
Бит | Имя | назначение |
0 | CF | Флаг переноса (Carry flag):казывает, был ли при сложении перенос или заимствование при вычитании. Используется в качестве входных данных для инструкций сложения и вычитания. |
2 | PF | Флаг четности: устанавливается, если младшие 8 битов результата содержат четное число единиц. |
4 | AF | Флаг настройки: указывает, был ли при сложении перенос или заимствование при вычитании младших 4 битов. |
6 | ZF | Флаг нуля (Zero flag): устанавливается, если результат операции равен нулю |
7 | SF | Флаг знака (Sign flag): устанавливается, если результат операции отрицательный. |
8 | TF | Флаг прерывания выполнения (Trap flag): используется при одношаговой отладке. |
9 | IF | Флаг разрешения прерывания: установка этого бита разрешает аппаратные прерывания. |
10 | DF | Флаг направления: контролирует направление обработки. Если не установлен, то порядок от самого младшего до самого старшего адреса. Если установлен, то порядок обратный - от самого старшего до самого младшего адреса. |
11 | OF | Флаг переполнения (Overflow flag): если устанавлен, то операция привела к переполнению со знаком. |
12-13 | IOPL | Уровень привилегий ввода-вывода (I/O privilege level): уровень привилегий текущего выполняемого потока. IOPL 0 — это режим ядра, а 3 — пользовательский режим. |
14 | NT | Флаг вложенной задачи (Nested task flag): управляет цепочкой прерываний. |
16 | RF | Флаг возобновления (Resume flag): используется для обработки исключений во время отладки. |
17 | VM | Флаг режима виртуальной машины 8086: если установлен, режим совместимости с 8086 активен. Этот режим позволяет запускать некоторые приложения MS-DOS в контексте операционной системы в защищенном режиме. |
18 | AC | Флаг проверки выравнивания (Alignment check flag): если установлен, проверка выравнивания памяти активна. Например, если установлен флаг AC, сохранение 16-битного значения по нечетному адресу вызывает исключение проверки выравнивания. Процессоры x86 могут выполнять невыровненный доступ к памяти, когда этот флаг не установлен, но количество требуемых командных циклов может увеличиться. |
19 | VIF | Флаг виртуального прерывания (Virtual interrupt flag): виртуальная версия флага IF в виртуальном режиме 8086.. |
20 | VIP | Флаг ожидания виртуального прерывания: Устанавливается, когда прерывание находится в состоянии ожидания в виртуальном режиме 8086. |
21 | ID | Флаг ID: если этот бит установлен, то поддерживается инструкция cpuid. Эта инструкция возвращает идентификатор процессора и информацию о его функциях. |
Основными являются флаги переноса, нуля, знака и переполнения, которые называют флагами состояния. Как видно, не все биты из 64-х разрядного регистра флагов имеют назначение. Неуказанные биты не используются.
В дополнение к регистрам общего назначения x86-64 предоставляет регистры специального назначения, в том числе восемь регистров для работы с числами с плавающей точкой, реализованных в модуле x87 с плавающей точкой (floating-point unit или FPU). Intel назвала эти регистры ST0 - ST7. Каждый регистр с плавающей точкой имеет ширину 80 бит. В отличие от регистров общего назначения обычная пользовательская программа не может получить к ним прямой доступ.
Также есть шестнадцать 128-битных регистров XMM (XMM0 - XMM15) и набор инструкций SSE/SSE2. Каждый регистр можно настроить как четыре 32-битных регистра с плавающей точкой; два 64-битных регистра двойной точности с плавающей точкой; или шестнадцать 8-битных, восемь 16-битных, четыре 32-битных, два 64-битных или один 128-битный целочисленный регистр. В более поздних вариантах семейства процессоров x86-64 AMD/Intel удвоили размер регистров до 256 бит каждый (переименовав их в YMM0-YMM15), добавив поддержки восьми 32-битных значений с плавающей точкой или четырех 64-битных значений с плавающей точкой двойной точности. (целочисленные операции по-прежнему ограничивались 128 битами).