[MIT 6.1810]Lab4 traps
1 RISC-V assembly (easy)
Which registers contain arguments to functions? For example, which register holds 13 in main’s call to printf?
在RISC-V中,函数的参数存放在寄存器 a0-a7 中,如果超过8个参数,可以用栈来传递。a0-a1 寄存器还用来传递函数的返回值。
1 | |
从上述代码中可以看出,printf 的参数13放在寄存器 a2 中进行传递。
Where is the call to function f in the assembly code for main? Where is the call to g? (Hint: the compiler may inline functions.)
f 和 g 都被inlined到 main 中了,编译器预计算出了 f(8) + 1 的值,直接将 12 加载到寄存器 a1 中,而没有直接调用函数。
At what address is the function printf located?
1 | |
从上述代码中可知,printf 在0x6bc处
What value is in the register ra just after the jalr to printf in main?
1 | |
当 jal 指令执行完毕后,会将下一条指令的地址放在 ra 中,因此 ra 中的值是0x34
Run the following code.
1 | |
What is the output? Here’s an ASCII table that maps bytes to characters.
The output depends on that fact that the RISC-V is little-endian. If the RISC-V were instead big-endian what would you set i to in order to yield the same output? Would you need to change 57616 to a different value?
在小端(little-endian)系统中,最低有效字节存储在最低地址。
i = 0x00646c72,在小端系统中,它会按字节顺序存储为 72 6c 64 00:
0x72对应字符'r'0x6c对应字符'l'0x64对应字符'd'0x00对应空字符(字符串结尾)
printf("H%x Wo%s", 57616, (char *) &i); 中,%x 会将 57616 以十六进制格式输出,而 %s 会将 i 的值按字符字符串输出。
因此,输出是:
H%x会输出H加上57616的十六进制形式,即e110。Wo%s会输出Wo加上i的内容,即rld。
所以在小端系统上,这段代码的输出为:
1 | |
在大端(big-endian)系统上,0x00646c72 将按字节顺序存储为 00 64 6c 72,这会将 i 解释为不同的字符序列,因此我们需要重新设置 i 以确保输出相同。
为了在大端系统上得到 rld 的字符顺序,我们需要将 i 设为 0x726c6400,这样在大端系统中存储的字节序将是 72 6c 64 00,即 rld。
57616 的值没有依赖字节顺序,它只是一个整数,所以无需更改。
In the following code, what is going to be printed after 'y='? (note: the answer is not a specific value.) Why does this happen?
1 | |
这段代码使用 printf 函数来输出两个占位符 %d,分别用于打印变量 x 和 y 的值。然而,只提供了一个参数 3,没有给出第二个参数。
由于缺少第二个参数,printf 会在内存中继续读取下一个位置的值来填充 y 的占位符。这种行为是未定义行为(undefined behavior),可能导致以下情况之一:
- 随机值:
printf会从栈或寄存器中读取一些未初始化的值,因此y可能会显示一个随机值。 - 程序崩溃:在某些系统上,未提供的参数会导致程序崩溃或打印出无效数据。
2 Backtrace (moderate)
本题要求我们实现 backtrace() 函数用来打印函数调用栈,函数调用栈的结构如下所示。可以看到,ra 寄存器的地址存放在 fp - 8 的位置上。在xv6中,内核栈的大小是一页,因此所有的栈帧都在同一页中,我们可以据此来停止 backtrace。
1 | |
1 | |