[PATCH] firmware: payload: test: Relocate GOT entries before calling C code
Anup Patel
anup at brainfault.org
Mon Sep 28 06:34:15 PDT 2026
On Fri, Aug 21, 2026 at 3:43 PM Alvin Chang <alvinga at andestech.com> wrote:
>
> The test payload is linked as a PIE but, unlike fw_base.S, its startup
> code never processed its own dynamic relocations. Nothing in the payload
> needed a GOT so far, so this went unnoticed.
>
> CONFIG_STACK_PROTECTOR_ALL=y changes that. GCC derives the
> __stack_chk_guard reference from an artificial declaration with default
> visibility, so under -fPIE it always loads the guard address through the
> GOT. The linker zeroes that entry and records an R_RISCV_RELATIVE
> relocation instead, which nobody applies. test_main() then reads the
> canary from a NULL pointer before the first sbi_ecall_console_puts(), so
> the payload hangs silently right after the OpenSBI boot banner. The other
> two configurations emit no canary in the payload, leaving .rela.dyn
> empty, which is why only this one breaks.
>
> Keep .rela.dyn in the payload image and apply the R_RISCV_RELATIVE
> entries at the top of _start, reusing the code from fw_base.S. The loop
> is skipped when .rela.dyn is empty.
>
> Fixes: edfbc1285dd9 ("firmware: Initial compiler built-in stack protector support")
> Reported-by: Anup Patel <anup at brainfault.org>
> Signed-off-by: Alvin Chang <alvinga at andestech.com>
LGTM.
Reviewed-by: Anup Patel <anup at brainfault.org>
Applied this patch to the riscv/opensbi repo.
Thanks,
Anup
> ---
> firmware/payloads/test.elf.ldS | 6 ++++++
> firmware/payloads/test_head.S | 30 ++++++++++++++++++++++++++++++
> 2 files changed, 36 insertions(+)
>
> diff --git a/firmware/payloads/test.elf.ldS b/firmware/payloads/test.elf.ldS
> index 2328a1b7..6632c132 100644
> --- a/firmware/payloads/test.elf.ldS
> +++ b/firmware/payloads/test.elf.ldS
> @@ -47,6 +47,12 @@ SECTIONS
> PROVIDE(_rodata_end = .);
> }
>
> + .rela.dyn : {
> + PROVIDE(__rela_dyn_start = .);
> + *(.rela*)
> + PROVIDE(__rela_dyn_end = .);
> + }
> +
> /* End of the read-only data sections */
>
> . = ALIGN(0x1000); /* Ensure next section is page aligned */
> diff --git a/firmware/payloads/test_head.S b/firmware/payloads/test_head.S
> index e4fcaaca..09d0ad18 100644
> --- a/firmware/payloads/test_head.S
> +++ b/firmware/payloads/test_head.S
> @@ -7,6 +7,7 @@
> * Anup Patel <anup.patel at wdc.com>
> */
>
> +#include <sbi/riscv_elf.h>
> #include <sbi/riscv_encoding.h>
> #define __ASM_STR(x) x
>
> @@ -24,6 +25,13 @@
> #define REG_S __REG_SEL(sd, sw)
> #define REG_ADDW __REG_SEL(addw, add)
>
> +/* Link time address of _payload_start, see test.elf.ldS */
> +#ifdef FW_PAYLOAD_OFFSET
> +#define PAYLOAD_LINK_START (FW_TEXT_START + FW_PAYLOAD_OFFSET)
> +#else
> +#define PAYLOAD_LINK_START 0
> +#endif
> +
> .section .entry, "ax", %progbits
> .align 3
> .globl _start
> @@ -45,6 +53,28 @@ _sc_fail:
> #endif
> bnez a3, _start_hang
>
> + /* relocate the global table content */
> + li t0, PAYLOAD_LINK_START /* link start */
> + lla t1, _payload_start /* load start */
> + sub t2, t1, t0 /* load offset */
> + lla t0, __rela_dyn_start
> + lla t1, __rela_dyn_end
> + beq t0, t1, _relocate_done
> +2:
> + REG_L t5, __SIZEOF_LONG__(t0) /* t5 <-- relocation info:type */
> + li t3, R_RISCV_RELATIVE /* reloc type R_RISCV_RELATIVE */
> + bne t5, t3, 3f
> + REG_L t3, 0(t0)
> + REG_L t5, (__SIZEOF_LONG__ * 2)(t0) /* t5 <-- addend */
> + add t5, t5, t2
> + add t3, t3, t2
> + REG_S t5, 0(t3) /* store runtime address to the GOT entry */
> +
> +3:
> + addi t0, t0, (__SIZEOF_LONG__ * 3)
> + blt t0, t1, 2b
> +_relocate_done:
> +
> /* Save a0 and a1 */
> lla a3, _boot_a0
> REG_S a0, 0(a3)
> --
> 2.43.0
>
More information about the opensbi
mailing list