la t0, SYMBOL
is an assembler pesudo instruction that puts the address of SYMBOL
into t0
. Depending on the addressing mode, it expands to something like
lui t0, SYMBOL[31:12]
addi t0, t0, SYMBOL[11:0]
where SYMBOL[31:12]
is the high bits of SYMBOL
, and SYMBOL[11:0]
is the low bits of SYMBOL
-- these aren't valid assembler syntax, and there's some tricks to play with sign extension to get this exactly correct.
lw t0, SYMBOL
is an assembler pseudo instruction that puts the value of memory at the address SYMBOL
into t0
. Depending on the addressing mode, it expands to something like
lui t0, SYMBOL[31:12]
lw t0, SYMBOL[11:0](t0)
Specifically the difference is that lw
performs a load from memory, while la
just generates an address. The sequence
la t0, SYMBOL
lw t0, 0(t0) # load word from memory address 0(t0)
is functionally equivalent to
lw t0, SYMBOL
but takes an extra instruction, specifically
lui t0, SYMBOL[31:12]
addi t0, t0, SYMBOL[11:0]
lw t0, 0(t0)
vs
lui t0, SYMBOL[31:12]
lw t0, SYMBOL[11:0](t0)
This should all be documentation in the RISC-V Assembly Programmer's Manual, but that is always a work in progress. If you find that's lacking then feel free to submit a patch or open an issue.