In Control and Status Registers section of riscv-asm-manual, there is an example:
.equ RTC_BASE, 0x40000000
.equ TIMER_BASE, 0x40004000
# setup machine trap vector
1: auipc t0, %pcrel_hi(mtvec) # load mtvec(hi)
addi t0, t0, %pcrel_lo(1b) # load mtvec(lo)
csrrw zero, mtvec, t0
...
# break on interrupt
mtvec:
csrrc t0, mcause, zero
bgez t0, fail # interrupt causes are less than zero
slli t0, t0, 1 # shift off high bit
...
I guess %pcrel_hi(mtvec)
calculate the hi-distance between mtvec
and current PC (here is the address of 1
symbol). Suppose the address of 1
symbol is 0x80010000, and that of mtvec
is 0x80020040. Then %pcrel_hi(mtvec) = (0x80020040 - 0x80010000) >> 12 = 0x00010
, so the result of auipc is 0x00010 << 12 + PC = 0x00010000 + 0x80010000 = 0x80020000
.
But %pcrel_lo
takes 1b
as its argument. How to calculate its result and get the final address of mtvec
? addi t0, t0, %pcrel_lo(mtvect)
seems to be the intuitive code, but actually not. Why?