Index: ELF/MarkLive.cpp =================================================================== --- ELF/MarkLive.cpp +++ ELF/MarkLive.cpp @@ -48,6 +48,7 @@ struct ResolvedReloc { InputSectionBase *Sec; uint64_t Offset; + SymbolBody *Symbol; }; } // end anonymous namespace @@ -78,10 +79,14 @@ typename ELFT::uint Offset = D->Value; if (D->isSection()) Offset += getAddend(Sec, Rel); - Fn({cast(D->Section), Offset}); + Fn({cast(D->Section), Offset, nullptr}); } else if (auto *U = dyn_cast(&B)) { for (InputSectionBase *Sec : CNamedSections.lookup(U->getName())) - Fn({Sec, 0}); + Fn({Sec, 0, nullptr}); + } else if (auto *C = dyn_cast(&B)) { + // We create synthetic sections later, so InX::Common is null here, + // fortunately we do not need it. + Fn({nullptr, 0, &B}); } } @@ -142,7 +147,7 @@ return; if (R.Sec->Flags & SHF_EXECINSTR) return; - Enqueue({R.Sec, 0}); + Enqueue({R.Sec, 0, nullptr}); }); } } @@ -200,6 +205,14 @@ if (R.Sec == &InputSection::Discarded) return; + // Handle common symbols. We put zero as offset to + // drop 'symbol unused' flag mark set earlier. We will + // check it in createCommonSection() later. + if (!R.Sec) { + cast(R.Symbol)->Offset = 0; + return; + } + // We don't gc non alloc sections. if (!(R.Sec->Flags & SHF_ALLOC)) return; @@ -218,10 +231,13 @@ 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}); + Enqueue({IS, D->Value, nullptr}); + } else if (auto *C = dyn_cast_or_null(Sym)) { + Enqueue({nullptr, 0, Sym}); + } }; // Add GC root symbols. @@ -235,7 +251,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()); @@ -250,7 +266,7 @@ if (Sec->Flags & SHF_LINK_ORDER) continue; if (isReserved(Sec) || Script->shouldKeep(Sec)) - Enqueue({Sec, 0}); + Enqueue({Sec, 0, nullptr}); else if (isValidCIdentifier(Sec->Name)) { CNamedSections[Saver.save("__start_" + Sec->Name)].push_back(Sec); CNamedSections[Saver.save("__stop_" + Sec->Name)].push_back(Sec); Index: ELF/Symbols.cpp =================================================================== --- ELF/Symbols.cpp +++ ELF/Symbols.cpp @@ -307,7 +307,8 @@ uint8_t StOther, uint8_t Type) : Defined(SymbolBody::DefinedCommonKind, Name, /*IsLocal=*/false, StOther, Type), - Alignment(Alignment), Size(Size) {} + Alignment(Alignment), Size(Size), Offset(Config->GcSections ? -1ULL : 0) { +} // If a shared symbol is referred via a copy relocation, its alignment // becomes part of the ABI. This function returns a symbol alignment. Index: ELF/SyntheticSections.cpp =================================================================== --- ELF/SyntheticSections.cpp +++ ELF/SyntheticSections.cpp @@ -77,9 +77,11 @@ return A->Alignment > B->Alignment; }); + // Allocate space for used common symbols. BssSection *Sec = make("COMMON"); for (DefinedCommon *Sym : Syms) - Sym->Offset = Sec->reserveSpace(Sym->Size, Sym->Alignment); + if (Sym->Offset != -1ULL) + Sym->Offset = Sec->reserveSpace(Sym->Size, Sym->Alignment); return Sec; } Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -451,6 +451,8 @@ if (auto *S = dyn_cast(Sec)) if (!S->getSectionPiece(D->Value)->Live) return false; + } else if (auto *D = dyn_cast(&B)) { + return D->Offset != -1ULL; } return true; } Index: test/ELF/common-gc.s =================================================================== --- test/ELF/common-gc.s +++ test/ELF/common-gc.s @@ -0,0 +1,53 @@ +# 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: Section { +# NOGC: Index: +# NOGC: Name: .bss +# NOGC-NEXT: Type: SHT_NOBITS +# NOGC-NEXT: Flags [ +# NOGC-NEXT: SHF_ALLOC +# NOGC-NEXT: SHF_WRITE +# NOGC-NEXT: ] +# NOGC-NEXT: Address: +# NOGC-NEXT: Offset: +# NOGC-NEXT: Size: 8 +# NOGC-NEXT: Link: +# NOGC-NEXT: Info: +# NOGC-NEXT: AddressAlignment: +# NOGC-NEXT: EntrySize: +# NOGC-NEXT: } +# NOGC: Symbols [ +# 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: Section { +# GC: Index: +# GC: Name: .bss +# GC-NEXT: Type: SHT_NOBITS +# GC-NEXT: Flags [ +# GC-NEXT: SHF_ALLOC +# GC-NEXT: SHF_WRITE +# GC-NEXT: ] +# GC-NEXT: Address: +# GC-NEXT: Offset: +# GC-NEXT: Size: 4 +# GC-NEXT: Link: +# GC-NEXT: Info: +# GC-NEXT: AddressAlignment: +# GC-NEXT: EntrySize: +# GC-NEXT: } +# GC: Symbols [ +# GC-NOT: Name: bar + +.comm foo,4,4 +.comm bar,4,4 + +.text +.globl _start +_start: + .quad foo Index: test/ELF/common-gc2.s =================================================================== --- test/ELF/common-gc2.s +++ 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 Index: test/ELF/linkerscript/commons-gc.s =================================================================== --- test/ELF/linkerscript/commons-gc.s +++ test/ELF/linkerscript/commons-gc.s @@ -0,0 +1,11 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t +# RUN: echo "SECTIONS { . = SIZEOF_HEADERS; foo = 1; }" > %t.script +# RUN: ld.lld %t --gc-sections --script %t.script -o %t1 +# RUN: llvm-readobj -symbols %t1 | FileCheck %s + +# CHECK: foo +# CHECK-NOT: bar + +.comm foo,4,4 +.comm bar,4,4