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

Dan*_*ien 29 c c++ windows callstack visual-c++

我最近使用/FAsuVisual C++编译器选项输出特别长的成员函数定义的源+汇编.在汇编输出中,在设置堆栈帧之后,只需调用一个神秘的_chkstk()函数.

MSDN页面上_chkstk()没有解释调用此函数的原因.我也看到了Stack Overflow问题在堆栈上分配更多页面大小的缓冲区会破坏内存吗?,但我不明白OP和接受的答案是在谈论什么.

_chkstk()CRT功能的目的是什么?它有什么作用?

Ste*_*sop 40

使用时线程的额外堆栈中的Windows页面.在堆栈的末尾,有一个保护页面映射为无法访问的内存 - 如果程序访问它(因为它试图使用比当前映射更多的堆栈),则存在访问冲突.操作系统捕获故障,在与旧保护页面相同的地址处的另一个堆栈页面中映射,创建一个刚刚超出旧保护页面的新保护页面,并从导致违规的指令中恢复.

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

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

  • 阅读完答案之后,我偶然发现了[KB100775:基于Windows NT的应用程序的堆栈检查说明](http://support.microsoft.com/kb/100775).实际上,"[`_chkstk()`]只是触发从当前堆栈指针位置到请求分配的每4K的内存地址." 谢谢你的解释清楚. (6认同)
  • 如果您遇到访问冲突 - 检查您是否有一个对于堆栈来说太大的变量。巨大的数组或数组的数组通常是罪魁祸首。 (2认同)

Mic*_*lle 7

我查看了代码__chkstk,它确实以一页的间隔执行重复的堆栈探测.所以这样,它不需要对OS进行任何调用.参数in rax是您要添加的数据的大小.它确保可以访问目标地址(当前rsp- rax).如果rax> rsp,则为地址0执行此操作.作为一个有趣的快捷方式,它首先将地址与gs:[10h]映射的当前最低页面进行比较; 如果目标地址> = this,那么它什么都不做.

顺便说一句,至少对于64位代码,拼写有两个下划线:__chkstk__.