汇编与 C 代码比较

Assembly Compared With C code

我目前正在学习汇编语言和 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  ,%eax               t2 = z*48
movl  12(%ebp),%edx         y
addl  8(%ebp),%edx          t1 = x+y
andl  535,%edx           t3 = t1&0xFFFF
imull %edx,%eax             Return t4 = t2*t3

不是使用 leal 然后移动 4 来将 z 乘以 48,我可以只使用 imull $48, %eax 吗?

此外,这是多次使用 %edx 寄存器。这是否意味着 t1 正在被覆盖?换句话说,如果我想的话,我还能在 t4 之前检索 t1 吗?

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

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

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

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