【问题标题】:understanding stack and frame pointer理解堆栈和帧指针
【发布时间】:2021-12-26 12:40:03
【问题描述】:

我试图理解堆栈和帧指针。我有下面的简单 C 程序:

#include <stdio.h>
#include <stdlib.h>


int myfunction(int counter) {
    int result = 5;
    printf("myfunction %p %p %p\n", &result, &counter, __builtin_frame_address(0));
    return 0;
}


int main()
{
    int i;
    int j;
    printf("main %p %p\n", &i, __builtin_frame_address(0));

    myfunction(4);
    return 0;
}

当我使用 gdb 运行程序并检查以内置框架的地址开头的内存位置时,我得到以下输出:

这引起了我的困惑。我假设地址为0xbffff608 的FP 将指向堆栈的起始地址,因此我预计resultcounter 的内存地址会高于或低于FP 地址,但这是内存地址的顺序不符合我的假设,有人可以帮忙澄清一下吗?

内存地址:

  • 0xbffff608(内置帧地址,我假设这是帧指针)
  • 0xbffff610(计数器参数的地址)
  • 0xbffff5f8(结果变量的地址)

让我困惑的是,我认为帧指针指示堆栈的起始地址,因此在这种情况下 0xbffff608 指向当前堆栈的起始地址,那么当前堆栈中的计数器和结果应该都在之后或之前开始帧指针。但是,现在情况好坏参半。 counter 的内存地址高于帧指针,而 result 的内存地址低于帧指针。如果帧指针指示堆栈的开始,那么为什么会出现这种情况?

更新:主函数反汇编

【问题讨论】:

  • Nitpick:打印指针时,应将其强制转换为 void-pointer
  • 哪个系统?我无法在我的系统上复制
  • 它的 linux ubuntu 32 位
  • 好的,32 位系统...好吧,我不是 100% 确定我使用 64 位系统,但据我所知,32 位系统的调用约定要求调用者放置在进行函数调用之前 堆栈上的参数。这可以解释count 的位置您查看生成的程序集了吗?在通话前查找push
  • 我确实在调用myfunction 之前看到了一个推送调用$0x4 是什么意思?那是被推入的参数整数 4 吗?

标签: c pointers stack


【解决方案1】:

帧指针的确切使用取决于系统和编译器,但观察可以解释如下:

counterresult 的区别在于counter 是由调用者(main())压入堆栈的参数,而result 是严格属于函数的局部变量(@ 987654326@).

只有result属于函数框架,因为函数只负责清理自己的局部变量,而参数由调用者清理。

调用者有责任清理参数是很有意义的,因为参数的大小可能不是恒定的(例如printf())。

【讨论】:

    【解决方案2】:

    栈的顺序是

    1. 参数
    2. 退货地址
    3. 基指针
    4. 局部变量

    在 处,您可以看到 ebp = esp 对于 myFunction 也会发生同样的情况。 如果您查看顺序,您会发现参数具有更高的地址。这就是为什么计数器有更高的地址和更低的结果。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-17
      • 1970-01-01
      • 2015-08-05
      • 1970-01-01
      • 2013-01-20
      • 1970-01-01
      相关资源
      最近更新 更多