RISC-V assembly
In RISC-V world, what does JALR
instruction do? What does ra
register do? What does ret
assembly do?
JALR
instruction do? What does ra
register do? What does ret
assembly do?ra
is ABI name for register x1
. It is to store return address.
ret
: Return from subroutine. The actual instructions are:
Code Example
Assembly version
Explain
main
uses jalr
to call g().
What does jar do?
RISC-V’s subroutine call jal (jump and link) places its return address in a register. This is faster in many computer designs, because it saves a memory access compared to systems that push a return address directly on a stack in memory.
In our example, the return address is saved in ra
. Then PC jumps to g() and continue executing. In beginning of g(), you can see it saves return address to stack: sd ra,8(sp)
At end of g(), it retrieves ra
back: ld ra,8(sp)
What is return address?
Assembly snippet
Gdb breakpoints and exam content in ra
Clearly, the return address is the address of the next instruction after JAL, which is 0x34.
We found the proof in RISCV-SPEC JAL stores the address of the instruction following the jump (pc+4) into register rd.
So before we calling function, we set return address first.
what does ret do?
Let’s see spec first:
jalr
saves return address to first param. This part we are clear. It then sets PC to rs1 + offset. So PC will continue from the new address. Now, let’s look at our ret instruction’s meaning
Save return address to x0, which does nothing in our code example. It then set PC to ra
+ 0, which means let program counter continues from the return address we saved before!
Summary
When your program is calling a function, it prepares the return address first before jump to the function. So that when the function about to return, it knows where it should return to. jalr
saves return address for current PC+4, jump to the calling function. ra
contains the return address.
When function returns, it calls ret
, which set its program counter to ra
. In this way, function is returned correctly and continue on the next line of code.
ret
, which set its program counter to ra
. In this way, function is returned correctly and continue on the next line of code.RISC-V calling convention
How to design Virtual Memory Area?
Proposal 1
Start from max VA - trampoline - trap frame. Every mmap, find current max end VA we use, deduct size, and round down to find start address. Save start addr, and end address.
Keep track of current max end virtual address. So every mmap knows where to start.
In munmap, we need to reset current max end if needed.
For searching, it is bad. Since it requires loop the entire list to find coverage.
How unix pipe works
Initialization
The system call pipe creates a pipe object, and two files. The two files link to the pipe, one for write, one for read. The system calls write back the FD of two files to user program.
Runtime
Shell calls fork to run write, and another fork to run read. In this way, 2 different process are running write and read work, so they can wait and wakeup each other if needed. The detail implementation of how pipe write and read work is in pipe.c. But the key take-away is since they are handled by different process, so they can sleep on chan, and got waken up by scheduler.
Design
A file can be a pipe type. A pipe is:
Two file write and read from the same pipe’s data array.
Brainstorming
broadcast feature
We could implement a broadcast system call similar to pipe. A write could be broadcast to multiple listeners. Once the writer is done, wakeup all sleeping processes, and let them read, and do something. Each listener updates how much they have read, last read position etc. How to run this new call?
IPC
Can we make a ‘pipe' talking to each other? We might need 2 data arrary in struct IPC_PIPE. One for fd1 write, one for fd2 write. Each pipe type file needs to remember it reads from which data content, and write to which one.
What stores in register ra
when context switching?
ra
when context switching?Assembly Flow
Process calls yield
to give up CPU, and let CPU scheduler to run. It calls the context switch assembly to save its registers, for later restoring purpose.
The assembly for calling the big swtch
is at 800020b6
:
switch
is at:
How it set ra
to pc+4
ra
to pc+4
Key code is here:
auipc ra,0x0
prepares ra
for the jump. ra
is set to 800020b2
.
jalr 1382(ra)
adds 0x1382 to 800020b2
, which is jumping to the swtch
context swtich assembly (at 80002618
).
After the jump, at this point, ra
is set to PC + 4, which is 800020ba
.
See GDB debug references
Stepi
shows the next instruction to execute.
Summary
Swtch
does not save the program counter. Instead, swtch
saves the ra
register, which holds the return address from which swtch
was called (PC + 4).
Last updated