On 1/27/26 10:41, Daniel Kiper wrote:
On Mon, Jan 26, 2026 at 06:59:33AM -0500, Nicholas Vinson wrote:
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.

I think in first place it begs for explanation why this is correct in our
case. Should not we fix our builds to make newer linkers happy?

Using a customized linker script actually does a better job of making newer linkers "happy" than trying to find a set of command-line flags that satisifies all supported linkers and properly produces the kernel.

Then 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, does not appear work. My testing with 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.


Switching to using a customized linker script solves the issue.

Signed-off-by: Nicholas Vinson <[email protected]>
---
  conf/Makefile.extra-dist    |  1 +
  conf/i386-pc-kernel.ld      | 38 +++++++++++++++++++++++++++++++++++
  grub-core/Makefile.core.def | 40 +++++++++++++++++++++++++++----------
  3 files changed, 69 insertions(+), 10 deletions(-)
  create mode 100644 conf/i386-pc-kernel.ld

diff --git a/conf/Makefile.extra-dist b/conf/Makefile.extra-dist
index d22b6c862..fd904cd33 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.ld

  EXTRA_DIST += grub-core/Makefile.core.def
  EXTRA_DIST += grub-core/Makefile.gcry.def
diff --git a/conf/i386-pc-kernel.ld b/conf/i386-pc-kernel.ld
new file mode 100644
index 000000000..80d5734b3
--- /dev/null
+++ b/conf/i386-pc-kernel.ld

s/ld/lds/ and I would rename i386-cygwin-img-ld.sc to

done.

i386-cygwin-img-ld.lds too. Of course in separate patch...

done.


@@ -0,0 +1,38 @@
+ENTRY(_start)
+
+PHDRS {
+    text PT_LOAD FLAGS(7);

text PT_LOAD FLAGS(7); /* PF_R | PF_W | PF_X */

done.


+}
+
+SECTIONS
+{
+    . = _grub_text_base;
+    .text : {
+        _start = .;
+        *(.text .text.*)
+    } :text
+    .rodata : {
+        *(.rodata .rodata.*)
+    } :text
+    .module_license : {
+        *(.module_license)
+    } :text
+    .data : {
+        *(.data .data.*)
+        . = ALIGN(0x10);

Where does this number come from? And I would define a constant at the
beginning of the linker script...


done.

+        _edata = .;
+    } :text
+    .bss : {
+        __bss_start = .;
+        *(.bss .bss.*)
+        *(COMMON)
+        . = ALIGN(0x10);

Ditto...


done.

+        _end = .;
+    } :text
+    /DISCARD/ : {
+        *(.interp)
+        *(.note*)
+        *(.comment)
+        *(.build-id)
+    }
+}
diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index 0cf155128..7cc7963c7 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -82,7 +82,8 @@ 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          = '-Wl,-T$(top_srcdir)/conf/i386-pc-kernel.ld';
+  i386_pc_ldflags          = '$(TARGET_IMG_BASE_LDOPT)=0x9000';

Could not we stick to "," and do not make a change to "="?

No. ld.bfd and ld.lld require '=' instead of ' ' when using --defsym.


    i386_qemu_ldflags        = '$(TARGET_IMG_LDFLAGS)';
    i386_qemu_ldflags        = '$(TARGET_IMG_BASE_LDOPT),0x9000';
    i386_coreboot_ldflags    = '$(TARGET_IMG_LDFLAGS)';
