Lab: traps
看make后的user/call.asm.
main:
void main(void) {
printf("%d %d\n", f(8)+1, 13);
exit(0);
}
Question:
addi sp,sp,-16: 将栈指针 sp 减去 16 字节,为将来在栈上分配空间做准备。
sd ra,8(sp): 将寄存器 ra 中的值存储在距离 sp 偏移 8 字节的位置,以便在返回时恢复 ra 的值。
sd s0,0(sp): 将寄存器 s0 中的值存储在距离 sp 偏移 0 字节的位置,以便在返回时恢复 s0 的值。
addi s0,sp,16: 将 s0 的值设置为栈指针 sp 加上 16,这是一个将来在栈上分配空间时要使用的偏移量。
auipc ra,0x0: 将全局地址 ra 设置为当前 PC 寄存器值的高位。
jalr -46(ra) # 1c : 跳转到 main 函数的地址,即将 PC 设置为 ra-46。跳转指令的返回地址将存储在 ra 中。
li a0,0: 将寄存器 a0 设置为 0,这是将要传递给 exit 函数的参数。
auipc ra,0x0: 将全局地址 ra 设置为当前 PC 寄存器值的高位。
jalr 628(ra) # 2c8 : 跳转到 exit 函数的地址,即将 PC 设置为 ra+628。这将退出程序并返回 0。
哪些寄存器包含函数参数?例如,哪个寄存器在main函数调用printf时保存了数字13?
在RISC-V中,前六个整数参数通过a0-a5传递,其他参数通过栈传递。因此,在main函数调用printf时,数字12和13分别存储在a1和a2寄存器中。
在main函数的汇编代码中,函数f和g的调用分别在哪里?(提示:编译器可能会内联函数。)
函数f的调用位于printf的第一个参数计算之前,即在地址0x24处。由于函数g是f的子例程,编译器可能会内联调用g函数,因此在main函数的汇编代码中可能没有对函数g的显式调用。
函数printf的地址在哪里?
函数printf的地址是0x630。
在main函数中jalr到printf后寄存器ra中的值是什么?
在jalr指令执行后,寄存器ra中存储着返回地址,即下一条指令的地址。因此,在jalr到printf的调用之后,ra寄存器中包含指向exit调用的下一条指令地址的值。
函数g的汇编代码在哪里?
0000000000000000 <g>:
0: 1141 addi sp,sp,-16
2: e422 sd s0,8(sp)
4: 0800 addi s0,sp,16
return x+3;
6: 250d addiw a0,a0,3
8: 6422 ld s0,8(sp)
a: 0141 addi sp,sp,16
c: 8082 ret
函数g的汇编代码在地址0x0。
Backtrace
对于调试,回溯通常很有用:在错误发生点之上的堆栈上的函数调用列表。 为了帮助回溯,编译器生成机器代码,在堆栈上维护一个堆栈帧,对应于当前调用链中的每个函数。 每个堆栈帧由返回地址和指向调用者堆栈帧的“帧指针”组成。 寄存器 s0 包含指向当前堆栈帧的指针(它实际上指向堆栈上保存的返回地址的地址加上 8)。 您的回溯应使用帧指针在堆栈中向上移动并在每个堆栈帧中打印保存的返回地址。
fp 指向当前栈帧的开始地址,sp 指向当前栈帧的结束地址。 (栈从高地址往低地址生长,所以 fp 虽然是帧开始地址,但是地址比 sp 高)
栈帧中从高到低第一个 8 字节 fp-8 是 return address,也就是当前调用层应该返回到的地址。
栈帧中从高到低第二个 8 字节 fp-16 是 previous address,指向上一层栈帧的 fp 开始地址。
剩下的为保存的寄存器、局部变量等。一个栈帧的大小不固定,但是至少 16 字节。
在 xv6 中,使用一个页来存储栈,如果 fp 已经到达栈页的上界,则说明已经到达栈底。
int g(int x) {
0: 1141 addi sp,sp,-16 // 扩张调用栈,得到一个 16 字节的栈帧
2: e422 sd s0,8(sp) // 将返回地址存到栈帧的第一个 8 字节中
4: 0800 addi s0,sp,16
return x+3;
}
6: 250d addiw a0,a0,3
8: 6422 ld s0,8(sp) // 从栈帧读出返回地址
a: 0141 addi sp,sp,16 // 回收栈帧
c: 8082 ret // 返回
注意栈的生长方向是从高地址到低地址,所以扩张是 -16,而回收是 +16。
PGROUNDDOWN(fp); 返回页面低地址
PGROUNDUP(fp); 返回页面高地址
用up-down 是一个页的大小(4096)
代码:
defs.h
/