C 使用;lea($30,%edx),%eax添加edx和30并将其放入eax
我正在准备明天的期中考试,前一期中考试的一个问题是: 考虑下面的C函数。编写相应的汇编语言函数以执行相同的操作C 使用;lea($30,%edx),%eax添加edx和30并将其放入eax,c,assembly,C,Assembly,我正在准备明天的期中考试,前一期中考试的一个问题是: 考虑下面的C函数。编写相应的汇编语言函数以执行相同的操作 int myFunction (int a) { return (a + 30); } 我写的是: .global _myFunction _myFunction: pushl %ebp movl %esp, %ebp movl 8(%ebp), %edx lea ($30, %edx), %eax leave ret
int myFunction (int a)
{
return (a + 30);
}
我写的是:
.global _myFunction
_myFunction:
pushl %ebp
movl %esp, %ebp
movl 8(%ebp), %edx
lea ($30, %edx), %eax
leave
ret
其中a为edx,a+30为eax。在这种情况下使用lea正确吗?是否需要这样做
lea ($30, %edx, 1), %eax
谢谢。如果您希望使用
leal
简单地添加30,那么您应该这样做:
leal 30(%edx), %eax
表示法为移位(基址寄存器
,偏移寄存器
,标度乘法器
)。位移放置在外侧30
被添加到edx
并存储在eax
中。在AT&T/GAS表示法中,可以同时省去偏移量和乘数。在我们的示例中,这给我们留下了本示例中的等效值base+displacement
或edx+30
赵也提出了一个很好的观点。假设教授要求您优化代码。myFunction
不使用局部变量,本身也不需要堆栈空间,这一事实存在一些低效性。因此,可以删除所有堆栈帧的创建和销毁。如果删除堆栈帧,则不再推%ebp。这意味着您的第一个参数inta
位于4(%esp)
。考虑到这一点,您的功能可以简化为以下简单功能:
.global _myFunction
_myFunction:
movl 4(%esp), %eax
addl $30, %eax
ret
当然,当您更改函数以使其需要在堆栈上存储内容时,您必须将堆栈帧代码放回(
pushl%ebp
,pushl%ebp
,leave
等)看起来至少是编译器生成的。但是,是否有任何原因表明该函数不仅仅是movl4(%esp),%eax
addl$30,%eax
ret
?如果您从未实际使用堆栈(即:除非您自己调用函数,否则为局部变量保留空间等),则构建堆栈帧不是很有用。如果您不需要设置标志,lea通常比add快。@MichaelPetch,我实际上读到了其他方法。据我所知,lea
防止指令重新排序,因为在执行lea
指令之前需要填充标志寄存器。在任何非古代CPU上使用lea
而不是add
应该是个坏主意。@Kay这是正确的。不过,如果你看看我的评论,我一般都会这么说。大多数优化器会查看上下文,以确定add或lea在任何给定情况下是否更有意义。寻址模式的乘法部分不能为零:如果存在,它总是1,2,4,8中的一个。但是,它所应用的操作数是可选的。base+置换是一种特殊情况。我最初使用“有效”一词,因为从观察者的角度来看,缺少偏移寄存器(索引)和乘数似乎等于零。在引擎盖下base+displacement
产生一种特殊的单字节地址模式编码,既不指定偏移寄存器(索引),也不指定乘法器。显然,一个副作用是,如果不指定offsetregister,则汇编程序将不允许在没有offsetregister(索引)的情况下指定任何标量,因为指令中根本没有编码scalarmultiplier。