简体   繁体   English

表示为汇编代码的C代码-如何解释?

[英]C Code represented as Assembler Code - How to interpret?

I got this short C Code. 我得到了这段简短的C代码。

#include <stdint.h>
uint64_t multiply(uint32_t x, uint32_t y) {

uint64_t res;
res = x*y;
return res;
}

int main() {

uint32_t a = 3, b = 5, z;
z = multiply(a,b);
return 0;
}

There is also an Assembler Code for the given C code above. 上面的给定C代码也有一个汇编程序代码。 I don't understand everything of that assembler code. 我不了解所有的汇编代码。 I commented each line and you will find my question in the comments for each line. 我评论了每一行,您会在每一行的评论中找到我的问题。

The Assembler Code is: 汇编代码是:

.text
multiply:
     pushl  %ebp  // stores the stack frame of the calling function on the stack
     movl   %esp, %ebp // takes the current stack pointer and uses it as the frame for the called function
     subl   $16, %esp // it leaves room on the stack, but why 16Bytes. sizeof(res) = 8Bytes
     movl   8(%ebp), %eax // I don't know quite what "8(%ebp) mean? It has to do something with res, because
     imull  12(%ebp), %eax // here is the multiplication done. And again "12(%ebp).
     movl   %eax, -8(%ebp) // Now, we got a negative number in front of. How to interpret this?
     movl   $0, -4(%ebp) // here as well
     movl   -8(%ebp), %eax // and here again.
     movl   -4(%ebp), %edx // also here
     leave
     ret
main:
     pushl  %ebp // stores the stack frame of the calling function on the stack
     movl   %esp, %ebp // // takes the current stack pointer and uses it as the frame for the called function
     andl   $-8, %esp // what happens here and why?
     subl   $24, %esp // here, it leaves room for local variables, but why 24 bytes? a, b, c: the size of each of them is 4 Bytes. So 3*4 = 12
     movl   $3, 20(%esp) // 3 gets pushed on the stack
     movl   $5, 16(%esp) // 5 also get pushed on the stack
     movl   16(%esp), %eax // what does 16(%esp) mean and what happened with z?
     movl   %eax, 4(%esp) // we got the here as well
     movl   20(%esp), %eax // and also here
     movl   %eax, (%esp) // what does happen in this line?
     call   multiply  // thats clear, the function multiply gets called
     movl   %eax, 12(%esp) // it looks like the same as two lines before, except it contains the number 12
     movl   $0, %eax // I suppose, this line is because of "return 0;"
     leave
     ret

Negative references relative to %ebp are for local variables on the stack. 相对于%ebp的负引用是针对堆栈上的局部变量的。

 movl   8(%ebp), %eax // I don't know quite what "8(%ebp) mean? It has to do something with res, because`

%eax = x %eax = x

 imull  12(%ebp), %eax // here is the multiplication done. And again "12(%ebp).

%eax = %eax * y %eax =%eax * y

 movl   %eax, -8(%ebp) // Now, we got a negative number in front of. How to interpret this?

(u_int32_t)res = %eax // sets low 32 bits of res (u_int32_t)res =%eax //设置低32位res

 movl   $0, -4(%ebp) // here as well

clears upper 32 bits of res to extend 32-bit multiplication result to uint64_t 清除res的高32位,以将32位乘法结果扩展到uint64_t

 movl   -8(%ebp), %eax // and here again.
 movl   -4(%ebp), %edx // also here

return ret; 返回ret //64-bit results are returned as a pair of 32-bit registers %edx:%eax // 64位结果作为一对32位寄存器%edx:%eax返回

As for the main, see x86 calling convention which may help making sense of what happens. 至于主要方面,请参见x86调用约定 ,这可能有助于弄清发生的情况。

 andl   $-8, %esp // what happens here and why?

stack boundary is aligned by 8. I believe it's ABI requirement 堆栈边界以8对齐。我相信这是ABI要求

 subl   $24, %esp // here, it leaves room for local variables, but why 24 bytes? a, b, c: the size of each of them is 4 Bytes. So 3*4 = 12

Multiples of 8 (probably due to alignment requirements) 8的倍数(可能是由于对齐要求)

 movl   $3, 20(%esp) // 3 gets pushed on the stack

a = 3 a = 3

 movl   $5, 16(%esp) // 5 also get pushed on the stack

b = 5 b = 5

 movl   16(%esp), %eax // what does 16(%esp) mean and what happened with z?

%eax = b %eax = b

z is at 12(%esp) and is not used yet. z为12(%esp),尚未使用。

 movl   %eax, 4(%esp) // we got the here as well

put b on the stack (second argument to multiply()) 将b放在堆栈上(multiple()的第二个参数)

 movl   20(%esp), %eax // and also here

