为什么 MARS MIPS 模拟器会抛出“从非法地址加载”异常?

问题描述

我创建了一个简单的递归 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 内容的地方。我有几个关于这种情况的问题:

  1. 为什么我实际上使用了存储指令而不是加载指令,但会收到 ADDRL 异常?
  2. 0x7fbffffc 可以被 4 整除,为什么我不能在其中存储字大小的数据?

我希望我已经清楚地表达了我的观点。提前致谢。

解决方法

MIPS 原因 0x14ADDRS 而不是 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 寄存器,而不是硬件如何做到这一点。