[lld] [lld][ELF] Fix crash when relaxation pass encounters synthetic sections (PR #184758)

via llvm-commits llvm-commits at lists.llvm.org
Fri Mar 6 01:13:49 PST 2026


https://github.com/wangleiat updated https://github.com/llvm/llvm-project/pull/184758

>From 821368f60bbb939dfbae5d05f6f23e9309e5abbb Mon Sep 17 00:00:00 2001
From: wanglei <wanglei at loongson.cn>
Date: Thu, 5 Mar 2026 16:31:32 +0800
Subject: [PATCH 1/3] =?UTF-8?q?[=F0=9D=98=80=F0=9D=97=BD=F0=9D=97=BF]=20in?=
 =?UTF-8?q?itial=20version?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Created using spr 1.3.7
---
 lld/ELF/Arch/LoongArch.cpp                    |  7 ++++-
 lld/ELF/Arch/RISCV.cpp                        | 11 +++++++-
 .../ELF/loongarch-relax-synthetic-in-text.s   | 27 ++++++++++++++++++
 lld/test/ELF/riscv-relax-synthetic-in-text.s  | 28 +++++++++++++++++++
 4 files changed, 71 insertions(+), 2 deletions(-)
 create mode 100644 lld/test/ELF/loongarch-relax-synthetic-in-text.s
 create mode 100644 lld/test/ELF/riscv-relax-synthetic-in-text.s

diff --git a/lld/ELF/Arch/LoongArch.cpp b/lld/ELF/Arch/LoongArch.cpp
index 90641de736c74..03eb0badac77c 100644
--- a/lld/ELF/Arch/LoongArch.cpp
+++ b/lld/ELF/Arch/LoongArch.cpp
@@ -1685,8 +1685,11 @@ bool LoongArch::relaxOnce(int pass) const {
   for (OutputSection *osec : ctx.outputSections) {
     if (!(osec->flags & SHF_EXECINSTR))
       continue;
-    for (InputSection *sec : getInputSections(*osec, storage))
+    for (InputSection *sec : getInputSections(*osec, storage)) {
+      if (!sec->relaxAux)
+        continue;
       changed |= relax(ctx, *sec);
+    }
   }
   return changed;
 }
@@ -1698,6 +1701,8 @@ void LoongArch::finalizeRelax(int passes) const {
     if (!(osec->flags & SHF_EXECINSTR))
       continue;
     for (InputSection *sec : getInputSections(*osec, storage)) {
+      if (!sec->relaxAux)
+        continue;
       RelaxAux &aux = *sec->relaxAux;
       if (!aux.relocDeltas)
         continue;
diff --git a/lld/ELF/Arch/RISCV.cpp b/lld/ELF/Arch/RISCV.cpp
index 85f49c9260565..43afa4c115459 100644
--- a/lld/ELF/Arch/RISCV.cpp
+++ b/lld/ELF/Arch/RISCV.cpp
@@ -743,6 +743,8 @@ void elf::initSymbolAnchors(Ctx &ctx) {
     if (!(osec->flags & SHF_EXECINSTR))
       continue;
     for (InputSection *sec : getInputSections(*osec, storage)) {
+      if (isa<SyntheticSection>(sec))
+        continue;
       sec->relaxAux = make<RelaxAux>();
       if (sec->relocs().size()) {
         sec->relaxAux->relocDeltas =
@@ -787,6 +789,8 @@ void elf::initSymbolAnchors(Ctx &ctx) {
     if (!(osec->flags & SHF_EXECINSTR))
       continue;
     for (InputSection *sec : getInputSections(*osec, storage)) {
+      if (!sec->relaxAux)
+        continue;
       llvm::sort(sec->relaxAux->anchors, [](auto &a, auto &b) {
         return std::make_pair(a.offset, a.end) <
                std::make_pair(b.offset, b.end);
@@ -1016,8 +1020,11 @@ bool RISCV::relaxOnce(int pass) const {
   for (OutputSection *osec : ctx.outputSections) {
     if (!(osec->flags & SHF_EXECINSTR))
       continue;
-    for (InputSection *sec : getInputSections(*osec, storage))
+    for (InputSection *sec : getInputSections(*osec, storage)) {
+      if (!sec->relaxAux)
+        continue;
       changed |= relax(ctx, pass, *sec);
+    }
   }
   return changed;
 }
@@ -1141,6 +1148,8 @@ void RISCV::finalizeRelax(int passes) const {
     if (!(osec->flags & SHF_EXECINSTR))
       continue;
     for (InputSection *sec : getInputSections(*osec, storage)) {
+      if (!sec->relaxAux)
+        continue;
       RelaxAux &aux = *sec->relaxAux;
       if (!aux.relocDeltas)
         continue;
diff --git a/lld/test/ELF/loongarch-relax-synthetic-in-text.s b/lld/test/ELF/loongarch-relax-synthetic-in-text.s
new file mode 100644
index 0000000000000..d96873d4e53da
--- /dev/null
+++ b/lld/test/ELF/loongarch-relax-synthetic-in-text.s
@@ -0,0 +1,27 @@
+# REQUIRES: loongarch
+# RUN: rm -rf %t && split-file %s %t
+# RUN: llvm-mc --filetype=obj -triple=loongarch64 %t/a.s -o %t/a.o
+# RUN: ld.lld -T %t/a.ld %t/a.o -o /dev/null
+
+## This test ensures that the relaxation pass does not crash when it encounters
+## a synthetic section (like .got) that has been placed inside an executable
+## output section via a linker script. Synthetic sections do not have relaxAux
+## data structures initialized.
+
+#--- a.s
+.global _start
+_start:
+  pcalau12i $a0, %got_pc_hi20(sym)
+  ld.d $a0, $a0, %got_pc_lo12(sym)
+
+.data
+sym:
+  .word 0
+
+#--- a.ld
+SECTIONS {
+  .text : {
+    *(.text)
+    *(.got)
+  }
+}
diff --git a/lld/test/ELF/riscv-relax-synthetic-in-text.s b/lld/test/ELF/riscv-relax-synthetic-in-text.s
new file mode 100644
index 0000000000000..3b01c147c41fe
--- /dev/null
+++ b/lld/test/ELF/riscv-relax-synthetic-in-text.s
@@ -0,0 +1,28 @@
+# REQUIRES: riscv
+# RUN: rm -rf %t && split-file %s %t
+# RUN: llvm-mc --filetype=obj -triple=riscv64 %t/a.s -o %t/a.o
+# RUN: ld.lld -T %t/a.ld %t/a.o -o /dev/null
+
+## This test ensures that the relaxation pass does not crash when it encounters
+## a synthetic section (like .got) that has been placed inside an executable
+## output section via a linker script. Synthetic sections do not have relaxAux
+## data structures initialized.
+
+#--- a.s
+.global _start
+_start:
+1:
+  auipc a0, %got_pcrel_hi(sym)
+  ld a0, %pcrel_lo(1b)(a0)
+
+.data
+sym:
+  .word 0
+
+#--- a.ld
+SECTIONS {
+  .text : {
+    *(.text)
+    *(.got)
+  }
+}

>From ff633dddfee33944ed268be549ca6a6d2798230c Mon Sep 17 00:00:00 2001
From: wanglei <wanglei at loongson.cn>
Date: Fri, 6 Mar 2026 16:08:29 +0800
Subject: [PATCH 2/3] Address @MaskRay's comments

Created using spr 1.3.7
---
 .../ELF/loongarch-relax-synthetic-in-text.s   | 22 ++++++++++++-----
 lld/test/ELF/riscv-relax-synthetic-in-text.s  | 24 ++++++++++++++-----
 2 files changed, 34 insertions(+), 12 deletions(-)

diff --git a/lld/test/ELF/loongarch-relax-synthetic-in-text.s b/lld/test/ELF/loongarch-relax-synthetic-in-text.s
index d96873d4e53da..ae27e47c37148 100644
--- a/lld/test/ELF/loongarch-relax-synthetic-in-text.s
+++ b/lld/test/ELF/loongarch-relax-synthetic-in-text.s
@@ -1,12 +1,22 @@
 # REQUIRES: loongarch
 # RUN: rm -rf %t && split-file %s %t
-# RUN: llvm-mc --filetype=obj -triple=loongarch64 %t/a.s -o %t/a.o
-# RUN: ld.lld -T %t/a.ld %t/a.o -o /dev/null
+# RUN: llvm-mc --filetype=obj -triple=loongarch64 -mattr=+relax %t/a.s -o %t/a.o
 
-## This test ensures that the relaxation pass does not crash when it encounters
-## a synthetic section (like .got) that has been placed inside an executable
-## output section via a linker script. Synthetic sections do not have relaxAux
-## data structures initialized.
+## Do not crash when we encounter a synthetic section (like .got) that has
+## been placed inside an executable output section via a linker script.
+## Synthetic sections do not have relaxAux data structures initialized.
+
+# RUN: ld.lld -T %t/a.ld %t/a.o -o %t/nopie
+# RUN: llvm-objdump -s -j.text %t/nopie | FileCheck %s --check-prefixes=CHECK-NOPIE
+
+# RUN: ld.lld -pie -T %t/a.ld %t/a.o -o %t/pie
+# RUN: llvm-objdump -s -j.text %t/pie | FileCheck %s --check-prefix=CHECK-PIE
+
+# CHECK-NOPIE:      Contents of section .text:
+# CHECK-NOPIE-NEXT: 0000 0400001a 8440c002 10000000 00000000
+
+# CHECK-PIE:        Contents of section .text:
+# CHECK-PIE-NEXT:   0060 0400001a 8400c502 00000000 00000000
 
 #--- a.s
 .global _start
diff --git a/lld/test/ELF/riscv-relax-synthetic-in-text.s b/lld/test/ELF/riscv-relax-synthetic-in-text.s
index 3b01c147c41fe..763870fa00deb 100644
--- a/lld/test/ELF/riscv-relax-synthetic-in-text.s
+++ b/lld/test/ELF/riscv-relax-synthetic-in-text.s
@@ -1,12 +1,24 @@
 # REQUIRES: riscv
 # RUN: rm -rf %t && split-file %s %t
-# RUN: llvm-mc --filetype=obj -triple=riscv64 %t/a.s -o %t/a.o
-# RUN: ld.lld -T %t/a.ld %t/a.o -o /dev/null
+# RUN: llvm-mc --filetype=obj -triple=riscv64 -mattr=+relax %t/a.s -o %t/a.o
 
-## This test ensures that the relaxation pass does not crash when it encounters
-## a synthetic section (like .got) that has been placed inside an executable
-## output section via a linker script. Synthetic sections do not have relaxAux
-## data structures initialized.
+## Do not crash when we encounter a synthetic section (like .got) that has
+## been placed inside an executable output section via a linker script.
+## Synthetic sections do not have relaxAux data structures initialized.
+
+# RUN: ld.lld -T %t/a.ld %t/a.o -o %t/nopie
+# RUN: llvm-objdump -s -j.text %t/nopie | FileCheck %s --check-prefixes=CHECK-NOPIE
+
+# RUN: ld.lld -pie -T %t/a.ld %t/a.o -o %t/pie
+# RUN: llvm-objdump -s -j.text %t/pie | FileCheck %s --check-prefix=CHECK-PIE
+
+# CHECK-NOPIE:      Contents of section .text:
+# CHECK-NOPIE-NEXT:  0000 17050000 03350501 00000000 00000000
+# CHECK-NOPIE-NEXT:  0010 18000000 00000000
+
+# CHECK-PIE:        Contents of section .text:
+# CHECK-PIE-NEXT:    0060 17050000 03350501 78000000 00000000
+# CHECK-PIE-NEXT:    0070 00000000 00000000
 
 #--- a.s
 .global _start

>From fb6918f63c7a32e69f1c5332735e5a47eb36cde4 Mon Sep 17 00:00:00 2001
From: wanglei <wanglei at loongson.cn>
Date: Fri, 6 Mar 2026 17:04:30 +0800
Subject: [PATCH 3/3] a few changes

Created using spr 1.3.7
---
 lld/ELF/Arch/LoongArch.cpp                    |  8 +++----
 lld/ELF/Arch/RISCV.cpp                        |  8 +++----
 .../ELF/loongarch-relax-synthetic-in-text.s   | 16 ++++++--------
 lld/test/ELF/riscv-relax-synthetic-in-text.s  | 21 +++++++------------
 4 files changed, 20 insertions(+), 33 deletions(-)

diff --git a/lld/ELF/Arch/LoongArch.cpp b/lld/ELF/Arch/LoongArch.cpp
index 03eb0badac77c..4c9ea3deece2d 100644
--- a/lld/ELF/Arch/LoongArch.cpp
+++ b/lld/ELF/Arch/LoongArch.cpp
@@ -1685,11 +1685,9 @@ bool LoongArch::relaxOnce(int pass) const {
   for (OutputSection *osec : ctx.outputSections) {
     if (!(osec->flags & SHF_EXECINSTR))
       continue;
-    for (InputSection *sec : getInputSections(*osec, storage)) {
-      if (!sec->relaxAux)
-        continue;
-      changed |= relax(ctx, *sec);
-    }
+    for (InputSection *sec : getInputSections(*osec, storage))
+      if (sec->relaxAux)
+        changed |= relax(ctx, *sec);
   }
   return changed;
 }
diff --git a/lld/ELF/Arch/RISCV.cpp b/lld/ELF/Arch/RISCV.cpp
index 43afa4c115459..d5a72336794fe 100644
--- a/lld/ELF/Arch/RISCV.cpp
+++ b/lld/ELF/Arch/RISCV.cpp
@@ -1020,11 +1020,9 @@ bool RISCV::relaxOnce(int pass) const {
   for (OutputSection *osec : ctx.outputSections) {
     if (!(osec->flags & SHF_EXECINSTR))
       continue;
-    for (InputSection *sec : getInputSections(*osec, storage)) {
-      if (!sec->relaxAux)
-        continue;
-      changed |= relax(ctx, pass, *sec);
-    }
+    for (InputSection *sec : getInputSections(*osec, storage))
+      if (sec->relaxAux)
+        changed |= relax(ctx, pass, *sec);
   }
   return changed;
 }
diff --git a/lld/test/ELF/loongarch-relax-synthetic-in-text.s b/lld/test/ELF/loongarch-relax-synthetic-in-text.s
index ae27e47c37148..672debca9bf94 100644
--- a/lld/test/ELF/loongarch-relax-synthetic-in-text.s
+++ b/lld/test/ELF/loongarch-relax-synthetic-in-text.s
@@ -6,17 +6,13 @@
 ## been placed inside an executable output section via a linker script.
 ## Synthetic sections do not have relaxAux data structures initialized.
 
-# RUN: ld.lld -T %t/a.ld %t/a.o -o %t/nopie
-# RUN: llvm-objdump -s -j.text %t/nopie | FileCheck %s --check-prefixes=CHECK-NOPIE
+# RUN: ld.lld -pie -T %t/a.ld %t/a.o -o %t/a.out
+# RUN: llvm-objdump -s %t/a.out | FileCheck %s
 
-# RUN: ld.lld -pie -T %t/a.ld %t/a.o -o %t/pie
-# RUN: llvm-objdump -s -j.text %t/pie | FileCheck %s --check-prefix=CHECK-PIE
-
-# CHECK-NOPIE:      Contents of section .text:
-# CHECK-NOPIE-NEXT: 0000 0400001a 8440c002 10000000 00000000
-
-# CHECK-PIE:        Contents of section .text:
-# CHECK-PIE-NEXT:   0060 0400001a 8400c502 00000000 00000000
+# CHECK:      Contents of section .text:
+# CHECK-NEXT: 0400001a 8400c502 00000000 00000000
+# CHECK-NEXT: Contents of section .dynamic:
+# CHECK-NEXT: fbffff6f 00000000 00000008 00000000
 
 #--- a.s
 .global _start
diff --git a/lld/test/ELF/riscv-relax-synthetic-in-text.s b/lld/test/ELF/riscv-relax-synthetic-in-text.s
index 763870fa00deb..df83464b27530 100644
--- a/lld/test/ELF/riscv-relax-synthetic-in-text.s
+++ b/lld/test/ELF/riscv-relax-synthetic-in-text.s
@@ -6,19 +6,14 @@
 ## been placed inside an executable output section via a linker script.
 ## Synthetic sections do not have relaxAux data structures initialized.
 
-# RUN: ld.lld -T %t/a.ld %t/a.o -o %t/nopie
-# RUN: llvm-objdump -s -j.text %t/nopie | FileCheck %s --check-prefixes=CHECK-NOPIE
-
-# RUN: ld.lld -pie -T %t/a.ld %t/a.o -o %t/pie
-# RUN: llvm-objdump -s -j.text %t/pie | FileCheck %s --check-prefix=CHECK-PIE
-
-# CHECK-NOPIE:      Contents of section .text:
-# CHECK-NOPIE-NEXT:  0000 17050000 03350501 00000000 00000000
-# CHECK-NOPIE-NEXT:  0010 18000000 00000000
-
-# CHECK-PIE:        Contents of section .text:
-# CHECK-PIE-NEXT:    0060 17050000 03350501 78000000 00000000
-# CHECK-PIE-NEXT:    0070 00000000 00000000
+# RUN: ld.lld -pie -T %t/a.ld %t/a.o -o %t/a.out
+# RUN: llvm-objdump -s %t/a.out | FileCheck %s
+
+# CHECK:      Contents of section .text:
+# CHECK-NEXT: 17050000 03350501 78000000 00000000
+# CHECK-NEXT: 00000000 00000000
+# CHECK-NEXT: Contents of section .dynamic:
+# CHECK-NEXT: fbffff6f 00000000 00000008 00000000
 
 #--- a.s
 .global _start



More information about the llvm-commits mailing list