[英]Dynamic expansion of the Linux stack
我注意到Linux堆栈开始很小并且由于递归/推送/ vlas导致的页面错误扩展到getrlimit(RLIMIT_STACK,...)
,给定或接受(在我的系统上默认为8MiB)。
奇怪的是,如果我通过直接寻址字节导致页面错误,在限制范围内,Linux将定期进行段错误而不扩展页面映射(尽管如果我在例如alloca之后执行此操作而导致堆栈扩展,则不会出现段错误)。
示例程序:
#include <stdio.h>
#include <unistd.h>
#include <stdint.h>
#include <stdlib.h>
#define CMD "grep stack /proc/XXXXXXXXXXXXXXXX/maps"
#define CMDP "grep stack /proc/%ld/maps"
void vla(size_t Sz)
{
char b[Sz];
b[0]='y';
b[1]='\0';
puts(b);
}
#define OFFSET (sizeof(char)<<12)
int main(int C, char **V)
{
char cmd[sizeof CMD]; sprintf(cmd,CMDP,(long)getpid());
if(system(cmd)) return 1;
for(int i=0; ; i++){
printf("%d\n", i);
char *ptr = (char*)(((uintptr_t)&ptr)-i*OFFSET);
if(C>1) vla(i*OFFSET); //pass an argument to the executable to turn this on
ptr[0] = 'x';
ptr[1] = '\0';
if(system(cmd)) return 1;
puts(ptr);
}
}
什么内核代码在做这个? 它如何区分自然堆栈增长和我在地址空间中徘徊?
linux内核将堆栈指针的内容作为限制(在合理的边界内)。 访问堆栈指针下方的堆栈减去65536并且32个无符号长整数的大小导致分段违规。 所以,如果你从堆栈中访问内存,你必须确保堆栈指针以某种方式减少访问量,以使linux内核扩大段。 请参阅/arch/x86/mm/fault.c
以下代码段:
if (sw_error_code & X86_PF_USER) {
/*
* 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, sw_error_code, address);
return;
}
}
堆栈指针寄存器的值在这里是关键!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.