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

我最近使用了/FAsu Visual C ++编译器选项来输出特别长的成员函数定义的源代码集合。 在汇编输出中,在堆栈框架设置完成后,会有一个调用神秘的_chkstk()函数。

_chkstk()上的MSDN页面没有解释调用这个函数的原因。 我也看到堆栈溢出问题在堆栈上分配一个页面大小的缓冲区会损坏内存? ,但我不明白OP和接受的答案是在说什么。

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

Solutions Collecting From Web of "_chkstk()函数的目的是什么?"

在使用时,为您的线程添加额外的Windows页面。 在堆栈的最后,有一个防护页映射为不可访问的内存 – 如果程序访问它(因为它试图使用比当前映射更多的堆栈),则存在访问冲突。 操作系统发现故障,将堆栈的另一个页面映射到旧守卫页面的相同地址,创建一个新的守卫页面,并从导致违规的指令中恢复。

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

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

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

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