relocate_image() doesn't update the relocation entries, so a second
relocation applies an offset relative to the first runtime address to
the link-time addresses and writes wrong values to wrong places.
This happens when the PBL is first relocated in place and
barebox_pbl_start() then copies it into the memory it was passed. ARM64
has handled this since fab26e665163 ("ARM: aarch64: Fixup relocation
table for the second relocation"), so let's rebase each entry after
applying it the same way.
Like on ARM, relocate_to_adr() now also copies the BSS, as it's already
in use and setup_c() won't clear it again at the destination.
Tested on QEMU virt with an image whose stage memory starts above the
address OpenSBI starts it at, which used to fault right after relocation.
Assisted-by: Claude:opus-5.5
Signed-off-by: Ahmad Fatoum <[email protected]>
---
arch/riscv/lib/reloc.c | 6 +++++-
arch/riscv/lib/setupc.S | 2 +-
2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/arch/riscv/lib/reloc.c b/arch/riscv/lib/reloc.c
index 99dde7bfffe2..9eede11b3528 100644
--- a/arch/riscv/lib/reloc.c
+++ b/arch/riscv/lib/reloc.c
@@ -46,7 +46,7 @@ static void relocate_image(unsigned long offset,
switch (RISC_R_TYPE(rela->r_info)) {
case R_RISCV_NONE:
- break;
+ continue;
case R_RISCV_RELATIVE:
*fixup = rela->r_addend + offset;
break;
@@ -63,6 +63,10 @@ static void relocate_image(unsigned long offset,
putc_ll('\n');
__hang();
}
+
+ /* Rebase the entry, so the image can be relocated again */
+ rela->r_addend += offset;
+ rela->r_offset += offset;
}
}
diff --git a/arch/riscv/lib/setupc.S b/arch/riscv/lib/setupc.S
index 68924f2f94df..ba9193288a81 100644
--- a/arch/riscv/lib/setupc.S
+++ b/arch/riscv/lib/setupc.S
@@ -53,7 +53,7 @@ ENTRY(relocate_to_adr_full)
ENDPROC(relocate_to_adr_full)
ENTRY(relocate_to_adr)
- lla a3, __bss_start /* skip piggy data */
+ lla a3, __bss_stop /* skip piggy data */
1:
addi sp, sp, -SZREG * 2
lla a1, _text /* a1: source address */
--
2.47.3