16-bit addressing modes only allow a single ModRM byte to encode the register (3 bits), mode (2 bits) and the register/memory operand (3 bits), so there's no room to encode a scale factor, or even to let arbitrary registers be bases or indices. NASM x86 16-bit addressing modes lists them all, it's not a long list! Just subsets of (BP|BX) + (DI|SI) + disp0/8/16
. Remember that in an instruction like add cx, [bx+si]
, the register destination needs the 3 bit /r
field in ModRM to encode which of the 8 GP registers.
(The 2-bit "mode" signals whether it's a register or memory, e.g. add bx, cx
vs. add [bx], cx
, and how many immediate displacement bytes there are: disp8 / disp16 or no displacement.)
In 32/64-bit addressing modes, the r/m field in ModRM can be an escape code that signals the presence of a SIB byte (Scale/Index/Base), which gives room to encode scaled-index addressing modes with a 2-bit shift count.
And also enough coding space to let us use any register as a base, and any register (except ESP) as an index. So 32-bit addressing modes make the registers more orthogonal. See rbp not allowed as SIB base? for the details on the escape sequences, e.g. [esp]
always needs a SIB byte because the encoding that would mean base=ESP is the escape code for the presence of a SIB byte.
See https://wiki.osdev.org/X86-64_Instruction_Encoding#32.2F64-bit_addressing_2 or the ModRM/SIB tables in Intel's manuals for more details.
BX|BP + SI|DI
) – Teraterai