Jack Li's Blog

xv6 lab trap

Lab Trap #

  • RISC-V assembly (easy)
  • Backtrace (moderate)
  • Alarm (hard)

RISC-V assembly (easy) #

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

Ans: a1, a2 will store arguments. Here li a2,13 means that load immediate 13 to a2.

void main(void) {
  1c:	1141                	add	sp,sp,-16
  1e:	e406                	sd	ra,8(sp)
  20:	e022                	sd	s0,0(sp)
  22:	0800                	add	s0,sp,16
  printf("%d %d\n", f(8)+1, 13);
  24:	4635                	li	a2,13
  26:	45b1                	li	a1,12
	//...	
}

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() stored at 000000000000000e and g() stored at 0000000000000000.

0000000000000000 <g>:
// ...

int g(int x) {
	// ...
}
  // ...

000000000000000e <f>:

int f(int x) {
	// ...
}

At what address is the function printf located?

0000000000000616 <printf>:

We can also get the same result by looking at how compiler calculates address

auipc: add upper immediate to program counter and save to register

jalr: jump to certain address based on register and offset

30:	00000097          	auipc	ra,0x0
34:	5e6080e7          	jalr	1510(ra) # 616 <printf>

So the following steps are:

  1. program counter = 30
  2. add 0 to program counter and save to ra
  3. jump to ra + 1510: hex(1510) + 0x30 = 0x5e6 + 0x30 = 0x616

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

Read risc-v-spec at page 16:

Register ra is used for return address. Therefore, jalr 1510(ra) ra store pc+4, 34 + 4 = 38.

Backtrace (moderate) #

void
backtrace(void)
{
  uint64 fp = r_fp();

  while(fp < PGROUNDUP(fp)) {
    uint64 ra = *(uint64*)(fp - 8); // return address at offset(-8)
    printf("%p\n", ra);
    fp = *(uint64*)(fp - 16); // previous frame pointer at offset(-16)
  }
}

Alarm (hard) #

TBD