Архитектура 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, вам не нужно беспокоиться о слотах задержки перехода.
Синхронизированный доступ к памяти
Инструкции по загрузке, изменению и хранению могут получить префикс блокировки , который изменяет инструкцию следующим образом:
Перед выполнением инструкции ЦП очищает все ожидающие операции с памятью, чтобы обеспечить когерентность. Все предварительные выборки данных отклоняются.
При выполнении инструкции ЦП будет иметь монопольный доступ к шине. Это обеспечивает атомарность операции загрузки, изменения и хранения.
Инструкция xchg автоматически подчиняется предыдущим правилам при обмене значениями с памятью.
Все остальные инструкции по умолчанию не блокировка.
Прогнозирование перехода
Прогнозируются безусловные скачки.
Условные скачки, по прогнозам, будут выполнены или не выполнены в зависимости от того, были ли они выполнены в последний раз. Размер кэша для записи журнала переходов ограничен.
Если ЦП не имеет записи о том, был ли выполнен условный прыжок во время последнего выполнения, он прогнозирует обратные условные прыжки как выполненные и вперед условные прыжки как не выполненные.
Трассы
Процессор x86 автоматически исправит доступ к несогласованной памяти с снижением производительности. Исключение не возникает.
Доступ к памяти считается выровненным, если адрес является целым числом, кратным размеру объекта. Например, все доступы BYTE выравниваются (все равно целое число, кратное 1), доступы WORD к четным адресам выравниваются, а адреса DWORD должны быть кратны 4 для выравнивания.
Префикс блокировки не следует использовать для доступа к несогласованной памяти.
Обратная связь
https://aka.ms/ContentUserFeedback.
Ожидается в ближайшее время: в течение 2024 года мы постепенно откажемся от GitHub Issues как механизма обратной связи для контента и заменим его новой системой обратной связи. Дополнительные сведения см. в разделеОтправить и просмотреть отзыв по