Архитектура 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

Аль

Низкий 8 бит eax

ah

Высокий 8 бит топор

Bl

Низкий 8 бит ebx

Bh

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

Cl

Низкий 8 бит ecx

ch

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

Dl

Низкий 8 бит edx

Dh

High 8 bits of dx

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

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

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

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

Eip

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

flags

flags

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

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

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

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

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

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

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

  • Win32 (__stdcall)

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

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

    Параметры функции передаются в стек, отправляются справа налево, указатель "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 updn Направление вверх — направление вниз
if (если); Флаг прерывания 0 1 diei Прерывания отключены — прерывания включены
Sf Флаг подписи 0 1 г. Положительный (или нулевой) — отрицательный
Zf Нулевой флаг 0 1 nzzr Ненулевое — ноль
Af Флаг вспомогательной переноски 0 1 naac Вспомогательная переноска отсутствует - Вспомогательная переноска
pf Флаг четности 0 1 pepo Нечетный четность — четность
Cf Перенос флага 0 1 nccy Без перевозки - Carry
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

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

S

SF=1

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

NS

SF=0

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

O

OF=1

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

NO

OF=0

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

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

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

E

ZF=1

value1 == value2.

NE

ZF=0

value1 != value2.

GE NL

SF=OF

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

LE NG

ZF=1 или SF!=OF

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

G NLE

ZF=0 и SF=OF

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

L NGE

SF!=OF

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

AE NB

CF=0

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

BE NA

CF=1 или ZF=1

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

A NBE

CF=0 и ZF=0

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

B NAE

CF=1

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

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

cmp eax, 5
jz equal

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

Типы данных

  • байт: 8 бит

  • word: 16 бит

  • dword: 32 бита

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

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

  • oword: 128 бит

Нотации

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

Notation Значение

r, r1, r2...

Регистры

m

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

#n

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

r/m

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

r/#n

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

r/m/#n

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

См3

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

T

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

accT

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

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

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

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

Конвейеризация

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

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

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

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

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

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

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

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

Прогнозирование перехода

Прогнозируются безусловные скачки.

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

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

Трассы

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

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

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