我认为你遇到的问题是“PC-absolute”这个概念,这实际上并不是一个东西。您的选项是“相对电脑”和“绝对”。 RISC-V 定义了两个寻址指令,可以有效地实现这些模式:
-
lui
(加载上立即数):这组rd
为 32 位值,低 12 位为 0,高 20 位来自 U 型立即数。
-
auipc
(将上立即数添加到程序计数器):此设置rd
为当前 PC 与一个 32 位值之和,其中低 12 位为 0,高 20 位来自 U 型立即数。
这些指令本质上是相同的:它们都采用 U 型立即数(即 32 位量的高 20 位),将其添加到某些内容,并产生结果rd
。不同之处在于lui
将立即添加到0
, while auipc
将其立即添加到 PC 中。有时,更容易将两种寻址模式视为“PC 相对”和“0 相对”,因为这使得区别更加明确。
虽然两者auipc
and lui
由于第二条指令被设计为双指令对中的第一条指令,因此并不是特别相关。两个都auipc
and lui
填充 32 位地址的高 20 位,让它们配对的指令填充低 12 位。 I 和 S 格式的指令被设计为可以很好地配对,并且基本 ISA 中的每条指令都有一个 I 或 S 变体,这种格式是有意义的。
作为一个具体的例子,下面的 C 代码执行一个非常简单的
int global;
int func(void) { return global; }
例如,假设 global 位于 0x20000004,func 中第一条指令的 PC 为 0x10000008。
当编译时-mcmodel=medlow
(0-相对寻址模式),你会得到
func:
lui a0, 0x20000
lw a0, 0x004(a0)
正如你所看到的,全局的完整绝对地址(0x2000004)被填充到指令对中。另一方面,当编译时-mcmodel=medany
(PC相对寻址模式)你会得到
func:
auipc a0, 0x10000
lw a0, 0x004(a0)
这次,只有 PC 之间的偏移量auipc
目标符号出现在指令对中。发生这种情况是因为 PC 明确地(通过使用auipc
指令)包含在寻址计算中。在这种情况下,即auipc
正在设置a0
to 0x2000004
:执行的计算是a0 = PC + (imm20 << 12)
,这里我们有0x10000004
对于 PC 和0x10000
for imm20
.
这些与 PC 相关的寻址序列还允许一定程度的位置独立性:如果您非常小心地限制正在执行的操作,则可以生成链接的二进制文件,这些二进制文件在以与链接位置不同的偏移量加载时仍然可以工作。实际上,这对于 POSIX 风格系统中完全位置无关的寻址来说是不够的(这就是为什么我们还有一个-fPIC
争论,就像其他人一样),但如果您处于严格约束的嵌入式系统中,您可能能够摆脱它。
对于最后的问题,就像 RISC-V ISA 中的几乎所有其他内容一样,auipc
and lui
符号扩展为 XLEN。在 32 位系统上,这些寻址模式可以生成系统中的任何地址,但 64 位系统则不然。这就是为什么我们将这些寻址模式称为“medany”和“medlow”:“med”代表“medium”,这意味着所有全局符号都必须适合一个 4GiB 窗口。 “低”部分意味着该窗口以绝对地址 0 为中心,而“任意”部分则意味着该窗口以所链接的任何 PC 为中心。