我目前正在学习汇编和C编程语言,我对它有几个问题。
C代码
int arith(int x, int y, int z) {
int t1 = x + y;
int t2 = z*48;
int t3 = t1 & 0xFFFF;
int t4 = t2 * t3;
return t4;
}
汇编代码
movl 16(%ebp),%eax z
leal (%eax,%eax,2), %eax z*3
sall $4,%eax t2 = z*48
movl 12(%ebp),%edx y
addl 8(%ebp),%edx t1 = x+y
andl $65535,%edx t3 = t1&0xFFFF
imull %edx,%eax Return t4 = t2*t3
不是使用leal然后移动4来将z乘以48,我可以使用imull $ 48,%eax吗?
此外,这是多次使用%edx寄存器。这是否意味着t1被覆盖?换句话说,如果我愿意,我还能在t4之前检索t1吗?
答案 0 :(得分:2)
尝试将程序集与代码逐行匹配可能不是解决此问题的最佳方法。编译器进行了一些优化,使程序尽可能高效地运行,这就是为什么你可能会注意到代码之间存在一些不一致的原因。
回答你的第一个问题,从技术上来说可行,但编译器再一次做了几次优化。因此,虽然使用imul看起来更直观,但编译器确定leal和sall更有效。 编辑:我只是想指出,在可能的情况下,几乎总是使用位移运算符而不是imul。 CPU的位移更便宜,因为它实际上只是移位位值而不是尝试执行一些可能需要更多CPU时间的数学运算。
现在关于"覆盖" T1。汇编没有关于程序变量的任何信息 - 它只知道它需要对某些值执行某些操作。虽然程序集可能使用4个不同的寄存器来存储t1-4,但编译器确定它是不必要的,并且您只需要2个寄存器来存储所有值。如果你考虑一下,这应该是有道理的。您的功能可以简化为几行代码。显然,这不是一个好主意,因为这会使其无法阅读,但是装配并不一定是为了能够阅读而且是可读的。如果你回到你的程序并在返回t4之前用t1执行了一些其他操作,你可能会注意到你的程序集与以前不同,并且它可能正在使用另一个寄存器,具体取决于值的使用方式。
如果您真的想在程序集中使用程序的准系统版本,请使用-Og标志进行编译以关闭编译器优化。它可能仍然与您的代码不完全匹配,但它可能使您更容易理解正在进行的操作。