小知识
qemu打印page table
ctrl a + c
info mem
RISC-V assembly (easy)
- Which registers contain arguments to functions? For example, which register holds 13 in main’s call to printf?
汇编代码如下图所示(可参考RISC-V常用汇编指令):
可以从代码第45~47行代码可以看出,main函数调用printf系统调用时传入的参数是通过a0 ~ 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的汇编代码在上图的第26~35行;而函数g的汇编代码位于第13~22行,经过对比代码一模一样,其原因是函数f在调用函数g时编译器采用了inline的方式直接将g函数内联展开了,节省了一次函数调用的时间。
- At what address is the function printf located?
根据第50行代码可得,printf的地址为ra+1536=pc+1536
(ra是当前pc指针的值)
- What value is in the register ra just after the jalr to printf in main?
由于ra会存放函数的返回地址,所以此时应该是等于pc+4
- Run the following code.
unsigned int i = 0x00646c72;
printf(“H%x Wo%s”, 57616, &i);
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?
大端序的话地址需要以字节为一组进行翻转,即改为0x726c6400,而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?
printf(“x=%d y=%d”, 3);结果如下:
可见y可能是一个随机的值,一个没有被初始化过的未定义的值。
Backtrace (moderate)
- 修改kernel/riscv.h,添加r_fp函数,通过内联汇编的方式获取s0寄存器的值:
static inline uint64
r_fp()
{
uint64 x;
asm volatile("mv %0, s0" : "=r" (x) );
return x;
}
- 修改kernel/printf.c,新建函数backtrace(),并在sys_sleep内进行调用:
void backtrace() {
uint64 sp = r_fp();
uint64 edge = PGROUNDUP(sp);
printf("backtrace:\n");
while (sp != edge) {
printf("%p\n", *((uint64*)(sp - 8)));
sp = *((uint64*)(sp - 16));
}
}
- 在kernel/defs.h中新增backtrace函数定义:
void backtrace(void);
- 在kernel/sysproc.c中的sys_sleep函数中调用backtrace():
测试结果如下:
能work之后,将其加入到kernel/printf中的panic函数中:
Alarm (hard)
test0: invoke handler
-
修改kernel/proc.h,在struct proc中添加三个字段:
-
修改kernel/sysproc.c,新增系统调用函数sys_sigalarm和sys_sigreturn:
int
sys_sigalarm(void)
{
int n;
uint64 addr;
if (argint(0, &n) < 0 || argaddr(1, &addr))
return -1;
struct proc* mp = myproc();
mp->elaps_ticks = 0;
mp->target_ticks = n;
mp->fn = (void(*)(void))addr;
return 0;
}
int
sys_sigreturn(void)
{
return 0;
}
-
修改user/usys.pl,新增sigalarm:
-
修改kernel/syscall.c,新增系统调用:
-
修改kernel/syscall.h:
-
修改user/user.h,添加函数原型:
-
修改kernel/trap.c:
-
修改kernel/proc.c中的allocproc函数:
运行结果如下:
test1/test2(): resume interrupted code
-
修改kernel/proc.h,新增字段:
-
修改kernel/sysproc.c:
-
修改kernel/trap.c中的usertrap函数:
-
修改kernel/proc.c中的allocproc函数:
和freeproc函数:
测试结果如下: