ModR/M
The ModR/M byte is an important part of instruction encoding for the x86 instruction set.
Description
Opcodes in x86 are generally one-byte, though two-byte instructions and prefixes exist. ModR/M is the byte following the opcode and specifies two operands for the instruction.[1]: §2.1 One operand is a register, while the other is a register or memory operand. The format is:
Bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|
Usage | MOD | REG | R/M |
The REG field specifies the register operand, per the following table:
REG | 000 | 001 | 010 | 011 | 100 | 101 | 110 | 111 |
---|---|---|---|---|---|---|---|---|
Byte operations | AL | CL | DL | BL | AH | CH | DH | BH |
Word operations | (E)AX | (E)CX | (E)DX | (E)BX | (E)SP | (E)BP | (E)SI | (E)DI |
Byte ops with REX (see below) | AL | CL | DL | BL | SPL | BPL | SIL | DIL |
Instructions which take only one operand do not use this field, and it is instead used as additional opcode bits, allowing eight such instructions to share a single opcode byte. In opcode listings, these are specified by following the opcode with a slash (/) and a digit 0-7.[1]: §3.1.1.1 For example, the opcode for byte increment is FE/0
[1]: 3-449 [2]: 183 , while for byte decrement it is FE/1
.[1]: 3-283 [2]: 171
The MOD field specifies the addressing mode for the register/memory operand, and the R/M field specifies the register to use. If the MOD field is 11, the R/M field specifies a register just like the REG field.
For other values of the MOD field, a memory operand is specified, with the a base register specified by the R/M field, to which a displacement is added. If MOD is 00, the displacement is zero. If MOD is 01, an 8-bit signed displacement is used. And is MOD is 10, a word-sized (16 or 32 bits, depending on operating mode) displacement is used.
The interpretation of the R/M field as a base register varies greatly between 16- and 32-bit addressing modes.
In 16-bit mode, the eight possible values of the R/M field specify a base register as follows:[1]: Table 2-1 [2]: Table A-33 [3][4]
- 000: [BX + SI + disp0/8/16]
- 001: [BX + DI + disp0/8/16]
- 010: [BP + SI + disp0/8/16]
- 011: [BP + DI + disp0/8/16]
- 100: [SI + disp0/8/16]
- 101: [DI + disp0/8/16]
- 110: [BP + disp0/8/16]
- 111: [BX + disp0/8/16]
where "disp0/8/16" is the displacement specified by the MOD bits.
As a special exception, the combination MOD=00 R/M=110, which would normally specify [BP + disp0], instead specifies a 16-bit address [disp16] with no register base at all. To address [BP+0], use the 1-byte displacement form with a displacement of 0.
This results in the full set of combinations:
R/M | MOD | |||
---|---|---|---|---|
00 | 01 | 10 | 11 | |
000 | [BX+SI] | [BX+SI+disp8] | [BX+SI+disp16] | AL / AX |
001 | [BX+DI] | [BX+DI+disp8] | [BX+DI+disp16] | CL / CX |
010 | [BP+SI] | [BP+SI+disp8] | [BP+SI+disp16] | DL / DX |
011 | [BP+DI] | [BP+DI+disp8] | [BP+DI+disp16] | BL / BX |
100 | [SI] | [SI+disp8] | [SI+disp16] | AH / SP |
101 | [DI] | [DI+disp8] | [DI+disp16] | CH / BP |
110 | [disp16] | [BP+disp8] | [BP+disp16] | DH / SI |
111 | [BX] | [BX+disp8] | [BX+disp16] | BH / DI |
In 32-bit mode, there are many differences.[1]: Table 2-2 [2]: Table A-34 [3][4] First, the MOD=10 case specifies a 32-bit displacement (disp32). Second, the R/M field specifies only a single base register, using the same encoding as the REG field. There are two exceptions:
- Like in 16-bit mode, the [EBP + disp0] encoding is usurped for a bare disp32. The [EBP+0] address must use the [EBP+disp8] encoding with disp8 set to 0. Note, however, that in 32-bit mode, the encoding for this is MOD=00 R/M=101.
- The encoding MOD≠11 R/M=100 does not specify [ESP] as a base as one would expect, but instead specifies an § SIB byte is present, and the resultant SCALE*INDEX+BASE value should be used to compute the address.
R/M | MOD | |||
---|---|---|---|---|
00 | 01 | 10 | 11 | |
000 | [EAX] | [EAX+disp8] | [EAX+disp32] | AL / AX / EAX |
001 | [ECX] | [ECX+disp8] | [ECX+disp32] | CL / CX / ECX |
010 | [EDX] | [EDX+disp8] | [EDX+disp32] | DL / DX / EDX |
011 | [EBX] | [EBX+disp8] | [EBX+disp32] | BL / BX / EBX |
100 | [SIB] |
[SIB+disp8] | [SIB+disp32] | AH / SP / ESP |
101 | [disp32] | [EBP+disp8] | [EBP+disp32] | CH / BP / EBP |
110 | [ESI] | [ESI+disp8] | [ESI+disp32] | DH / SI / ESI |
111 | [EDI] | [EDI+disp8] | [EDI+disp32] | BH / DI / EDI |
The combination MOD=00 R/M=100, which specifies a SIB byte with no displacement, has a similar special case if the base register is coded as 101 (EBP). In that case, the base register is omitted but a word displacement is used, producing a [SCALE*INDEX+disp32] addressing mode.
SIB byte
The SIB byte is an optional post-opcode byte in x86 assembly on the i386 and later, used for complex addressing.
SIB bytes are formatted similarly to ModR/M bytes, and take the form of (scale * index) + base + displacement
, where the SCALE is 1, 2, 4, or 8. BASE and INDEX each encode a register.[5] The displacement is a constant offset, whose size is given by the MOD field as usual, which encoded after the SIB byte and added to the final address.[3]
A REX prefix allows the SIB byte to use 16 integer registers.[1]
The general format is as follows:
Bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|
Usage | SCALE | INDEX | BASE |
There are, however, two exceptions:
- An INDEX of ESP is forbidden. The encoding INDEX=100 denotes a zero index irrespective of the SCALE field. Normally, an addressing mode without an index would simply use a bare ModR/M byte without a SIB byte at all, but this is necessary to encode an ESP-relative address ([ESP+disp0/8/32]) or an absolute address ([disp32]).
- When MOD=00, a BASE of 101, which would specify EBP with zero displacement, instead specifies no base register and a 32-bit displacement. If a zero displacement is desired, it must be encoded as a disp8 with a value of 0. This is analogous to the treatment of the MOD=00 R/M=101 case.
64-bit changes
AMD's 64-bit extension to the original instruction set make relatively few changes to 32-bit addressing, with the most significant being that in long mode, 64-bit addressing is the default. 64-bit registers (RAX, RBX, RCX, etc.) are used rather than 32-bit registers for address computation. The displacement is not widened to 64 bits; MOD=11 continues to specify a 32-bit displacement, which is sign-extended to 64 bits.[2]: §1.5
This may be changed with the address size override prefix 0x67
, which changes to 32-bit addressing for the following instruction.[2]: §1.2.3
A second major addition is the REX prefix.[2]: §1.2.7,§1.4.4 In long mode, opcodes whose highest four bits are 0100
(decimal 4) are a REX prefix, which provide an additional bit for each register field of the following instruction, doubling the number of available processor registers from eight to sixteen.[2]: §1.4 Specifically, the four low-order bits are:
- W: If set, the operation is preformed on 64-bit operands.
- R: Extends the REG field to 4 bits.
- X: Extends the INDEX field of the SIB byte (if present) to 4 bits.
- B: Extends the R/M field (or the SIB byte's BASE if MOD≠11 R/M=100) to 4 bits.
There is one additional effect of a REX prefix: a REX prefix changes how byte registers are addressed. Without a prefix, the available byte registers are AL/CL/DL/BL, then AH/CH/DH/BH. When a REX prefix is present, even a REX prefix of 01000000
, byte instructions consistently address the low byte of the corresponding word registers, so the available byte become AL/CL/DL/BL/SPL/BPL/SIL/DIL.[2]: §2.3.1
The third significant change is RIP-relative addressing.[2]: §1.7 Then MOD=00 R/M=101 encoding, which specifies a disp32 address (with no base register) in 32-bit mode, specifies [RIP+disp32] in long mode. With an address-size override prefix, this becomes [EIP+disp32].[2]: §1.7.3 The absolute [disp32] mode may be obtained by using MOD=00 R/M=100 to force use of a SIB byte, followed by a SIB byte with BASE=101 and INDEX=100.[2]: §1.7.1
For the special-case addressing encodings R/M=100 (to force a SIB byte), MOD=00 R/M=101 (substitute RIP+disp32), and MOD=00 R/M=100 BASE=101 (substitute disp32), the REX.B prefix is not considered.[2]: §1.8.2 These special-case encodings apply to registers R12 (binary 1100) and R13 (binary 1101) as well,[4] and the same slightly-longer encodings must be used. This is because these exceptions change the encoded instruction size, so must be decoded very quickly so that the following instruction may be located.
The special case where INDEX=100 suppresses the index register (scaling RSP is forbidden), however, does respect the REX.X bit; it is possible to scale R12.[2]: §1.8.2 This is for two reasons:
- there is no alternative way to encode indexing with R12, so this would be a serious limitation, and
- the exception changes the computed address but not the encoded instruction size, so there is more time in the instruction pipeline to resolve the special case.
References
- ^ a b c d e f g h i j Intel Corporation (September 2016). "Intel® 64 and IA-32 Architectures Software Developer's Manual, Volume 2A" (PDF). Retrieved 2024-08-19.
- ^ a b c d e f g h i j k l m n o p q Advanced Micro Devices (March 2024). "AMD64 Architecture Programmer's Manual Volume 3: General-Purpose and System Instructions" (PDF). rev. 3.36. Retrieved 2024-08-19.
- ^ a b c d e f "80386 Programmer's Reference Manual -- Section 17.2". www.scs.stanford.edu. Retrieved 28 July 2022.
- ^ a b c d e f "X86-64 Instruction Encoding". OSDev.org. Retrieved 2024-08-19.
- ^ Hartman, Chris. "Encoding instructions". University of Alaska Fairbanks. Retrieved 28 July 2022.