XV6 Series: MIT Lab4 2024

Write-ups
Write-ups for lab4 2024
Published

January 14, 2025

RISC-V assembly

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

In RISC, a0-a7 registers are used to store function’s arguments. Specifically, for the printf, register a2 holds the value 13.

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
28: 00001517            auipc   a0,0x1
2c: 84850513            add a0,a0,-1976 # 870 <malloc+0x100>
30: 68c000ef            jal 6bc <printf>
exit(0);
34: 4501                    li  a0,0
36: 26e000ef            jal 2a4 <exit>

int f(int x) {
   e:   1141                    add sp,sp,-16
  10:   e422                    sd  s0,8(sp)
  12:   0800                    add s0,sp,16
  return g(x);
}
  1. 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.)

From the code above, we can see that the calls to function f and g are optimized in main. That means the output of the function calls are computed in compiled time. You can see that the register a1 holds the result of the f(8) + 1.

  1. At what address is the function printf located?

From the code above, we can see that the printf function is located at 0x6bc.

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

Notes: jal(jump and link): jump to the address and save the address of the next instruction in the ra register.

By this definition, then the register ra will store the address of the next instruction, which is 0x34 in this case.

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

In little-endian system, the least significant byte is stored at the lowest address. That means the value i = 0x00646c72 is stored as 72 6c 64 00 in memory. In which,

  • 0x72 is r
  • 0x6c is l
  • 0x64 is d
  • 0x00 is \0

Also, in printf, %x is used to print the hexadecimal format.

Therefore, the output is: He110 World

If RISC-V is big-endian, then the value of i should be 0x726c6400 and the value of 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);

Since the printf function requires two arguments for 2 format specifiers, but only one argument is provided, the output will be undefined or the program will be crashed.

Backtrace

General Knowledge

Compiler generates machine code to maintain a stack frame on the stack corresponding to each function call in the current call chain. Each stack frame contains the return address, and the “frame pointer” to the caller’s stack frame.

Register s0 contains the pointer to the current stack frame. The address of the caller’s stack frame is stored at s0 - 8, and the address of the previous frame pointer is stored at s0 - 16.

Implementation

void
backtrace(void) {
  uint64 fp = r_fp();
  printf("backtrace:\n");
  while (fp != PGROUNDDOWN(fp)) {
    printf("%p\n", (void*) (*(uint64 *)(fp - 8)));
    fp = *(uint64 *)(fp - 16);
  }
}

General Knowledge (Optional)

There are three types of events that cause a user process to “trap” into the kernel:

  • System call (requests by user for OS services)
  • Interrupts (external device(s) want attention)
  • Program fault (illegal action by program)

In case of the system call, the ecall trigger the trap process by:

  • Switch to supervisor mode (S mode)
  • Store PC to sepc
  • Set PC to stvec The stvec holds the address of the trampoline code a.k.a the trap handler code.