【发布时间】:2011-04-29 13:37:47
【问题描述】:
对于这条 LEAL 指令,0x10 的功能是什么?是乘法还是加法还是别的什么?
leal 0x10(%ebx), %eax
有人可以澄清一下吗?这是 Linux 机器上的 x86 汇编器。
【问题讨论】:
标签: assembly x86 instructions
对于这条 LEAL 指令,0x10 的功能是什么?是乘法还是加法还是别的什么?
leal 0x10(%ebx), %eax
有人可以澄清一下吗?这是 Linux 机器上的 x86 汇编器。
【问题讨论】:
标签: assembly x86 instructions
lea代表“加载有效地址”;它是一种使用 IA32 指令集的复杂寻址模式进行算术运算的方法。 l 后缀是一种区分 GNU 语法中指令操作数大小的方法,就像你的 Linux 机器上的那样。
所以,简而言之,是的,它是一种加法指令。它还可以同时处理乘以 2、4 或 8。
另见this related question(他们使用英特尔语法讨论相同的指令):
【讨论】:
leal 或 lea 全名是“加载有效地址”,它就是这样做的:它进行地址计算。
在您的示例中,地址计算非常简单,因为它只是向 ebx 添加了一个偏移量并将结果存储在 eax 中:
eax = ebx + 0x10
lea 可以做得更多。它可以添加寄存器,将寄存器与常数 2、4 和 8 相乘,用于字、整数和双精度数的地址计算。它还可以添加偏移量。
请注意, lea 的特殊之处在于它永远不会修改标志,即使您将其用作上面示例中的简单添加也是如此。编译器有时会利用此功能并用 lea 替换添加以帮助调度程序。出于这个原因,在编译代码中执行简单算术运算的 lea 指令并不少见。
【讨论】:
要添加到 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。
本质上,操作:
leal 来源,目的地 => 目的地 = 地址 来源
如果你熟悉 C,它相当于:
char * 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
希望对你有帮助
【讨论】:
GNU 2.18 文档
https://sourceware.org/binutils/docs-2.18/as/i386_002dMemory.html
AT&T:-4(%ebp),英特尔:[ebp - 4]
然后英特尔语法是不言自明的。
更重要的是,文档还解释了一般情况:
英特尔语法间接内存引用形式
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 当你看到它时,就会清楚为什么地址的某些部分可能会被省略,以及每个表单将编译成什么。
【讨论】: