[PATCH] riscv: Build SPL with -fno-pic

Yao Zi me at ziyao.cc
Mon Dec 15 18:22:37 CET 2025


For RISC-V ports, both SPL and proper U-Boot are unconditionally built
with -fpic, i.e. position-independent code, which means symbols may be
addressed through GOT. This is useful for proper U-Boot, where we have
relocate_code in arch/riscv/cpu/start.S and could relocate the GOT
entries and other .data members to run at any address.

But for SPL, there's no self-relocating mechanism, all we could do is
relying on the linker to fill correct addresses into the binary at link
time, forming a position-dependent image. This effectively makes the
GOT, which is generated by usage of -fpic and couldn't be optimized out
at link time, an unnecessary size burden.

Moreover, our current linkscript for SPL doesn't take .got section into
account, allowing the linker to put the GOT at unexpected positions,
like after _end/_image_binary_end symbols. This has caused real-world
boot failures[1] when SPL is linked by LLD.

These two reasons make building SPL with -fno-pic good choice,
eliminating the usage of GOT at the first place. This patch replaces
-fpic with -fno-pic in PLATFORM_CPPFLAGS when building SPL.

We also need to force medany code model for SPL to allow putting the
executable at any contiguous 4GiB memory range, instead of only the
lowest and highest 2GiB when using medlow. This wans't an issue
previously, since GCC ignores -mcmodel=medlow when -fpic is specified,
but is problematic with Clang, or without -fpic.

Building position-dependent code also produces bss/data/rodata section
variants with "s" prefix on RISC-V, i.e. sbss/sdata/srodata. These are
"small" sections which compilers expect to be put together, addressable
through a single instruction relative to $gp register and thus saving
code size. This is called GP-relaxation[2]. However, U-Boot takes $gp
for global data pointer, making it impossible, so these sections are
merged into their "larger" variants in linkscript.

Reported-by: Nathaniel Hourt <i at nathaniel.land>
Closes: https://lore.kernel.org/all/932979cb47c4fded7ac19216ca172504@nathaniel.land/
Link: https://lore.kernel.org/all/9c0038ed1494e9f293bf4faaf5e66ed8@nathaniel.land/ # [1]
Signed-off-by: Yao Zi <me at ziyao.cc>
---

I've tested the patch with

	starfive_visionfive2_defconfig (StarFive VisionFive2)
	sifive_unleashed_defconfig (QEMU -machine sifive_u)
	th1520_lpi4a_defconfig (Lichee Pi 4A 16GiB)

built with either GCC or Clang, all these ports boot well. When building
with GCC, this also shrinks SPL of starfive_visionfive2_defconfig by
1.5KiB (1%),

without patch;
	-rw-r--r-- 1 ziyao ziyao 149169 Dec 15 11:56 u-boot-spl.bin

with patch:
	-rw-r--r-- 1 ziyao ziyao 147731 Dec 15 11:57 u-boot-spl.bin

This is a relatively large change to RISC-V SPL, so I'm willing to wait
for some time for more comments and wider testing. Thanks for your time!

 arch/riscv/Makefile           | 5 ++++-
 arch/riscv/config.mk          | 8 +++++++-
 arch/riscv/cpu/u-boot-spl.lds | 3 +++
 3 files changed, 14 insertions(+), 2 deletions(-)

diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile
index fdda6da1df32..90d98eaba6bc 100644
--- a/arch/riscv/Makefile
+++ b/arch/riscv/Makefile
@@ -32,13 +32,16 @@ endif
 ifeq ($(CONFIG_RISCV_ISA_ZBB),y)
 	ARCH_ZBB = _zbb
 endif
+ifeq ($(CONFIG_XPL_BUILD),y)
+	CMODEL = medany
+else
 ifeq ($(CONFIG_CMODEL_MEDLOW),y)
 	CMODEL = medlow
 endif
 ifeq ($(CONFIG_CMODEL_MEDANY),y)
 	CMODEL = medany
 endif
-
+endif
 
 RISCV_MARCH = $(ARCH_BASE)$(ARCH_A)$(ARCH_F)$(ARCH_D)$(ARCH_C)$(ARCH_ZBB)
 ABI = $(ABI_BASE)$(ABI_D)
diff --git a/arch/riscv/config.mk b/arch/riscv/config.mk
index eddd6a3b9a29..4d6fd7434171 100644
--- a/arch/riscv/config.mk
+++ b/arch/riscv/config.mk
@@ -35,7 +35,13 @@ EFI_LDS			:= elf_riscv64_efi.lds
 PLATFORM_ELFFLAGS	+= -B riscv -O elf64-$(large-endian)riscv
 endif
 
-PLATFORM_CPPFLAGS	+= -ffixed-x3 -fpic
+ifdef CONFIG_XPL_BUILD
+PLATFORM_CPPFLAGS	+= -fno-pic
+else
+PLATFORM_CPPFLAGS	+= -fpic
+endif
+
+PLATFORM_CPPFLAGS	+= -ffixed-x3
 PLATFORM_RELFLAGS	+= -fno-common -ffunction-sections -fdata-sections
 LDFLAGS_u-boot		+= --gc-sections -static -pie
 
diff --git a/arch/riscv/cpu/u-boot-spl.lds b/arch/riscv/cpu/u-boot-spl.lds
index 0717833df556..dc028702a5d8 100644
--- a/arch/riscv/cpu/u-boot-spl.lds
+++ b/arch/riscv/cpu/u-boot-spl.lds
@@ -25,11 +25,13 @@ SECTIONS
 	. = ALIGN(4);
 	.rodata : {
 		*(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
+		*(SORT_BY_ALIGNMENT(SORT_BY_NAME(.srodata*)))
 	} > .spl_mem
 
 	. = ALIGN(4);
 	.data : {
 		*(.data*)
+		*(.sdata*)
 	} > .spl_mem
 	. = ALIGN(4);
 
@@ -52,6 +54,7 @@ SECTIONS
 	.bss : {
 		__bss_start = .;
 		*(.bss*)
+		*(.sbss*)
 		. = ALIGN(8);
 		__bss_end = .;
 	} > .bss_mem
-- 
2.51.2



More information about the U-Boot mailing list