The i386-pc kernel image fails to build because of changes made to
address ld.lld-21 and newer linking issues. Specifically, with
ld.lld-21, if you try to set the text section address below image base
address when linking a non-relocatable binary, ld.lld wil fail to link.

Switching to using a customized linker script solves the issue and is a
more robost solution to supporting multiple linkers than attempting to
find a set of command-line flags that satisified all supported linkers
and links the kernel properly. In the worst case, continued use of
command-line flags could result in having to create code branches to
support various linkers.

For example, when dealing with just ld.bfd and ld.lld, the behavioral
differences between the two made finding a proper subset of flags that
worked impossible. The previous attempt dropped -Ttext for --image-base,
which has been proven not to work. The simplest correction,
-Wl,--image-base=0 -Wl,-Ttext, did not work because that option resulted
in a GRUB kernel that entered into a tight infinite refresh loop.

Moreover, ld.lld does not order the sections the same way ld.bfd does,
and that results in object files with gaps or holes when sections are
stripped. I suspect, but did not investigate, that this plays a role in
the infinite refresh loop I mentioned earlier.

The easiest way to resolve all this is to use customized linker scripts.
These scripts, by default, override any default configuration the linker
would otherwise impose, allow for complete control in aligning sections,
and allows GRUB to specify where in the load segment each section goes.

This change does require linkers to support the --defsym flag, which
requires its argument to be of the form 'sym=address' as 'sym address'
is not supported.

Signed-off-by: Nicholas Vinson <[email protected]>
---
 conf/Makefile.extra-dist    |  1 +
 conf/i386-pc-kernel.lds     | 51 +++++++++++++++++++++++++++++++++++++
 grub-core/Makefile.core.def | 31 +++++++++++-----------
 3 files changed, 68 insertions(+), 15 deletions(-)
 create mode 100644 conf/i386-pc-kernel.lds

diff --git a/conf/Makefile.extra-dist b/conf/Makefile.extra-dist
index d22b6c862..892df8208 100644
--- a/conf/Makefile.extra-dist
+++ b/conf/Makefile.extra-dist
@@ -17,6 +17,7 @@ EXTRA_DIST += docs/grub.cfg
 EXTRA_DIST += docs/osdetect.cfg
 
 EXTRA_DIST += conf/i386-cygwin-img-ld.sc
+EXTRA_DIST += conf/i386-pc-kernel.lds
 
 EXTRA_DIST += grub-core/Makefile.core.def
 EXTRA_DIST += grub-core/Makefile.gcry.def
diff --git a/conf/i386-pc-kernel.lds b/conf/i386-pc-kernel.lds
new file mode 100644
index 000000000..d40c7736c
--- /dev/null
+++ b/conf/i386-pc-kernel.lds
@@ -0,0 +1,51 @@
+ENTRY(_start)
+
+/*
+ * Align sections to a 16-byte boundary. This guarantees ABI compatibility with
+ * C generated code
+ */
+SECTION_ALIGN = 0x10;
+
+PHDRS {
+    text PT_LOAD FLAGS(7) /* PF_R | PF_W | PF_X */;
+}
+
+SECTIONS
+{
+    /*
+     * Set section alignment to 1. This allows sections to be aligned without
+     * creating holes in the VMA space or gaps in the file.
+     */
+    . = _grub_text_base;
+    .text ALIGN(0x1) : {
+        _start = .;
+        *(.text .text.*)
+        . = ALIGN(SECTION_ALIGN);
+    } :text
+    .rodata ALIGN(0x1) : {
+        *(.rodata .rodata.*)
+        . = ALIGN(SECTION_ALIGN);
+    } :text
+    .module_license ALIGN(0x1) : {
+        *(.module_license)
+        . = ALIGN(SECTION_ALIGN);
+    } :text
+    .data ALIGN(0x1) : {
+        *(.data .data.*)
+        . = ALIGN(SECTION_ALIGN);
+        _edata = .;
+    } :text
+    .bss ALIGN(0x1) : {
+        __bss_start = .;
+        *(.bss .bss.*)
+        *(COMMON)
+        . = ALIGN(SECTION_ALIGN);
+        _end = .;
+    } :text
+    /DISCARD/ : {
+        *(.interp)
+        *(.note*)
+        *(.comment)
+        *(.build-id)
+    }
+}
diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index 0cf155128..1a91e53d6 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -10,6 +10,7 @@ transform_data = {
   installdir = noinst;
   name = genmod.sh;
   common = genmod.sh.in;
+  i386_pc_ldflags = '$(TARGET_IMG_LDFLAGS)';
 };
 
 transform_data = {
@@ -82,21 +83,21 @@ kernel = {
   riscv64_efi_stripflags   = '--strip-unneeded -K start -R .note -R .comment 
-R .note.gnu.gold-version -R .eh_frame';
 
   i386_pc_ldflags          = '$(TARGET_IMG_LDFLAGS)';
-  i386_pc_ldflags          = '$(TARGET_IMG_BASE_LDOPT),0x9000';
+  i386_pc_ldflags          = 
'$(TARGET_IMG_BASE_LDOPT)$(TARGET_IMG_BASE_LDOPT_ARG_SEP)0x9000';
   i386_qemu_ldflags        = '$(TARGET_IMG_LDFLAGS)';
-  i386_qemu_ldflags        = '$(TARGET_IMG_BASE_LDOPT),0x9000';
+  i386_qemu_ldflags        = 
'$(TARGET_IMG_BASE_LDOPT)$(TARGET_IMG_BASE_LDOPT_ARG_SEP)0x9000';
   i386_coreboot_ldflags    = '$(TARGET_IMG_LDFLAGS)';
-  i386_coreboot_ldflags    = '$(TARGET_IMG_BASE_LDOPT),0x9000';
+  i386_coreboot_ldflags    = 
'$(TARGET_IMG_BASE_LDOPT)$(TARGET_IMG_BASE_LDOPT_ARG_SEP)0x9000';
   i386_multiboot_ldflags   = '$(TARGET_IMG_LDFLAGS)';
-  i386_multiboot_ldflags   = '$(TARGET_IMG_BASE_LDOPT),0x9000';
+  i386_multiboot_ldflags   = 
'$(TARGET_IMG_BASE_LDOPT)$(TARGET_IMG_BASE_LDOPT_ARG_SEP)0x9000';
   i386_ieee1275_ldflags    = '$(TARGET_IMG_LDFLAGS)';
-  i386_ieee1275_ldflags    = '$(TARGET_IMG_BASE_LDOPT),0x10000';
+  i386_ieee1275_ldflags    = 
'$(TARGET_IMG_BASE_LDOPT)$(TARGET_IMG_BASE_LDOPT_ARG_SEP)0x10000';
   i386_xen_ldflags         = '$(TARGET_IMG_LDFLAGS)';
-  i386_xen_ldflags         = '$(TARGET_IMG_BASE_LDOPT),0';
+  i386_xen_ldflags         = 
'$(TARGET_IMG_BASE_LDOPT)$(TARGET_IMG_BASE_LDOPT_ARG_SEP)0';
   x86_64_xen_ldflags       = '$(TARGET_IMG_LDFLAGS)';
   x86_64_xen_ldflags       = '$(TARGET_IMG_BASE_LDOPT),0';
   i386_xen_pvh_ldflags     = '$(TARGET_IMG_LDFLAGS)';
-  i386_xen_pvh_ldflags     = '$(TARGET_IMG_BASE_LDOPT),0x100000';
+  i386_xen_pvh_ldflags     = 
'$(TARGET_IMG_BASE_LDOPT)$(TARGET_IMG_BASE_LDOPT_ARG_SEP)0x100000';
 
   mips_loongson_ldflags    = '-Wl,-Ttext,0x80200000';
   powerpc_ieee1275_ldflags = '-Wl,-Ttext,0x200000';
@@ -450,10 +451,10 @@ image = {
   sparc64_ieee1275 = boot/sparc64/ieee1275/boot.S;
 
   i386_pc_ldflags = '$(TARGET_IMG_LDFLAGS)';
-  i386_pc_ldflags = '$(TARGET_IMG_BASE_LDOPT),0x7C00';
+  i386_pc_ldflags = 
'$(TARGET_IMG_BASE_LDOPT)$(TARGET_IMG_BASE_LDOPT_ARG_SEP)0x7C00';
 
   i386_qemu_ldflags = '$(TARGET_IMG_LDFLAGS)';
-  i386_qemu_ldflags = 
'$(TARGET_IMG_BASE_LDOPT),$(GRUB_BOOT_MACHINE_LINK_ADDR)';
+  i386_qemu_ldflags = 
'$(TARGET_IMG_BASE_LDOPT)$(TARGET_IMG_BASE_LDOPT_ARG_SEP)$(GRUB_BOOT_MACHINE_LINK_ADDR)';
   i386_qemu_ccasflags = 
'-DGRUB_BOOT_MACHINE_LINK_ADDR=$(GRUB_BOOT_MACHINE_LINK_ADDR)';
 
   /* The entry point for a.out binaries on sparc64 starts
@@ -478,7 +479,7 @@ image = {
   cppflags = '-DHYBRID_BOOT=1';
   
   i386_pc_ldflags = '$(TARGET_IMG_LDFLAGS)';
-  i386_pc_ldflags = '$(TARGET_IMG_BASE_LDOPT),0x7C00';
+  i386_pc_ldflags = 
'$(TARGET_IMG_BASE_LDOPT)$(TARGET_IMG_BASE_LDOPT_ARG_SEP)0x7C00';
 
   objcopyflags = '-O binary';
   enable = i386_pc;
@@ -489,7 +490,7 @@ image = {
 
   i386_pc = boot/i386/pc/cdboot.S;
   i386_pc_ldflags = '$(TARGET_IMG_LDFLAGS)';
-  i386_pc_ldflags = '$(TARGET_IMG_BASE_LDOPT),0x7C00';
+  i386_pc_ldflags = 
'$(TARGET_IMG_BASE_LDOPT)$(TARGET_IMG_BASE_LDOPT_ARG_SEP)0x7C00';
 
   sparc64_ieee1275 = boot/sparc64/ieee1275/boot.S;
 
@@ -509,7 +510,7 @@ image = {
   i386_pc = boot/i386/pc/pxeboot.S;
 
   i386_pc_ldflags = '$(TARGET_IMG_LDFLAGS)';
-  i386_pc_ldflags = '$(TARGET_IMG_BASE_LDOPT),0x7C00';
+  i386_pc_ldflags = 
'$(TARGET_IMG_BASE_LDOPT)$(TARGET_IMG_BASE_LDOPT_ARG_SEP)0x7C00';
 
   objcopyflags = '-O binary';
   enable = i386_pc;
@@ -520,7 +521,7 @@ image = {
   i386_pc = boot/i386/pc/diskboot.S;
 
   i386_pc_ldflags = '$(TARGET_IMG_LDFLAGS)';
-  i386_pc_ldflags = '$(TARGET_IMG_BASE_LDOPT),0x8000';
+  i386_pc_ldflags = 
'$(TARGET_IMG_BASE_LDOPT)$(TARGET_IMG_BASE_LDOPT_ARG_SEP)0x8000';
 
   sparc64_ieee1275 = boot/sparc64/ieee1275/diskboot.S;
   sparc64_ieee1275_ldflags = '-Wl,-Ttext=0x4200';
@@ -536,7 +537,7 @@ image = {
   i386_pc = boot/i386/pc/lnxboot.S;
 
   i386_pc_ldflags = '$(TARGET_IMG_LDFLAGS)';
-  i386_pc_ldflags = '$(TARGET_IMG_BASE_LDOPT),0x6000';
+  i386_pc_ldflags = 
'$(TARGET_IMG_BASE_LDOPT)$(TARGET_IMG_BASE_LDOPT_ARG_SEP)0x6000';
 
   objcopyflags = '-O binary';
   enable = i386_pc;
@@ -578,7 +579,7 @@ image = {
   i386_pc_nodist = rs_decoder.h;
 
   objcopyflags = '-O binary';
-  ldflags = '$(TARGET_IMG_LDFLAGS) $(TARGET_IMG_BASE_LDOPT),0x8200';
+  ldflags = '$(TARGET_IMG_LDFLAGS) 
$(TARGET_IMG_BASE_LDOPT)$(TARGET_IMG_BASE_LDOPT_ARG_SEP)0x8200';
   enable = i386_pc;
 };
 
-- 
2.53.0


_______________________________________________
Grub-devel mailing list
[email protected]
https://lists.gnu.org/mailman/listinfo/grub-devel

Reply via email to