Поделиться через


Архитектура x86

Процессор Intel x86 использует архитектуру сложного набора инструкций (CISC), что означает, что существует скромное количество регистров специального назначения вместо большого количества регистров общего назначения. Это также означает, что сложные инструкции специального назначения будут преобладать.

Процессор x86 трассирует свое наследие по крайней мере до 8-разрядного процессора Intel 8080. Многие особенности в наборе инструкций x86 обусловлены обратной совместимостью с этим процессором (и с его вариантом Zilog Z-80).

Microsoft Win32 использует процессор x86 в 32-разрядном плоском режиме. Эта документация будет сосредоточена только на неструктурированном режиме.

РегистрЫ

Архитектура x86 состоит из следующих непривилегированных целых регистров.

eax

Аккумулятор

ebx

Базовый регистр

ecx

Регистр счетчика

edx

Регистр данных — можно использовать для доступа к портам ввода-вывода и арифметических функций

esi

Регистр исходного индекса

edi

Регистр индекса назначения

ebp

Базовый регистр указателя

esp

Указатель стека

Все целые регистры имеют 32 бита. Однако многие из них имеют 16-разрядные или 8-разрядные подрегистры.

ax

Младшие 16 битов eax

bx

Низкий 16 бит ebx

cx

Нижние 16 бит ecx

dx

Младшие 16 бит edx

si

Младшие 16 битов esi

di

Младшие 16 биты edi

bp

Низкий 16 бит ebp

sp

Низкие 16 битов esp

al

Низкие 8 битов eax

ах

Высокие 8 битов регистра ax

бл

Низкие 8 битов ebx

bh

Высокий 8 бит bx

cl

Низкие 8 битов ecx

ч

Высокий 8 бит cx

dl

Низкие 8 битов edx

dh

Высокие 8 бит dx

Работа с подрегистром влияет только на подрегистр и ни на одну из частей за пределами подрегистра. Например, хранение в регистра оставляет высокие 16 битов eax без изменений.

При использовании команды ? (Вычисление выражения), регистры должны быть префиксированы знаком '@' (@). Например, следует использовать ? @ax вместо ? ax. Это гарантирует, что отладчик распознает ax как регистр, а не символ.

Однако (@) не требуется в команде r (Registers). Например, r ax=5 всегда будет интерпретироваться правильно.

Два других регистра важны для текущего состояния процессора.

eip

указатель инструкций

флаги

Флаги

Указатель инструкции — это адрес выполняемой инструкции.

Регистр флагов — это набор однобитовых флагов. Многие инструкции изменяют флаги, чтобы описать результат инструкции. Затем эти флаги можно проверить с помощью инструкций условного перехода. Дополнительные сведения см. в флагах x86.

Соглашения о вызовах

Архитектура x86 имеет несколько различных способов вызова. К счастью, все они следуют тем же правилам сохранения регистра и возврата функции.

  • Функции должны сохранять все регистры, за исключением eax, ecxи edx, которые могут быть изменены в вызове функции, и esp, который должен обновляться в соответствии с соглашением о вызове.

  • eax регистр получает возвращаемые значения функции, если результат равен 32 битам или меньше. Если результат равен 64 битам, результат хранится в паре edx:eax.

