Linux 如何知道何时为调用堆栈分配更多页面?

2024-04-07

鉴于以下程序,segfault()(顾名思义)将通过访问堆栈下方的 256k 来使程序出现段错误。nofault()然而,逐渐将堆栈推到下方 1m,但永远不会出现段错误。

此外,运行segfault() after nofault()也不会导致错误。

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

但反汇编表明没有任何变化%rsp。这是有道理的,因为这会搞砸调用堆栈。

我假设最大堆栈大小将在编译时被烘焙到二进制文件中(回想起来,编译器很难做到这一点),或者它只是定期检查%rsp然后添加一个缓冲区。

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

#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,内核将错误作为信号传递给进程。

我试图找到足够接近的地址的精确定义%rsp触发堆栈增长,并提出了这个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)不是段错误和无段错误之间的实际分界点。看起来大约是这个值的两倍。因此,我将坚持使用含糊的“相当接近”作为我的官方答案。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Linux 如何知道何时为调用堆栈分配更多页面? 的相关文章

随机推荐