Intel 和 AT&T 语法中内存寻址的一般形式如下:
[base + index*scale + disp]
disp(base, index, scale)
我的问题如下:
- 可以是任何寄存器吗
base
?index
- 可以取什么值
scale
,是 1、2、4 和 8(默认值为 1)? - 是否可以互换(唯一
index
的disp
区别index
是寄存器disp
是立即数)?
Intel 和 AT&T 语法中内存寻址的一般形式如下:
[base + index*scale + disp]
disp(base, index, scale)
我的问题如下:
base
?index
scale
,是 1、2、4 和 8(默认值为 1)?index
的disp
区别index
是寄存器disp
是立即数)?这在英特尔的手册中有描述:
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 编码为disp32
32 位机器代码中的 32 位。
-128 .. +127 的字节偏移可以使用短格式的 8 位编码。您的汇编程序会为您处理这个问题,使用最短的有效编码进行位移。
对于 64 位寻址模式,所有这些在 64 位模式下都是相同的,disp32 也像 disp8 一样被符号扩展为 64 位。