x86 体系结构x86 Architecture

Intel x86 处理器使用复杂的指令集计算机(CISC)体系结构,这意味着有适度数量的专用寄存器,而不是大量通用寄存器。The Intel x86 processor uses complex instruction set computer (CISC) architecture, which means there is a modest number of special-purpose registers instead of large quantities of general-purpose registers. 这也意味着复杂的特殊用途说明将主流。It also means that complex special-purpose instructions will predominate.

X86 处理器至少以8位 Intel 8080 处理器的速度跟踪其遗产。The x86 processor traces its heritage at least as far back as the 8-bit Intel 8080 processor. X86 指令集中的许多 peculiarities 是由于与该处理器的向后兼容性(及其 Zilog Z-80 变体)。Many peculiarities in the x86 instruction set are due to the backward compatibility with that processor (and with its Zilog Z-80 variant).

Microsoft Win32 在32 位平面模式下使用 x86 处理器。Microsoft Win32 uses the x86 processor in 32-bit flat mode. 本文档将仅重点介绍平面模式。This documentation will focus only on the flat mode.

寄存器Registers

X86 体系结构由以下非特权整数寄存器组成。The x86 architecture consists of the following unprivileged integer registers.

eaxeax

累加器Accumulator

ebxebx

基寄存器Base register

ecxecx

计数器注册Counter register

edxedx

数据注册-可用于 i/o 端口访问和算术函数Data register - can be used for I/O port access and arithmetic functions

esiesi

源索引寄存器Source index register

ediedi

目标索引寄存器Destination index register

ebpebp

基指针寄存器Base pointer register

能力esp

堆栈指针Stack pointer

所有整数寄存器均为32位。All integer registers are 32 bit. 但是,其中许多是16位或8位 subregisters。However, many of them have 16-bit or 8-bit subregisters.

ax150ax

低16位eaxLow 16 bits of eax

bxbx

低16位ebxLow 16 bits of ebx

cxcx

最小16位ecxLow 16 bits of ecx

dxdx

低16位edxLow 16 bits of edx

sisi

Esi的低16位Low 16 bits of esi

didi

低16位ediLow 16 bits of edi

最佳bp

最少16位ebpLow 16 bits of ebp

spsp

低16位espLow 16 bits of esp

fc-alal

低8位eaxLow 8 bits of eax

ah

Ax的高8位High 8 bits of ax

blbl

低8位ebxLow 8 bits of ebx

bhbh

高8位bxHigh 8 bits of bx

clcl

低8位ecxLow 8 bits of ecx

48ch

8位cxHigh 8 bits of cx

磁盘dl

低8位edxLow 8 bits of edx

dhdh

Dx的高8位High 8 bits of dx

对 subregister 的操作只会影响 subregister,而不会影响 subregister 以外的部分。Operating on a subregister affects only the subregister and none of the parts outside the subregister. 例如,存储到ax寄存器会使eax寄存器的高16位保持不变。For example, storing to the ax register leaves the high 16 bits of the eax register unchanged.

使用时 (计算表达式) command,寄存器应以 "at" 符号( @ )作为前缀。When using the ? (Evaluate Expression) command, registers should be prefixed with an "at" sign ( @ ). 例如,你应该使用? @ax而不是 ? axFor example, you should use ? @ax rather than ? ax. 这可确保调试器将ax识别为寄存器,而不是符号。This ensures that the debugger recognizes ax as a register rather than a symbol.

但是, r (寄存器) 命令中不需要(@)。However, the (@) is not required in the r (Registers) command. 例如, r ax = 5将始终正确解释。For instance, r ax=5 will always be interpreted correctly.

其他两个寄存器对于处理器的当前状态很重要。Two other registers are important for the processor's current state.

eipeip

指令指针instruction pointer

随意flags

flagsflags

指令指针是要执行的指令的地址。The instruction pointer is the address of the instruction being executed.

