You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

N64平台MIPS汇编分析中,函数序言可操作自身栈帧范围外的内存吗?

N64 MIPS汇编栈帧疑问解答

先修正核心认知偏差

你对MIPS栈的边界计算方向完全搞反了,这是所有疑问的根源:

  • MIPS栈是向下增长(向低地址延伸),函数执行序言调整SP后,当前函数的合法栈帧范围,是「调整后的SP(低地址边界)」到「刚进入函数时的原始SP(高地址边界)」之间的所有空间,而非从调整后的SP继续向低地址减预留大小。
  • 你提到的ADDIR SP, SP, -0x030是反汇编字体识别错误,实际是MIPS常用的不触发溢出的立即数加指令ADDIU SP, SP, -0x30,这条指令的作用就是从原始SP往低地址挪0x30,划出当前函数的栈空间。
  • 换算关系:把调整后的SP记为SP_new,刚进入函数还没改SP的原始值记为SP_old,则 SP_new = SP_old - 0x30,移项可得 SP_old = SP_new + 0x30。
  • 也就是说,当前函数可合法使用的栈地址范围是 [SP_new, SP_new + 0x2F],你目前看到的除A1外的所有栈写入操作(RA 0x24、S0 0x20、V0 0x2C、R0 0x10)的偏移,都落在这个区间内,完全符合规范,不需要往SP_new更低的地址找空间。

两个核心疑问的具体解释

1. 仅用到少量空间,为什么要预留0x30?

预留栈空间的大小不是只按要保存的寄存器数量算,还要满足MIPS ABI的栈对齐要求:

  • N64常用的O32或原生N64 ABI要求栈必须是16字节对齐,保证浮点寄存器存取、栈上变量访问的硬件效率。
  • 你目前看到的最大栈偏移是存V0的0x2C(SP),如果只预留刚好覆盖的空间,最终栈对齐会被破坏,编译器或手写汇编都会向上取整到最近的16字节倍数,0x30刚好是16的整数倍,完全符合规范。
  • 剩下没用到的栈空间,要么是给函数后续的局部变量预留的(你目前只跟踪了序言和两次写操作,后面大概率还会用到),要么是对齐填充的冗余空间。

2. A1存到SP+0x34真的是越界修改其他函数栈吗?

先换算这个地址的实际位置:
SP_new + 0x34 = (SP_old - 0x30) + 0x34 = SP_old + 0x4
这个位置确实在常规栈范围外,通常是抄录或反汇编的信息存在小误差,常见原因有两种:

  • 指令顺序抄错:SW A1, 0x0034(SP)实际执行在ADDIU SP, SP, -0x30之前,此时SP还等于SP_old,SP_old + 0x34属于O32 ABI规定的调用方栈上的参数溢出区(调用方必须提前在栈上预留至少4字的溢出空间,供被调用函数保存入参),这种写入完全合法。
  • 偏移识别错误:如果反汇编的序言第一句实际是ADDIU SP, SP, -0x34而非-0x30,那SP_new + 0x34刚好等于SP_old,也就是栈帧的最高边界,完全在合法范围内,大概率是看反汇编时漏看了偏移最后一位的4。

补充:就算真的写到SP_old+0x4,N64早期的手写SDK代码偶尔会直接复用调用方栈上提前留好的未使用空间,只要调用方提前标记这块空间可复用,就不属于非法栈覆盖。

内容的提问来源于stack exchange,提问作者Ploufy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.26 18:45:02