gpt4 book ai didi

c - 查找栈帧大小

转载 作者:IT王子 更新时间:2023-10-29 00:23:58 25 4
gpt4 key购买 nike

调用函数的栈帧可以通过__builtin_frame_address(1)轻松获取,但是栈帧的大小呢?

是否有一个函数可以让我知道调用函数的堆栈帧有多大?

最佳答案

我的第一 react 是,为什么会有人想要这个?对于 C 函数来说,动态确定堆栈帧的大小应该被认为是不好的做法。 cdecl( 经典 C 调用约定)的全部意义在于函数本身(“被调用者”)不知道堆栈帧的大小。当切换到不同的平台、不同的地址大小(例如从 32 位到 64 位)、不同的编译器甚至不同的编译器设置(特别是优化)时,任何偏离该理念的行为都可能导致代码中断。

另一方面,由于 gcc 已经提供了这个函数 __builtin_frame_address,看看从那里可以得到多少信息会很有趣。

来自documentation :

The frame address is normally the address of the first word pushed on to the stack by the function.

在 x86 上,函数通常以:

push ebp       ; bp for 16-bit, ebp for 32-bit, rbp for 64-bit

换句话说,__builtin_frame_address 返回调用者堆栈帧的基指针。不幸的是,基指针很少或根本没有说明任何堆栈帧的开始或结束位置;基指针指向堆栈帧中间某处的位置(在参数局部变量之间)。

如果你只对保存局部变量的栈帧部分感兴趣,那么函数本身就拥有所有的知识。该部分的大小是堆栈指针和基指针之间的差异。

register char * const basepointer  asm("ebp");
register char * const stackpointer asm("esp");

size_localvars = basepointer - stackpointer;

请记住,gcc 似乎从一开始就在堆栈上分配空间,用于保存从被调用者内部调用的其他函数的参数。严格来说,那个空间属于那些其他函数的堆栈帧,但边界不明确。这是否是一个问题,取决于您的目的;您将如何处理计算出的栈帧大小?

至于另一部分(参数),则视情况而定。如果您的函数具有固定数量的参数,那么您可以简单地测量(形式)参数的大小。它不能保证调用者实际上将相同数量的参数压入堆栈,但假设调用者编译时没有针对被调用者的原型(prototype)发出警告,它应该没问题。

void callee(int a, int b, int c, int d)
{
size_params = sizeof d + (char *)&d - (char *)&a;
}

您可以结合这两种技术来获得完整的堆栈框架(包括返回地址和保存的基指针):

register char * const stackpointer asm("esp");

void callee(int a, int b, int c, int d)
{
total_size = sizeof d + (char *)&d - stackpointer;
}

但是,如果您的函数具有可变数量的参数(“省略号”,如 printf 具有),则只有调用者知道参数的大小。除非被调用者有办法导出参数的大小和数量(在 printf 风格的函数的情况下,通过分析格式字符串),否则您必须让调用者将该信息传递给被叫者。

编辑:请注意,这只适用于让一个函数测量他自己的堆栈框架。被调用者无法计算其调用者的栈帧大小;被调用者必须向调用者询问该信息。

但是,被调用者可以对调用者局部变量的大小进行有根据的猜测。此 block 从被调用者的参数结束处开始 (sizeof d + (char *)&d),并在调用者的基指针 (__builtin_frame_address(1)) 处结束。由于编译器强加的地址对齐,起始地址可能会稍微不准确;计算出的大小可能包括一 block 未使用的堆栈空间。

void callee(int a, int b, int c, int d)
{
size_localvars_of_caller = __builtin_frame_address(1) - sizeof d - (char *)&d;
}

关于c - 查找栈帧大小,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21501222/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com