abrash-black-book/13-04.md
2013-12-30 20:26:41 +11:00

102 lines
No EOL
6.1 KiB
Markdown

### 32-Bit Addressing Modes {#Heading7}
The 386 and 486 both support 32-bit addressing modes, in which any
register may serve as the base memory addressing register, and almost
any register may serve as the potentially scaled index register. For
example,
mov al,BaseTable[ecx+edx*4]
uses a perfectly valid 32-bit address, with the byte accessed being the
one at the offset in DS pointed to by the sum of EDX times 4 plus the
offset of **BaseTable** plus ECX. This is a very powerful memory
addressing scheme, far superior to 8088-style 16-bit addressing, but
it's not without its quirks and costs, so let's take a quick look at
32-bit addressing. (By the way, 32-bit addressing is not limited to
protected mode; 32-bit instructions may be used in real mode, although
each instruction that uses 32-bit addressing must have an address-size
prefix byte, and the presence of a prefix byte costs a cycle on a 486.)
Any register may serve as the base register component of an address. Any
register except ESP may also serve as the index register, which can be
scaled by 1, 2, 4, or 8. (Scaling is very handy for performing lookups
in arrays and tables.) The same register may serve as both base and
index register, except for ESP, which can only be the base.
Incidentally, it makes sense that ESP can't be scaled; ESP presumably
always points to a valid stack, and I can't think of any reason you'd
want to use the stack pointer times 2, 4, or 8 in an address. ESP is, by
its nature, a base rather than index pointer.
That's all there is to the functionality of 32-bit addressing; it's very
simple, much simpler than 16-bit addressing, with its sharply limited
memory addressing register combinations. The costs of 32-bit addressing
are a bit more subtle. The only performance cost (apart from the
aforementioned 1-cycle penalty for using 32-bit addressing in real mode)
is a 1-cycle penalty imposed for using an index register. In this
context, you use an index register when you use a register that's
scaled, or when you use the sum of two registers to point to memory.
**MOV BL,[EBX\*2]** uses an index register and takes an extra cycle, as
does **MOV CL,[EAX+EDX]; MOV CL,[EAX+100H]** is not indexed, however.
The other cost of 32-bit addressing is in instruction size. Old-style
16-bit addressing usually (except in a few special cases) uses one extra
byte, which Intel calls the Mod-R/M byte, which is placed immediately
after each instruction's opcode to describe the memory addressing mode,
plus 1 or 2 optional bytes of addressing displacement—that is, a
constant value to add into the address. In many cases, 32-bit addressing
continues to use the Mod-R/M byte, albeit with a different
interpretation; in these cases, 32-bit addressing is no larger than
16-bit addressing, except when a 32-bit displacement is involved. For
example, **MOV AL, [EBX]** is a 2-byte instruction; **MOV AL,
[EBX+10H]** is a 3-byte instruction; and **MOV AL, [EBX+10000H]** is a
6-byte instruction.
------------------- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
![](images/i.jpg) *Note that 1 and 4-byte displacements, but not 2-byte displacements, are supported for 32-bit addressing. Code size can be greatly improved by keeping stack frame variables within 128 bytes of EBP, and variables in pointed-to structures within 127 bytes of the start of the structure, so that displacements can be 1 rather than 4 bytes.*
------------------- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
However, because 32-bit addressing supports many more addressing
combinations than 16-bit addressing, the Mod-R/M byte can't describe all
the combinations. Therefore, whenever an index register (as described
above) is involved, a second byte, the SIB byte, follows the Mod-R/M
byte to provide additional address information. Consequently, whenever
you use a scaled memory addressing register or use the sum of two
registers to point to memory, you automatically add 1 cycle and 1 byte
to that instruction. This is not to say that you shouldn't use index
registers when they're needed, but if you find yourself using them
inside key loops, you should see if it's possible to move the index
calculation outside the loop as, for example, in a loop like this:
LoopTop:
add ax,DataTable[ebx*2]
inc ebx
dec cx
jnz LoopTop
You could change this to the following for greater performance:
add ebx,ebx ;ebx*2
LoopTop:
add ax,DataTable[ebx]
add ebxX,2
dec cx
jnz LoopTop
shr ebx,1 ;ebx*2/2
I'll end this chapter with two more quirks of 32-bit addressing. First,
as with 16-bit addressing, addressing that uses EBP as a base register
both accesses the SS segment by default and always has a displacement of
at least 1 byte. This reflects the common use of EBP to address a stack
frame, but is worth keeping in mind if you should happen to use EBP to
address non-stack memory.
Lastly, as I mentioned, ESP cannot be scaled. In fact, ESP cannot be an
index register; it must be a base register. Ironically, however, ESP is
the one register that cannot be used to address memory without the
presence of an SIB byte, even if it's used without an index register.
This is an outcome of the way in which the SIB byte extends the
capabilities of the Mod-R/M byte, and there's nothing to be done about
it, but it's at least worth noting that ESP-based, non-indexed
addressing makes for instructions that are a byte larger than other
non-indexed addressing (but not any slower; there's no 1-cycle penalty
for using ESP as a base register) on the 486.