@@ -449,8 +450,11 @@ image = {
    i386_qemu = boot/i386/qemu/boot.S;
    sparc64_ieee1275 = boot/sparc64/ieee1275/boot.S;

+  i386_pc_extra_dist = '$(top_srcdir)/conf/i386-pc-kernel.ld';
+
    i386_pc_ldflags = '$(TARGET_IMG_LDFLAGS)';
-  i386_pc_ldflags = '$(TARGET_IMG_BASE_LDOPT),0x7C00';
+  i386_pc_ldflags = '-Wl,-T$(top_srcdir)/conf/i386-pc-kernel.ld';
+  i386_pc_ldflags = '$(TARGET_IMG_BASE_LDOPT)=0x7C00';

Ditto...

    i386_qemu_ldflags = '$(TARGET_IMG_LDFLAGS)';
    i386_qemu_ldflags = 
'$(TARGET_IMG_BASE_LDOPT),$(GRUB_BOOT_MACHINE_LINK_ADDR)';
@@ -475,10 +479,13 @@ image = {
    name = boot_hybrid;
    i386_pc = boot/i386/pc/boot.S;

+  i386_pc_extra_dist = '$(top_srcdir)/conf/i386-pc-kernel.ld';
+
    cppflags = '-DHYBRID_BOOT=1';

    i386_pc_ldflags = '$(TARGET_IMG_LDFLAGS)';
-  i386_pc_ldflags = '$(TARGET_IMG_BASE_LDOPT),0x7C00';
+  i386_pc_ldflags = '-Wl,-T$(top_srcdir)/conf/i386-pc-kernel.ld';
+  i386_pc_ldflags = '$(TARGET_IMG_BASE_LDOPT)=0x7C00';

Ditto and below...

    objcopyflags = '-O binary';
    enable = i386_pc;
@@ -486,10 +493,13 @@ image = {

  image = {
    name = cdboot;
-

Please drop this change...

done.


    i386_pc = boot/i386/pc/cdboot.S;
+
+  i386_pc_extra_dist = '$(top_srcdir)/conf/i386-pc-kernel.ld';
+
    i386_pc_ldflags = '$(TARGET_IMG_LDFLAGS)';
-  i386_pc_ldflags = '$(TARGET_IMG_BASE_LDOPT),0x7C00';
+  i386_pc_ldflags = '-Wl,-T$(top_srcdir)/conf/i386-pc-kernel.ld';
+  i386_pc_ldflags = '$(TARGET_IMG_BASE_LDOPT)=0x7C00';

    sparc64_ieee1275 = boot/sparc64/ieee1275/boot.S;

@@ -508,8 +518,11 @@ image = {
    name = pxeboot;
    i386_pc = boot/i386/pc/pxeboot.S;

+  i386_pc_extra_dist = '$(top_srcdir)/conf/i386-pc-kernel.ld';
+
    i386_pc_ldflags = '$(TARGET_IMG_LDFLAGS)';
-  i386_pc_ldflags = '$(TARGET_IMG_BASE_LDOPT),0x7C00';
+  i386_pc_ldflags = '-Wl,-T$(top_srcdir)/conf/i386-pc-kernel.ld';
+  i386_pc_ldflags = '$(TARGET_IMG_BASE_LDOPT)=0x7C00';

    objcopyflags = '-O binary';
    enable = i386_pc;
@@ -519,8 +532,11 @@ image = {
    name = diskboot;
    i386_pc = boot/i386/pc/diskboot.S;

+  i386_pc_extra_dist = '$(top_srcdir)/conf/i386-pc-kernel.ld';
+
    i386_pc_ldflags = '$(TARGET_IMG_LDFLAGS)';
-  i386_pc_ldflags = '$(TARGET_IMG_BASE_LDOPT),0x8000';
+  i386_pc_ldflags = '-Wl,-T$(top_srcdir)/conf/i386-pc-kernel.ld';
+  i386_pc_ldflags = '$(TARGET_IMG_BASE_LDOPT)=0x8000';

    sparc64_ieee1275 = boot/sparc64/ieee1275/diskboot.S;
    sparc64_ieee1275_ldflags = '-Wl,-Ttext=0x4200';
@@ -535,8 +551,11 @@ image = {
    name = lnxboot;
    i386_pc = boot/i386/pc/lnxboot.S;

+  i386_pc_extra_dist = '$(top_srcdir)/conf/i386-pc-kernel.ld';
+
    i386_pc_ldflags = '$(TARGET_IMG_LDFLAGS)';
-  i386_pc_ldflags = '$(TARGET_IMG_BASE_LDOPT),0x6000';
+  i386_pc_ldflags = '-Wl,-T$(top_srcdir)/conf/i386-pc-kernel.ld';
+  i386_pc_ldflags = '$(TARGET_IMG_BASE_LDOPT)=0x6000';

    objcopyflags = '-O binary';
    enable = i386_pc;
@@ -576,10 +595,11 @@ image = {
    name = lzma_decompress;
    i386_pc = boot/i386/pc/startup_raw.S;
    i386_pc_nodist = rs_decoder.h;
+  i386_pc_extra_dist = '$(top_srcdir)/conf/i386-pc-kernel.ld';

    objcopyflags = '-O binary';
-  ldflags = '$(TARGET_IMG_LDFLAGS) $(TARGET_IMG_BASE_LDOPT),0x8200';
-  enable = i386_pc;
+  ldflags = '$(TARGET_IMG_LDFLAGS) -Wl,-T$(top_srcdir)/conf/i386-pc-kernel.ld 
$(TARGET_IMG_BASE_LDOPT)=0x8200';
+  lnable = i386_pc;

Hmmm... Looks like a mistake...

Fixed.

Thanks,
Nicholas Vinson

Daniel


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

Reply via email to