【译】x86程序员手册07 - 2.5操作数选择
2.5 Operand Selection 操作数选择
An instruction can act on zero or more operands, which are the data manipulated by the instruction. An example of a zero-operand instruction is NOP (no operation). An operand can be in any of these locations:
作为指令使用的数据,一条指令可以有0或多个操作数。0个操作数的指令例子是NOP(空操作)。一个操作数可以出现在下面的任意一个位置:
- In the instruction itself (an immediate operand)
在指令中(一个立即数)
- In a register (EAX, EBX, ECX, EDX, ESI, EDI, ESP, or EBP in the case of 32-bit operands; AX, BX, CX, DX, SI, DI, SP, or BP in the case of 16-bit operands; AH, AL, BH, BL, CH, CL, DH, or DL in the case of 8-bit operands; the segment registers; or the EFLAGS register for flag operations)
在寄存器中(32位操作数:EAX\EBX\ECX\EDX\ESI\EDI\ESP或EBP;16位操作数:AX\BX\CX\DX\SI\DI\SP或BP;8位操作数:AH\AL\BH\BL\CH\CL\DH或DL;在段寄存器中;或者在标志操作中是EFLAGS寄存器中)
- In memory
在内存中
- At an I/O port
在一个I/O端口中
Immediate operands and operands in registers can be accessed more rapidly than operands in memory since memory operands must be fetched from memory. Register operands are available in the CPU. Immediate operands are also available in the CPU, because they are prefetched as part of the instruction.
比起内存中的操作数必须从内存中取得相比,立即数和在寄存器中的操作数可以被更迅速地访问。对CPU而方,寄存器操作数是有效的。立即数也是有效的。因为它们作为指令的一部分是被预先读取到CPU中。
Of the instructions that have operands, some specify operands implicitly; others specify operands explicitly; still others use a combination of implicit and explicit specification; for example:
在拥有操作数的指令中,一些会隐式地指明操作数;另一个是显式指定操作数的;还有一些是复合的;比如:
Implicit operand: AAM 隐式操作数 AAM
By definition, AAM (ASCII adjust for multiplication) operates on the contents of the AX register.
根据定义,AAM(针对乘法对ASCII的调整)是在对AX寄存器中内容的操作。
Explicit operand: XCHG EAX, EBX 显式操作数 XCHG EAX,EBX
The operands to be exchanged are encoded in the instruction after the opcode.
操作结束后,指令中的操作数进行交换。
Implicit and explicit operands: PUSH COUNTER 混合指明的操作数:PUSH COUNTER
The memory variable COUNTER (the explicit operand) is copied to the top of the stack (the implicit operand).
内存变量COUNTER(显示操作数)被拷贝到栈顶(隐式指定的操作数)。
Note that most instructions have implicit operands. All arithmetic instructions, for example, update the EFLAGS register.
注意:绝大多数指令都有隐式操作数。比如:所有的算数指令都会更新EFLAGS寄存器。
An 80386 instruction can explicitly reference one or two operands. Two-operand instructions, such as MOV, ADD, XOR, etc., generally overwrite one of the two participating operands with the result. A distinction can thus be made between the source operand (the one unaffected by the operation) and the destination operand (the one overwritten by the result).
80386指令会明确使用一个或两个操作数。两个操作数指令比如:MOV\ADD\XOR。一般来讲作为执行结果会覆盖掉二个参与的操作数中的一个。在源操作数(不会被操作影响)和目的操作数(会被操作结果覆盖)之间有一个区别。
For most instructions, one of the two explicitly specified -- the source or the -- be either in a register or in memory. The other operand must be in a register or be an immediate source operand. Thus, the explicit two-operand instructions of the 80386 permit operations of the following kinds:
对于大多数指令而言,两个明确指定的操作数之一,要么在寄存器中,要么在内存中。另一个操作数一定是在寄存器中或者是一个立即数。这样,80386中明确有两个操作数的指令允许的操作行为是下列之一:
- Register-to-register 寄存器到寄存器
- Register-to-memory 寄存器到内存
- Memory-to-register 内存到寄存器
- Immediate-to-register 立即数到寄存器
- Immediate-to-memory 立即数到内存
Certain string instructions and stack manipulation instructions, however, transfer data from memory to memory. Both operands of some string instructions are in memory and are implicitly specified. Push and pop stack operations allow transfer between memory operands and the memory-based stack.
然而,字符串指令和栈操作指令,可以在内存之间传送数据。一些字符串指令的两个操作数都在内存中,并且隐式被指定。入栈及出栈操作可以进行内存操作数之间传送,但要求操作数所在内存是基于栈的。
2.5.1 Immediate Operands 立即数
Certain instructions use data from the instruction itself as one (and sometimes two) of the operands. Such an operand is called an immediate operand. The operand may be 32-, 16-, or 8-bits long. For example:
一些指令使用自身的数据作为其中一个操作数(有时是两个)。因此一个操作数被叫作立即数。操作数可以是32位、16位或8位长度。例如:
SHR PATTERN, 2 //右移2位。
One byte of the instruction holds the value 2, the number of bits by which to shift the variable PATTERN.
指令中的一个字节持有数值2,用来指定将PATTERN移位的数量。
TEST PATTERN, 0FFFF00FFH
A doubleword of the instruction holds the mask that is used to test the variable PATTERN.
指令中的双字表示用来测试PATTERN的模式。
2.5.2 Register Operands 寄存器操作数
Operands may be located in one of the 32-bit general registers (EAX, EBX, ECX, EDX, ESI, EDI, ESP, or EBP), in one of the 16-bit general registers (AX, BX, CX, DX, SI, DI, SP, or BP), or in one of the 8-bit general registers (AH, BH, CH, DH, AL, BL, CL,or DL).
可以指定下列寄存器中的一个:32位通用寄存器(EAX\EBX\ECX\EDX\ESI\EDI\ESP或EBP)、16位通用寄存器(AX\BX\CX\DX\SI\DI\SP或BP)或8位通用寄存器(AH\BH\CH\DH\AL\BL\CL或DL)。
The 80386 has instructions for referencing the segment registers (CS, DS, ES, SS, FS, GS). These instructions are used by applications programs only if systems designers have chosen a segmented memory model.
80386有些指令会引用段寄存器(CS\DS\ES\SS\FS\GS)。这些指令仅当系统设计者已选定了段内存模式时可以被应用程序使用。
The 80386 also has instructions for referring to the flag register. The flags may be stored on the stack and restored from the stack. Certain instructions change the commonly modified flags directly in the EFLAGS register. Other flags that are seldom modified can be modified indirectly via the flags image in the stack.
80386也有些指令会引用标志寄存器。标志可以被保存在栈上或从栈上恢复。某些指令会修改EFLAGS寄存器中的标志位。一些很少修改的标志也可以通过栈中的标志映像直接修改。
2.5.3 Memory Operands 内存操作数
Data-manipulation instructions that address operands in memory must specify (either directly or indirectly) the segment that contains the operand and the offset of the operand within the segment. However, for speed and compact instruction encoding, segment selectors are stored in the high speed segment registers. Therefore, data-manipulation instructions need to specify only the desired segment register and an offset in order to address a memory operand.
数据操作指令中的内存地址操作数必须指定(直接或间接)包含操作数的段和其在段内的偏移。然而,为了速度和压缩指令编码,段选择子被存储在高速的段寄存器中。这样,数据操作指令就仅需要指定需要的段寄存器和一个要编址的内存操作数的偏移。
An 80386 data-manipulation instruction that accesses memory uses one of the following methods for specifying the offset of a memory operand within its segment:
80386访问内存的数据操作指令使用下列方法之一来指定内存操作数在段内的偏移:
- Most data-manipulation instructions that access memory contain a byte that explicitly specifies the addressing method for the operand. A byte, known as the modR/M byte, follows the opcode and specifies whether the operand is in a register or in memory. If the operand is in memory, the address is computed from a segment register and any of the following values: a base register, an index register, a scaling factor, a displacement. When an index register is used, the modR/M byte is also followed by another byte that identifies the index register and scaling factor. This addressing method is the most flexible.
大多数访问内存的数据操作指令包含一个字节来明确指出操作数的寻址方法。这个字节,被叫做modR/M字节,放在操作符之后,并且指出是否一个操作数是在寄存器内还是在内存中。如果一个操作数在内存中,其地址通过段寄存器和下列值之一来进行计算:一个基址寄存器、一个索引寄存器、一个比例因子或一个置位符。当使用索引寄存器时,modR/M字节也会跟在另一个指定索引寄存器和比例因子字节的后面这种寻址方法是最适应的。
- A few data-manipulation instructions implicitly use specialized addressing methods:
少量的数据操作指令隐式使用下面寻址方法:
- For a few short forms of MOV that implicitly use the EAX register, the offset of the operand is coded as a doubleword in the instruction. No base register, index register, or scaling factor are used.
对于一些短表MOV指令来说,隐式使用EAX寄存器,其指令中操作数的偏移地址被编码作双字。不使用基址寄存器、索引寄存器或比例因子。
- String operations implicitly address memory via DS:ESI, (MOVS, CMPS, OUTS, LODS, SCAS) or via ES:EDI (MOVS, CMPS, INS, STOS).
字符串操作隐式通过DS:ESI(MOVS、CMPS、OUTS、LODS、SCAS)或ES:EDI(MOVS、CMPS、INS、STOS)来寻址内存。
- Stack operations implicitly address operands via SS:ESP registers; e.g., PUSH, POP, PUSHA, PUSHAD, POPA, POPAD, PUSHF, PUSHFD, POPF, POPFD, CALL, RET, IRET,IRETD, exceptions, and interrupts.
栈操作通过SS:ESP来隐式地寻址操作数;如:PUSH、POP、PUSHA、PUSHAD、POPA、POPAD、PUSHF、PUSHFD、POPF、POPFD、CALL、RET、IRET、IRETD、异常和中断。
2.5.3.1 Segment Selection 段选择
Data-manipulation instructions need not explicitly specify which segment register is used. For all of these instructions, specification of a segment register is optional. For all memory accesses, if a segment is not explicitly specified by the instruction, the processor automatically chooses a segment register according to the rules of Table 2-1. (If systems designers have chosen a flat model of memory organization, the segment registers and the rules that the processor uses in choosing them are not apparent to applications programs.)
数据操作指定不需要明确指定使用哪个段寄存器。对于所有的这些指令,段寄存器的指定是可选的。对于所有的内存访问,如果指令没有明确指定段,处理器会按照表2-1所示的规则自动选择一个段寄存器。(如果系统设计者选择扁平模式做为内存组织,那这种处理器选择段寄存器的规则对于应用程序而言就不再是明显的。)
There is a close connection between the kind of memory reference and the segment in which that operand resides. As a rule, a memory reference implies the current data segment (i.e., the implicit segment selector is in DS). However, ESP and EBP are used to access items on the stack; therefore, when the ESP or EBP register is used as a base register, the current stack segment is implied (i.e., SS contains the selector).
这种内存与段之间的关系可以关闭。作为规则,内存引用隐式使用当前数据段(隐含的段选择子在DS中)。然而,ESP和EBP被用来访问栈上的元素;因此,当ESP和EBP寄存器被用作基址寄存器时,当前栈段是隐式的(比如:SS中保有选择子)。
Special instruction prefix elements may be used to override the default segment selection. Segment-override prefixes allow an explicit segment selection. The 80386 has a segment-override prefix for each of the segment registers. Only in the following special cases is there an implied segment selection that a segment prefix cannot override:
特殊的指令前缀元素可以覆盖默认的段选择。段覆盖前缀允许一个明确的段选择。80386中每一个段寄存器都有一个段覆盖前缀。仅在下列情况中,一个明确的段选择不能被段前缀覆盖:
- The use of ES for destination strings in string instructions.
在字符串指令中ES被用做目的字符串地址。
- The use of SS in stack instructions.
在栈操作指令中只使用SS。
- The use of CS for instruction fetches.
取指指令必须使用CS。
Table 2-1. Default Segment Register Selection Rules
Memory Reference Needed Segment Implicit Segment Selection Rule
Register
Used
Instructions Code (CS) Automatic with instruction prefetch
Stack Stack (SS) All stack pushes and pops. Any
memory reference that uses ESP or
EBP as a base register.
Local Data Data (DS) All data references except when
relative to stack or string
destination.
Destination Strings Extra (ES) Destination of string instructions.
2.5.3.2 Effective-Address Computation 有效地址计算
The modR/M byte provides the most flexible of the addressing methods, and instructions that require a modR/M byte as the second byte of the instruction are the most common in the 80386 instruction set. For memory operands defined by modR/M, the offset within the desired segment is calculated by taking the sum of up to three components:
modR/M字节为寻址方式提供了更多的伸缩性,需要modR/M字节做为第二个字节的指令在80386的指令集中是很常见的。对于通过modR/M字节来定义的内存操作数来说,在段内的偏移是通过以下三个部分之和:
- A displacement element in the instruction.
置位符元素
- A base register.
基址寄存器。
- An index register. The index register may be automatically multiplied by a scaling factor of 2, 4, or 8.
索引寄存器。索引寄存器可以自动乘以比例因子2、4或8.
The offset that results from adding these components is called an effective address. Each of these components of an effective address may have either a positive or negative value. If the sum of all the components exceeds 2^(32), the effective address is truncated to 32 bits. Figure 2-10 illustrates the full set of possibilities for modR/M addressing.
加上这些运算结果的偏移被叫做高效地址。组成高效地址的部分可以是正数或负数。如果运算之和超过2^(32),高效地址被截断到32位。图2-10解释modR/M寻址的可能结果。
The displacement component, because it is encoded in the instruction, is useful for fixed aspects of addressing; for example:
置位符部分,由于被编码在指令中,对于固定寻址方面很有用;比如:
- Location of simple scalar operands.
简单的数量操作数的定位。
- Beginning of a statically allocated array.
静态分配的数据的起始位置。
- Offset of an item within a record.
记录中一个元素的偏移。
The base and index components have similar functions. Both utilize the same set of general registers. Both can be used for aspects of addressing that are determined dynamically; for example:
基址和索引部分有着相似的功能。都是使用同一套通用寄存器。都能被用在动态寻址中;比如:
- Location of procedure parameters and local variables in stack.
栈内程序参数和本地变量的位置。
- The beginning of one record among several occurrences of the same record type or in an array of records.
在多个相同记录或一个记录数组中定位一个记录的起始位置。
- The beginning of one dimension of multiple dimension array.
多维数组中一维的起始地址。
- The beginning of a dynamically allocated array.
动态分配数组的起始地址。
The uses of general registers as base or index components differ in the following respects:
通用寄存器作为基址或索引部分在下面几个方面是不同的:
- ESP cannot be used as an index register.
ESP不能被用做索引寄存器。
- When ESP or EBP is used as the base register, the default segment is the one selected by SS. In all other cases the default segment is DS.
当ESP或EBP被用做基址寄存器时,默认段是SS。其他情况中默认段是DS。
The scaling factor permits efficient indexing into an array in the common cases when array elements are 2, 4, or 8 bytes wide. The shifting of the index register is done by the processor at the time the address is evaluated with no performance loss. This eliminates the need for a separate shift or multiply instruction.
当数组元素是2、4或8位宽度时,比例因子会让索引数组变得更高效。当地址被计算完毕后,处理器会自动修改索引寄存器,而没有性能损失。也就不再需要单独的移位或乘法指令。
The base, index, and displacement components may be used in any combination; any of these components may be null. A scale factor can be used only when an index is also used. Each possible combination is useful for data structures commonly used by programmers in high-level languages and assembly languages. Following are possible uses for some of the various combinations of address components.
基址、索引和置位符部分可以任意组合;这些组合不会是null值。比例因子仅当索引被使用时才能使用。对于在高级语言或汇编语言中使用的数据结构来说,每个可能的组合都是有用的。下面是这些变化组合的可能用法。
DISPLACEMENT 置位符
The displacement alone indicates the offset of the operand. This combination is used to directly address a statically allocated scalar operand. An 8-bit, 16-bit, or 32-bit displacement can be used.
置位符单独用来表示操作数的偏移。这种组合用来直接寻址一个静态分配的数量操作数。可以使用8、16或32位的置位符。
BASE 基址
The offset of the operand is specified indirectly in one of the general registers, as for "based" variables.
操作数的偏移被间接地指向某个通用寄存器,作为基本的变数。
BASE + DISPLACEMENT 基址+置位符
A register and a displacement can be used together for two distinct purposes:
寄存器和置位符一起有两个目的:
- Index into static array when element size is not 2, 4, or 8 bytes. The displacement component encodes the offset of the beginning of the array. The register holds the results of a calculation to determine the offset of a specific element within the array.
当数组元素大小不是2、4或8时,用来索引静态数组。置位符部分编码数组的起始偏移量。寄存器保存的运算结果来永定数组中元素的偏移量。
- Access item of a record. The displacement component locates an within record. The base register selects one of several occurrences of record, thereby providing a compact encoding for this common function.
访问记录的元素。置位符定位记录内部。基址寄存器选择其中一个记录。因此可以为通用功能提供压缩编码。
An important special case of this combination, is to access parameters in the procedure activation record in the stack. In this case, EBP is the best choice for the base register, because when EBP is used as a base register, the processor automatically uses the stack segment register (SS) to locate the operand, thereby providing a compact encoding for this common function.
在这种组合中有一个重要的例外,就是在访问栈上激活程序的参数时。在这种情况下,EBP是做为基址寄存器的最好选择,因为当EBP被用做基址寄存器时,处理器会自动使用栈段寄存器(SS)来定位操作数,这样就能为通用功能提供一个压缩编码。
(INDEX * SCALE) + DISPLACEMENT 索引 * 比例 +置位符
This combination provides efficient indexing into a static array when the element size is 2, 4, or 8 bytes. The displacement addresses the beginning of the array, the index register holds the subscript of the desired array element, and the processor automatically converts the subscript into an index by applying the scaling factor.
当数组元素大小为2、4或8位时,这种组合能提供在静态数组中的高效索引。置位符编址数据的起始位,索引寄存器保留数组元素的下标,通过乘比例因子处理器自动转换下标到索引。
BASE + INDEX + DISPLACEMENT 基址 + 索引 + 置位符
Two registers used together support either a two-dimensional array (the displacement determining the beginning of the array) or one of several instances of an array of records (the displacement indicating an item in the record).
两个寄存器一起使用来表示两维数组(置位符决定数组起始地址)或多个一个记录数组实例中的一个(置位符指定记录中的元素)。
BASE + (INDEX * SCALE) + DISPLACEMENT 基址 + 索引 * 比例 + 置位符
This combination provides efficient indexing of a two-dimensional array when the elements of the array are 2, 4, or 8 bytes wide.
当数组元素大小为2、4或8位时,这种组合能为二维数组提供高效索引。