简体   繁体   English

装配与C代码比较

[英]Assembly Compared With C code

I am currently learning assembly and C programming languages and I have a couple of questions about it. 我目前正在学习汇编和C编程语言,我有几个问题。

C code 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;
}

Assembly code 汇编代码

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

Instead of using leal and then shifting by 4 to multiply z by 48, could I just use imull $48, %eax ? 而不是使用leal然后移动4乘以z乘以48,我可以使用imull $ 48,%eax吗?

Also, this is using the %edx register several times. 此外,这是多次使用%edx寄存器。 Does this mean t1 is being overwritten? 这是否意味着t1被覆盖? In other words, would I still be able to retrieve t1 right before t4 if I wanted to? 换句话说,如果我想,我还能在t4之前检索t1吗?

Trying to match assembly to your code line by line probably isn't the best way to approach this. 尝试将程序集与代码逐行匹配可能不是解决此问题的最佳方法。 The compiler makes several optimizations to make your program run as efficiently as possible, which is why you may notice some inconsistencies between your code. 编译器进行了一些优化以使程序尽可能高效地运行,这就是为什么您可能会注意到代码之间存在一些不一致的原因。

To answer your first question, technically that would work, but once again the compiler does make several optimizations. 要回答你的第一个问题,从技术上来说可行,但编译器再次做了几次优化。 So while it may seem more intuitive to use imul, the compiler determined that leal and sall is more efficient. 因此,虽然使用imul看起来更直观,但编译器确定leal和sall更有效。 EDIT: I just want to point out that bit shift operators are almost always used instead of imul, when possible. 编辑:我只是想指出,在可能的情况下,几乎总是使用位移运算符而不是imul。 Bit shifting is much cheaper for the CPU since it quite literally is just shifting bit values rather than trying to perform some mathematical operation that may take more CPU time. CPU的位移更便宜,因为它实际上只是改变位值而不是尝试执行可能需要更多CPU时间的数学运算。

Now regarding "overwriting" t1. 现在关于“覆盖”t1。 Assembly doesn't have any information about your program variables - all it knows is that it needs to perform some operations on some values. 程序集没有任何关于程序变量的信息 - 它只知道它需要对某些值执行某些操作。 While the assembly could potentially use 4 different registers to store t1-4, the compiler determined that it was unnecessary and that you only need 2 registers for all of the values. 虽然程序集可能使用4个不同的寄存器来存储t1-4,但编译器确定它是不必要的,并且您只需要2个寄存器来存储所有值。 If you think about it, this should make sense. 如果你考虑一下,这应该是有道理的。 Your function could be reduced to just a few lines of code. 您的功能可以简化为几行代码。 Obviously that isn't a good idea since that would make it impossible to read, but assembly isn't necessarily designed to be "readable". 显然,这不是一个好主意,因为这会使其无法阅读,但装配不一定是“可读的”。 If you went back to your program and performed some other operation with t1 before returning t4, you may notice that your assembly is different than before and that it may be using another register, depending on how the value is used. 如果你回到你的程序并在返回t4之前用t1执行了一些其他操作,你可能会注意到你的程序集与以前不同,并且它可能正在使用另一个寄存器,具体取决于值的使用方式。

If you really want a barebones version of your program in assembly, compile with the -Og flag to turn down compiler optimizations. 如果您真的想在程序集中使用程序的准系统版本,请使用-Og标志进行编译以关闭编译器优化。 It may still not exactly match your code, but it might make it easier for you to understand what's going on. 它可能仍然不完全匹配您的代码,但它可能使您更容易理解正在发生的事情。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM