2

这是程序:

#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 与 main() 中的 ESP 的值不同?不应该mov ebp, esp 使 EBP ==0xffffcf88吗?我认为这会将 EBP 设置为 ESP。

编辑:

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

ESP0xffffcf88在两个值(均为 4 个字节)被推入堆栈之前。之后,它的值为0xffffcf88 - 0x8== 0xffffcf80。这就是 EBP 的当前值。然后 ESP -= 0x10。

ESP的值是如何修改的?是这样的mov ESP, ESP - 0x8吗?

4

1 回答 1

2

我希望我能理解你的问题。

首先,您对帧指针的新值是正确的。在这里,您需要知道“break test_function”实际上在函数序言执行后停止了 gdb,因此您已经过了将 ebp 显式存储到堆栈的点。见详细说明

每次推送(或调用)时,ESP 会减少 4。它也被局部变量所需的空间量等减少(减去一些立即值)。 在 x86 上使用了不同的“调用约定”,因此这些细节可能会有所不同。

其中的某些部分也是编译器特定的。例如,默认情况下 GCC 在 x86 上保持堆栈 4 字对齐(原因之一是让 SSE 单元满意)。请参阅此 SO 线程

顺便说一句:只要编译器知道如何从函数中的任何点展开堆栈,帧指针实际上是多余的,并且通常在优化代码中将其省略。

于 2014-09-18T07:03:32.833 回答