linux 如何知道何时为调用堆栈分配更多页面? [英] How does linux know when to allocate more pages to a call stack?

查看:50
本文介绍了linux 如何知道何时为调用堆栈分配更多页面?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

给出下面的程序, segfault()将(顾名思义)通过访问堆栈下方的256k进行segfault程序.但是, nofault()会逐渐推入堆栈下方,一直到下方1m,但绝不会出现段错误.

Given the program below, segfault() will (As the name suggests) segfault the program by accessing 256k below the stack. nofault() however, gradually pushes below the stack all the way to 1m below, but never segfaults.

另外,在 nofault()之后运行 segfault()也不会导致错误.

Additionally, running segfault() after nofault() doesn't result in an error either.

如果我将 sleep() s放在 nofault()中,并用时间来 cat/proc/$ pid/maps ,我会看到分配的堆栈空间在第一次调用和第二次调用之间增加,这解释了为什么 segfault()之后不会崩溃-有足够的内存.

If I put sleep()s in nofault() and use the time to cat /proc/$pid/maps I see the allocated stack space grows between the first and second call, this explains why segfault() doesn't crash afterwards - there's plenty of memory.

但是反汇编显示%rsp 没有变化.这是有道理的,因为那样会破坏调用堆栈.

But the disassembly shows there's no change to %rsp. This makes sense since that would screw up the call stack.

我假设最大堆栈大小将在编译时放入二进制文件中(回想起来,这对于编译器来说很难做到),或者只是定期检查%rsp 和在那之后添加一个缓冲区.

I presumed that the maximum stack size would be baked into the binary at compile time (In retrospect that would be very hard for a compiler to do) or that it would just periodically check %rsp and add a buffer after that.

内核如何知道何时增加堆栈内存?

How does the kernel know when to increase the stack memory?

#include <stdio.h>
#include <unistd.h>

void segfault(){
  char * x;
  int a;
  for( x = (char *)&x-1024*256; x<(char *)(&x+1); x++){
    a = *x & 0xFF;
    printf("%p = 0x%02x\n",x,a);
  }
}

void nofault(){
  char * x;
  int a;
  sleep(20);
  for( x = (char *)(&x); x>(char *)&x-1024*1024; x--){
    a = *x & 0xFF;
    printf("%p = 0x%02x\n",x,a);
  }
  sleep(20);
}

int main(){
  nofault();
  segfault();
}

推荐答案

当您访问未映射的页面时,处理器会引发页面错误.内核的页面错误处理程序检查地址是否合理地接近进程的%rsp ,如果是,则分配一些内存并恢复进程.如果您离%rsp 太远,内核会将故障作为信号传递给进程.

The processor raises a page fault when you access an unmapped page. The kernel's page fault handler checks whether the address is reasonably close to the process's %rsp and if so, it allocates some memory and resumes the process. If you are too far below %rsp, the kernel passes the fault along to the process as a signal.

我试图找到确切的地址定义,这些地址最接近%rsp 以触发堆栈增长,并从 linux/arch/x86/mm.c <提出了这个建议./code>:

I tried to find the precise definition of what addresses are close enough to %rsp to trigger stack growth, and came up with this from linux/arch/x86/mm.c:

/*
 * Accessing the stack below %sp is always a bug.
 * The large cushion allows instructions like enter
 * and pusha to work. ("enter $65535, $31" pushes
 * 32 pointers and then decrements %sp by 65535.)
 */
if (unlikely(address + 65536 + 32 * sizeof(unsigned long) < regs->sp)) {
        bad_area(regs, error_code, address);
        return;
}

但是通过试验您的程序,我发现 65536 + 32 * sizeof(unsigned long)并不是段错误和无段错误之间的实际临界点.它似乎是该值的两倍.所以我会坚持用模糊的合理接近"作为我的官方回答.

But experimenting with your program I found that 65536+32*sizeof(unsigned long) isn't the actual cutoff point between segfault and no segfault. It seems to be about twice that value. So I'll just stick with the vague "reasonably close" as my official answer.

这篇关于linux 如何知道何时为调用堆栈分配更多页面?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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