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