【发布时间】:2021-01-25 04:32:17
【问题描述】:
在riscv-asm-manual的控制和状态寄存器部分,有一个例子:
.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
...
我猜%pcrel_hi(mtvec) 计算mtvec 和当前PC 之间的高距离(这里是1 符号的地址)。假设1符号的地址为0x80010000,mtvec的地址为0x80020040。那么%pcrel_hi(mtvec) = (0x80020040 - 0x80010000) >> 12 = 0x00010,所以auipc的结果是0x00010 << 12 + PC = 0x00010000 + 0x80010000 = 0x80020000。
但%pcrel_lo 将1b 作为其参数。如何计算其结果并得到mtvec的最终地址? addi t0, t0, %pcrel_lo(mtvect) 似乎是直观的代码,但实际上并非如此。为什么?
【问题讨论】:
-
godbolt.org/z/EebPsc 确认返回全局变量地址的普通 C 函数的普通编译器输出做同样的事情,使用
addi和%pcrel_lo(.LBB0_1)auipc 地址,而不是目标象征。所以这不是一些特殊的用例做一些不同的事情,这显然是 RISC-V 始终适用于与位置无关的代码。 -
是的,这似乎是一个约定,但我只是想知道
%pcrel_lo(label)将如何计算。 -
我也没摸透,等人来回答这个问题。我只是在检查这是否正常之后才发表评论以显示我的结果,或者以某种方式特定于这个关于中断处理程序的示例。