%eax = a %eax = a

 movl   %eax, (%esp) // what does happen in this line?

put a on the stack (first argument to multiply()) 将一个放在堆栈上(multiple()的第一个参数)

 call   multiply  // thats clear, the function multiply gets called

multiply returns 64-bit result in %edx:%eax 乘法返回%edx:%eax中的64位结果

 movl   %eax, 12(%esp) // it looks like the same as two lines before, except it contains the number 12

z = (uint32_t) multiply() z =(uint32_t)乘法()

 movl   $0, %eax // I suppose, this line is because of "return 0;"

yup. 对。 return 0; 返回0;

Arguments are pushed onto the stack when the function is called. 调用函数时,参数会被压入堆栈。 Inside the function, the stack pointer at that time is saved as the base pointer. 在函数内部,此时的堆栈指针将另存为基本指针。 (You got that much already.) The base pointer is used as a fixed location from which to reference arguments (which are above it, hence the positive offsets) and local variables (which are below it, hence the negative offsets). (您已经获得了很多。)基本指针用作固定的位置,从该位置可以引用参数(在它上面,因此是正偏移量)和局部变量(在它下面,因此是负偏移量)。

The advantage of using a base pointer is that it is stable throughout the entire function, even when the stack pointer changes (due to function calls and new scopes). 使用基本指针的优点是,即使堆栈指针发生更改(由于函数调用和新作用域),它也可以在整个函数中保持稳定。

So 8(%ebp) is one argument, and 12(%ebp) is the other. 因此8(%ebp)是一个参数,而12(%ebp)是另一个参数。

The code is likely using more space on the stack than it needs to, because it is using temporary variables that could be optimized out of you had optimization turned on. 该代码可能在堆栈上使用了比其需要的空间更多的空间,因为它使用的临时变量可以在优化被打开的情况下进行优化。

You might find this helpful: http://en.wikibooks.org/wiki/X86_Disassembly/Functions_and_Stack_Frames 您可能会发现这很有帮助: http : //en.wikibooks.org/wiki/X86_Disassembly/Functions_and_Stack_Frames

I started typing this as a comment but it was getting too long to fit. 我开始输入此内容作为评论,但已太长而无法容纳。

You can compile your example with -masm=intel so the assembly is more readable. 您可以使用-masm=intel编译示例,从而使程序集更具可读性。 Also, don't confuse the push and pop instructions with mov . 另外,请勿将pushpop指令与mov混淆。 push and pop always increments and decrements esp respectively before derefing the address whereas mov does not. 在取消引用地址之前, pushpop 总是分别增加和减少esp ,而mov则没有。

There are two ways to store values onto the stack. 有两种方法可以将值存储到堆栈中。 You can either push each item onto it one item at a time or you can allocate up-front the space required and then load each value onto the stackslot using mov + relative offset from either esp or ebp . 您可以一次push每个项目push一个项目,也可以预先分配所需的空间,然后使用mov +相对espebp相对偏移将每个值加载到堆栈槽中。

In your example, gcc chose the second method since that's usually faster because, unlike the first method, you're not constantly incrementing esp before saving the value onto the stack. 在您的示例中,gcc选择了第二种方法,因为它通常更快,因为与第一种方法不同,在将值保存到堆栈之前,您并不会不断地增加esp

To address your other question in comment, x86 instruction set does not have a mov instruction for copying values from memory location a to another memory location b directly. 为了解决您在注释中遇到的其他问题,x86指令集没有可将值直接从存储位置a复制到另一个存储位置bmov指令。 It is not uncommon to see code like: 看到类似以下代码的情况并不少见:

  mov   eax, [esp+16]
  mov   [esp+4], eax
  mov   eax, [esp+20]
  mov   [esp], eax
  call  multiply(unsigned int, unsigned int)
  mov   [esp+12], eax

Register eax is being used as an intermediate temporary variable to help copy data between the two stack locations. 寄存器eax用作中间临时变量,以帮助在两个堆栈位置之间复制数据。 You can mentally translate the above as: 您可以将以上内容翻译为:

esp[4] = esp[16]; // argument 2
esp[0] = esp[20]; // argument 1
call multiply
esp[12] = eax;    // eax has return value

Here's what the stack approximately looks like right before the call to multiply : 这是调用multiply之前堆栈的大致样子:

lower addr    esp       =>  uint32_t:a_copy = 3 <--.  arg1 to 'multiply'
              esp + 4       uint32_t:b_copy = 5 <--.  arg2 to 'multiply'
    ^         esp + 8       ????
    ^         esp + 12      uint32_t:z = ?      <--.
    |         esp + 16      uint32_t:b = 5         |  local variables in 'main'
    |         esp + 20      uint32_t:a = 3      <--.
    |         ...
    |         ...
higher addr   ebp           previous frame

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

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