Index: ELF/InputSection.h =================================================================== --- ELF/InputSection.h +++ ELF/InputSection.h @@ -25,6 +25,7 @@ template class ICF; template class DefinedRegular; +template class DefinedCommon; template class ObjectFile; template class OutputSection; template class OutputSectionBase; @@ -256,6 +257,17 @@ const llvm::object::Elf_Mips_RegInfo *Reginfo = nullptr; }; +// A special kind of section used to store common symbols +template class CommonInputSection : public InputSection { + typedef typename ELFT::uint uintX_t; + +public: + CommonInputSection(); + +private: + typename ELFT::Shdr Hdr; +}; + } // namespace elf } // namespace lld Index: ELF/InputSection.cpp =================================================================== --- ELF/InputSection.cpp +++ ELF/InputSection.cpp @@ -14,6 +14,7 @@ #include "InputFiles.h" #include "LinkerScript.h" #include "OutputSections.h" +#include "SymbolTable.h" #include "Target.h" #include "Thunks.h" @@ -666,6 +667,44 @@ return S->SectionKind == InputSectionBase::MipsOptions; } +// Due to initialization order in C++ memberwise initialization or +// construction is invoked after base class construction. This helper +// function is needed to zero initialize Elf_Shdr, before passing it +// to InputSection constructor +template static T *zero(T *val) { + return static_cast(memset(val, 0, sizeof(*val))); +} + +template +CommonInputSection::CommonInputSection() + : InputSection(nullptr, zero(&Hdr)) { + + std::vector *> Symbols; + Hdr.sh_size = 0; + Hdr.sh_type = SHT_NOBITS; + Hdr.sh_flags = SHF_ALLOC | SHF_WRITE; + + for (Symbol *S : Symtab::X->getSymbols()) + if (auto *C = dyn_cast>(S->body())) + Symbols.push_back(C); + + std::stable_sort( + Symbols.begin(), Symbols.end(), + [](const DefinedCommon *A, const DefinedCommon *B) { + return A->Alignment > B->Alignment; + }); + + for (DefinedCommon *C : Symbols) { + this->Alignment = std::max(this->Alignment, C->Alignment); + Hdr.sh_size = alignTo(Hdr.sh_size, C->Alignment); + + // Compute symbol offset relative to beginning of input section. + C->Offset = Hdr.sh_size; + C->CS = this; + Hdr.sh_size += C->Size; + } +} + template class elf::InputSectionBase; template class elf::InputSectionBase; template class elf::InputSectionBase; @@ -695,3 +734,8 @@ template class elf::MipsOptionsInputSection; template class elf::MipsOptionsInputSection; template class elf::MipsOptionsInputSection; + +template class elf::CommonInputSection; +template class elf::CommonInputSection; +template class elf::CommonInputSection; +template class elf::CommonInputSection; Index: ELF/LinkerScript.h =================================================================== --- ELF/LinkerScript.h +++ ELF/LinkerScript.h @@ -23,6 +23,8 @@ template class InputSectionBase; template class OutputSectionBase; template class OutputSectionFactory; +template class DefinedCommon; +template class CommonInputSection; typedef std::function Expr; @@ -120,7 +122,8 @@ public: std::vector *> - createSections(OutputSectionFactory &Factory); + createSections(OutputSectionFactory &Factory, + CommonInputSection *Common); std::vector> createPhdrs(ArrayRef *> S); @@ -137,7 +140,7 @@ getSectionMap(); std::vector *> - getInputSections(const InputSectionDescription *); + getInputSections(const InputSectionDescription *, CommonInputSection *); // "ScriptConfig" is a bit too long, so define a short name for it. ScriptConfiguration &Opt = *ScriptConfig; Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -95,7 +95,8 @@ // Returns input sections filtered by given glob patterns. template std::vector *> -LinkerScript::getInputSections(const InputSectionDescription *I) { +LinkerScript::getInputSections(const InputSectionDescription *I, + CommonInputSection *Common) { ArrayRef Patterns = I->Patterns; ArrayRef ExcludedFiles = I->ExcludedFiles; std::vector *> Ret; @@ -106,12 +107,17 @@ if (ExcludedFiles.empty() || !match(ExcludedFiles, sys::path::filename(F->getName()))) Ret.push_back(S); + + if ((llvm::find(Patterns, "COMMON") != Patterns.end()) && Common->getSize()) + Ret.push_back(Common); + return Ret; } template std::vector *> -LinkerScript::createSections(OutputSectionFactory &Factory) { +LinkerScript::createSections(OutputSectionFactory &Factory, + CommonInputSection *Common) { std::vector *> Ret; // Add input section to output section. If there is no output section yet, @@ -128,7 +134,7 @@ for (auto &P : getSectionMap()) { StringRef OutputName = P.first; const InputSectionDescription *I = P.second; - for (InputSectionBase *S : getInputSections(I)) { + for (InputSectionBase *S : getInputSections(I, Common)) { if (OutputName == "/DISCARD/") { S->Live = false; reportDiscarded(S); Index: ELF/OutputSections.cpp =================================================================== --- ELF/OutputSections.cpp +++ ELF/OutputSections.cpp @@ -1448,7 +1448,7 @@ break; } case SymbolBody::DefinedCommonKind: - return Out::Bss; + return cast>(Sym)->CS->OutSec; case SymbolBody::SharedKind: if (cast>(Sym)->needsCopy()) return Out::Bss; Index: ELF/SymbolTable.cpp =================================================================== --- ELF/SymbolTable.cpp +++ ELF/SymbolTable.cpp @@ -322,13 +322,15 @@ // We have a new non-common defined symbol with the specified binding. Return 1 // if the new symbol should win, -1 if the new symbol should lose, or 0 if there // is a conflict. If the new symbol wins, also update the binding. -static int compareDefinedNonCommon(Symbol *S, bool WasInserted, uint8_t Binding) { +template +static int compareDefinedNonCommon(Symbol *S, bool WasInserted, + uint8_t Binding) { if (int Cmp = compareDefined(S, WasInserted, Binding)) { if (Cmp > 0) S->Binding = Binding; return Cmp; } - if (isa(S->body())) { + if (isa>(S->body())) { // Non-common symbols take precedence over common symbols. if (Config->WarnCommon) warning("common " + S->body()->getName() + " is overridden"); @@ -350,9 +352,10 @@ int Cmp = compareDefined(S, WasInserted, Binding); if (Cmp > 0) { S->Binding = Binding; - replaceBody(S, N, Size, Alignment, StOther, Type, File); + replaceBody>(S, N, Size, Alignment, StOther, Type, + File); } else if (Cmp == 0) { - auto *C = dyn_cast(S->body()); + auto *C = dyn_cast>(S->body()); if (!C) { // Non-common symbols take precedence over common symbols. if (Config->WarnCommon) @@ -388,7 +391,7 @@ insert(Name, Sym.getType(), Sym.getVisibility(), /*CanOmitFromDynSym*/ false, /*IsUsedInRegularObj*/ true, Section ? Section->getFile() : nullptr); - int Cmp = compareDefinedNonCommon(S, WasInserted, Sym.getBinding()); + int Cmp = compareDefinedNonCommon(S, WasInserted, Sym.getBinding()); if (Cmp > 0) replaceBody>(S, Name, Sym, Section); else if (Cmp == 0) @@ -404,7 +407,7 @@ std::tie(S, WasInserted) = insert(Name, STT_NOTYPE, StOther & 3, /*CanOmitFromDynSym*/ false, /*IsUsedInRegularObj*/ true, nullptr); - int Cmp = compareDefinedNonCommon(S, WasInserted, Binding); + int Cmp = compareDefinedNonCommon(S, WasInserted, Binding); if (Cmp > 0) replaceBody>(S, Name, StOther); else if (Cmp == 0) @@ -421,7 +424,7 @@ std::tie(S, WasInserted) = insert(N, STT_NOTYPE, STV_HIDDEN, /*CanOmitFromDynSym*/ false, /*IsUsedInRegularObj*/ true, nullptr); - int Cmp = compareDefinedNonCommon(S, WasInserted, STB_GLOBAL); + int Cmp = compareDefinedNonCommon(S, WasInserted, STB_GLOBAL); if (Cmp > 0) replaceBody>(S, N, Value, Section); else if (Cmp == 0) @@ -459,8 +462,8 @@ bool WasInserted; std::tie(S, WasInserted) = insert(Name, Type, StOther & 3, CanOmitFromDynSym, /*IsUsedInRegularObj*/ false, F); - int Cmp = - compareDefinedNonCommon(S, WasInserted, IsWeak ? STB_WEAK : STB_GLOBAL); + int Cmp = compareDefinedNonCommon(S, WasInserted, + IsWeak ? STB_WEAK : STB_GLOBAL); if (Cmp > 0) replaceBody(S, Name, StOther, Type, F); else if (Cmp == 0) Index: ELF/Symbols.h =================================================================== --- ELF/Symbols.h +++ ELF/Symbols.h @@ -167,7 +167,7 @@ BitcodeFile *file() { return (BitcodeFile *)this->File; } }; -class DefinedCommon : public Defined { +template class DefinedCommon : public Defined { public: DefinedCommon(StringRef N, uint64_t Size, uint64_t Alignment, uint8_t StOther, uint8_t Type, InputFile *File); @@ -178,12 +178,15 @@ // The output offset of this common symbol in the output bss. Computed by the // writer. - uint64_t OffsetInBss; + uint64_t Offset; // The maximum alignment we have seen for this symbol. uint64_t Alignment; uint64_t Size; + + // Virtual input section for common symbols. + CommonInputSection *CS; }; // Regular defined symbols read from object file symbol tables. @@ -433,7 +436,8 @@ // assume that the size and alignment of ELF64LE symbols is sufficient for any // ELFT, and we verify this with the static_asserts in replaceBody. llvm::AlignedCharArrayUnion< - DefinedBitcode, DefinedCommon, DefinedRegular, + DefinedBitcode, DefinedCommon, + DefinedRegular, DefinedSynthetic, Undefined, SharedSymbol, LazyArchive, LazyObject> Body; Index: ELF/Symbols.cpp =================================================================== --- ELF/Symbols.cpp +++ ELF/Symbols.cpp @@ -63,8 +63,10 @@ return VA - Out::TlsPhdr->p_vaddr; return VA; } - case SymbolBody::DefinedCommonKind: - return Out::Bss->getVA() + cast(Body).OffsetInBss; + case SymbolBody::DefinedCommonKind: { + auto &D = cast>(Body); + return D.CS->OutSec->getVA() + D.CS->OutSecOff + D.Offset; + } case SymbolBody::SharedKind: { auto &SS = cast>(Body); if (!SS.NeedsCopyOrPltAddr) @@ -175,7 +177,7 @@ } template typename ELFT::uint SymbolBody::getSize() const { - if (const auto *C = dyn_cast(this)) + if (const auto *C = dyn_cast>(this)) return C->Size; if (const auto *DR = dyn_cast>(this)) return DR->Size; @@ -218,8 +220,10 @@ : Defined(SymbolBody::DefinedSyntheticKind, N, STV_HIDDEN, 0 /* Type */), Value(Value), Section(Section) {} -DefinedCommon::DefinedCommon(StringRef N, uint64_t Size, uint64_t Alignment, - uint8_t StOther, uint8_t Type, InputFile *File) +template +DefinedCommon::DefinedCommon(StringRef N, uint64_t Size, + uint64_t Alignment, uint8_t StOther, + uint8_t Type, InputFile *File) : Defined(SymbolBody::DefinedCommonKind, N, StOther, Type), Alignment(Alignment), Size(Size) { this->File = File; @@ -329,3 +333,8 @@ template class elf::DefinedSynthetic; template class elf::DefinedSynthetic; template class elf::DefinedSynthetic; + +template class elf::DefinedCommon; +template class elf::DefinedCommon; +template class elf::DefinedCommon; +template class elf::DefinedCommon; Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -68,12 +68,11 @@ void writeSections(); void writeBuildId(); - void addCommonSymbols(std::vector &Syms); - std::unique_ptr Buffer; BumpPtrAllocator Alloc; std::vector *> OutputSections; + std::unique_ptr> CommonSection; OutputSectionFactory Factory; void addRelIpltSymbols(); @@ -223,9 +222,11 @@ copyLocalSymbols(); addReservedSymbols(); - OutputSections = ScriptConfig->DoLayout - ? Script::X->createSections(Factory) - : createSections(); + CommonSection = llvm::make_unique>(); + OutputSections = + ScriptConfig->DoLayout + ? Script::X->createSections(Factory, CommonSection.get()) + : createSections(); finalizeSections(); if (HasError) return; @@ -490,30 +491,6 @@ H.p_align = std::max(H.p_align, Sec->getAlignment()); } -// Until this function is called, common symbols do not belong to any section. -// This function adds them to end of BSS section. -template -void Writer::addCommonSymbols(std::vector &Syms) { - if (Syms.empty()) - return; - - // Sort the common symbols by alignment as an heuristic to pack them better. - std::stable_sort(Syms.begin(), Syms.end(), - [](const DefinedCommon *A, const DefinedCommon *B) { - return A->Alignment > B->Alignment; - }); - - uintX_t Off = Out::Bss->getSize(); - for (DefinedCommon *C : Syms) { - Off = alignTo(Off, C->Alignment); - Out::Bss->updateAlignment(C->Alignment); - C->OffsetInBss = Off; - Off += C->Size; - } - - Out::Bss->setSize(Off); -} - template static Symbol *addOptionalSynthetic(SymbolTable &Table, StringRef Name, OutputSectionBase *Sec, @@ -734,7 +711,6 @@ // Now that we have defined all possible symbols including linker- // synthesized ones. Visit all symbols to give the finishing touches. - std::vector CommonSymbols; for (Symbol *S : Symtab.getSymbols()) { SymbolBody *Body = S->body(); @@ -743,9 +719,6 @@ if (S->IsUsedInRegularObj && Body->isUndefined() && !S->isWeak()) reportUndefined(Symtab, Body); - if (auto *C = dyn_cast(Body)) - CommonSymbols.push_back(C); - if (!includeInSymtab(*Body)) continue; if (Out::SymTab) @@ -763,7 +736,12 @@ if (HasError) return; - addCommonSymbols(CommonSymbols); + // If linker script processor hasn't added common symbol section yet, + // then add it to .bss now. + if (!CommonSection->OutSec && CommonSection->getSize()) { + Out::Bss->addSection(CommonSection.get()); + Out::Bss->assignOffsets(); + } // So far we have added sections from input object files. // This function adds linker-created Out::* sections. Index: test/ELF/linkerscript/linkerscript-common.s =================================================================== --- test/ELF/linkerscript/linkerscript-common.s +++ test/ELF/linkerscript/linkerscript-common.s @@ -0,0 +1,49 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t +# RUN: echo "SECTIONS { .common : { *(COMMON) } }" > %t.script +# RUN: ld.lld -o %t1 --script %t.script %t +# RUN: llvm-readobj -s -t %t1 | FileCheck %s + +# q2 alignment is greater than q1, so it should have smaller offset +# because of sorting +# CHECK: Section { +# CHECK: Index: 1 +# CHECK-NEXT: Name: .common (1) +# CHECK-NEXT: Type: SHT_NOBITS (0x8) +# CHECK-NEXT: Flags [ (0x3) +# CHECK-NEXT: SHF_ALLOC (0x2) +# CHECK-NEXT: SHF_WRITE (0x1) +# CHECK-NEXT: ] +# CHECK-NEXT: Address: 0x200 +# CHECK-NEXT: Offset: 0x158 +# CHECK-NEXT: Size: 256 +# CHECK-NEXT: Link: 0 +# CHECK-NEXT: Info: 0 +# CHECK-NEXT: AddressAlignment: 256 +# CHECK-NEXT: EntrySize: 0 +# CHECK-NEXT: } +# CHECK: Symbol { +# CHECK: Name: q1 (8) +# CHECK-NEXT: Value: 0x280 +# CHECK-NEXT: Size: 128 +# CHECK-NEXT: Binding: Global (0x1) +# CHECK-NEXT: Type: Object (0x1) +# CHECK-NEXT: Other: 0 +# CHECK-NEXT: Section: .common (0x1) +# CHECK-NEXT: } +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Name: q2 (11) +# CHECK-NEXT: Value: 0x200 +# CHECK-NEXT: Size: 128 +# CHECK-NEXT: Binding: Global (0x1) +# CHECK-NEXT: Type: Object (0x1) +# CHECK-NEXT: Other: 0 +# CHECK-NEXT: Section: .common (0x1) +# CHECK-NEXT: } + +.globl _start +_start: + jmp _start + +.comm q1,128,8 +.comm q2,128,256