问题描述
我创建了一个简单的递归 factorial()
函数,该函数在计算 mul_alt()
时调用名为 n * factorial(n-1)
的递归乘法函数。因此,return n * factorial(n-1)
函数执行 factorial()
而不是 return mul_alt(n,factorial(n-1))
(在 C 符号中),其中被调用的函数将添加 n + n + ...
factorial(n-1)
次。我制作了这个复杂的程序,因为我的班级要求这样做。
该程序在 n n > 9 时,该程序将在 n = 10
处返回一个异常,协处理器为 0 的以下值:
$8 (vaddr) = 0x7fbffffc
$12 (status) = 0x0000ff13
$13 (cause) = 0x00000014
$14 (epc) = 0x0040008c
从 status
寄存器的前两位,我了解到异常处理程序返回了一个 ADDRL
异常,这意味着从非法地址加载。而 epc
寄存器显示了导致错误的指令的地址,即
0x0040008c: sw $s1,4($sp)
我的 $sp
寄存器的值为 0x7fbffff8
。所以0x7fbffff8 + 0x4 = 0x7fbffffc
(它是存储在vaddr
中的值)是store 指令试图存储$s1
内容的地方。我有几个关于这种情况的问题:
- 为什么我实际上使用了存储指令而不是加载指令,但会收到
ADDRL
异常? -
0x7fbffffc
可以被 4 整除,为什么我不能在其中存储字大小的数据?
我希望我已经清楚地表达了我的观点。提前致谢。
解决方法
MIPS 原因 0x14
是 ADDRS
而不是 ADDRL
。 ExcCode = 0x14/4 = 5:地址
这是一个简单的堆栈溢出。 MARS 堆栈可以到达 0x7fc00000,因此允许大约 4M 字节。
// from the default memory configuration menu selection
public static int stackPointer = MemoryConfigurations.getDefaultStackPointer(); //0x7fffeffc;
public static int stackBaseAddress = MemoryConfigurations.getDefaultStackBaseAddress(); //0x7ffffffc;
public static int stackLimitAddress = stackBaseAddress - BLOCK_LENGTH_WORDS * BLOCK_TABLE_LENGTH * WORD_LENGTH_BYTES;
// where these constants are 1024,1024,and 4 respectively
默认值(来自默认内存配置)为 0x7ffffffc (stackBase)、0x7ffffeffc (stackPointer)、0x7fc00000 (stackLimitAddress)。
没有将堆栈空间增加到 4MB 以上的菜单选项。
有一个内存配置菜单,但它错误地将堆栈限制报告为与所有可用配置的堆基值相同的值。事实并非如此:根据源代码,堆栈限制始终为堆栈基数 - 4MB。
堆基址和堆栈限制地址之间的内存地址受到保护,除非您使用 sbrk
系统调用扩展堆。没有进一步扩展堆栈。
另一方面,SPIM 似乎根据需要扩展堆栈空间,但仅当您修改堆栈指针寄存器时,而不是在堆栈指针下方存储到内存中时。因此,在 SPIM 中,如果将堆栈指针寄存器修改为随机值,即使将堆栈指针放回加载或存储之前的位置,它也会立即无法扩展堆栈空间(不进行存储或加载)。该寄存器 - 确实是奇怪的行为,但似乎他们特别对待 $sp
寄存器,而不是硬件如何做到这一点。