了解程序集中的c函数

时间:2013-03-04 19:51:25

标签: assembly intel

我正在尝试学习如何理解汇编程序中的c函数。我使用“gcc code.c -m32 -o code -S -fno-stack-protector”编译了以下c程序

#include <stdio.h>

void function( int a, int b, int c )
{
   char buffer1[5];
   char buffer2[10];
}

void main()
{
   function( 1, 2, 3 );
}

声明输出如下:

        .section    __TEXT,__text,regular,pure_instructions
    .globl  _function
    .align  4, 0x90
_function:
    pushl   %ebp
    movl    %esp, %ebp
    subl    $28, %esp
    movl    16(%ebp), %eax
    movl    12(%ebp), %ecx
    movl    8(%ebp), %edx
    movl    %edx, -4(%ebp)
    movl    %ecx, -8(%ebp)
    movl    %eax, -12(%ebp)
    addl    $28, %esp
    popl    %ebp
    ret

    .globl  _main
    .align  4, 0x90
_main:
    pushl   %ebp
    movl    %esp, %ebp
    subl    $24, %esp
    movl    $1, (%esp)
    movl    $2, 4(%esp)
    movl    $3, 8(%esp)
    call    _function
    addl    $24, %esp
    popl    %ebp
    ret


.subsections_via_symbols

esp和ebp寄存器不能相等,因为定义int a,b,c的偏移量在_main和_function中是不同的。什么行从ebp中减去4?

谢谢!

2 个答案:

答案 0 :(得分:2)

调用函数通常是这样的:

1)在函数外部,参数被压入堆栈

subl    $24, %esp
movl    $1, (%esp)
movl    $2, 4(%esp)
movl    $3, 8(%esp)

2)在函数内部,在堆栈上分配空间来保存参数和局部变量。

subl $ 28,%esp

在这种情况下,你有3个整数和15个字符,总共27个字节;这与4字节边界对齐。

3)然后将参数复制到本地堆栈空间。

movl    16(%ebp), %eax
movl    12(%ebp), %ecx
movl    8(%ebp), %edx
movl    %edx, -4(%ebp)
movl    %ecx, -8(%ebp)
movl    %eax, -12(%ebp)

这里,16(%ebp)和friends是外推的参数的地址,-4(%ebp)是新分配的堆栈空间中的地址,这些值被复制到这些地址中。

答案 1 :(得分:1)

没有必要在任何地方减去4,因为它是返回地址(给定32位架构)将消耗堆栈中的前4个字节。

因此,当引用堆栈上的元素时,$ 4的差异。在 call指令之前,尚未推送返回地址。因此抵消$ 0 $ 4和$ 8在主要方面是正常的:

movl    $1, (%esp)
movl    $2, 4(%esp)
movl    $3, 8(%esp)

执行:

call    _function
main中的

将eip(返回地址)的内容推送到堆栈上,从而将esp提高4。

在函数中,返回地址(消耗4个字节)将位于堆栈顶部,正确的偏移量为 - $ 4, - $ 8和 - $ 12这正是函数中使用的值:

movl    %edx, -4(%ebp)
movl    %ecx, -8(%ebp)
movl    %eax, -12(%ebp)