assembly 关于[base + index*scale + disp]和AT&T disp(base,index,scale)的几个问题

nwo49xxi  于 2022-11-13  发布在  其他
关注(0)|答案(1)|浏览(180)

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

[base + index*scale + disp]      # Intel, including GAS .intel_syntax noprefix
disp(base, index, scale)         # AT&T

我的问题如下:

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

dpiehjr41#

英特尔手册中对此进行了说明:

3.7.5指定偏移量

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

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

将这些分量相加得到的偏移量称为有效地址。
对于比例因子1、2、4或8,比例因子编码为2位移位计数(0、1、2、3)。是的,如果您写入(%edi, %edx),则*1(移位计数= 0)是默认值;相当于(%edi, %edx, 1)
在AT&T的语法中,disp(base, index, scale)-常量在括号外。一些英特尔语法汇编器也允许1234[ebx]这样的语法,其他的则不允许。但是AT&T的语法是严格的;寻址模式的每一个组成部分都 * 只能 * 在其适当的位置。例如:

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

执行零扩展16位(“字”)从地址foo-0x10 + edx*2加载到EAX。EDX是变址寄存器,比例因子为2。没有基址寄存器。foo-0x10都是位移的一部分,两个链接时间常数。foo是链接器将填入并从中减去0x 10的符号地址(因为-0x10汇编时间偏移量)。
如果可以选择的话,只使用基址,而不使用小数位数为1的索引。索引需要一个SIB字节来编码,这会使指令更长。这就是为什么编译器选择8(%ebp)这样的寻址模式来访问堆栈内存,而不是8(,%ebp)
另请参阅Referencing the contents of a memory location. (x86 addressing modes),以取得有关何时可以使用基底、和/或索引、和/或置换的详细信息。
16位位移量只能在16位寻址模式下进行编码,该模式使用不能包含比例因子的different format,并且limited selection of which registers可以是基址或索引。
因此,像1234(%edx)这样的模式必须将1234编码为32位机器码中的32位disp32
从-128到+127的字节偏移量可以使用短格式的8位编码。您的汇编程序将为您处理这一问题,对偏移量使用最短的有效编码。
对于64位寻址模式,所有这些在64位模式中是相同的,disp 32也像disp 8一样被符号扩展到64位。
64-位模式确实增加了一种新的不同寻址模式,symbol(%rip),它不适用于任何通用寄存器,仅与RIP有32位偏移。参见 * How do RIP-relative variable references like "[RIP + _a]" in x86-64 GAS Intel-syntax work? *,其中也介绍了AT&T语法。

相关问题