[Concept,07/12] x86: Link 16-bit startup into separate 32-bit ELF
Commit Message
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
@@ -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
new file mode 100644
@@ -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) }
+}