标志注册是一组单一位标志。The flags register is a collection of single-bit flags. 许多说明会改变标志来描述指令的结果。Many instructions alter the flags to describe the result of the instruction. 然后,可以通过条件跳转说明测试这些标志。These flags can then be tested by conditional jump instructions. 有关详细信息,请参阅X86 标志See x86 Flags for details.

调用约定Calling Conventions

X86 体系结构具有多个不同的调用约定。The x86 architecture has several different calling conventions. 幸运的是,它们都遵循相同的寄存器保留和函数返回规则:Fortunately, they all follow the same register preservation and function return rules:

  • 函数必须保留所有寄存器, eaxecxedx除外,可以在函数调用中更改这些寄存器 ,并且必须根据调用约定对其进行更新。Functions must preserve all registers, except for eax, ecx, and edx, which can be changed across a function call, and esp, which must be updated according to the calling convention.

  • 如果结果为32位或更小,则eax寄存器接收函数返回值。The eax register receives function return values if the result is 32 bits or smaller. 如果结果为64位,则结果存储在edx: eax对中。If the result is 64 bits, then the result is stored in the edx:eax pair.

下面是用于 x86 体系结构的调用约定的列表:The following is a list of calling conventions used on the x86 architecture:

  • Win32 ( __stdcallWin32 (__stdcall)

    函数参数在堆栈上传递,从右到左推送,被调用方清理堆栈。Function parameters are passed on the stack, pushed right to left, and the callee cleans the stack.

  • 本机C++方法调用(也称为 thiscall)Native C++ method call (also known as thiscall)

    函数参数将在堆栈上传递,从右到左推送,在ecx寄存器中传递 "this" 指针,被调用方清理堆栈。Function parameters are passed on the stack, pushed right to left, the "this" pointer is passed in the ecx register, and the callee cleans the stack.

  • COM ( __ 用于方法C++调用的 stdcall)COM (__stdcall for C++ method calls)

    函数参数在堆栈上传递,从右到左,然后将 "this" 指针推送到堆栈上,然后调用函数。Function parameters are passed on the stack, pushed right to left, then the "this" pointer is pushed on the stack, and then the function is called. 被调用方清理堆栈。The callee cleans the stack.

  • __fastcall__fastcall

    ecxedx寄存器中传递前两个 DWORD 或更小的参数。The first two DWORD-or-smaller arguments are passed in the ecx and edx registers. 剩余的参数在堆栈上传递(从右到左)。The remaining parameters are passed on the stack, pushed right to left. 被调用方清理堆栈。The callee cleans the stack.

  • __cdecl__cdecl

    函数参数在堆栈上传递,从右到左推送,并且调用方清理堆栈。Function parameters are passed on the stack, pushed right to left, and the caller cleans the stack. __cdecl调用约定用于具有可变长度参数的所有函数。The __cdecl calling convention is used for all functions with variable-length parameters.

调试器显示寄存器和标志Debugger Display of Registers and Flags

下面是一个示例调试器寄存器显示:Here is a sample debugger register display:

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和调试器显示的整个最后一行。In user-mode debugging, you can ignore the iopl and the entire last line of the debugger display.

x86 标志x86 Flags

在前面的示例中,第二行末尾的双字母代码是标志In the preceding example, the two-letter codes at the end of the second line are flags. 这些都是单数位寄存器,并且有多种用途。These are single-bit registers and have a variety of uses.

下表列出了 x86 标志:The following table lists the x86 flags:

标志代码标志名称值标志状态说明Flag Code Flag Name Value Flag Status Status Description of

溢出标志Overflow Flag

0 1 nvov0 1 nvov

无溢出溢出dfNo overflow Overflow df

方向标志Direction Flag

0 1 updn0 1 updn

如果Direction up Direction down if

中断标志Interrupt Flag

0 1 diei0 1 diei

中断已禁用中断启用sfInterrupts disabled Interrupts enabled sf

签名标志Sign Flag

0 1 plng0 1 plng

正值(或零)负zfPositive (or zero) Negative zf

零标志Zero Flag

0 1 nzzr0 1 nzzr

非零零afNonzero Zero af

辅助携带标志Auxiliary Carry Flag

0 1 naac0 1 naac

无辅助执行辅助传输pfNo auxiliary carry Auxiliary carry pf

奇偶校验标志Parity Flag

0 1 pepo0 1 pepo

奇偶校验奇偶校验偶cfParity even Parity odd cf

携带标志Carry Flag

0 1 nccy0 1 nccy

No 携带tfNo carry Carry tf

陷阱标志Trap Flag

如果tf等于1,则在执行一条指令后,处理器将引发状态_单个_步骤异常。If tf equals 1, the processor will raise a STATUS_SINGLE_STEP exception after the execution of one instruction. 调试器使用此标志来实现单步跟踪。This flag is used by a debugger to implement single-step tracing. 它不应被其他应用程序使用。It should not be used by other applications.

iopliopl

I/o 特权级别I/O Privilege Level

这是一个2位整数,其值介于0和3之间。This is a two-bit integer, with values between zero and 3. 操作系统使用它来控制对硬件的访问。It is used by the operating system to control access to hardware. 应用程序不应使用此方法。It should not be used by applications.

当寄存器作为某些命令在调试器命令窗口中显示时,将显示 "标记状态"。When registers are displayed as a result of some command in the Debugger Command window, it is the flag status that is displayed. 但是,如果想要使用r (寄存器) 命令更改标志,则应通过标记代码对其进行引用。However, if you want to change a flag using the r (Registers) command, you should refer to it by the flag code.

在 WinDbg 的 "寄存器" 窗口中,标志代码用于查看或更改标志。In the Registers window of WinDbg, the flag code is used to view or alter flags. 不支持标志状态。The flag status is not supported.

下面是一个示例。Here is an example. 在上述寄存器显示中,将显示标志状态 " ng "。In the preceding register display, the flag status ng appears. 这意味着符号标志当前设置为1。This means that the sign flag is currently set to 1. 若要更改此项,请使用以下命令:To change this, use the following command:

r sf=0

这会将符号标志设置为零。This sets the sign flag to zero. 如果执行其他注册,则不会显示 " ng " 状态代码。If you do another register display, the ng status code will not appear. 相反,将显示pl状态代码。Instead, the pl status code will be displayed.

符号标志、零标志和携带标志是最常用的标志。The Sign Flag, Zero Flag, and Carry Flag are the most commonly-used flags.

条件和条款Conditions

描述一个或多个标志的状态的条件A condition describes the state of one or more flags. X86 上的所有条件操作都以条件表示。All conditional operations on the x86 are expressed in terms of conditions.

汇编程序使用一个或两个字母缩写来表示条件。The assembler uses a one or two letter abbreviation to represent a condition. 可以用多个缩写来表示条件。A condition can be represented by multiple abbreviations. 例如,AE ("大于或等于")与 NB 相同(如下所示):For example, AE ("above or equal") is the same condition as NB ("not below"). 下表列出了一些常见条件及其含义。The following table lists some common conditions and their meaning.

条件名称Condition Name FlagsFlags 含义Meaning

ZZ

ZF = 1ZF=1

上次操作的结果为零。Result of last operation was zero.

NZNZ

ZF = 0ZF=0

上次操作的结果不是零。Result of last operation was not zero.

CC

CF = 1CF=1

上次操作要求具有 "执行" 或 "借用"。Last operation required a carry or borrow. (对于无符号整数,表示溢出。)(For unsigned integers, this indicates overflow.)

NCNC

CF = 0CF=0

最后一道工序不需要带有或借用的。Last operation did not require a carry or borrow. (对于无符号整数,表示溢出。)(For unsigned integers, this indicates overflow.)

SS

SF = 1SF=1

上次操作的结果设置了其高位。Result of last operation has its high bit set.

NSNS

SF = 0SF=0

上次操作的结果是其高清晰。Result of last operation has its high bit clear.

OO

Of = 1OF=1

当被视为带符号的整数运算时,最后一个操作导致溢出或下溢。When treated as a signed integer operation, the last operation caused an overflow or underflow.

NO

Of = 0OF=0

当被视为带符号整数运算时,最后一个操作不会导致溢出或下溢。When treated as signed integer operation, the last operation did not cause an overflow or underflow.

还可以使用条件来比较两个值。Conditions can also be used to compare two values. Cmp指令比较了两个操作数,然后设置了标志,就像从另一个操作数中减去一个操作数一样。The cmp instruction compares its two operands, and then sets flags as if subtracted one operand from the other. 以下条件可用于检查cmp value1value2的结果。The following conditions can be used to check the result of cmp value1, value2.

条件名称Condition Name FlagsFlags 表示 CMP 操作之后的。Meaning after a CMP operation.

EE

ZF = 1ZF=1

value1 == value2value1 == value2.

NENE

ZF = 0ZF=0

value1 ! = value2value1 != value2.

GE NLGE NL

SF = OFSF=OF

value1 >= value2 value1 >= value2. 值被视为有符号整数。Values are treated as signed integers.

LE NGLE NG

ZF = 1 或 SF! = ofZF=1 or SF!=OF

value1 <= value2value1 <= value2. 值被视为有符号整数。Values are treated as signed integers.

G NLEG NLE

ZF = 0,SF = ofZF=0 and SF=OF

value1 > value2value1 > value2. 值被视为有符号整数。Values are treated as signed integers.

L NGEL NGE

SF! = OFSF!=OF

value1 < value2value1 < value2. 值被视为有符号整数。Values are treated as signed integers.

AE NBAE NB

CF = 0CF=0

value1 >= value2value1 >= value2. 值被视为无符号整数。Values are treated as unsigned integers.

为 NABE NA

CF = 1 或 ZF = 1CF=1 or ZF=1

value1 <= value2value1 <= value2. 值被视为无符号整数。Values are treated as unsigned integers.

NA NBE

CF = 0,ZF = 0CF=0 and ZF=0

value1 > value2value1 > value2. 值被视为无符号整数。Values are treated as unsigned integers.

B NAEB NAE

CF = 1CF=1

value1 < value2value1 < value2. 值被视为无符号整数。Values are treated as unsigned integers.

条件通常用于处理cmp测试指令的结果。Conditions are typically used to act on the result of a cmp or test instruction. 例如,For example,

cmp eax, 5
jz equal

通过计算表达式(eax -5)并根据结果设置标志来比较eax寄存器与数字5。compares the eax register against the number 5 by computing the expression (eax - 5) and setting flags according to the result. 如果减法的结果为零,则将设置zr标志,并且jz条件将为 true,因此将执行跳转。If the result of the subtraction is zero, then the zr flag will be set, and the jz condition will be true so the jump will be taken.

数据类型Data Types

  • 字节:8位byte: 8 bits

  • word:16位word: 16 bits

  • dword:32位dword: 32 bits

  • qword:64位(包括浮点双精度型)qword: 64 bits (includes floating-point doubles)

  • tword:80位(包括浮点扩展双精度型)tword: 80 bits (includes floating-point extended doubles)

  • oword:128位oword: 128 bits

图解Notation

下表指示用于描述汇编语言说明的表示法。The following table indicates the notation used to describe assembly language instructions.

图解Notation 含义Meaning

rr1r2r, r1, r2...

寄存器Registers

mm

内存地址(有关详细信息,请参阅 "后续寻址模式" 部分。)Memory address (see the succeeding Addressing Modes section for more information.)

#n#n

立即常量Immediate constant

r/mr/m

寄存器或内存Register or memory

r/#nr/#n

注册或立即常量Register or immediate constant

r/m/#nr/m/#n

Register、memory 或 immediate 常量Register, memory, or immediate constant

字幕cc

上述条件部分中列出的条件代码。A condition code listed in the preceding Conditions section.

关心T

"B"、"W" 或 "D" (字节、字或 dword)"B", "W", or "D" (byte, word or dword)

accTaccT

大小"累加器":如果 t = "B",则ax if t = "W",或者如果t = "D",则为eaxSize T accumulator: al if T = "B", ax if T = "W", or eax if T = "D"

寻址模式Addressing Modes

有几种不同的寻址模式,但它们全都采用t ptr [expr] ,其中T是某种数据类型(请参见前面的数据类型部分), expr是涉及常量和寄存器的表达式。There are several different addressing modes, but they all take the form T ptr [expr], where T is some data type (see the preceding Data Types section) and expr is some expression involving constants and registers.

大多数模式的表示法可能不太困难。The notation for most modes can be deduced without much difficulty. 例如, BYTE PTR [esi + edx*8 + 3] 表示 "采用esi寄存器的值,将edx寄存器值的8倍添加到它,添加三个,然后访问生成的地址处的字节。"For example, BYTE PTR [esi+edx*8+3] means "take the value of the esi register, add to it eight times the value of the edx register, add three, then access the byte at the resulting address."

传送Pipelining

Pentium 是双重问题,这意味着它可以在一个时钟周期内最多执行两个操作。The Pentium is dual-issue, which means that it can perform up to two actions in one clock tick. 但是,当它能够同时执行两个操作(称为配对)时,这些规则非常复杂。However, the rules on when it is capable of doing two actions at once (known as pairing) are very complicated.

由于 x86 是 CISC 的处理器,因此不必担心跳过延迟槽。Because x86 is a CISC processor, you do not have to worry about jump delay slots.

同步内存访问Synchronized Memory Access

"加载"、"修改" 和 "存储" 指令可接收一个前缀,该前缀用于修改说明,如下所示:Load, modify, and store instructions can receive a lock prefix, which modifies the instruction as follows:

  1. 发出指令之前,CPU 将刷新所有挂起的内存操作以确保一致性。Before issuing the instruction, the CPU will flush all pending memory operations to ensure coherency. 放弃所有数据预提取。All data prefetches are abandoned.

  2. 发出指令时,CPU 将具有对总线的独占访问权限。While issuing the instruction, the CPU will have exclusive access to the bus. 这可确保加载/修改/存储操作的原子性。This ensures the atomicity of the load/modify/store operation.

Xchg指令会在它与内存交换值时自动服从前面的规则。The xchg instruction automatically obeys the previous rules whenever it exchanges a value with memory.

所有其他说明默认为 nonlocking。All other instructions default to nonlocking.

跳转预测Jump Prediction

预测跳跃跳跃。Unconditional jumps are predicted to be taken.

根据条件跳转是在上次执行时执行,还是不采取条件跳转。Conditional jumps are predicted to be taken or not taken, depending on whether they were taken the last time they were executed. 记录跳跃历史记录的缓存大小受到限制。The cache for recording jump history is limited in size.

如果 CPU 没有一条记录,指出是在上次执行条件跳转时还是不执行该操作,则它会根据所采用的方式预测后向条件跳转,并将其转发到不采用的条件。If the CPU does not have a record of whether the conditional jump was taken or not taken the last time it was executed, it predicts backward conditional jumps as taken and forward conditional jumps as not taken.

关联Alignment

X86 处理器会自动更正未对齐的内存访问,同时降低性能。The x86 processor will automatically correct unaligned memory access, at a performance penalty. 不引发异常。No exception is raised.

如果地址是对象大小的整数倍,则内存访问被视为对齐。A memory access is considered aligned if the address is an integer multiple of the object size. 例如,所有字节访问都是对齐的(所有的都是1的整数倍),即使地址是相同的,也是如此,而 DWORD 地址必须是4的倍数才能对齐。For example, all BYTE accesses are aligned (everything is an integer multiple of 1), WORD accesses to even addresses are aligned, and DWORD addresses must be a multiple of 4 in order to be aligned.

不应将前缀用于未对齐的内存访问。The lock prefix should not be used for unaligned memory accesses.