Регистр
Регистр
Внутри микросхемы центрального процессора (CPU) имеются ячейки памяти, которые и называются регистрами, они еще могут называться сверх-оперативной памятью (СОЗУ - сверхоперативное запоминающее устройство). Так как регистры находятся прямо внутри процессора, скорость доступа к ним значительно выше, чем к обычно оперативной памяти, однако их объем составляет лишь единицы байт, поэтому процессором регистры используются для выполнения простейших операций, как то арифметические и логические операции, также имеются регистры, в которых хранятся адреса оперативной памяти с которыми оперирует процессор (адрес стека в регистре ESP, адрес текущей выполняемой процессором команды в регистре EIP и так далее)
Регистры процессора
Постоянно происходит технический прогресс и особенно разработка компьютеров не стоит на месте, совсем недавно лучшими были 8 битные процессоры, а последнее время речь идёт уже о 64 битных. Но в данный момент (2011 год) нас больше всего интересуют 32 битные процессоры, которые содержат 32 битные регистры.
Битность процессора напрямую связана с битностью регистров и их аббревиатурой, поэтому:
AX, CX, SP, IP, ... - харакетризуют 16 битные регистры EAX, ECX, ESP, EIP, ... - 32 битные (добавляется буква E от англ. enchanced - "расширенный") RAX, RCX, RSP, RIP, ... - 64 битные (добавляется буква R)
Существуют следующие типы регистров:
- Регистры общего назначения (РОН) - EAX, EBX, ECX, EDX, ESI, EDI, EBP, ESP
- Регистр-указатель команд - EIP
- Регистр флагов - EFL (EFLAGS)
- Сегментные регистры - SS, CS, DS, ES
Описание регистров
Регистры общего назначения (РОН) служат для хранения промежуточных вычислений.
- RAX, RCX, RDX, RBX, RSP, RBP, RSI, RDI, R8 — R15 — 64-битные
- EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI, R8D — R15D — 32-битные (extended AX)
- AX, CX, DX, BX, SP, BP, SI, DI, R8W — R15W — 16-битные
- AH, AL, CH, CL, DH, DL, BH, BL, SPL, BPL, SIL, DIL, R8B — R15B — 8-битные (половинки 16-ти битных регистров)
например, AH — high AX — старшая половинка 8 бит AL — low AX — младшая половинка 8 бит
RAX | RCX | RDX | RBX | ||||||||||||||||||||||||||||
EAX | ECX | EDX | EBX | ||||||||||||||||||||||||||||
AX | CX | DX | BX | ||||||||||||||||||||||||||||
AH | AL | CH | CL | DH | DL | BH | BL |
RSP | RBP | RSI | RDI | Rx | |||||||||||||||||||||||||||||||||||
ESP | EBP | ESI | EDI | RxD | |||||||||||||||||||||||||||||||||||
SP | BP | SI | DI | RxW | |||||||||||||||||||||||||||||||||||
SPL | BPL | SIL | DIL | RxB |
где x — 8..15.
Регистры RAX, RCX, RDX, RBX, RSP, RBP, RSI, RDI, Rx, RxD, RxW, RxB, SPL, BPL, SIL, DIL доступны только в 64-битном режиме работы процессора.
Часто используемые расшифровки
- EAX - регистр-аккумулятор
- ECX - регистр-счетчик (при выполнение циклов)
- ESI - [SI = Source Index] (указывает на адрес-источник при строковых операциях)
- ESI - [DI = Destination Index] (указывает на адрес-приёмник при строковых операциях)
- EIP - [IP = Instruction Pointer]
Регистр флагов FLAGS (16 бит) / EFLAGS (32 бита) / RFLAGS (64 бита) — содержит текущее состояние процессора.
Регистром называется функциональный узел, осуществляющий приём, хранение и передачу информации. Регистры состоят из группы триггеров, обычно D. По типу приёма и выдачи информации различают 2 типа регистров:
- С последовательным приёмом и выдачей информации — сдвиговые регистры.
- С параллельным приёмом и выдачей информации — параллельные регистры.
Сдвиговые регистры представляют собой последовательно соединённую цепочку триггеров. Основной режим работы — сдвиг разрядов кода от одного триггера к другому на каждый импульс тактового сигнала.
По назначению регистры различаются на:
- аккумулятор — используется для хранения промежуточных результатов арифметических и логических операций и инструкций ввода-вывода;
- флаговые — хранят признаки результатов арифметических и логических операций;
- общего назначения — хранят операнды арифметических и логических выражений, индексы и адреса;
- индексные — хранят индексы исходных и целевых элементов массива;
- указательные — хранят указатели на специальные области памяти (указатель текущей операции, указатель базы, указатель стека);
- сегментные — хранят адреса и селекторы сегментов памяти;
- управляющие — хранят информацию, управляющую состоянием процессора, а также адреса системных таблиц.
Сегментные регистры — Регистры указывающие на сегменты.
CS (Code Segment), DS (Data Segment), SS (Stack Segment), ES, FS, GS
В реальном режиме работы процессора сегментные регистры содержат адрес начала 64Kb сегмента, смещенный вправо на 4 бита.
В защищенном режиме работы процессора сегментные регистры содержат селектор сегмента памяти, выделенного ОС.
CS — указатель на кодовый сегмент. Связка CS:IP (CS:EIP/CS:RIP — в защищенном/64-битном режиме) указывает на адрес в памяти следующей команды.
Счётчик команд
IP
IP — регистр, содержащий адрес-смещение следующей команды, подлежащей исполнению, относительно кодового сегмента CS в процессорах семейства x86.
Регистр IP связан с CS в виде CS:IP, где CS является текущим кодовым сегментом, а IP — текущим смещением относительно этого сегмента.
Регистр IP является 16-разрядным регистром-указателем. Кроме него, в состав регистров этого типа входят SP (Stack Pointer — указатель стека) и BP (Base Pointer — базовый указатель).
- Принцип работы
Например, CS содержит значение 2CB5[0]H
, в регистре IP хранится смещение 123H
.
Адрес следующей инструкции, подлежащей исполнению, вычисляется путем суммирования адреса в CS (сегменте кода) со смещением в регистре IP:
-
2CB50H + 123H = 2CC73H
Таким образом, адрес следующей инструкции для исполнения равен 2CC73H
.
При выполнении текущей инструкции процессор автоматически изменяет значение в регистре IP, в результате чего регистровая пара CS:IP всегда указывает на следующую подлежащую исполнению инструкцию.
EIP
Начиная с процессора 80386 была введена 32-разрядная версия регистра-указателя — EIP. В данном случае IP является младшей частью этого регистра (первые 16 разрядов). Принцип работы EIP в целом схож с работой регистра IP. Основная разница состоит в том, что в защищённом режиме, в отличие от реального режима, регистр CS является селектором (селектор указывает не на сам сегмент в памяти, а на его дескриптор сегмента в таблице дескрипторов).
Смерть и возрождение сегментной модели организации памяти
Разрабатывая архитектуру x86-64, инженеры корпорации AMD решили навсегда покончить с главным «рудиментом» архитектуры x86 — сегментной моделью памяти, которая передавалась по наследству ещё со времён 8086. Однако, как потом оказалось, они очень погорячились. Архитектура стала абсолютно невиртуализируемой. При разработке новой версии своего продукта для виртуализации программисты компании VMWare столкнулись с непреодолимыми трудностями при реализации 64-битной виртуальной машины. Поскольку, для отделения кода монитора от кода «гостя» программой использовался механизм сегментации, эта задача стала практически неразрешимой. Осознав свою ошибку, AMD вернула ограниченный вариант сегментной организации памяти начиная с ревизии D архитектуры AMD64, что позволило запускать 64-битные ОС в виртуальных машинах. Intel, однако, этому примеру не последовала, и поэтому ни на одном её процессоре, не поддерживающем средства аппаратной виртуализации, запустить 64-битную виртуальную машину нельзя. С целью проверки того, возможен ли на данном процессоре запуск 64-битных гостевых ОС или нет, VMWare предоставляет вместе со своими продуктами специальную утилиту. Также следует отметить, что первоначально попавшие «под нож» команды LAHF и SAHF, которые также активно используются ПО виртуализации, затем также были возвращены в систему команд. С распространением средств аппаратной виртуализации потребность в сегментации вновь постепенно отпадет.
Есть ли разница какие регистры использовать?
На этот вопрос нельзя ответить однозначно, все зависит от конкретного случая. Например если функция берет значение для какой-то своей работы из регистра eax (это только к примеру), то, если мы положим это значение в регистр ecx, функция об этом не узнает, и все равно возьмет значение из регистра eax. А что там будет лежать, если мы поместили нужное значение не в eax, а в ecx, только одному Богу известно. Но вот другой пример:
mov eax, address_of_function call eax
В этом случае (если адрес функции помещается в eax только для того, чтобы сделать вызов этой функции и для примера значение регистра ebx в этот момент не нужно) то можно написать и так:
mov ebx, address_of_function call ebx
Чем отличается регистр eax от ax?
eax = Extended ax, т.е. расширенный регистр ax. eax, в отличие от ax, является 32-х разрядным регистром (ax - 16-ти разрядный регистр, хранит в себе 2 байта), т.е. способен хранить в себе 4 байта. ax является младшей частью регистра eax, т.е., при изменении регистра ax, регистр eax тоже будет меняться. Аналогичное ситуация и с другими регистрами (ebx, ecx, edx, esp, ebp и т.д.)
А что значит младшая часть?
Регистр eax (беру eax просто для примера) является 32-х разрядным. Если представить его значение в двоичной системе счисления как последовательность из 32-х нулей и единиц, то, если взять правые 16 бит подряд, это и будет младшая часть регистра eax, которая будет определять значение регистра ax. Левые 16 бит подряд - это старшая часть регистра eax. Аналогично, 16-ти разрядный регистр ax делится на регистр ah и al, которые соответственно являются старшей и младшей частями регистра ax. Также регистр ebx (ecx, edx тоже) например делится на старшую часть и младшую часть. Младшая часть определяет значение регистра bx, который в свою очередь делится на bh и bl. Если вам что-то не понятно с разрядами и представлением в двоичной (и других) системе счисления, то почитайте про системы счисления.
Как найти старшую часть расширенного регистра (eax, ebx, ..., esi, edi)?
Предлагаю два способа:
1) Например надо найти старшую часть регистра esi и поместить ее в ax. Это достигается следующей парой команд:
mov eax, esi <--- Помещаем esi в eax shr eax, 10h <--- Сдвигаем биты eax на 16 разрядов вправо.
Поясняю. Старшая часть регистра eax - это его левые (старшие) 16 разрядов. Если мы эти 16 разрядов сдвинем влево на 16 позиций, то они окажутся как раз на месте, где до этого были правые (младшие) 16 разрядов, т.е. в регистре ax. Все!
2) Например надо найти старшую часть регистра ebx. Для этого пишем:
rol ebx, 10h
После этого все разряды регистра ebx сдвинутся по кругу на 16 позиций вправо. Старшие 16 разрядов окажутся на месте младших 16 разрядов. А младшие 16 разрядов окажутся на месте старших =) Аналогично, в регистре bx окажется старшая часть предыдущего состояния регистра ebx. Надеюсь понятно =)