装配与C代码比较

时间:2016-04-24 03:07:24

标签: c assembly x86 att

我目前正在学习汇编和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吗?

1 个答案:

答案 0 :(得分:2)

尝试将程序集与代码逐行匹配可能不是解决此问题的最佳方法。编译器进行了一些优化,使程序尽可能高效地运行,这就是为什么你可能会注意到代码之间存在一些不一致的原因。

回答你的第一个问题,从技术上来说可行,但编译器再一次做了几次优化。因此,虽然使用imul看起来更直观,但编译器确定leal和sall更有效。 编辑:我只是想指出,在可能的情况下,几乎总是使用位移运算符而不是imul。 CPU的位移更便宜,因为它实际上只是移位位值而不是尝试执行一些可能需要更多CPU时间的数学运算。

现在关于"覆盖" T1。汇编没有关于程序变量的任何信息 - 它只知道它需要对某些值执行某些操作。虽然程序集可能使用4个不同的寄存器来存储t1-4,但编译器确定它是不必要的,并且您只需要2个寄存器来存储所有值。如果你考虑一下,这应该是有道理的。您的功能可以简化为几行代码。显然,这不是一个好主意,因为这会使其无法阅读,但是装配并不一定是为了能够阅读而且是可读的。如果你回到你的程序并在返回t4之前用t1执行了一些其他操作,你可能会注意到你的程序集与以前不同,并且它可能正在使用另一个寄存器,具体取决于值的使用方式。

如果您真的想在程序集中使用程序的准系统版本,请使用-Og标志进行编译以关闭编译器优化。它可能仍然与您的代码不完全匹配,但它可能使您更容易理解正在进行的操作。