为什么一个程序及其所有使用 RISC-V 工具链构建的静态定义系统必须适合 2 GB 地址范围?

Why must a program and all its statically defined systems built with the RISC-V Toolchain fit within a 2-GB address range?

我正在尝试构建一个 64 位可执行 RISC-V ELF,使用带有 newlib 的 RISC-V 工具链和一个链接器脚本,该脚本将文本部分放在 0x100 处,数据部分从 0x100000000 开始(大于 2国标限制)。但是,我收到以下错误:

relocation truncated to fit: R_RISCV_HI20 against symbol `__global_pointer$' defined in .sdata section in a.out
collect2: error: ld returned 1 exit status

我注意到 RISC-V 选项指定了这两个 --mcmodel 选项:

-mcmodel=medlow
    Generate code for the medium-low code model. The program and its statically defined symbols must lie within a single 2 GiB address range and must lie between absolute addresses -2 GiB and +2 GiB. Programs can be statically or dynamically linked. This is the default code model.

-mcmodel=medany
    Generate code for the medium-any code model. The program and its statically defined symbols must be within any single 2 GiB address range. Programs can be statically or dynamically linked.

但是,我很困惑为什么即使使用 64 位寄存器,为什么不能在我的可执行文件中使用整个 64 位地址 space。任何澄清将不胜感激。

x86-64、ARM64等其他64位平台也有类似情况

加载静态地址的正常方式是作为 32 位立即数,绝对地址或 pc 相对地址。这比每次使用地址时都需要 64 位立即数更有效,后者往往需要更长和更慢的指令序列。但这确实意味着所有静态代码和数据都需要容纳在 2 GB 中。

您可以将更多的 64 位地址 space 用于动态分配的对象,因为它们不需要将地址编码到二进制文件中。此限制仅适用于 static 代码和数据。另外,我不确定 RISC-V,但我相信在其他平台上,2 GB 的限制分别适用于每个共享库,因此仍然可以通过将多个部分分解成共享库来编写一个非常大的应用程序。

在 x86-64 和 ARM64 上,GCC 确实支持“大型”代码模型,其中所有静态地址都加载为 64 位,具有相应的性能损失。 RISC-V 目前似乎不支持此功能。