分配了多少内存给调用堆栈?

发布于 2025-01-11 11:39:22 字数 2078 浏览 4 评论 0原文

以前我见过很多C++函数的汇编。在gcc中,它们都以这些指令开头:

push    rbp
mov     rbp, rsp
sub     rsp, <X>  ; <X> is size of frame

我知道这些指令存储前一个函数的帧指针,然后为当前函数设置一个帧。但在这里,程序集既不要求映射内存(如 malloc),也不检查 rbp 指向的内存是否分配给进程。

因此它假设启动代码已经为调用堆栈的整个深度映射了足够的内存。那么到底为调用堆栈分配了多少内存呢?启动代码如何知道调用栈的最大深度?

这也意味着,我可以远距离访问越界数组,因为虽然它不在当前帧中,但它映射到进程。所以我写了这段代码:

int main() {
    int arr[3] = {};
    printf("%d", arr[900]);
}

当索引为 900 时,这是以 SIGSEGV 退出。但令人惊讶的是,当索引为 901 时,它不会。同样,对于某些随机索引,它以 SIGSEGV 退出不适合某些人。在 编译器浏览器

Previously I had seen assembly of many functions in C++. In gcc, all of them start with these instructions:

push    rbp
mov     rbp, rsp
sub     rsp, <X>  ; <X> is size of frame

I know that these instructions store the frame pointer of previous function and then sets up a frame for current function. But here, assembly is neither asking for mapping memory (like malloc) and nor it is checking weather the memory pointed by rbp is allocated to the process.

So it assumes that startup code has mapped enough memory for the entire depth of call stack. So exactly how much memory is allocated for call stack? How does startup code can know the maximum depth of call stack?

It also means that, I can access array out of bound for a long distance since although it is not in current frame, it mapped to the process. So I wrote this code:

int main() {
    int arr[3] = {};
    printf("%d", arr[900]);
}

This is exiting with SIGSEGV when index is 900. But surprisingly not when index is 901. Similarly, it is exiting with SIGSEGV for some random indices and not for some. This behavior was observed when compiled with gcc-x86-64-11.2 in compiler explorer.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

深者入戏 2025-01-18 11:39:22

启动代码如何知道调用栈的最大深度?

事实并非如此。

在大多数常见的实现中,堆栈的大小是恒定的。

如果程序超出了常量大小的堆栈,则称为堆栈溢出。这就是为什么您必须避免在自动存储中创建大型对象(通常是但不一定是数组),以及为什么必须避免具有线性深度的递归(例如递归链表算法)。

那么到底为调用堆栈分配了多少内存?

在大多数桌面/服务器系统上,它是可配置的,并且默认为一到几兆字节。在嵌入式系统上它可能要少得多。

当索引为 900 时,会以 SIGSEGV 退出。但令人惊讶的是,当索引为 901 时,不会退出。

在这两种情况下,程序的行为都是未定义的。

是否可以知道分配的堆栈大小?

是的。您可以阅读目标系统的文档。如果您打算编写可移植程序,那么您必须假设所有目标系统的最小值。对于桌面/服务器,我提到的 1 MB 是合理的。

C++ 中没有获取大小的标准方法。

How does startup code can know the maximum depth of call stack?

It doesn't.

In most common implementation, the size of the stack is constant.

If the program exceeds the constant sized stack, that is called a stack overflow. This is why you must avoid creating large objects (which are typically, but not necessarily, arrays) in automatic storage, and why you must avoid recursion with linear depth (such as recursive linked list algorithms).

So exactly how much memory is allocated for call stack?

On most desktop/server systems it's configurable, and defaults to one to few megabytes. It can be much less on embedded systems.

This is exiting with SIGSEGV when index is 900. But surprisingly not when index is 901.

In both cases, the behaviour of the program is undefined.

Is it possible to know the allocated stack size?

Yes. You can read the documentation of the target system. If you intend to write a portable program, then you must assume the minimum of all target systems. For desktop/server, 1 megabyte that I mentioned is reasonable.

There is no standard way to acquire the size within C++.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文