Архитектура 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-разрядные подрегистры.
топор |
Низкий 16 бит eax |
bx |
Низкий 16 бит ebx |
cx |
Низкий 16 бит эккса |
dx |
Низкий 16 бит edx |
си |
Низкий 16 бит esi |
ди |
Низкий 16 бит эди |
bp |
Низкий 16 бит ebp |
sp |
Низкий 16 бит esp |
Аль |
Низкий 8 бит eax |
ah |
Высокие 8 битов оси |
BL |
Низкий 8 бит ebx |
bh |
Высокий 8 бит bx |
cl |
Низкие 8 бит эккса |
ch |
Высокий 8 бит cx |
dl |
Низкий 8 бит эдкса |
dh |
Высокие 8 бит dx |
Работа с подрегистером влияет только на подрегистр и ни одну из частей за пределами подрегистрастра. Например, хранение в регистре оси оставляет высокие 16 битов регистра eax без изменений.
При использовании ? (Вычислять выражение) команда, регистры должны быть префиксированы знаком at ( @ ). Например, следует использовать ? @axа не топор. Это гарантирует, что отладчик распознает оси как регистр, а не символ.
Однако в команде r (Registers) не требуется (@). Например, r ax=5 всегда будет интерпретироваться правильно.
Два других регистра важны для текущего состояния процессора.
eip |
указатель инструкций |
flags |
flags |
Указатель инструкции — это адрес выполняемой инструкции.
Регистрация флагов — это коллекция однобитовых флагов. Многие инструкции изменяют флаги, чтобы описать результат инструкции. Затем эти флаги можно проверить с помощью инструкций условного перехода. Дополнительные сведения см. в разделе флагов 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:
Код флага | Имя флага | Значение | Состояние флага | Description |
---|---|---|---|---|
из | Флаг переполнения | 0 1 | nvov | Нет переполнения — переполнение |
df | Флаг направления | 0 1 | updn | Направление вверх — направление вниз |
if | Флаг прерывания | 0 1 | diei | Прерывания отключены— включенные прерывания |
sf | Флаг подписи | 0 1 | гигг | Положительный (или нулевой) — отрицательный |
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 |
Результат последней операции равен нулю. |
Новая Зеландия |
ZF=0 |
Результат последней операции не был нулевым. |
C |
CF=1 |
Последняя операция требует переноса или заимствования. (Для целых чисел без знака это означает переполнение.) |
NC |
CF=0 |
Последняя операция не требовала переноса или заимствования. (Для целых чисел без знака это означает переполнение.) |
S |
SF=1 |
Результат последней операции имеет свой высокий битовый набор. |
NS |
SF=0 |
Результат последней операции имеет свой высокий бит ясно. |
O |
OF=1 |
При обработке как операции со знаком целочисленного числа последняя операция вызвала переполнение или переполнение. |
Нет |
OF=0 |
При обработке как операции со знаком целочисленного числа последняя операция не приводила к переполнению или переполнению. |
Условия также можно использовать для сравнения двух значений. Инструкция cmp сравнивает два операнда, а затем задает флаги, как если бы вычитали один операнд из другого. Следующие условия можно использовать для проверки результата cmp value1, value2.
Название условия | Флаги | Значение после операции CMP. |
---|---|---|
E |
ZF=1 |
value1 == value2. |
NE |
ZF=0 |
value1 != value2. |
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 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 будет true, поэтому переход будет принят.
Типы данных
байт: 8 бит
word: 16 бит
dword: 32 бита
qword: 64 бита (включает в себя двойные точки с плавающей запятой)
tword: 80 бит (включает расширенные двойные точки с плавающей запятой)
oword: 128 бит
Нотация
В следующей таблице указывается нотация, используемая для описания инструкций языка сборки.
Представление | Значение |
---|---|
r, r1, r2... |
Регистры |
m |
Адрес памяти (дополнительные сведения см. в разделе об успешном режиме адресации.) |
№ n |
Немедленная константа |
r/m |
Регистрация или память |
r/#n |
Регистрация или немедленная константа |
r/m/#n |
Регистрация, память или немедленная константа |
кубовый |
Код условия, указанный в предыдущем разделе условий. |
T |
"B", "W" или "D" (байт, слово или dword) |
accT |
Размер аккумулятора T: al if T = "B", ax if T = "W" или eax if T = "D" |
Режимы адресации
Существует несколько различных режимов адресации, но все они принимают форму T ptr [expr], где T является некоторым типом данных (см. предыдущий раздел типов данных) и экспр является некоторым выражением, включающим константы и регистры.
Нотация для большинства режимов может быть выведена без большой сложности. Например, BYTE PTR [esi+edx*8+3] означает "принять значение регистра esi , добавить в него восемь раз значение регистра edx , добавить три, а затем получить доступ к байту в результирующем адресе".
Организация конвейера
Эта функция является двойной проблемой, что означает, что она может выполнять до двух действий в одном часовом тике. Однако правила о том, когда он способен выполнять два действия одновременно (известное как связывание), очень сложны.
Так как x86 является процессором CISC, вам не нужно беспокоиться о слотах задержки прыжков.
Синхронизированный доступ к памяти
Инструкции по загрузке, изменению и хранению могут получать префикс блокировки , который изменяет инструкцию следующим образом:
Перед выдачой инструкции ЦП будет очищать все ожидающие операции памяти, чтобы обеспечить совместную работу. Все предварительные выборки данных отказались.
При выполнении инструкции ЦП будет иметь эксклюзивный доступ к шине. Это гарантирует атомарность операции загрузки и изменения или хранения.
Инструкция xchg автоматически подчиняется предыдущим правилам при обмене значением с памятью.
Все остальные инструкции по умолчанию не блокировать.
Прогнозирование перехода
Безусловные скачки прогнозируются.
Условные прыжки прогнозируются для того, чтобы приниматься или не приниматься, в зависимости от того, были ли они взяты в последний раз, когда они были выполнены. Кэш для записи журнала переходов ограничен размером.
Если ЦП не имеет записи о том, был ли выполнен условный переход или не использовался последний раз, он прогнозирует обратные условные прыжки, как взятые и вперед условные прыжки, как не принятые.
Выравнивание
Процессор x86 автоматически исправит неуправляемый доступ к памяти при штрафе производительности. Исключение не возникает.
Доступ к памяти считается выровненным, если адрес является целым числом, кратным размером объекта. Например, все доступы BYTE выравниваются (все целое число кратно 1), доступ WORD к даже адресам выравнивается, и DWORD-адреса должны быть несколькими из 4, чтобы быть выровненными.
Префикс блокировки не должен использоваться для неуправляемого доступа к памяти.