The link register is the register that holds the return address during a subroutine call. When call executes, the address of the instruction after the call is stored here; when ret executes, it jumps to whatever’s in this register.

In Nios II it’s r31 (alias ra for “return address”). In ARM it’s lr (or r14). In MIPS it’s $ra. Same role in all of them.

What call does

When the processor executes call LABEL:

  1. The address of the next instruction (PC + 4 by the time the call is decoded) is copied into the link register.
  2. PC is set to LABEL.

The next instruction in memory is conceptually pre-loaded into the link register so the subroutine knows where to return.

What ret does

When the processor executes ret:

  1. PC is set to the contents of the link register.

That’s it. PC now points to where execution should resume — the instruction immediately after the original call.

Why it’s a register and not a stack push

Two reasons:

  1. Speed. A register is faster to write than a memory store. For leaf subroutines (ones that don’t call any other subroutines), the return address can stay in the link register the whole time — no memory access needed.
  2. Simplicity. Hardware doesn’t have to maintain a stack pointer or do memory writes during the call instruction itself. The hardware path is trivial: copy PC to LR, copy target to PC.

The trade-off is that only one return address fits. If the subroutine calls another subroutine, the new call overwrites the link register, and the original return address is lost. To handle this, subroutines that aren’t leaves must explicitly save the link register elsewhere — typically by pushing it onto the stack.

A non-leaf subroutine on entry typically does:

subi sp, sp, 4        # make space on stack
stw  ra, 0(sp)        # save return address

And before returning:

ldw  ra, 0(sp)        # restore return address
addi sp, sp, 4        # release space
ret                    # return

Now the link register can be safely clobbered by intermediate call instructions during the subroutine’s body — the original return address is preserved on the stack.

For leaf subroutines, this dance is unnecessary — the link register stays valid throughout, no stack manipulation required. This is why leaf functions are slightly cheaper than non-leaf functions, a fact compilers often exploit.

In other architectures

x86 doesn’t have a link register — call pushes the return address directly onto the stack, and ret pops it. That makes nested calls automatic (each push naturally adds another return address) but every call costs a memory write. It also makes return-oriented programming (ROP) attacks easier: an attacker who can write to the stack controls which “gadgets” the CPU returns to. Modern x86 mitigates this with CET shadow stacks (Intel CET / AMD SSP), which maintain a hardware-protected parallel copy of return addresses; on ret the CPU faults if the popped value doesn’t match the shadow copy. Link-register architectures sidestep the original problem by keeping the leaf return address out of writable memory entirely.

ARM, MIPS, RISC-V, and Nios II all use a link register. The leaf-vs-non-leaf optimization is common to all of them.