Re: [PATCH 2/5] grub-core: Update kernel image generation

Nicholas Vinson <[email protected]> Tue, 3 Feb 2026 09:08:10 -0500
Newsgroups org.gnu.grub-devel
Message-ID <[email protected]>
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