MIPS递归程序栈存储疑问:返回地址为何不会被覆盖?
关于MIPS递归阶乘栈帧的疑问解答
首先纠正概念:你提到的存储返回地址和参数的区域是栈(stack),不是堆(heap)。栈是后进先出(LIFO)的内存结构,MIPS中栈顶由寄存器$sp指向,且栈向低地址方向增长,这是理解递归存储逻辑的核心。
为什么每次调用fact时执行sub $sp, $sp, 8不会导致数据被覆盖?核心原因是每次递归调用都会开辟独立的栈帧(stack frame),这些栈帧的内存地址完全不重叠:
- 第一次调用
fact(n)时,sub $sp, $sp, 8将栈顶指针$sp向低地址移动8字节,这8字节就是当前调用的专属栈帧,用来存储返回地址$ra(存在4($sp))和当前参数$a0(存在0($sp))。 - 递归调用
fact(n-1)时,会再次执行sub $sp, $sp, 8,此时$sp在上一次的基础上继续向低地址移动8字节,新栈帧位于更低的内存地址,和上一层栈帧没有地址重叠。也就是说,新的4($sp)和0($sp)是全新的内存位置,根本不会触及上一层存储的数据。
举个具体地址的例子(假设初始$sp = 0x1000):
- 调用
fact(5):$sp变为0xFF8,$ra存在0xFFC(0xFF8 + 4),5存在0xFF8。 - 调用
fact(4):$sp变为0xFF0,$ra存在0xFF4(0xFF0 +4),4存在0xFF0。 - 调用
fact(3):$sp变为0xFE8,$ra存在0xFEC,3存在0xFE8。 - ……以此类推,直到递归到
fact(0)。
当递归开始返回时,每次执行add $sp, $sp, 8,$sp会回到上一层栈帧的位置,此时就能正确取出之前存储的$ra和$a0,继续执行上一层的逻辑。每个栈帧只属于对应的递归调用层,彼此完全独立,自然不会出现覆盖的问题。
内容的提问来源于stack exchange,提问作者Chea
相关产品推荐
相关产品推荐

