汇编中的间接寻址 (x86)

indirect adressing in assembly (x86)

这是间接寻址的格式:

example: 

| Base | + Index * Scale | + Discplacement  |
|------|-----------------|------------------|
| EAX  |    EBX  *   2   |8-Bit Displacement|

但是有些地方我还不明白:

完整的公式类似于“address = (base + index << scale + displacement) & mask”。

注1:“scale”是一个移位计数,没有乘法。它只是为了方便人类而被描述为乘法。

注意 2:“掩码”代表 wrapping/truncation 到目标大小。例如。如果 base + index << scale + displacement 计算出 0x0000000212345678 但 CPU 需要一个 32 位地址,那么掩码将为 0x00000000FFFFFFFF,实际结果将为 0x12345678。

If we have an address in EAX and add EBX*2 will this take the address/value located in EBX*2 and add it to the value/address in EAX?

是的。例如。如果 EAX = 3 且 EBX = 10,则 EAX+EBX*2 将为 23.

What exactly is the Displacement, why is there 8 Bit,32 Bit or No Displacement possible and not let's say 4 Bit or 2 Bit displacement?

位移只是一个加到其余部分的数字。用于内存访问;它通常用于访问结构字段(例如“结构地址 + 结构中第 n 个字段的偏移量”)和堆栈位置(例如“堆栈顶部 - 从堆栈顶部的偏移量”)。

A CPU 大多只是读取一个数字序列;然后需要能够解码数字以确定指令是什么以及它的操作数是什么(一旦数字被解码,它就会执行相应的指令)。更多的可能性使解码更难,这需要用有用性来证明。 2 位和 4 位位移可以简单地四舍五入到 8 位,因此很难证明解码中的额外复杂性是合理的。

只有 2 位(ModRM 字节中的模式字段)表示寄存器与无显示的内存、8 位显示的内存或 32 位显示的内存。有更多的选择会从其他东西中拿走更多的东西; disp 是一个简单的二进制值(经过符号扩展),它 本身 不使用可变长度编码。 (还好,不然指令长度解码就得看,不能只看前缀+操作码+ModRM字节。)

If we have values that are 4 Byte big each - in the EAX register we would be multiplying EAX*4 but why is this multiplication with byte values (I know each cell has 1 byte). Does this mean that it automatically transforms byte to bit?

“EAX * 4”实际上是“EAX << 2”。小的移位计数非常常见(例如 shl eax,cl),因为“移位计数太大”(例如在 32 位计算中大于 32)加上对目标大小的屏蔽使得它毫无意义。例如,考虑一个虚构的“address = (EAX << 32) & 0xFFFFFFFF”(这是没有意义的,因为它可以替换为“address = 0”)。

本质上,对于 32 位地址计算,从 0 到 31 的移位计数可能有用,较小的移位计数(从 0 到 3)最有用。此时我们可以回到“更多的可能性使解码更难,这需要用有用性来证明”来理解为什么80x86只支持从0到3(或乘数1、2、4和8)的移位计数;尽管其他班次计数(例如“EAX << 4”或“EAX*16”)偶尔可能会有用。

2、4 和 8 是数组的常见元素大小,因此这个 2 位移位计数使得可以索引双字数组,例如使用保存元素编号而不是字节偏移量的寄存器。