jalr
jalr
rd, rs, off
rd = pc + 4; goto rs + off
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

jalr is a cousin of jal, and the r at the end means register. Both jump and leave a return-address breadcrumb behind (the jal page explains that mechanism). The difference is where they jump *to*. jal jumps to a fixed label decided when you write the program. jalr jumps to an address held in a register — a destination that can be computed while the program runs.

That distinction matters more than it first appears. A fixed jump is like going to a friend's house whose address you already know; a jalr jump is like going to whatever address is written on a card you are handed at runtime. This is what makes returning from a function possible: the caller left a return address in the ra register, and the function gets back by doing a jalr to whatever address ra now contains. In fact the everyday ret instruction is exactly a jalr to ra.

The same ability powers anything where the destination is not known in advance: calling a function whose address was passed in, or picking one of many routines from a table of addresses (the way a big switch statement or an interpreter dispatches).

The form is jalr rd, rs, offset: jump to the address in register rs (optionally plus a small offset), saving the return address into rd. As with jal, the link register it writes gets overwritten, so the same care about preserving ra applies.