[英]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.