繁体   English   中英

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

[英]How does linux know when to allocate more pages to a call stack?

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

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

如果我将sleep()放入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提出了这个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)不是段错误和无段错误之间的实际临界点。 它似乎是该值的两倍。 因此,我将坚持以模糊的“合理接近”作为我的正式答案。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM