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