Issue
I am trying to build a 64-bit executable RISC-V ELF using the RISC-V toolchain with newlib and a linker script that places the text section at 0x100 and the data section starting at 0x100000000 (greater than the 2 GB limit). However, I get the following error:
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
I noticed that the RISC-V options specify these two --mcmodel options:
-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.
However, I am confused why even with 64-bit registers, why cannot use the entire 64-bit address space within my executable. Any clarification would be greatly appreciated.
Solution
There are similar situations on other 64-bit platforms such as x86-64 and ARM64.
The normal way to load a static address is as a 32-bit immediate, either absolute or pc-relative. This is more efficient than requiring 64-bit immediates every time an address is used, which tend to need a longer and slower sequence of instructions. But it does mean that all static code and data needs to fit in 2 GB.
You can use much more of the 64-bit address space for dynamically allocated objects, since they don't need their addresses coded into the binary. This limit is only for static code and data. Also, I'm not sure about RISC-V, but I believe on other platforms, the 2 GB limit applies separately to each shared library, so a really huge application could still be written by breaking off pieces into shared libraries.
On x86-64 and ARM64, GCC does support a "large" code model in which all static addresses are loaded as 64-bit, with the corresponding performance penalty. It looks like this is not currently supported for RISC-V.
Answered By - Nate Eldredge