Leu*_*nko 7 c assembly stack callstack
(我认为这个问题很可能已经重复或者已经在这里回答了,但是由于"堆栈分配"和相关术语的干扰,寻找答案很难.)
我有一个玩具编译器,我一直在研究脚本语言.为了能够在脚本正在进行时暂停执行并返回到主机程序,它有自己的堆栈:带有"堆栈指针"变量的简单内存块,使用正常的C代码操作递增对于那种事情等等.到目前为止没有意思.
目前我编译为C.但我也有兴趣调查编译机器代码 - 同时保持二级堆栈和在预定义控制点返回主机程序的能力.
所以...我认为在我自己的代码中使用传统的堆栈寄存器不太可能是一个问题,我假设寄存器会发生什么,只要一切都在我完成时就恢复了(如果我做的话,请纠正我)在这一点上我错了.但是 ......如果我希望脚本代码调用其他库代码,使用这个"虚拟堆栈"离开程序是否安全,或者为此目的将它返回原始堆栈是否必不可少?
像这一个和这个的答案表明堆栈不是传统的内存块,但它依赖于特殊的,系统特定的行为来处理页面错误和诸如此类的东西.
所以:
这显然不是必需的,因为简单地将指针返回到实际堆栈将是完全可用的,或者就此而言,首先不要滥用它们并且只是放置更少的寄存器,我可能不应该尝试这样做在所有(尤其是由于明显超出我的深度).但无论如何我仍然很好奇.想知道这些事情是如何运作的.
编辑:对不起,当然应该说.我正在研究x86(我自己的机器为32位),Windows和Ubuntu.没有异国情调.
所有这些答案都基于“通用处理器架构”,并且由于它涉及生成汇编代码,因此它必须是“特定于目标的” - 如果您决定在处理器 X 上执行此操作,该处理器对堆栈有一些奇怪的处理,如下所示显然不值得在屏幕表面上写[纸的替代品]。一般来说,对于 x86,除非另有说明,否则以下内容成立。
Run Code Online (Sandbox Code Playgroud)is it safe to move the stack pointers into some other area of memory?堆栈内存不“特殊”吗?我认为线程库必须做这样的事情,因为它们创建更多的堆栈......
这样的记忆并不特殊。然而,这假设它不在 x86 架构上,其中堆栈段用于限制堆栈使用。虽然这是可能的,但在实现中却很少见。我知道几年前诺基亚有一个特殊的操作系统,使用 32 位模式的段。据我现在能想到的,这是我接触过的唯一一个使用 x86 分段模式所描述的堆栈段的。
假设使用堆栈寄存器和指令可以安全地操作任何内存区域,我想不出为什么调用具有已知调用深度(即没有递归,没有函数指针)的任何函数会出现问题,只要虚拟堆栈上有可用数量。正确的?
正确的。只要您不期望能够在不切换回原始堆栈的情况下返回某些其他功能。只要堆栈足够深,有限级别的递归也是可以接受的[某些类型的问题如果不使用递归肯定很难解决 - 例如二叉树搜索]。
无论如何,堆栈溢出显然是正常代码中的一个问题,但是在这样的系统中溢出会产生额外的灾难性后果吗?
事实上,如果你运气不好的话,这将是一个很难破解的错误。
我建议您使用对VirtualProtect()(Windows)或mprotect()(Linux 等)的调用将“堆栈末尾”标记为不可读且不可写,这样如果您的代码意外脱离堆栈,它会正确崩溃,而不是其他更微妙的崩溃未定义的行为[因为不能保证下面的内存(较低地址)不可用,所以如果它确实离开堆栈,您可以覆盖一些其他有用的东西,这会导致一些非常难以调试的错误]。
添加一些偶尔检查堆栈深度的代码(您知道堆栈的开始和结束位置,因此检查特定堆栈值是否“超出范围”应该不难[如果您给自己一些“额外的缓冲区”堆栈顶部和您保护的“我们死了”区域之间的“空间” - 如果是撞车的汽车,他们会称之为“崩溃区域”]。您还可以用可识别的模式,并检查其中有多少是“未触及的”。