`riscv-rt`: Linker relocation issue (QEMU / OpenSBI)
I am experimenting with the RISC-V ISA via QEMU emulation, and I am having trouble figuring out how to link in the _heap_size symbol appropriately, so that I can follow through with heap allocation. I followed the riscv-rt documentation closely. I am attempting to use QEMU with OpenSBI, but I am not experienced with linker configuration. Here is my memory layout specification:
MEMORY
{
RAM : ORIGIN = 0x80200000, LENGTH = 0x8000000
FLASH : ORIGIN = 0x20000000, LENGTH = 16M
}
REGION_ALIAS("REGION_TEXT", RAM);
REGION_ALIAS("REGION_RODATA", RAM);
REGION_ALIAS("REGION_DATA", RAM);
REGION_ALIAS("REGION_BSS", RAM);
REGION_ALIAS("REGION_HEAP", RAM);
REGION_ALIAS("REGION_STACK", RAM);
I understand that to mean that there is 16M of reserved flash memory at the beginning of the address space (OpenSBI), followed by RAM address space. I would expect all of the memory regions to fit within RAM since the FLASH space is reserved by QEMU OpenSBI firmware.
I have the following example program:
#![no_std]
#![no_main]
extern crate panic_halt;
mod uart;
mod print;
use riscv_rt::entry;
use uart::Uart;
extern "C" {
static _heap_size: u8;
}
#[entry]
fn __start() -> ! {
let heap_size = unsafe { &_heap_size as *const u8 as usize };
println!("hello world");
println!("heap size = {}", heap_size);
loop {}
}
The problem is that the linker cannot relocate _heap_size provided by riscv-rt and I do not understand why. I tried changing the code model to medium:
relocation R_RISCV_PCREL_HI20 out of range: -524800 is not in [-524288, 524287]; references _heap_size
Having worked with this crate & OpenSBI a little bit myself, I can't say for 100 % certain, but I think that the relatively large memory size reserved for RAM here (0x8000000 == 128 Mebibytes) causes the program to become "too large" for the link strategy used by this crate as defined in link.x. riscv-rt tries to optimally use all the space given to it, by filling out the necessary stuff at the beginning of the given memory area, and then reserving the rest for stack / heap. However, the rest can be too much for e.g., RISC-V jump instructions to handle.
One way to properly solve this would be to try to use a link script from OpenSBI/QEMU side and try to adapt your runtime into it.
A more hacky solution which would work for either verification of the issue or initial testing, could be to reduce the size you reserve for RAM and see if the program would be able to link in that case.
I would maybe think of riscv-rt:s default link strategy be a really good fit for small microcontrollers, but not necessarily the best solution for heavy lifters such as desktop operating systems and their bootloaders.
I have the same issue, but reducing the size of RAM does not solve the issue. @hegza Any other ideas? I have a custom linker.x file that mimmicks this crate's link.x. In my case, no FLASH is involved. I am not sure what "link strategy" refers to; can you elaborate?
When using this crate via git = "...", branch = "master" in Cargo.toml and then
MEMORY
{
FLASH (rx) : ORIGIN = 0x20000000, LENGTH = 16M
RAM (rwxa) : ORIGIN = 0x80200000, LENGTH = 16M
}
in the linker script addition, it seems to be working..
We ran into this or a similar issue with @hegza and were able to solve it by setting riscv64-unknown-elf-ld as linker in config.toml
linker = "riscv64-unknown-elf-ld"
Why use OpenSBI though? Are you trying to write S-mode software?
In our case it wasn't OpenSBI but an application thay needed access to a memory located in the high bits.