调用函数时EBP会发生什么

时间:2014-09-17 16:49:50

标签: gdb stackframe

这是该计划:

#include <stdio.h>

void test_function(int a, int b, int c, int d){

    int flag;   
    flag = 31337;

}

int main(){

    test_function(1,2,3,4);
}

来自GDB:

    Breakpoint 1, main () at stack_example.c:14
    14      test_function(1,2,3,4);
    (gdb) i r esp ebp eip
    esp            0xffffcf88   0xffffcf88
    ebp            0xffffcf98   0xffffcf98
    eip            0x8048402    0x8048402 <main+6>
    (gdb) cont
    Continuing.

    Breakpoint 2, test_function (a=1, b=2, c=3, d=4) at stack_example.c:8
    8       flag = 31337;
    (gdb) i r esp ebp eip
    esp            0xffffcf70   0xffffcf70
    ebp            0xffffcf80   0xffffcf80
    eip            0x80483f3    0x80483f3 <test_function+6>
    (gdb) 

Dump of assembler code for function test_function:
   0x080483ed <+0>: push   ebp
   x080483ee <+1>:  mov    ebp,esp
   0x080483f0 <+3>: sub    esp,0x10
=> 0x080483f3 <+6>: mov    DWORD PTR [ebp-0x4],0x7a69
   0x080483fa <+13>:    leave  
   0x080483fb <+14>:    ret    

来自GDB, 为什么EBP与ESP在main()中的值不同?不应该mov ebp, esp 制作EBP == 0xffffcf88?我认为这将EBP设置为ESP。

编辑:

我想我可能已回答了我自己的问题。请指正。 当返回地址和保存的帧指针被压入堆栈时,移动ESP。

在将两个值(均为4个字节)压入堆栈之前,ESP值为0xffffcf88。之后,它的值为0xffffcf88 - 0x8 == 0xffffcf80。这就是EBP目前的价值所在。然后ESP - = 0x10。

ESP的价值如何修改?它是mov ESP, ESP - 0x8吗?

1 个答案:

答案 0 :(得分:2)

我希望我理解你的问题。

首先,你对帧指针的新值是正确的。在这里你需要知道&#34; break test_function&#34;实际上在执行了函数序言后停止gdb,所以你已经超过了ebp显式存储到堆栈的点。 请参阅detailed explanation

每次推送(或通话)时,ESP减少4。它也减少了(减去一些立即值)局部变量所需的空间量等。 Different "calling conventions" are being used on x86,所以这些细节可能会有所不同。

这部分内容也是特定于编译器的。例如,GCC默认情况下在x86上保持堆栈4字对齐(出于一个原因,保持SSE单元满意)。请参阅this SO thread

BTW:只要编译器知道如何从函数中的任何一点解开堆栈,帧指针实际上是冗余的,并且通常使用优化代码省略它。