简体   繁体   English

c函数的汇编代码

[英]assembly code of the c function

I'm trying to understand the assembly code of the C function. 我正在尝试理解C函数的汇编代码。 I could not understand why andl -16 is done at the main. 我无法理解为什么andl -16在主要部分完成。 Is it for allocating space for the local variables. 是为局部变量分配空间。 If so why subl 32 is done for main. 如果是这样,为什么subl 32是为main做的。

I could not understand the disassembly of the func1 . 我无法理解func1的反汇编。 As read the stack grows from higher order address to low order address for 8086 processors. 随着读取,堆栈从高阶地址增长到8086处理器的低阶地址。 So here why is the access on positive side of the ebp(for parameters offset) and why not in the negative side of ebp. 那么为什么在ebp的正侧(对于参数偏移)进行访问以及为什么不在ebp的负侧进行访问。 The local variables inside the func1 is 3 + return address + saved registers - So it has to be 20, but why is it 24? func1中的局部变量是3 +返回地址+保存的寄存器 - 所以它必须是20,但为什么它是24? ( subl $24,esp ) subl $24,esp

#include<stdio.h>
int add(int a, int b){
 int res = 0;
 res = a + b;
 return res;
}
int func1(int a){
 int s1,s2,s3;
 s1 = add(a,a);
 s2 = add(s1,a);
 s3 = add(s1,s2);
 return s3;
}
int main(){
 int a,b;
 a = 1;b = 2;
 b = func1(a);
 printf("\n a : %d b : %d \n",a,b);
 return 0;
}

assembly code : 汇编代码:

       .file   "sample.c"
        .text
.globl add
        .type   add, @function
add:
        pushl   %ebp
        movl    %esp, %ebp
        subl    $16, %esp
        movl    $0, -4(%ebp)
        movl    12(%ebp), %eax
        movl    8(%ebp), %edx
        leal    (%edx,%eax), %eax
        movl    %eax, -4(%ebp)
        movl    -4(%ebp), %eax
        leave
        ret
        .size   add, .-add
.globl func1
        .type   func1, @function
func1:
        pushl   %ebp
        movl    %esp, %ebp
        subl    $24, %esp
        movl    8(%ebp), %eax
        movl    %eax, 4(%esp)
        movl    8(%ebp), %eax
        movl    %eax, (%esp)
        call    add
        movl    %eax, -4(%ebp)
        movl    8(%ebp), %eax
        movl    %eax, 4(%esp)
        movl    -4(%ebp), %eax
        movl    %eax, (%esp)
        call    add
        movl    %eax, -8(%ebp)
        movl    -8(%ebp), %eax
        movl    %eax, 4(%esp)
        movl    -4(%ebp), %eax
        movl    %eax, (%esp)
                                      call    add
        movl    %eax, -12(%ebp)
        movl    -12(%ebp), %eax
        leave
        ret
        .size   func1, .-func1
        .section        .rodata
.LC0:
        .string "\n a : %d b : %d \n"
        .text
.globl main
        .type   main, @function
main:
        pushl   %ebp
        movl    %esp, %ebp
        andl    $-16, %esp
        subl    $32, %esp
        movl    $1, 28(%esp)
        movl    $2, 24(%esp)
        movl    28(%esp), %eax
        movl    %eax, (%esp)
        call    func1
        movl    %eax, 24(%esp)
        movl    $.LC0, %eax
        movl    24(%esp), %edx
        movl    %edx, 8(%esp)
        movl    28(%esp), %edx
        movl    %edx, 4(%esp)
        movl    %eax, (%esp)
        call    printf
        movl    $0, %eax
        leave
        ret
        .size   main, .-main
        .ident  "GCC: (Ubuntu/Linaro 4.4.4-14ubuntu5) 4.4.5"
        .section        .note.GNU-stack,"",@progbits

The andl $-16, %esp aligns the stack pointer to a multiple of 16 bytes, by clearing the low four bits. andl $-16, %esp通过清除低4位将堆栈指针与16字节的倍数对齐。

The only places where positive offsets are used with (%ebp) are parameter accesses. 正向偏移与(%ebp)一起使用的唯一地方是参数访问。

You did not state what your target platform is or what switches you used to compile with. 您没有说明您的目标平台是什么或者您用于编译的开关。 The assembly code shows some Ubuntu identifier has been inserted, but I am not familiar with the ABI it uses, beyond that it is probably similar to ABIs generally used with the Intel x86 architecture. 汇编代码显示已插入一些Ubuntu标识符,但我不熟悉它使用的ABI,除此之外它可能类似于通常与Intel x86架构一起使用的ABI。 So I am going to guess that the ABI requires 8-byte alignment at routine calls, and so the compiler makes the stack frame of func1 24 bytes instead of 20 so that 8-byte alignment is maintained. 所以我猜测ABI在例程调用时需要8字节对齐,因此编译器使func1的堆栈帧为24字节而不是20字节,以便保持8字节对齐。

I will further guess that the compiler aligned the stack to 16 bytes at the start of main as a sort of “preference” in the compiler, in case it uses SSE instructions that prefer 16-byte alignment, or other operations that prefer 16-byte alignment. 我将进一步猜测,编译器将堆栈在main的开头与16字节对齐,作为编译器中的一种“首选项”,以防它使用喜欢16字节对齐的SSE指令或其他更喜欢16字节的操作对准。

So, we have: 所以,我们有:

In main , the andl $-16, %esp aligns the stack to a multiple of 16 bytes as a compiler preference. mainandl $-16, %esp将堆栈与16个字节的倍数对齐,作为编译器首选项。 Inside main , 28(%esp) and 24(%esp) refer to temporary values the compiler saves on the stack, while 8(%esp) , 4(%esp) , and (%esp) are used to pass parameters to func1 and printf . main内部, 28(%esp)24(%esp)是指编译器在堆栈上保存的临时值,而8(%esp)4(%esp)(%esp)用于将参数传递给func1printf We see from the fact that the assembly code calls printf but it is commented out in your code that you have pasted C source code that is different from the C source code used to generate the assembly code: This is not the correct assembly code generated from the C source code. 我们从汇编代码调用printf的事实中看到,但是在代码中注释掉了你已粘贴的C源代码与用于生成汇编代码的C源代码不同:这不是正确的汇编代码生成的C源代码。

In func1 , 24 bytes are allocated on the stack instead of 20 to maintain 8-byte alignment. func1 ,在堆栈上分配24个字节而不是20个字节以保持8字节对齐。 Inside func1 , parameters are accessed through 8(%ebp) and 4(%ebp) . func1内部,通过8(%ebp)4(%ebp)访问参数。 Locations from -12(%ebp) to -4(%ebp) are used to hold values of your variables. -12(%ebp)-4(%ebp)位置用于保存变量的值。 4(%esp) and (%esp) are used to pass parameters to add . 4(%esp)(%esp)用于传递要add参数。

Here is the stack frame of func1 : 这是func1的堆栈框架:

- 4(%ebp) = 20(%esp): s1.
    - 8(%ebp) = 16(%esp): s2.
    -12(%ebp) = 12(%esp): s3.
    -16(%ebp) =  8(%esp): Unused padding.
    -20(%ebp) =  4(%esp): Passes second parameter of add.
    -24(%ebp) =  0(%esp): Passes first parameter of add.

我建议用objdump -S的输出来解决这个问题,这会让你与C源交互。

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

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