zac*_*zac 2 c assembly operating-system
我对此有点模糊 - 但我认为操作系统需要能够跟踪进程线程正在使用(或保留)虚拟地址空间中的哪些页面.对于程序员通过VirtualAlloc(或您的OS等效)明确请求的内存,这很容易.但是,随着线程执行时堆栈的增长/收缩,堆栈会溢出不同数量的页面.很明显,应用程序员没有请求使用这些页面 - 那么谁来处理对操作系统的请求?C运行时?我不认为操作系统可以自动执行此操作.我缺乏汇编知识来转储可执行文件并检查自己..
Linux是开源的,你可以看看它做了什么.这是来自arch/x86/mm/fault.c,__do_page_fault处理(等待)页面错误的函数:
vma = find_vma(mm, address);
if (unlikely(!vma)) {
bad_area(regs, error_code, address);
return;
}
if (likely(vma->vm_start <= address))
goto good_area;
if (unlikely(!(vma->vm_flags & VM_GROWSDOWN))) {
bad_area(regs, error_code, address);
return;
}
if (error_code & 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, error_code, address);
return;
}
}
if (unlikely(expand_stack(vma, address))) {
bad_area(regs, error_code, address);
return;
}
Run Code Online (Sandbox Code Playgroud)
find_vma找到在错误地址之上结束的第一个映射区域.如果故障高于起始地址,那么这是对已经映射的内存的正常访问,所以这里没有任何事情要做(转到good_area).
否则,如果它不是一个可以长大的区域,我们就会出错.我们剩下的是在一个可以长大的区域内进行访问.这是堆栈的常见情况.
接下来,代码检查故障和堆栈指针的关系.通常通过首先移动堆栈指针来分配局部变量,但这不是存储器访问,因此不会产生错误.堆栈将在第一次访问时扩展,因此应该在堆栈指针之上.评论Accessing the stack below %sp is always a bug.与此有关.然而,一些指令临时访问堆栈指针下方,因此为此做了一些限制.一些ABI也利用所谓的红色区域,该红色区域是堆栈指针下方的固定大小区域,可自由使用.您可以看到它认为在大约64kB的堆栈指针内的任何访问都是有效的访问.如果一切顺利,堆栈实际上是扩展的.