diff options
-rw-r--r-- | lld/ELF/InputSection.cpp | 9 | ||||
-rw-r--r-- | lld/ELF/InputSection.h | 15 | ||||
-rw-r--r-- | lld/ELF/MarkLive.cpp | 2 | ||||
-rw-r--r-- | lld/ELF/OutputSections.cpp | 4 | ||||
-rw-r--r-- | lld/ELF/OutputSections.h | 3 | ||||
-rw-r--r-- | lld/ELF/Writer.cpp | 9 | ||||
-rw-r--r-- | lld/test/ELF/string-gc.s | 54 |
7 files changed, 85 insertions, 11 deletions
diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp index 6737c2d8367..41703fb73b3 100644 --- a/lld/ELF/InputSection.cpp +++ b/lld/ELF/InputSection.cpp @@ -419,7 +419,8 @@ MergeInputSection<ELFT>::MergeInputSection(elf::ObjectFile<ELFT> *F, StringRef Data((const char *)D.data(), D.size()); std::vector<std::pair<uintX_t, uintX_t>> &Offsets = this->Offsets; - uintX_t V = Config->GcSections ? -1 : 0; + uintX_t V = Config->GcSections ? MergeInputSection<ELFT>::PieceDead + : MergeInputSection<ELFT>::PieceLive; if (Header->sh_flags & SHF_STRINGS) { uintX_t Offset = 0; while (!Data.empty()) { @@ -478,15 +479,15 @@ typename ELFT::uint MergeInputSection<ELFT>::getOffset(uintX_t Offset) { // 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<MergeOutputSection<ELFT> *>(this->OutSec); + if (!MOS->shouldTailMerge()) return Base + Addend; // Map the base to the offset in the output section and cache it. ArrayRef<uint8_t> D = this->getSectionData(); StringRef Data((const char *)D.data(), D.size()); StringRef Entry = Data.substr(Start, End - Start); - Base = - static_cast<MergeOutputSection<ELFT> *>(this->OutSec)->getOffset(Entry); + Base = MOS->getOffset(Entry); return Base + Addend; } diff --git a/lld/ELF/InputSection.h b/lld/ELF/InputSection.h index 908375f1a63..ea8fd438cdf 100644 --- a/lld/ELF/InputSection.h +++ b/lld/ELF/InputSection.h @@ -144,9 +144,22 @@ public: typename InputSectionBase<ELFT>::Kind SectionKind); // For each piece of data, we maintain the offsets in the input section and - // in the output section. The latter may be -1 if it is not assigned yet. + // in the output section. std::vector<std::pair<uintX_t, uintX_t>> Offsets; + // Merge input sections may use the following special values as the output + // section offset: + enum { + // The piece is dead. + PieceDead = uintX_t(-1), + // The piece is live, and an offset has not yet been assigned. After offsets + // have been assigned, if the output section uses tail merging, the field + // will still have this value and the output section offset is available + // from MergeOutputSection<ELFT>::getOffset(). Otherwise, this value has no + // special significance, it just means that the offset is 0. + PieceLive = uintX_t(0), + }; + std::pair<std::pair<uintX_t, uintX_t> *, uintX_t> getRangeAndSize(uintX_t Offset); }; diff --git a/lld/ELF/MarkLive.cpp b/lld/ELF/MarkLive.cpp index 5b20ccca047..f8000007913 100644 --- a/lld/ELF/MarkLive.cpp +++ b/lld/ELF/MarkLive.cpp @@ -143,7 +143,7 @@ template <class ELFT> void elf::markLive() { if (auto *MS = dyn_cast<MergeInputSection<ELFT>>(R.Sec)) { std::pair<std::pair<uintX_t, uintX_t> *, uintX_t> T = MS->getRangeAndSize(R.Offset); - T.first->second = 0; + T.first->second = MergeInputSection<ELFT>::PieceLive; } if (R.Sec->Live) return; diff --git a/lld/ELF/OutputSections.cpp b/lld/ELF/OutputSections.cpp index 50108de6845..c3c9672e708 100644 --- a/lld/ELF/OutputSections.cpp +++ b/lld/ELF/OutputSections.cpp @@ -1271,7 +1271,7 @@ void MergeOutputSection<ELFT>::addSection(InputSectionBase<ELFT> *C) { if (this->Header.sh_flags & SHF_STRINGS) { for (unsigned I = 0, N = Offsets.size(); I != N; ++I) { auto &P = Offsets[I]; - if (P.second == (uintX_t)-1) + if (P.second == MergeInputSection<ELFT>::PieceDead) continue; uintX_t Start = P.first; @@ -1279,7 +1279,7 @@ void MergeOutputSection<ELFT>::addSection(InputSectionBase<ELFT> *C) { StringRef Entry = Data.substr(Start, End - Start); uintX_t OutputOffset = Builder.add(Entry); if (shouldTailMerge()) - OutputOffset = -1; + OutputOffset = MergeInputSection<ELFT>::PieceLive; P.second = OutputOffset; } return; diff --git a/lld/ELF/OutputSections.h b/lld/ELF/OutputSections.h index 1a305fbf1b0..d8c0e5b7484 100644 --- a/lld/ELF/OutputSections.h +++ b/lld/ELF/OutputSections.h @@ -310,8 +310,6 @@ template <class ELFT> class MergeOutputSection final : public OutputSectionBase<ELFT> { 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 @@ public: void writeTo(uint8_t *Buf) override; unsigned getOffset(StringRef Val); void finalize() override; + bool shouldTailMerge() const; private: llvm::StringTableBuilder Builder; diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index 63ed12a64e1..a590827c2e0 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -1118,9 +1118,16 @@ template <class ELFT> static bool includeInSymtab(const SymbolBody &B) { return false; if (auto *D = dyn_cast<DefinedRegular<ELFT>>(&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<MergeInputSection<ELFT>>(D->Section)) + if (S->getRangeAndSize(D->Value).first->second == + MergeInputSection<ELFT>::PieceDead) + return false; } return true; } diff --git a/lld/test/ELF/string-gc.s b/lld/test/ELF/string-gc.s new file mode 100644 index 00000000000..b6b1e868f5d --- /dev/null +++ b/lld/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" |