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

via llvm-commits llvm-commits at lists.llvm.org
Thu Mar 5 00:40:42 PST 2026


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

In LoongArch and RISC-V, the relaxation pass iterates over input sections
within executable output sections. When a linker script places a synthetic
section (e.g., .got) into such an output section, the linker would crash
because synthetic sections do not have the relaxAux field initialized.

The relaxAux data structure is only allocated for non-synthetic sections
in initSymbolAnchors. This patch adds the necessary null checks in the
relaxation loops (relaxOnce and finalizeRelax) to skip sections that
do not require relaxation.

A null check is also added to elf::initSymbolAnchors to ensure the
subsequent sorting of anchors is safe.

Fixes: #184757


>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] =?UTF-8?q?[=F0=9D=98=80=F0=9D=97=BD=F0=9D=97=BF]=20initia?=
 =?UTF-8?q?l=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)
+  }
+}



More information about the llvm-commits mailing list