为什么 MARS MIPS 模拟器会抛出 "Load from an Illegal Address" 异常?
Why did the MARS MIPS Simulator throws a "Load from an Illegal Address" exception?
我创建了一个简单的递归 factorial()
函数,它在计算 n * factorial(n-1)
时调用名为 mul_alt()
的递归乘法函数。因此,factorial()
函数执行 return mul_alt(n, factorial(n-1))
而不是 return n * factorial(n-1)
(在 C 表示法中),其中被调用的函数将添加 n + n + ...
factorial(n-1)
次。由于 class 的要求,我制作了这个复杂的程序。
该程序在 n <= 9 时工作正常,但是当我尝试 n > 9
时,该程序将 return 在 n = 10
处出现异常,协处理器 0 的值如下:
(vaddr) = 0x7fbffffc
(status) = 0x0000ff13
(cause) = 0x00000014
(epc) = 0x0040008c
从 status
寄存器的前两位,我了解到异常处理程序 returned 了一个 ADDRL
异常,这意味着 从非法地址加载。而epc
寄存器显示的是导致错误的指令地址,即
0x0040008c: sw $s1, 4($sp)
我的 $sp
寄存器的值为 0x7fbffff8
。所以 0x7fbffff8 + 0x4 = 0x7fbffffc
(存储在 vaddr
中的值)是 store 指令试图存储 $s1
的内容的地方。关于这种情况,我有几个问题:
- 为什么我得到了一个
ADDRL
异常,虽然我实际上使用了存储指令 -- 而不是加载?
0x7fbffffc
能被4整除,那为什么我不能在里面存word大小的数据呢?
我希望我已经表达清楚了我的观点。提前谢谢你。
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)、0x7ffffffc (stackPointer)、0x7fc00000 (stackLimitAddress)。
没有用于将堆栈增加 space 超过 4MB 的菜单选项。
有一个内存配置菜单,但它错误地将堆栈限制报告为与所有可用配置的堆基数相同的值。事实并非如此:根据源代码,堆栈限制始终为堆栈基数 - 4MB。
除非您使用sbrk
系统调用扩展堆,否则堆基地址和堆栈限制地址之间的内存地址将受到保护。没有进一步扩展堆栈。
另一方面,SPIM 似乎会根据需要扩展堆栈 space,但仅当您修改堆栈指针寄存器时,而不是存储到堆栈指针下方的内存中时。因此在 SPIM 中,如果您将堆栈指针寄存器修改为随机值,即使您将堆栈指针放回加载前的位置,它也会立即无法展开堆栈 space(不进行存储或加载)或相对于该寄存器存储 — 确实是奇怪的行为,但似乎他们特别对待 $sp
寄存器,而不是硬件如何处理它。
我创建了一个简单的递归 factorial()
函数,它在计算 n * factorial(n-1)
时调用名为 mul_alt()
的递归乘法函数。因此,factorial()
函数执行 return mul_alt(n, factorial(n-1))
而不是 return n * factorial(n-1)
(在 C 表示法中),其中被调用的函数将添加 n + n + ...
factorial(n-1)
次。由于 class 的要求,我制作了这个复杂的程序。
该程序在 n <= 9 时工作正常,但是当我尝试 n > 9
时,该程序将 return 在 n = 10
处出现异常,协处理器 0 的值如下:
(vaddr) = 0x7fbffffc
(status) = 0x0000ff13
(cause) = 0x00000014
(epc) = 0x0040008c
从 status
寄存器的前两位,我了解到异常处理程序 returned 了一个 ADDRL
异常,这意味着 从非法地址加载。而epc
寄存器显示的是导致错误的指令地址,即
0x0040008c: sw $s1, 4($sp)
我的 $sp
寄存器的值为 0x7fbffff8
。所以 0x7fbffff8 + 0x4 = 0x7fbffffc
(存储在 vaddr
中的值)是 store 指令试图存储 $s1
的内容的地方。关于这种情况,我有几个问题:
- 为什么我得到了一个
ADDRL
异常,虽然我实际上使用了存储指令 -- 而不是加载? 0x7fbffffc
能被4整除,那为什么我不能在里面存word大小的数据呢?
我希望我已经表达清楚了我的观点。提前谢谢你。
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)、0x7ffffffc (stackPointer)、0x7fc00000 (stackLimitAddress)。
没有用于将堆栈增加 space 超过 4MB 的菜单选项。
有一个内存配置菜单,但它错误地将堆栈限制报告为与所有可用配置的堆基数相同的值。事实并非如此:根据源代码,堆栈限制始终为堆栈基数 - 4MB。
除非您使用sbrk
系统调用扩展堆,否则堆基地址和堆栈限制地址之间的内存地址将受到保护。没有进一步扩展堆栈。
另一方面,SPIM 似乎会根据需要扩展堆栈 space,但仅当您修改堆栈指针寄存器时,而不是存储到堆栈指针下方的内存中时。因此在 SPIM 中,如果您将堆栈指针寄存器修改为随机值,即使您将堆栈指针放回加载前的位置,它也会立即无法展开堆栈 space(不进行存储或加载)或相对于该寄存器存储 — 确实是奇怪的行为,但似乎他们特别对待 $sp
寄存器,而不是硬件如何处理它。