On 2025-12-15 11: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.
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]>
[Patch elided]
Happy New Year, at least for those of us in the west =)
Thank you, Yao Zi, for making this! I have done some initial testing,
based on v2026.01-rc4, on my Mars board, and my results are mixed.
Right now, it seems to be a coin toss whether any given configuration
yields a spl/u-boot-spl-nodtb.bin which is a multiple of 8 bytes, or 4
bytes (but not 8). In the latter case, it doesn't work, even though _end
points accurately to that 4-byte-aligned end-of-the-image position. In
the former case, however, where the -nodtb.bin ends on an 8-byte
boundary, it works great.
I have made some attempts to modify u-boot-spl.lds to add an ALIGN(8)
directive before the _end symbol, and this makes the _end point to the
next 8-byte boundary rather than a 4-byte (and not 8) boundary, but it
doesn't cause the -nodtb.bin to be padded with those last 4 bytes. My
attempts to pad it manually, concatenate the dtb, and run that through
mkimage to get the final u-boot-spl.bin.normal.out image, have yielded
no success. This failure surprises me; I was expecting that to work... I
haven't had further inspiration on things to try. :-]
In conclusion, it seems to me that your patch is working fine, but I'm
still having woes with DTB alignment. For now, I can get working builds
by tweaking the config until it happens to give an 8-byte aligned _end
pointer.
Oh, and sizes of u-boot-spl.bin.normal.out:
Without no-fpic patch: 152537
With no-fpic patch: 151749
—
Nathaniel