关于这条 LEAL 指令,0x10 的功能是什么?是乘法还是加法还是别的什么?
leal 0x10(%ebx), %eax
有人可以澄清一下吗?这是 Linux 机器上的 x86 汇编程序。
关于这条 LEAL 指令,0x10 的功能是什么?是乘法还是加法还是别的什么?
leal 0x10(%ebx), %eax
有人可以澄清一下吗?这是 Linux 机器上的 x86 汇编程序。
leal 或 lea 全名是“加载有效地址”,它正是这样做的:它进行地址计算。
在您的示例中,地址计算非常简单,因为它只是将偏移量添加到 ebx 并将结果存储在 eax 中:
eax = ebx + 0x10
lea 可以做的更多。它可以添加寄存器,将寄存器与常数 2、4 和 8 相乘,用于字、整数和双精度数的地址计算。它还可以添加偏移量。
请注意, lea 的特殊之处在于它永远不会修改标志,即使您将其用作上面示例中的简单添加也是如此。编译器有时会利用此功能并用 lea 替换添加以帮助调度程序。出于这个原因,经常看到 lea 指令在编译代码中执行简单的算术运算。
lea
代表“加载有效地址”;这是一种使用 IA32 指令集的复杂寻址模式进行算术运算的方法。后缀是一种区分 GNU 语法中指令操作数大小的l
方法,就像你在 Linux 机器上的那样。
所以,简而言之,是的,它是一种加法指令。它还可以同时处理乘以 2、4 或 8 的乘法。
另请参阅此相关问题(他们使用英特尔语法来讨论相同的指令):
GNU 2.18 文档
https://sourceware.org/binutils/docs-2.18/as/i386_002dMemory.html
AT&T:-4(%ebp),英特尔:[ebp - 4]
然后英特尔语法是不言自明的。
更重要的是,文档还解释了一般情况:
形式为 Intel 语法间接内存引用
section:[base + index*scale + disp]
被翻译成 AT&T 语法
section:disp(base, index, scale)
其中 base 和 index 是可选的 32 位基址和索引寄存器,disp 是可选的位移,而 scale 取值 1、2、4 和 8,乘以 index 以计算操作数的地址
当我们省略地址的某些部分时,AT&T 中的事情确实会变得有点混乱,例如-4(%ebp)
,但是通过文档中的示例,我们可以轻松推断出所有语法案例。
要真正了解发生了什么,我建议您查看指令的编码方式。这是一个很好的教程:http ://www.c-jump.com/CIS77/CPU/x86/lecture.html当您看到它时,就会清楚为什么地址的某些部分可能会被省略,以及每种形式是什么将编译为。
要添加到 Nils 的响应中,
作为复习,IA32 汇编器中的寻址模式通常是以下形式:
IO(Rb, Ri, s),其中:
IO = 立即偏移
Rb = 基址寄存器
Ri = 索引寄存器
s = 比例因子 {1, 2, 4, 8}
所以有效地址计算为*IO + [Eb] + [Ei] s
leal看起来与其他指令如 movl 类似,但有点特殊。它不是从源读取到目标,而是将源的有效地址复制到目标。
因此,正如 Nils 所指出的,它可以用于为以后的内存引用生成指针,也可以用于基本的算术运算。
例如:
让寄存器 %edx 包含一个值 x
leal 1(%edx, %edx, 8), %eax
将 1 + x + 8*x = 1 + 9x 的有效地址加载到寄存器 %eax。
本质上,操作:
真正的 来源,目的地 => 目的地=来源地址
如果您熟悉 C,它相当于:
字符 * b = &a;
其中 char a 的地址分配给 char 指针 b
更多示例:
让寄存器 %eax 保存值 x,寄存器 %ecx 保存值 y
leal (%eax, %ecx, 4), %edx 将 x + 4y 赋值给寄存器 %edx
leal 0xB(, %ecx, 5), %edx 会将值 0xB + 5y = 11 + 5y 分配给 %edx
leal (%eax, %eax,2), %eax 会将值 3x 分配给寄存器 %eax
希望这可以帮助