[llvm-branch-commits] [lld] release/22.x: [lld][ELF] Fix crash when relaxation pass encounters synthetic sections (PR #186725)

via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Sun Mar 15 19:20:58 PDT 2026


https://github.com/llvmbot created https://github.com/llvm/llvm-project/pull/186725

Backport 655d5e7f690c37aad1da453ed5e3f354d5781d68

Requested by: @wangleiat

>From 673dc7449bbc9cdf930b9d319a2cc50d7bd2ebed Mon Sep 17 00:00:00 2001
From: wanglei <wanglei at loongson.cn>
Date: Mon, 16 Mar 2026 10:06:34 +0800
Subject: [PATCH] [lld][ELF] Fix crash when relaxation pass encounters
 synthetic sections

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

Reviewers: MaskRay

Pull Request: https://github.com/llvm/llvm-project/pull/184758

(cherry picked from commit 655d5e7f690c37aad1da453ed5e3f354d5781d68)
---
 lld/ELF/Arch/LoongArch.cpp                    |  5 ++-
 lld/ELF/Arch/RISCV.cpp                        |  9 ++++-
 .../ELF/loongarch-relax-synthetic-in-text.s   | 31 +++++++++++++++++
 lld/test/ELF/riscv-relax-synthetic-in-text.s  | 33 +++++++++++++++++++
 4 files changed, 76 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 9682b4722ac1e..7e6f14a7cc8f4 100644
--- a/lld/ELF/Arch/LoongArch.cpp
+++ b/lld/ELF/Arch/LoongArch.cpp
@@ -1579,7 +1579,8 @@ bool LoongArch::relaxOnce(int pass) const {
     if (!(osec->flags & SHF_EXECINSTR))
       continue;
     for (InputSection *sec : getInputSections(*osec, storage))
-      changed |= relax(ctx, *sec);
+      if (sec->relaxAux)
+        changed |= relax(ctx, *sec);
   }
   return changed;
 }
@@ -1591,6 +1592,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 bdb728bc19e7b..4c2bca27e1047 100644
--- a/lld/ELF/Arch/RISCV.cpp
+++ b/lld/ELF/Arch/RISCV.cpp
@@ -706,6 +706,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 =
@@ -750,6 +752,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);
@@ -980,7 +984,8 @@ bool RISCV::relaxOnce(int pass) const {
     if (!(osec->flags & SHF_EXECINSTR))
       continue;
     for (InputSection *sec : getInputSections(*osec, storage))
-      changed |= relax(ctx, pass, *sec);
+      if (sec->relaxAux)
+        changed |= relax(ctx, pass, *sec);
   }
   return changed;
 }
@@ -1104,6 +1109,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..67c355e5a7595
--- /dev/null
+++ b/lld/test/ELF/loongarch-relax-synthetic-in-text.s
@@ -0,0 +1,31 @@
+# REQUIRES: loongarch
+# RUN: rm -rf %t && split-file %s %t
+# RUN: llvm-mc --filetype=obj -triple=loongarch64 -mattr=+relax %t/a.s -o %t/a.o
+
+## 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/a.out
+# RUN: llvm-objdump -s %t/a.out | FileCheck %s
+
+# CHECK:      Contents of section .text:
+# CHECK-NEXT: 0400001a 8440c002 10000000 00000000
+
+#--- 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..d892da3fdd3a4
--- /dev/null
+++ b/lld/test/ELF/riscv-relax-synthetic-in-text.s
@@ -0,0 +1,33 @@
+# REQUIRES: riscv
+# RUN: rm -rf %t && split-file %s %t
+# RUN: llvm-mc --filetype=obj -triple=riscv64 -mattr=+relax %t/a.s -o %t/a.o
+
+## 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/a.out
+# RUN: llvm-objdump -s %t/a.out | FileCheck %s
+
+# CHECK:      Contents of section .text:
+# CHECK-NEXT: 17050000 03350501 00000000 00000000
+# CHECK-NEXT: 18000000 00000000
+
+#--- 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-branch-commits mailing list