[PATCH] riscv: Build SPL with -fno-pic
Heinrich Schuchardt
xypron.glpk at gmx.de
Fri Jan 2 11:53:04 CET 2026
On 12/15/25 18:22, Yao Zi wrote:
> 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.
The assumption "for SPL there's no self-relocating mechanism" is wrong.
We can build RISC-V with CONFIG_SPL_RELOC_LOADER=y. And it may make
sense to do so if U-Boot SPL is located in flash memory. Please, do not
drop this capability.
>
> 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.
Adding the .got section to the linker script would resolve this issue.
Best regards
Heinrich
>
> 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
More information about the U-Boot
mailing list