寻找堆栈帧大小 [英] Finding stack frame size

查看:89
本文介绍了寻找堆栈帧大小的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

一个调用函数的栈帧可以很容易地通过 __ builtin_frame_address(1),但对于堆栈帧的大小得到?

The stack frame of a caller function can be easily obtained via __builtin_frame_address(1), but what about the stack frame size?

有没有可以让我知道有多大的函数的调用函数的栈帧?

Is there a function that will let me know how big is the stack frame of the caller function?

推荐答案

我的第一反应会是,为什么会有人要吗?应该认为是不好的实践的C函数来动态确定堆栈帧的大小。整点的 CDECL 的(的经典的C调用约定)是函数本身(被叫方)不具有堆栈帧大小的知识。从哲学的分流可能导致您的code,以切换到不同的平台,不同的地址的大小(例如从32位到64位)时打破,不同的编译器,甚至不同的编译器设置(特别是优化)。

My first reaction would have been, why would anybody want this? It should be considered bad practice for a C function to dynamically determine the size of the stack frame. The whole point of cdecl (the classic C calling convention) is that the function itself (the 'callee') has no knowledge of the size of the stack frame. Any diversion from that philosophy may cause your code to break when switching over to a different platform, a different address size (e.g. from 32-bit to 64-bit), a different compiler or even different compiler settings (in particular optimizations).

在另一方面,由于的gcc 的已经提供了这个功能 __ builtin_frame_address ,这将是有趣的,看看有多少信息可以从那里派生

On the other hand, since gcc already offers this function __builtin_frame_address, it will be interesting to see how much information can be derived from there.

文档

的帧地址通常是第一个字的地址由功能推到堆栈中。

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

在x86上,一个典型的函数开头:

On x86, a function typically starts with:

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

在换句话说, __ builtin_frame_address 返回调用者的堆栈帧的基指针的。
不幸的是,基指针表示很少或没有什么地方的任何堆栈帧开始或结束;
基指针指向是在栈帧中间的某个位置(之间的参数局部变量)。

In other words, __builtin_frame_address returns the base pointer of the caller's stack frame. Unfortunately, the base pointer says little or nothing about where any stack frame starts or ends; the base pointer points to a location that is somewhere in the middle of the stack frame (between the parameters and the local variables).

如果你只对持有局部变量栈帧的一部分感兴趣,则函数本身所具有的一切知识。该部分的大小是堆栈指针和基指针之间的差。

If you are only interested in the part of the stack frame that holds the local variables, then the function itself has all the knowledge. The size of that part is the difference between the stack pointer and the base pointer.

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

size_localvars = basepointer - stackpointer;

请记住,海湾合作委员会似乎是直接从被用于保存从被调用内部调用等功能参数开始分配堆栈上的空间。严格地说,该空间属于的那些其他函数的堆栈帧,但边界不清。这是否是一个问题,要看你的目的;你会用计算堆栈帧的大小呢?

Please keep in mind that gcc seems to allocate space on the stack right from the beginning that is used to hold parameters for other functions called from inside the callee. Strictly speaking, that space belongs to the stack frames of those other functions, but the boundary is unclear. Whether this is a problem, depends on your purpose; what you are going to do with the calculated stack frame size?

至于其他部分(参数),这取决于。如果你的函数有一个固定的参数号码,然后你可以简单地测量(正式的)参数的大小。它并不保证调用者实际上压入堆栈的参数相同的金额,但不承担对被叫方的原型警告编译调用者,应该OK。

As for the other part (the parameters), that depends. If your function has a fixed number of parameters, then you could simply measure the size of the (formal) parameters. It does not guarantee that the caller actually pushed the same amount of parameters on the stack, but assuming the caller compiled without warnings against callee's prototype, it should be OK.

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

您可以结合两种技术来获取完整的StackFrame(包括返回地址和保存的基指针):

You can combine the two techniques to get the full stackframe (including return address and saved base pointer):

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 式的功能,通过分析格式字符串),你就必须让来电者传递到被叫方的信息。

If however, your function has a variable number of parameter (an 'ellipsis', like printf has), then the size of the parameters is known only to the caller. Unless the callee has a way to derive the size and number of parameters (in case of a printf-style function, by analyzing the format string), you would have to let the caller pass that information on to the callee.

编辑:
请注意,这只能让一个功能测量自己的堆栈帧。的被调用无法计算他的调用者的堆栈帧大小;被叫方将不得不问来电者的信息。

Please note, this only works to let a function measure his own stack frame. A callee cannot calculate his caller's stack frame size; callee will have to ask caller for that information.

然而,被叫方的可以的做出有关来电者的局部变量的大小的猜测。此块开始的位置,被叫方的参数结束(的sizeof(D)+(字符*)和D ),并在调用者的基指针结束( __ builtin_frame_address(1) )。起始地址可能不太精确,由于编译器所施加的地址对齐;计算出的尺寸可以包括一块未使用堆栈空间。

However, callee can make an educated guess about the size of caller's local variables. This block starts where callee's parameters end (sizeof d + (char *)&d), and ends at caller's base pointer (__builtin_frame_address(1)). The start address may be slightly inaccurate due to address alignment imposed by the compiler; the calculated size may include a piece of unused stack space.

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

这篇关于寻找堆栈帧大小的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