diff options
-rw-r--r-- | lld/ELF/MarkLive.cpp | 22 | ||||
-rw-r--r-- | lld/ELF/Symbols.cpp | 2 | ||||
-rw-r--r-- | lld/ELF/Symbols.h | 10 | ||||
-rw-r--r-- | lld/ELF/SyntheticSections.cpp | 4 | ||||
-rw-r--r-- | lld/ELF/Writer.cpp | 4 | ||||
-rw-r--r-- | lld/test/ELF/common-gc.s | 41 | ||||
-rw-r--r-- | lld/test/ELF/common-gc2.s | 15 |
7 files changed, 88 insertions, 10 deletions
diff --git a/lld/ELF/MarkLive.cpp b/lld/ELF/MarkLive.cpp index fe1c217981b..38dda922553 100644 --- a/lld/ELF/MarkLive.cpp +++ b/lld/ELF/MarkLive.cpp @@ -72,6 +72,12 @@ template <class ELFT, class RelT> static void resolveReloc(InputSectionBase &Sec, RelT &Rel, std::function<void(ResolvedReloc)> Fn) { SymbolBody &B = Sec.getFile<ELFT>()->getRelocTargetSym(Rel); + + if (auto *Sym = dyn_cast<DefinedCommon>(&B)) { + Sym->Live = true; + return; + } + if (auto *D = dyn_cast<DefinedRegular>(&B)) { if (!D->Section) return; @@ -79,10 +85,12 @@ static void resolveReloc(InputSectionBase &Sec, RelT &Rel, if (D->isSection()) Offset += getAddend<ELFT>(Sec, Rel); Fn({cast<InputSectionBase>(D->Section), Offset}); - } else if (auto *U = dyn_cast<Undefined>(&B)) { + return; + } + + if (auto *U = dyn_cast<Undefined>(&B)) for (InputSectionBase *Sec : CNamedSections.lookup(U->getName())) Fn({Sec, 0}); - } } // Calls Fn for each section that Sec refers to via relocations. @@ -218,10 +226,14 @@ template <class ELFT> void elf::markLive() { Q.push_back(S); }; - auto MarkSymbol = [&](const SymbolBody *Sym) { - if (auto *D = dyn_cast_or_null<DefinedRegular>(Sym)) + auto MarkSymbol = [&](SymbolBody *Sym) { + if (auto *D = dyn_cast_or_null<DefinedRegular>(Sym)) { if (auto *IS = cast_or_null<InputSectionBase>(D->Section)) Enqueue({IS, D->Value}); + return; + } + if (auto *S = dyn_cast_or_null<DefinedCommon>(Sym)) + S->Live = true; }; // Add GC root symbols. @@ -235,7 +247,7 @@ template <class ELFT> void elf::markLive() { // Preserve externally-visible symbols if the symbols defined by this // file can interrupt other ELF file's symbols at runtime. - for (const Symbol *S : Symtab->getSymbols()) + for (Symbol *S : Symtab->getSymbols()) if (S->includeInDynsym()) MarkSymbol(S->body()); diff --git a/lld/ELF/Symbols.cpp b/lld/ELF/Symbols.cpp index 5f1e69b2601..86f29b05d26 100644 --- a/lld/ELF/Symbols.cpp +++ b/lld/ELF/Symbols.cpp @@ -273,7 +273,7 @@ DefinedCommon::DefinedCommon(StringRef Name, uint64_t Size, uint32_t Alignment, uint8_t StOther, uint8_t Type) : Defined(SymbolBody::DefinedCommonKind, Name, /*IsLocal=*/false, StOther, Type), - Alignment(Alignment), Size(Size) {} + Live(!Config->GcSections), Alignment(Alignment), Size(Size) {} // If a shared symbol is referred via a copy relocation, its alignment // becomes part of the ABI. This function returns a symbol alignment. diff --git a/lld/ELF/Symbols.h b/lld/ELF/Symbols.h index 02855c5ff9f..910981f89ff 100644 --- a/lld/ELF/Symbols.h +++ b/lld/ELF/Symbols.h @@ -161,13 +161,17 @@ public: return S->kind() == SymbolBody::DefinedCommonKind; } - // The output offset of this common symbol in the output bss. Computed by the - // writer. - uint64_t Offset; + // True if this symbol is not GC'ed. Liveness is usually a notion of + // input sections and not of symbols, but since common symbols don't + // belong to any input section, their liveness is managed by this bit. + bool Live; // The maximum alignment we have seen for this symbol. uint32_t Alignment; + // The output offset of this common symbol in the output bss. + // Computed by the writer. + uint64_t Offset; uint64_t Size; }; diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp index cc50f39f55a..0337292f771 100644 --- a/lld/ELF/SyntheticSections.cpp +++ b/lld/ELF/SyntheticSections.cpp @@ -77,9 +77,11 @@ template <class ELFT> InputSection *elf::createCommonSection() { return A->Alignment > B->Alignment; }); + // Allocate space for common symbols. BssSection *Sec = make<BssSection>("COMMON"); for (DefinedCommon *Sym : Syms) - Sym->Offset = Sec->reserveSpace(Sym->Size, Sym->Alignment); + if (Sym->Live) + Sym->Offset = Sec->reserveSpace(Sym->Size, Sym->Alignment); return Sec; } diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index 83d5739ff0e..98a4176aaf7 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -451,7 +451,11 @@ static bool includeInSymtab(const SymbolBody &B) { if (auto *S = dyn_cast<MergeInputSection>(Sec)) if (!S->getSectionPiece(D->Value)->Live) return false; + return true; } + + if (auto *Sym = dyn_cast<DefinedCommon>(&B)) + return Sym->Live; return true; } diff --git a/lld/test/ELF/common-gc.s b/lld/test/ELF/common-gc.s new file mode 100644 index 00000000000..99fde9ea3c3 --- /dev/null +++ b/lld/test/ELF/common-gc.s @@ -0,0 +1,41 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t + +# RUN: ld.lld %t -o %t2 +# RUN: llvm-readobj -sections -symbols %t2 | FileCheck %s --check-prefix=NOGC + +# NOGC: Name: .bss +# NOGC-NEXT: Type: +# NOGC-NEXT: Flags [ +# NOGC-NEXT: SHF_ALLOC +# NOGC-NEXT: SHF_WRITE +# NOGC-NEXT: ] +# NOGC-NEXT: Address: +# NOGC-NEXT: Offset: +# NOGC-NEXT: Size: 8 + +# NOGC: Name: bar +# NOGC: Name: foo + +# RUN: ld.lld -gc-sections %t -o %t1 +# RUN: llvm-readobj -sections -symbols %t1 | FileCheck %s --check-prefix=GC + +# GC: Name: .bss +# GC-NEXT: Type: +# GC-NEXT: Flags [ +# GC-NEXT: SHF_ALLOC +# GC-NEXT: SHF_WRITE +# GC-NEXT: ] +# GC-NEXT: Address: +# GC-NEXT: Offset: +# GC-NEXT: Size: 4 + +# GC-NOT: Name: bar + +.comm foo,4,4 +.comm bar,4,4 + +.text +.globl _start +_start: + .quad foo diff --git a/lld/test/ELF/common-gc2.s b/lld/test/ELF/common-gc2.s new file mode 100644 index 00000000000..165bf625394 --- /dev/null +++ b/lld/test/ELF/common-gc2.s @@ -0,0 +1,15 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t +# RUN: ld.lld -gc-sections -export-dynamic %t -o %t1 +# RUN: llvm-readobj --dyn-symbols %t1 | FileCheck %s + +# CHECK: Name: bar@ +# CHECK: Name: foo@ + +.comm foo,4,4 +.comm bar,4,4 + +.text +.globl _start +_start: + .quad foo |