@@ -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 */
@@ -7,6 +7,7 @@
* Anup Patel <anup.patel@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)
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@brainfault.org> Signed-off-by: Alvin Chang <alvinga@andestech.com> --- firmware/payloads/test.elf.ldS | 6 ++++++ firmware/payloads/test_head.S | 30 ++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+)