XV6 Lab - Traps

掉入陷阱

上回书说到,内存里有个trapframe很是碍眼。这个实验就来揭开他的神秘面纱,你会发现traps是实现系统调用的根本机制。

Lab4 Traps

简答题:RISC-V assembly

这里展示了样例程序的汇编call.asm,其内容为一些简单的函数调用,要求我们回答一些问题增进对RISC-V汇编的理解。内容不难,多看RISC-V手册(riscv-spec.pdf (mit.edu)),多问gpt。

  1. Which registers contain arguments to functions? For example, which register holds 13 in main’s call to printf?

    a0-a7. a2.

  2. 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.)

    0x26: compiler computed return value of f . 0x14: compiler inlined g to f.

  3. At what address is the function printf located?

    0x64a.

  4. What value is in the register ra just after the jalr to printf in main?

    0x38.

1
unsigned int i = 0x00646c72;printf("H%x Wo%s", 57616, &i);
  1. Run the following code. What is the output?  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?

    HE110 World. 0x726c6400. No, c code doesn’t care little-endian or not, compiler will handle it.

  2. In the following code, printf("x=%d y=%d", 3);what is going to be printed after 'y='? (note: the answer is not a specific value.) Why does this happen?

    a2. 典中典格式化字符串漏洞。

Lab4-1: Backtrace

实现backtrace(),打印当前函数堆栈。要求插桩到sys_sleep()系统调用处执行。我们知道,所谓函数栈就是通过帧指针fp链起来的一个栈,每个函数调用实例都按固定格式维护一堆局部变量,称为栈桢(stack frame),其内容包括:返回地址、fp、寄存器值、局部变量。布局如图:

1
2
3
4
5
6
7
8
9
high address
[ caller frame ]
[ ret, 
  fp, -> caller frame
  saved reg, 
  local vars...
] <- sp
[ callee frame ]
low address

fp指向上一个栈帧的起始地址,而sp指向当前栈顶。因此,我们可以根据fp递归遍历,根据fp和ret的固定偏移获取ret值,即所执行代码的地址。具体到实现,还需要解决以下问题:

  • 从sp如何获取fp?gcc将fp存储到了s0寄存器中。实验手册提供了读取fp的内联汇编代码。
  • 如何判断递归结束?按理说到main就应该结束,但并没有判断函数名的方法。好在实验指导说堆栈固定在一个内存页中,只需要用 PGROUNDDOWN(fp)PGROUNDUP(fp)判断page边界即可。

代码量很少:

1
2
3
4
5
6
7
8
void backtrace(){
  printf("backtrace:\n");
  uint64 fp = r_fp();
  while (PGROUNDDOWN(fp) < fp && PGROUNDUP(fp) > fp){
    printf("%p\n", *(uint64*)(fp - 0x8));
    fp = *(uint64*)(fp - 0x10);
  }
}

实验指导说用addr2line检验以下: 最后0x12找不到对应的代码一开始猜测应该是用户态文件所以-e找不到,但后来发现是没检测page的上界导致的。

Lab4-2: Alarm

实现sigalarm(interval, handler)系统调用。在调用的 n 个时间单位后,调用handler函数。

还是先从测试代码user/alarmtest.c入手,发现分为4关

test0();

test1();

test2();

test3();

Licensed under CC BY-NC-SA 4.0
Built with Hugo
Theme Stack designed by Jimmy