auipc rd, imm20 (add upper immediate to pc):
add imm20 << 12 to the address of this instruction and write
the result in register rdjalr rd, imm12(rs) (jump and link register):
set pc to rs + imm12 (sign-extended, LSB cleared);
write pc + 4 to register rdjalr rs:
pseudoinstruction for jalr ra, 0(rs)ret: set pc to ra,
pseudoinstruction for jalr zero, 0(ra)call imm32 (usually with gcc -S):
PC-relative call with 32-bit offset,
pseudoinstruction for auipc ra, imm32_hi; jalr ra, imm32_lo(ra)long bar(long x)
{
return x;
}
long foo(long x)
{
return bar(x) + 1;
}
long main(void)
{
return foo(0) + foo(1);
}$ riscv64-unknown-elf-gcc -O -fno-omit-frame-pointer -mcmodel=medany -mno-relax -fno-pie -no-pie -fno-inline -o foo foo.c
$ riscv64-unknown-elf-objdump -d foo
...
0000000000010188 <bar>:
10188: 1141 addi sp,sp,-16
1018a: e422 sd s0,8(sp)
1018c: 0800 addi s0,sp,16
1018e: 6422 ld s0,8(sp)
10190: 0141 addi sp,sp,16
10192: 8082 ret
0000000000010194 <foo>:
10194: 1141 addi sp,sp,-16
10196: e406 sd ra,8(sp)
10198: e022 sd s0,0(sp)
1019a: 0800 addi s0,sp,16
1019c: 00000097 auipc ra,0x0
101a0: fec080e7 jalr -20(ra) # 10188 <bar>
101a4: 0505 addi a0,a0,1
101a6: 60a2 ld ra,8(sp)
101a8: 6402 ld s0,0(sp)
101aa: 0141 addi sp,sp,16
101ac: 8082 ret
00000000000101ae <main>:
101ae: 1101 addi sp,sp,-32
101b0: ec06 sd ra,24(sp)
101b2: e822 sd s0,16(sp)
101b4: e426 sd s1,8(sp)
101b6: 1000 addi s0,sp,32
101b8: 4501 li a0,0
101ba: 00000097 auipc ra,0x0
101be: fda080e7 jalr -38(ra) # 10194 <foo>
101c2: 84aa mv s1,a0
101c4: 4505 li a0,1
101c6: 00000097 auipc ra,0x0
101ca: fce080e7 jalr -50(ra) # 10194 <foo>
101ce: 9526 add a0,a0,s1
101d0: 60e2 ld ra,24(sp)
101d2: 6442 ld s0,16(sp)
101d4: 64a2 ld s1,8(sp)
101d6: 6105 addi sp,sp,32
101d8: 8082 ret
... .
.
.
+-> +----------------+ |
| | main's ra | |
| | previous s0/fp ----+
| | saved s1 |
| | ... |
| +----------------+ <-+
| | foo's ra @main | |
+---- previous s0/fp | |
+----------------+ |
.
.
.backtrace() (kernel/printf.c)stvec (supervisor trap vector base address register); search for “w_stvec” in kernel/trap.csepcstvecsret instruction: the cpu returns to the address specified in sepc and switches to the orignal (user/kernel) modeprintf("%d\n", *(volatile char *)0xdeadbeef); to main() in user/echo.c
scause: 13 (0xd), “load access fault”sepc: pc of the faulted instructionstval: the virtual memory address$ echo
usertrap(): unexpected scause 0x000000000000000d (load page fault) pid=3
sepc=0x000000000000001a stval=0x00000000deadbeeflbu instruction at the address from sepc)lbu instruction at address 0x1auservec (kernel/trampoline.S) at address 0x3ffffff000
TRAMPOLINE defined in kernel/memlayout.husertrap() in kernel/trap.c)p->trapframe->epc = r_sepc() do? save the user program counter (i.e., 0x1a)exit() kills the current processp->killed = 1 (usertrap() in kernel/trap.c)?
usertrapret()w_sepc(p->trapframe->epc) do?
write the saved user program counter (i.e., 0x1a) to sepc, where cpu will resume execution upon sret((void (*)(uint64,uint64))fn)(TRAPFRAME, satp) do? jump to trampoline code userret (kernel/trampoline.S)sret, which returns to user: the same lbu instruction at address 0x1ap->trapframe->epc += 4p->trapframe->a1 = 42)#include <sys/syscall.h>
#include <unistd.h>
/*
* syscall number & return value: %rax
* syscall arguments: %rdi, %rsi, %rdx, %r10, %r8, %r9
* %rcx and %r11 are not preserved
*
* To compile, use `gcc -nostdlib`.
*/
void _start(void)
{
int fd = 1;
char buf[] = "hello world!\n";
size_t n = sizeof(buf) - 1;
asm volatile ("syscall"
: /* ignore output */
: "a"(__NR_write), "D"(fd), "S"(buf), "d"(n)
: "rcx", "r11", "memory"
);
asm volatile ("syscall"
: /* no output */
: "a"(__NR_exit), "D"(0)
);
}ecall instruction - see the priv speca7a0–a5a0usertrap() (kernel/trap.c): calls syscall() if scause is 8 (i.e., ecall from user space)syscall() (kernel/syscall.c): dispatches based on a7 & sets a0 to return valuewrite(fd, buf, n) in xv6
sys_write (kernel/sysfile.c): how to retrieve the values of fd, buf, and n?
from what registers? where & when are these registers stored?buf in kernel?
buf is a user-space pointer; we cannot simply dereference it in kernelcopyin() (kernel/vm.c)stvec, sepc, scause, stval, sstatus, sscratchecall, sretkernel/trampoline.S, kernel/trap.chandle_exception, handle_syscall),
kernel/syscall_table.c (sys_call_table)