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 <[email protected]> Closes: https://lore.kernel.org/all/[email protected]/ Link: https://lore.kernel.org/all/[email protected]/ # [1] Signed-off-by: Yao Zi <[email protected]> --- 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

