jalr

jalr

RISC-V Assembly Reference

lyszt.net covers jalr and other RISC-V instructions in more detail.

Encoding format

R
31–25funct7
24–20rs2
19–15rs1
14–12funct3
11–7rd
6–0opcode
I
31–20imm[11:0]
19–15rs1
14–12funct3
11–7rd
6–0opcode
S
31–25imm[11:5]
24–20rs2
19–15rs1
14–12funct3
11–7imm[4:0]
6–0opcode
B
31–25imm[12,10:5]
24–20rs2
19–15rs1
14–12funct3
11–7imm[4:1,11]
6–0opcode
U
31–12imm[31:12]
11–7rd
6–0opcode
J
31–12imm[20,10:1,11,19:12]
11–7rd
6–0opcode

Description

jalr belongs to the same family as jal, with the r standing for register. Both instructions jump and store a return address, as described on the jal page. The difference is the jump target. jal jumps to a label fixed when the program is written, while jalr jumps to an address held in a register, which lets the destination be computed at run time.

This is what allows a function to return. The caller puts a return address in the ra register, and the function jumps back by using jalr to reach the address in ra. The ret instruction is a jalr to ra.

The same capability applies whenever the destination is unknown in advance. It covers calls to a function whose address was passed in, and selection among routines listed in a table of addresses, which is how a large switch statement or an interpreter dispatches.

According to the RISC-V manual, jalr adds the sign-extended 12-bit immediate to register rs1, then clears the least significant bit of the result. It stores the address of the next instruction, pc plus 4, in rd, and x0 can serve as the destination when no return address is needed. A lui followed by jalr reaches any 32-bit absolute address, and an auipc followed by jalr reaches any 32-bit pc-relative address. Both jump instructions raise an exception if the target address is not aligned to a four-byte boundary.

The format of jalr appears below. It jumps to the address in register rs plus an optional small offset, and stores the return address in rd.

jalr rd, rs, offset

As with jal, the register it writes is overwritten, so the same care about preserving ra applies.

Example

la t0, target
jalr ra, t0, 0   # jump to target; ra holds the return address