From: Simon Glass <simon.glass@canonical.com> On x86_64 with 16-bit init, start16.o and resetvec.o are built as 32-bit objects and cannot be linked into the 64-bit PIE binary. Add a linker script (u-boot-16bit.lds) and Makefile rules to link them into a small 32-bit ELF (u-boot-x86-16bit.elf) with the correct section addresses. The existing objcopy rules then extract the .start16 and .resetvec sections from this ELF instead of from the main u-boot binary. Co-developed-by: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Simon Glass <simon.glass@canonical.com> --- arch/x86/Makefile | 27 ++++++++++++++++++++++++++- arch/x86/cpu/u-boot-16bit.lds | 30 ++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 arch/x86/cpu/u-boot-16bit.lds diff --git a/arch/x86/Makefile b/arch/x86/Makefile index 8abedd6e5e9..955a728e361 100644 --- a/arch/x86/Makefile +++ b/arch/x86/Makefile @@ -29,9 +29,34 @@ libs-y += arch/x86/cpu/ libs-y += arch/x86/lib/ OBJCOPYFLAGS_u-boot-x86-start16.bin := -O binary -j .start16 +OBJCOPYFLAGS_u-boot-x86-reset16.bin := -O binary -j .resetvec + +ifneq ($(CONFIG_X86_64)$(CONFIG_X86_16BIT_INIT),yy) +# Normal case: extract 16-bit sections from the u-boot ELF u-boot-x86-start16.bin: u-boot FORCE $(call if_changed,objcopy) -OBJCOPYFLAGS_u-boot-x86-reset16.bin := -O binary -j .resetvec u-boot-x86-reset16.bin: u-boot FORCE $(call if_changed,objcopy) +else +# 64-bit with 16-bit init: the 16-bit objects are built as 32-bit and +# not linked into the 64-bit u-boot. Link them into a small 32-bit +# ELF with the correct addresses so that cross-references (e.g., +# resetvec -> start16 -> _start) are resolved. +u-boot-x86-16bit.lds: $(srctree)/arch/x86/cpu/u-boot-16bit.lds prepare FORCE + $(call if_changed_dep,cpp_lds) + +LDFLAGS_u-boot-x86-16bit.elf := -m elf_i386 -static -nostdlib \ + --defsym=_start=$(CONFIG_TEXT_BASE) + +u-boot-x86-16bit.elf: arch/x86/cpu/start16.o arch/x86/cpu/resetvec.o \ + u-boot-x86-16bit.lds FORCE + $(LD) $(LDFLAGS_u-boot-x86-16bit.elf) -T u-boot-x86-16bit.lds \ + arch/x86/cpu/start16.o arch/x86/cpu/resetvec.o -o $@ + +u-boot-x86-start16.bin: u-boot-x86-16bit.elf FORCE + $(call if_changed,objcopy) + +u-boot-x86-reset16.bin: u-boot-x86-16bit.elf FORCE + $(call if_changed,objcopy) +endif diff --git a/arch/x86/cpu/u-boot-16bit.lds b/arch/x86/cpu/u-boot-16bit.lds new file mode 100644 index 00000000000..048d0f17b4f --- /dev/null +++ b/arch/x86/cpu/u-boot-16bit.lds @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Linker script for 16-bit x86 startup code (start16 + resetvec). + * + * Written by Simon Glass <simon.glass@canonical.com> + * + * Used when building a 64-bit U-Boot with integrated 16-bit init. + * The 16-bit objects are built as 32-bit and linked separately so that + * the 64-bit PIE binary does not see 16-bit relocations. + */ + +#include <config.h> + +OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") +OUTPUT_ARCH(i386) + +SECTIONS +{ + . = START_16 - RESET_SEG_START; + .start16 : AT (START_16) { + KEEP(*(.start16)); + } + + . = RESET_VEC_LOC - RESET_SEG_START; + .resetvec : AT (RESET_VEC_LOC) { + KEEP(*(.resetvec)); + } + + /DISCARD/ : { *(.note.gnu.property) } +} -- 2.43.0