Index: ELF/InputSection.cpp =================================================================== --- ELF/InputSection.cpp +++ ELF/InputSection.cpp @@ -478,15 +478,15 @@ // Compute the Addend and if the Base is cached, return. uintX_t Addend = Offset - Start; uintX_t &Base = I->second; - if (Base != uintX_t(-1)) + auto *MOS = static_cast *>(this->OutSec); + if (!MOS->shouldTailMerge()) return Base + Addend; // Map the base to the offset in the output section and cache it. ArrayRef D = this->getSectionData(); StringRef Data((const char *)D.data(), D.size()); StringRef Entry = Data.substr(Start, End - Start); - Base = - static_cast *>(this->OutSec)->getOffset(Entry); + Base = MOS->getOffset(Entry); return Base + Addend; } Index: ELF/OutputSections.h =================================================================== --- ELF/OutputSections.h +++ ELF/OutputSections.h @@ -310,8 +310,6 @@ class MergeOutputSection final : public OutputSectionBase { typedef typename ELFT::uint uintX_t; - bool shouldTailMerge() const; - public: MergeOutputSection(StringRef Name, uint32_t Type, uintX_t Flags, uintX_t Alignment); @@ -319,6 +317,7 @@ void writeTo(uint8_t *Buf) override; unsigned getOffset(StringRef Val); void finalize() override; + bool shouldTailMerge() const; private: llvm::StringTableBuilder Builder; Index: ELF/OutputSections.cpp =================================================================== --- ELF/OutputSections.cpp +++ ELF/OutputSections.cpp @@ -1279,7 +1279,7 @@ StringRef Entry = Data.substr(Start, End - Start); uintX_t OutputOffset = Builder.add(Entry); if (shouldTailMerge()) - OutputOffset = -1; + OutputOffset = 0; P.second = OutputOffset; } return; Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -1118,9 +1118,15 @@ return false; if (auto *D = dyn_cast>(&B)) { + // Always include absolute symbols. + if (!D->Section) + return true; // Exclude symbols pointing to garbage-collected sections. - if (D->Section && !D->Section->Live) + if (!D->Section->Live) return false; + if (auto *S = dyn_cast>(D->Section)) + if (S->getRangeAndSize(D->Value).first->second == typename ELFT::uint(-1)) + return false; } return true; } Index: test/ELF/string-gc.s =================================================================== --- /dev/null +++ test/ELF/string-gc.s @@ -0,0 +1,54 @@ +// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +// RUN: ld.lld %t.o -o %t --gc-sections +// RUN: llvm-readobj -symbols %t | FileCheck %s + +// CHECK: Symbols [ +// CHECK-NEXT: Symbol { +// CHECK-NEXT: Name: (0) +// CHECK-NEXT: Value: 0x0 +// CHECK-NEXT: Size: 0 +// CHECK-NEXT: Binding: Local (0x0) +// CHECK-NEXT: Type: None (0x0) +// CHECK-NEXT: Other: 0 +// CHECK-NEXT: Section: Undefined (0x0) +// CHECK-NEXT: } +// CHECK-NEXT: Symbol { +// CHECK-NEXT: Name: s1 (8) +// CHECK-NEXT: Value: 0x10120 +// CHECK-NEXT: Size: 0 +// CHECK-NEXT: Binding: Local (0x0) +// CHECK-NEXT: Type: Object (0x1) +// CHECK-NEXT: Other [ (0x2) +// CHECK-NEXT: STV_HIDDEN (0x2) +// CHECK-NEXT: ] +// CHECK-NEXT: Section: .rodata (0x1) +// CHECK-NEXT: } +// CHECK-NEXT: Symbol { +// CHECK-NEXT: Name: _start (1) +// CHECK-NEXT: Value: 0x11000 +// CHECK-NEXT: Size: 0 +// CHECK-NEXT: Binding: Global (0x1) +// CHECK-NEXT: Type: Function (0x2) +// CHECK-NEXT: Other: 0 +// CHECK-NEXT: Section: .text (0x2) +// CHECK-NEXT: } +// CHECK-NEXT: ] + +.text +.globl _start +.type _start,@function +_start: +movl $s1, %eax + +.hidden s1 +.type s1,@object +.section .rodata.str1.1,"aMS",@progbits,1 +.globl s1 +s1: +.asciz "abcd" + +.hidden s2 +.type s2,@object +.globl s2 +s2: +.asciz "efgh"