[lld] 09abee8 - [ELF] Support non-section Defined symbols at MergeInputSection end (#195801)

via llvm-commits llvm-commits at lists.llvm.org
Tue May 5 10:11:47 PDT 2026


Author: Fangrui Song
Date: 2026-05-05T10:11:42-07:00
New Revision: 09abee845d2136630fc3f50524148daa55a740a8

URL: https://github.com/llvm/llvm-project/commit/09abee845d2136630fc3f50524148daa55a740a8
DIFF: https://github.com/llvm/llvm-project/commit/09abee845d2136630fc3f50524148daa55a740a8.diff

LOG: [ELF] Support non-section Defined symbols at MergeInputSection end (#195801)

Commit bb443359a8ad ("[ELF] Validate merge section offsets in getSymVA
and
match GNU ld") accepts offset == section_size for section-symbol
references
in getSymVA, and skips the out-of-bounds case in MarkLive.

This patch extends the support for non-section Defined symbols,
modifying the per-symbol pre-resolution added by commit 42cc45477727
("[ELF] Optimize binary search in getSectionPiece").

Fix #118148

Added: 
    

Modified: 
    lld/ELF/SyntheticSections.cpp
    lld/test/ELF/merge-piece-oob.s

Removed: 
    


################################################################################
diff  --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp
index 3c08c392ff214..805d0530f12ad 100644
--- a/lld/ELF/SyntheticSections.cpp
+++ b/lld/ELF/SyntheticSections.cpp
@@ -3813,14 +3813,17 @@ template <class ELFT> void elf::splitSections(Ctx &ctx) {
     // For non-section Defined symbols in merge sections, pre-resolve the piece
     // index to avoid potentially repeated binary search (MarkLive, RelocScan,
     // includeInSymtab). Encode each non-section Defined symbol's value as
-    // ((pieceIdx + 1) << mergeValueShift) | intraPieceOffset.
+    // ((pieceIdx + 1) << mergeValueShift) | intraPieceOffset. A one-past-end
+    // label is anchored on the last piece.
     auto resolve = [](Defined *d) {
       auto *ms = dyn_cast_or_null<MergeInputSection>(d->section);
       if (!ms || d->isSection())
         return;
-      SectionPiece &piece = ms->getSectionPiece(d->value);
+      uint64_t v = d->value;
+      SectionPiece &piece = v >= ms->content().size() ? ms->pieces.back()
+                                                      : ms->getSectionPiece(v);
       uint32_t idx = &piece - ms->pieces.data();
-      uint64_t off = d->value - piece.inputOff;
+      uint64_t off = v - piece.inputOff;
       d->value = ((uint64_t)(idx + 1) << mergeValueShift) | off;
     };
     for (Symbol *sym : file->getLocalSymbols())

diff  --git a/lld/test/ELF/merge-piece-oob.s b/lld/test/ELF/merge-piece-oob.s
index 829f45cbc75e7..8ce5cc46d6960 100644
--- a/lld/test/ELF/merge-piece-oob.s
+++ b/lld/test/ELF/merge-piece-oob.s
@@ -3,8 +3,11 @@
 ## Non-section symbols and offset <= section_size are accepted, matching GNU ld.
 
 # RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64
-# RUN: not ld.lld --threads=1 %t.o -o /dev/null -shared 2>&1 | FileCheck %s -DPREFIX=error --implicit-check-not=error:
-# RUN: ld.lld --threads=1 %t.o -o /dev/null -shared --noinhibit-exec 2>&1 | FileCheck %s -DPREFIX=warning --implicit-check-not=warning:
+# RUN: llvm-mc %s -o %t.err.o -filetype=obj -triple=x86_64 --defsym=ERR=1
+
+## OOB section-symbol offsets diagnose (or warn).
+# RUN: not ld.lld --threads=1 %t.err.o -o /dev/null -shared 2>&1 | FileCheck %s -DPREFIX=error --implicit-check-not=error:
+# RUN: ld.lld --threads=1 %t.err.o -o /dev/null -shared --noinhibit-exec 2>&1 | FileCheck %s -DPREFIX=warning --implicit-check-not=warning:
 
 ## .foo is 8 bytes with entsize=8 (1 piece). .foo+8 (offset==size) is accepted.
 # CHECK:      [[PREFIX]]: {{.*}}:(.foo): offset 0x9 is outside the section
@@ -18,19 +21,31 @@
 ## Test that --gc-sections with an out-of-bounds offset doesn't crash.
 ## .data is discarded but .data.retain (SHF_GNU_RETAIN) is kept.
 ## The bad offset prevents the piece from being marked live, so .foo is discarded.
-# RUN: not ld.lld %t.o -o /dev/null --gc-sections 2>&1 | FileCheck %s --check-prefix=GC
+# RUN: not ld.lld %t.err.o -o /dev/null --gc-sections 2>&1 | FileCheck %s --check-prefix=GC
 # GC: error: relocation refers to a discarded section: .foo
 
+# RUN: ld.lld -r %t.o -o %t.ro
+# RUN: llvm-readelf -s -r %t.ro | FileCheck %s --check-prefix=RELOC
+
+# RELOC:      R_X86_64_64 {{.*}} str_end + 0
+# RELOC-NEXT: R_X86_64_64 {{.*}} fixed_end + 0
+
+# RELOC:      0000000000000004 {{.*}} str_end
+# RELOC:      0000000000000008 {{.*}} fixed_end
+
 .globl _start
 _start:
 
 .data
 .quad .foo + 8
+.quad .rodata.str1.1 + 4
+.quad str_end
+.quad fixed_end
+
+.ifdef ERR
 .quad .foo + 9
 .quad .foo + 0x100000000
 .quad .foo - 1
-.quad .rodata.str1.1 + 3
-.quad .rodata.str1.1 + 4
 .quad .rodata.str1.1 + 5
 
 .quad a0 - 1
@@ -38,10 +53,15 @@ _start:
 
 .section .data.retain,"awR"
 .quad .foo - 2
+.endif
 
 .section	.foo,"aM", at progbits,8
 a0:
 .quad 0
+.globl fixed_end
+fixed_end:
 
 .section	.rodata.str1.1,"aMS", at progbits,1
 .asciz	"abc"
+.globl str_end
+str_end:


        


More information about the llvm-commits mailing list