Index: lld/trunk/ELF/MarkLive.cpp =================================================================== --- lld/trunk/ELF/MarkLive.cpp +++ lld/trunk/ELF/MarkLive.cpp @@ -72,6 +72,12 @@ static void resolveReloc(InputSectionBase &Sec, RelT &Rel, std::function Fn) { SymbolBody &B = Sec.getFile()->getRelocTargetSym(Rel); + + if (auto *Sym = dyn_cast(&B)) { + Sym->Live = true; + return; + } + if (auto *D = dyn_cast(&B)) { if (!D->Section) return; @@ -79,10 +85,12 @@ if (D->isSection()) Offset += getAddend(Sec, Rel); Fn({cast(D->Section), Offset}); - } else if (auto *U = dyn_cast(&B)) { + return; + } + + if (auto *U = dyn_cast(&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 @@ Q.push_back(S); }; - auto MarkSymbol = [&](const SymbolBody *Sym) { - if (auto *D = dyn_cast_or_null(Sym)) + auto MarkSymbol = [&](SymbolBody *Sym) { + if (auto *D = dyn_cast_or_null(Sym)) { if (auto *IS = cast_or_null(D->Section)) Enqueue({IS, D->Value}); + return; + } + if (auto *S = dyn_cast_or_null(Sym)) + S->Live = true; }; // Add GC root symbols. @@ -235,7 +247,7 @@ // 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()); Index: lld/trunk/ELF/Symbols.h =================================================================== --- lld/trunk/ELF/Symbols.h +++ lld/trunk/ELF/Symbols.h @@ -161,13 +161,17 @@ 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; }; Index: lld/trunk/ELF/Symbols.cpp =================================================================== --- lld/trunk/ELF/Symbols.cpp +++ lld/trunk/ELF/Symbols.cpp @@ -273,7 +273,7 @@ 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. Index: lld/trunk/ELF/SyntheticSections.cpp =================================================================== --- lld/trunk/ELF/SyntheticSections.cpp +++ lld/trunk/ELF/SyntheticSections.cpp @@ -77,9 +77,11 @@ return A->Alignment > B->Alignment; }); + // Allocate space for common symbols. BssSection *Sec = make("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; } Index: lld/trunk/ELF/Writer.cpp =================================================================== --- lld/trunk/ELF/Writer.cpp +++ lld/trunk/ELF/Writer.cpp @@ -451,7 +451,11 @@ if (auto *S = dyn_cast(Sec)) if (!S->getSectionPiece(D->Value)->Live) return false; + return true; } + + if (auto *Sym = dyn_cast(&B)) + return Sym->Live; return true; } Index: lld/trunk/test/ELF/common-gc.s =================================================================== --- lld/trunk/test/ELF/common-gc.s +++ lld/trunk/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 Index: lld/trunk/test/ELF/common-gc2.s =================================================================== --- lld/trunk/test/ELF/common-gc2.s +++ lld/trunk/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