_chkstk() 函数的目的是什么?

2021-12-22 00:00:00 windows c visual-c++ c++ callstack

我最近使用了 /FAsu Visual C++ 编译器option 输出一个特别长的成员函数定义的源代码+程序集.在汇编输出中,在设置堆栈帧后,会调用一个神秘的 _chkstk() 函数.

I recently used the /FAsu Visual C++ compiler option to output the source + assembly of a particularly long member function definition. In the assembly output, after the stack frame is set up, there is a single call to a mysterious _chkstk() function.

_chkstk() 上的 MSDN 页面a> 没有解释调用这个函数的原因.我还看到了堆栈溢出问题 在堆栈上分配更多页面大小的缓冲区会损坏内存吗?,但我确实这样做了不明白 OP 和接受的答案在说什么.

The MSDN page on _chkstk() does not explain the reason why this function is called. I have also seen the Stack Overflow question Allocating a buffer of more a page size on stack will corrupt memory?, but I do not understand what the OP and the accepted answer are talking about.

_chkstk() CRT 函数的目的是什么?它有什么作用?

What is the purpose of the _chkstk() CRT function? What does it do?

推荐答案

Windows 页面在额外堆栈中供您的线程使用.在堆栈的末尾,有一个保护页被映射为不可访问的内存――如果程序访问它(因为它试图使用比当前映射更多的堆栈),就会出现访问冲突.操作系统捕获错误,映射到与旧保护页相同地址的另一堆栈页中,在旧保护页之后创建一个新的保护页,然后从导致违规的指令恢复.

Windows pages in extra stack for your thread as it is used. At the end of the stack, there is one guard page mapped as inaccessible memory -- if the program accesses it (because it is trying to use more stack than is currently mapped), there's an access violation. The OS catches the fault, maps in another page of stack at the same address as the old guard page, creates a new guard page just beyond the old one, and resumes from the instruction that caused the violation.

如果一个函数有不止一页的局部变量,那么它访问的第一个地址可能会超过当前栈尾的一页.因此,它会错过保护页面并触发操作系统没有意识到的访问冲突,因为需要更多堆栈.如果所需的总堆栈特别大,它甚至可能超出保护页,超出分配给堆栈的虚拟地址空间的末尾,并进入实际用于其他用途的内存.

If a function has more than one page of local variables, then the first address it accesses might be more than one page beyond the current end of the stack. Hence it would miss the guard page and trigger an access violation that the OS doesn't realise is because more stack is needed. If the total stack required is particularly huge, it could perhaps even reach beyond the guard page, beyond the end of the virtual address space assigned to stack, and into memory that's actually in use for something else.

因此,_chkstk 确保有足够的空间用于局部变量.您可以想象它通过以页面大小的间隔按递增顺序接触局部变量的内存来实现这一点,以确保它不会错过保护页面(所谓的堆栈探测").我不知道它是否真的这样做了,不过,它可能需要更直接的路由并指示操作系统映射到一定数量的堆栈中.无论哪种方式,如果所需的总数大于堆栈可用的虚拟地址空间,那么操作系统可以抱怨它而不是做一些未定义的事情.

So, _chkstk ensures that there is enough space for the local variables. You can imagine that it does this by touching the memory for the local variables at page-sized intervals, in increasing order, to ensure that it doesn't miss the guard page (so-called "stack probes"). I don't know whether it actually does that, though, possibly it takes a more direct route and instructs the OS to map in a certain amount of stack. Either way, if the total required is greater than the virtual address space available for stack, then the OS can complain about it instead of doing something undefined.

相关文章