我试图通过https://schweigi.github.io/assembler-simulator/了解asm和堆栈溢出。 据我所知,常规堆栈溢出超出堆栈边界进入RAM。 我的问题是如果堆栈溢出超出 RAM边界会发生什么。
在模拟器中,如果你有一个包含代码的程序:
PUSH 53 ; 53 or 0x35 is opcode for PUSH
JMP 0 ; loop it
程序覆盖自己将堆栈推到RAM之外,堆栈指针变为-1。 在真实场景中,真实节目会发生什么?
答案 0 :(得分:2)
维基百科的一个非常好的定义:
在软件中,如果调用堆栈指针超出,则发生堆栈溢出 堆栈绑定。调用堆栈可能包含有限的数量 地址空间,通常在程序开始时确定。尺寸 调用堆栈取决于许多因素,包括编程 语言,机器架构,多线程和数量 有效内存。当程序试图使用更多空间时 在调用堆栈上可用(即,当它尝试访问时 超出调用堆栈边界的内存,本质上是一个缓冲区 溢出),据说堆栈溢出,通常导致a 程序崩溃。
堆栈绑定的定义,堆栈有多少内存并不是一件普遍的事情。一些(旧的)处理器有一个内置的8或16深度堆栈,我们只能看到返回地址,你的函数调用太深,你开始覆盖以后可能需要的地址。
在Windows / linux / mac机器上,您处于虚拟地址空间,保护您不要在分配的空间之外徘徊,在可能的设计解决方案中将您的堆栈分配为自己受保护的ram blob(与程序,数据和堆分开),如果你偏离了边缘,就会出现内存故障,如果你尝试使用虚拟地址进行任何数据访问,你将无法访问。
毫无疑问还有很多其他有趣的案例,但是一个程序的普通ram视图位于你的程序和一些数据的较低地址,在较高的地址你有一个向下增长的堆栈,以及中间是堆本质上或其中的一部分被定义为堆,以提供一定量的堆栈空间。通常情况下,如果你试图通过无休止地推动将要发生的事情进行操作,那么堆栈将向下填充该值,直到它覆盖正在执行的循环,并且取决于处理器的工作方式,如果从中获取,它仍然可以继续缓存,或者它将尝试执行您填充缓存的字节,具体取决于那些可能会或可能不会崩溃的内容。如果它试图执行那些字节,那么除非它们是基于堆栈的,否则它不再用垃圾“填充”缓存。
所以很多系统上的“堆栈溢出”只意味着你的堆栈和堆栈或堆栈和程序发生冲突,软件试图使用堆栈和数据的相同地址,并取决于谁在读写当确定谁得到坏数据或使用错误的返回地址等时,最有可能导致崩溃,但有时只是可怕的不良行为。您可以使用递归函数轻松地测试它,您可以递归调用它直到它崩溃。