19

Intel 和 AT&T 语法中内存寻址的一般形式如下:

[base + index*scale + disp]
disp(base, index, scale)

我的问题如下:

  • 可以是任何寄存器吗baseindex
  • 可以取什么值scale,是 1、2、4 和 8(默认值为 1)?
  • 是否可以互换(唯一indexdisp区别index是寄存器disp是立即数)?
4

1 回答 1

15

这在英特尔的手册中有描述:

3.7.5 指定偏移
内存地址的偏移部分可以直接指定为静态值(称为位移)或通过由以下一个或多个组件组成的地址计算来指定:

  • 位移— 8、16 或 32 位值。
  • Base — 通用寄存器中的值。
  • 索引— 通用寄存器中的值。[不能是 ESP/RSP]
  • 比例因子- 乘以索引值的 2、4 或 8 值。

添加这些组件所产生的偏移量称为有效地址。

比例因子被编码为 2 位移位计数 (0,1,2,3),比例因子为 1、2、4 或 8。是的,*1如果您使用 (shift count = 0) 是默认值写(%edi, %edx);这相当于(%edi, %edx, 1)


在 AT&T 语法中,它是disp(base, index, scale)- 常量在括号之外。一些 Intel 语法汇编器也允许类似 的语法1234[ebx],而另一些则不允许。但是 AT&T 的语法是死板的;寻址模式的每个组件都只能放在适当的位置。例如:

movzwl  foo-0x10(,%edx,2), %eax

将零扩展的 16 位(“字”)从 address 加载到 EAX 中foo-0x10 + edx*2。EDX 是索引寄存器,比例因子为 2。没有基址寄存器。 foo并且-0x10都是位移的一部分,都是链接时间常数。 foo是链接器将填充并从中减去 0x10 的符号地址(因为-0x10汇编时偏移)。

如果可以选择,请仅使用基数而不是比例为 1 的索引。索引需要 SIB 字节进行编码,从而使指令更长。这就是编译器选择8(%ebp)访问堆栈内存之类的寻址模式的原因,而不是8(,%ebp).

另请参阅引用内存位置的内容。(x86 寻址模式)了解更多关于何时可以使用基数、和/或索引和/或位移的信息。


16 位位移只能在 16 位寻址模式下编码,该模式使用不同的格式,不能包含比例因子,并且对于哪些寄存器可以是基址或索引的选择非常有限。

因此,像这样的模式1234(%edx)必须将 1234 编码为disp3232 位机器代码中的 32 位。

-128 .. +127 的字节偏移可以使用短格式的 8 位编码。您的汇编程序会为您处理这个问题,使用最短的有效编码进行位移。


对于 64 位寻址模式,所有这些在 64 位模式下都是相同的,disp32 也像 disp8 一样被符号扩展为 64 位。

于 2015-01-14T06:51:27.893 回答