Ниже приведен список соглашений о вызовах, используемых в архитектуре x86:

  • Win32 (__stdcall)

    Параметры функции передаются в стек, отправляются справа влево, а вызывающий объект очищает стек.

  • Вызов метода Native C++ (также известный как этот вызов)

    Параметры функции передаются в стек, заносятся справа налево, указатель "this" передается в регистре ecx, а вызываемая функция очищает стек.

  • COM (__stdcall для вызовов методов C++

    Параметры функции передаются в стек, перенаправляются справа влево, а затем указатель "this" отправляется в стек, а затем вызывается функция. Вызываемая функция очищает стек.

  • __fastcall

    Первые два аргумента DWORD или меньшего размера передаются в регистры ecx и edx. Остальные параметры передаются через стек, помещаются в порядке справа налево. Вызывающий объект очищает стек.

  • __cdecl

    Параметры функции передаются в стек, отправляются справа влево, а вызывающий объект очищает стек. Соглашение о вызове __cdecl используется для всех функций с параметрами переменной длины.

Отображение регистров и флагов в отладчике

Ниже приведен пример отображения регистра отладчика:

eax=00000000 ebx=008b6f00 ecx=01010101 edx=ffffffff esi=00000000 edi=00465000
eip=77f9d022 esp=05cffc48 ebp=05cffc54 iopl=0         nv up ei ng nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=0038  gs=0000             efl=00000286

При отладке в пользовательском режиме можно игнорировать iopl и всю последнюю строку отображения отладчика.

Флаги x86

В предыдущем примере двухбуквенный код в конце второй строки флаги. Это однобитовые регистры и могут использоваться по-разному.

В следующей таблице перечислены флаги x86:

Код флага Имя флага Ценность Состояние флага Описание
из Флаг переполнения 0 1 nvov Нет переполнения — переполнение
df Флаг направления 0 1 вверх/вниз Направление вверх — направление вниз
, если Флаг прерывания 0 1 diei Отключены прерывания — включены прерывания
sf Сигнальный флаг 0 1 plng Положительный (или нулевой) — отрицательный
zf Нулевой флаг 0 1 nzzr Nonzero - Zero
af Вспомогательный флаг 0 1 naac Отсутствие вспомогательного переноса - Вспомогательный перенос
pf Флаг четности 0 1 pepo Чётность нечётная — Чётность чётная
cf Флаг переноски 0 1 nccy Нет переноса - Перенос
tf Флаг ловушки Если tf равно 1, процессор вызовет исключение STATUS_SINGLE_STEP после выполнения одной инструкции. Этот флаг используется отладчиком для реализации одношаговой трассировки. Он не должен использоваться другими приложениями.
iopl Уровень привилегий ввода-вывода Уровень привилегий ввода-вывода — это двух битовое целое число с значениями от нуля до 3. Она используется операционной системой для управления доступом к оборудованию. Его не следует использовать приложениями.

Когда регистры отображаются в результате выполнения некоторой команды в окне команд отладчика, отображается состояние флага . Однако если вы хотите изменить флаг с помощью команды r (Registers), следует ссылаться на него с помощью кода флага .

В окне "Регистры" WinDbg код флага используется для просмотра или изменения флагов. Состояние флага не поддерживается.

Ниже приведен пример. В предыдущем регистре отображается состояние флагов ng. Это означает, что флаг знака в настоящее время имеет значение 1. Чтобы изменить это, используйте следующую команду:

r sf=0

При этом флаг знака равен нулю. Если вы выполните другое регистровое отображение, код состояния ng не будет. Вместо этого отобразится код состояния pl.

Флаг знака, нулевой флаг и флаг переноски являются наиболее часто используемыми флагами.

Условия

Условие описывает состояние одного или нескольких флагов. Все условные операции x86 выражаются с точки зрения условий.

Ассемблер использует одну или две буквы в виде аббревиатуры для представления условия. Условие может быть представлено несколькими аббревиациями. Например, AE ("выше" или "равно") совпадает с условием NB ("не ниже"). В следующей таблице перечислены некоторые распространенные условия и их значение.

Имя условия Флаги Значение

Z

ZF=1

Результат последней операции равен нулю.

NZ

ZF=0

Результат последней операции не был нулевым.

C

CF=1

Последняя операция требовала переноса или заимствования. (Для целых чисел без знака это означает переполнение.)

NC

CF=0

Последняя операция не требовала переноса или заимствования. (Для целых чисел без знака это означает переполнение.)

С

SF=1

Результат последней операции имеет свой высокий битовый набор.

NS

SF=0

Результат последней операции имеет свой высокий бит ясно.

O

OF=1

При обработке как операции со знаком целочисленного числа последняя операция вызвала переполнение или переполнение.

НЕТ

OF=0

При обработке как знаковой целочисленной операции, последняя операция не приводила к переполнению или выходу за пределы.

Условия также можно использовать для сравнения двух значений. Инструкция cmp сравнивает два операнда, а затем задает флаги, как если бы вычитали один операнд из другого. Следующие условия можно использовать для проверки результата cmpvalue1, value2.

Имя условия Флаги Значение после операции CMP.

E

ZF=1

value1 == value2.

NE

ZF=0

значение1 != значение2.

GE NL

SF=OF

value1>= value2. Значения обрабатываются как целые числа со знаком.

LE NG

ZF=1 или SF!=OF

value1<= value2. Значения обрабатываются как целые числа со знаком.

G NLE

ZF=0 и SF=OF

value1>value2. Значения обрабатываются как целые числа со знаком.

L NGE

SF!=OF

value1<value2. Значения обрабатываются как целые числа со знаком.

AE NB

CF=0

value1>= value2. Значения обрабатываются как целые числа без знака.

BE NA

CF=1 или ZF=1

value1<= value2. Значения обрабатываются как целые числа без знака.

A НБЕ

CF=0 и ZF=0

value1>value2. Значения обрабатываются как целые числа без знака.

B NAE

CF=1

value1<value2. Значения обрабатываются как целые числа без знака.

Условия обычно используются для действия на результат инструкции cmp или test. Например

cmp eax, 5
jz equal

сравнивает eax регистр с числом 5 путем вычисления выражения (eax - 5) и задания флагов в соответствии с результатом. Если результат вычитания равен нулю, то будет установлен флаг zr, и условие jz выполнится, поэтому будет произведён переход.

Типы данных

  • байт: 8 бит

  • слово: 16 бит

  • dword: 32 бита

  • qword: 64 бита (включает в себя двойные точки с плавающей запятой)

  • tword: 80 бит (включает расширенные двойные числа с плавающей запятой)

  • oword: 128 бит

Нотация

В следующей таблице указывается нотация, используемая для описания инструкций языка сборки.

Нотация Значение

r, r1, r2...

Регистры

m

Адрес памяти (дополнительные сведения см. в следующем разделе о режимах адресации.)

#n

Немедленная константа

r/m

Регистр или память

r/#n

Регистр или немедленная константа

r/m/#n

Регистрация, память или немедленная константа

cc

Код условия, указанный в предыдущем разделе условий.

T

"B", "W" или "D" (байт, слово или двойное слово)

accT

Размер T аккумулятор: al, если T = "B", ax, если T = "W", или eax, если T = "D"

Режимы адресации

Существует несколько различных режимов адресации, но все они принимают форму T ptr [expr], где T является некоторым типом данных (см. предыдущий раздел "Типы данных") и экспр является некоторым выражением, включающее константы и регистры.

Нотация для большинства режимов может быть выведена без большой сложности. Например, BYTE PTR [esi+edx*8+3] означает "взять значение регистра esi, прибавить к нему значение регистра edx, умноженное на восемь, добавить три, а затем получить доступ к байту в результирующем адресе".

Организация конвейера

Pentium обладает двусопроводительной архитектурой, что означает, что он может выполнять до двух операций за один тактовый цикл. Однако правила, определяющие, когда он способен выполнять два действия одновременно (называемые пара), очень сложны.

Поскольку x86 является процессором CISC, вам не нужно беспокоиться о слотах задержки переходов.

Синхронизированный доступ к памяти

Инструкции по загрузке, изменению и хранению могут получать префикс блокировки , который изменяет инструкцию следующим образом:

  1. Перед выдачей инструкции ЦП выполнит очистку всех ожидающих операций памяти, чтобы обеспечить согласованность. Все предварительные выборки данных отменены.

  2. При выполнении инструкции ЦП будет иметь эксклюзивный доступ к шине. Это гарантирует атомарность операции загрузки и изменения или хранения.

Инструкция xchg автоматически подчиняется предыдущим правилам при обмене значением с памятью.

Все остальные инструкции по умолчанию не блокировать.

Прогнозирование прыжка

Ожидается, что безусловные переходы будут выполнены.

Условные переходы прогнозируются как совершаемые или не совершаемые в зависимости от того, были ли они выполнены в последний раз их выполнения. Кэш для записи журнала переходов ограничен размером.

Если в ЦПУ нет записи о том, был ли выполнен условный переход или не был выполнен последний раз, он прогнозирует обратные условные переходы как выполненные, а прямые условные переходы как невыполненные.

Выравнивание

Процессор x86 автоматически исправит несогласованный доступ к памяти с потерей производительности. Исключение не возникает.

Доступ к памяти считается выровненным, если адрес является целым числом, кратным размером объекта. Например, все доступы BYTE выравниваются (все целое число кратно 1), доступ WORD к даже адресам выравнивается, и DWORD-адреса должны быть несколькими из 4, чтобы быть выровненными.

Префикс блокировки не следует использовать для невыравненных доступов к памяти.

См. также

x64 архитектура

X86-64 Википедия