diff options
-rw-r--r-- | lld/ELF/InputSection.cpp | 44 | ||||
-rw-r--r-- | lld/ELF/InputSection.h | 12 | ||||
-rw-r--r-- | lld/ELF/LinkerScript.cpp | 12 | ||||
-rw-r--r-- | lld/ELF/LinkerScript.h | 7 | ||||
-rw-r--r-- | lld/ELF/OutputSections.cpp | 2 | ||||
-rw-r--r-- | lld/ELF/SymbolTable.cpp | 21 | ||||
-rw-r--r-- | lld/ELF/Symbols.cpp | 19 | ||||
-rw-r--r-- | lld/ELF/Symbols.h | 10 | ||||
-rw-r--r-- | lld/ELF/Writer.cpp | 46 | ||||
-rw-r--r-- | lld/test/ELF/linkerscript/linkerscript-common.s | 49 |
10 files changed, 165 insertions, 57 deletions
diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp index 7ac25bca43c..2529cbd1c8b 100644 --- a/lld/ELF/InputSection.cpp +++ b/lld/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 @@ bool MipsOptionsInputSection<ELFT>::classof(const InputSectionBase<ELFT> *S) { return S->SectionKind == InputSectionBase<ELFT>::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<ELFT> constructor +template <class T> static T *zero(T *Val) { + return static_cast<T *>(memset(Val, 0, sizeof(*Val))); +} + +template <class ELFT> +CommonInputSection<ELFT>::CommonInputSection() + : InputSection<ELFT>(nullptr, zero(&Hdr)) { + std::vector<DefinedCommon<ELFT> *> Symbols; + Hdr.sh_size = 0; + Hdr.sh_type = SHT_NOBITS; + Hdr.sh_flags = SHF_ALLOC | SHF_WRITE; + this->Live = true; + + for (Symbol *S : Symtab<ELFT>::X->getSymbols()) + if (auto *C = dyn_cast<DefinedCommon<ELFT>>(S->body())) + Symbols.push_back(C); + + std::stable_sort( + Symbols.begin(), Symbols.end(), + [](const DefinedCommon<ELFT> *A, const DefinedCommon<ELFT> *B) { + return A->Alignment > B->Alignment; + }); + + for (DefinedCommon<ELFT> *C : Symbols) { + this->Alignment = std::max<uintX_t>(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->Section = this; + Hdr.sh_size += C->Size; + } +} + template class elf::InputSectionBase<ELF32LE>; template class elf::InputSectionBase<ELF32BE>; template class elf::InputSectionBase<ELF64LE>; @@ -695,3 +734,8 @@ template class elf::MipsOptionsInputSection<ELF32LE>; template class elf::MipsOptionsInputSection<ELF32BE>; template class elf::MipsOptionsInputSection<ELF64LE>; template class elf::MipsOptionsInputSection<ELF64BE>; + +template class elf::CommonInputSection<ELF32LE>; +template class elf::CommonInputSection<ELF32BE>; +template class elf::CommonInputSection<ELF64LE>; +template class elf::CommonInputSection<ELF64BE>; diff --git a/lld/ELF/InputSection.h b/lld/ELF/InputSection.h index d4d2d2517a1..76889501c37 100644 --- a/lld/ELF/InputSection.h +++ b/lld/ELF/InputSection.h @@ -25,6 +25,7 @@ class SymbolBody; template <class ELFT> class ICF; template <class ELFT> class DefinedRegular; +template <class ELFT> class DefinedCommon; template <class ELFT> class ObjectFile; template <class ELFT> class OutputSection; template <class ELFT> class OutputSectionBase; @@ -256,6 +257,17 @@ public: const llvm::object::Elf_Mips_RegInfo<ELFT> *Reginfo = nullptr; }; +// A special kind of section used to store common symbols +template <class ELFT> class CommonInputSection : public InputSection<ELFT> { + typedef typename ELFT::uint uintX_t; + +public: + CommonInputSection(); + +private: + typename ELFT::Shdr Hdr; +}; + } // namespace elf } // namespace lld diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp index 395f1268d58..36c8689692d 100644 --- a/lld/ELF/LinkerScript.cpp +++ b/lld/ELF/LinkerScript.cpp @@ -95,7 +95,8 @@ LinkerScript<ELFT>::getSectionMap() { // Returns input sections filtered by given glob patterns. template <class ELFT> std::vector<InputSectionBase<ELFT> *> -LinkerScript<ELFT>::getInputSections(const InputSectionDescription *I) { +LinkerScript<ELFT>::getInputSections(const InputSectionDescription *I, + CommonInputSection<ELFT> *Common) { ArrayRef<StringRef> Patterns = I->Patterns; ArrayRef<StringRef> ExcludedFiles = I->ExcludedFiles; std::vector<InputSectionBase<ELFT> *> Ret; @@ -106,12 +107,17 @@ LinkerScript<ELFT>::getInputSections(const InputSectionDescription *I) { if (ExcludedFiles.empty() || !match(ExcludedFiles, sys::path::filename(F->getName()))) Ret.push_back(S); + + if ((llvm::find(Patterns, "COMMON") != Patterns.end())) + Ret.push_back(Common); + return Ret; } template <class ELFT> std::vector<OutputSectionBase<ELFT> *> -LinkerScript<ELFT>::createSections(OutputSectionFactory<ELFT> &Factory) { +LinkerScript<ELFT>::createSections(OutputSectionFactory<ELFT> &Factory, + CommonInputSection<ELFT> *Common) { std::vector<OutputSectionBase<ELFT> *> Ret; // Add input section to output section. If there is no output section yet, @@ -128,7 +134,7 @@ LinkerScript<ELFT>::createSections(OutputSectionFactory<ELFT> &Factory) { for (auto &P : getSectionMap()) { StringRef OutputName = P.first; const InputSectionDescription *I = P.second; - for (InputSectionBase<ELFT> *S : getInputSections(I)) { + for (InputSectionBase<ELFT> *S : getInputSections(I, Common)) { if (OutputName == "/DISCARD/") { S->Live = false; reportDiscarded(S); diff --git a/lld/ELF/LinkerScript.h b/lld/ELF/LinkerScript.h index db9559bd0de..64f68561155 100644 --- a/lld/ELF/LinkerScript.h +++ b/lld/ELF/LinkerScript.h @@ -23,6 +23,8 @@ namespace elf { template <class ELFT> class InputSectionBase; template <class ELFT> class OutputSectionBase; template <class ELFT> class OutputSectionFactory; +template <class ELFT> class DefinedCommon; +template <class ELFT> class CommonInputSection; typedef std::function<uint64_t(uint64_t)> Expr; @@ -120,7 +122,8 @@ template <class ELFT> class LinkerScript { public: std::vector<OutputSectionBase<ELFT> *> - createSections(OutputSectionFactory<ELFT> &Factory); + createSections(OutputSectionFactory<ELFT> &Factory, + CommonInputSection<ELFT> *Common); std::vector<PhdrEntry<ELFT>> createPhdrs(ArrayRef<OutputSectionBase<ELFT> *> S); @@ -137,7 +140,7 @@ private: getSectionMap(); std::vector<InputSectionBase<ELFT> *> - getInputSections(const InputSectionDescription *); + getInputSections(const InputSectionDescription *, CommonInputSection<ELFT> *); // "ScriptConfig" is a bit too long, so define a short name for it. ScriptConfiguration &Opt = *ScriptConfig; diff --git a/lld/ELF/OutputSections.cpp b/lld/ELF/OutputSections.cpp index b06b1b5d176..2b409ff4fc2 100644 --- a/lld/ELF/OutputSections.cpp +++ b/lld/ELF/OutputSections.cpp @@ -1448,7 +1448,7 @@ SymbolTableSection<ELFT>::getOutputSection(SymbolBody *Sym) { break; } case SymbolBody::DefinedCommonKind: - return Out<ELFT>::Bss; + return cast<DefinedCommon<ELFT>>(Sym)->Section->OutSec; case SymbolBody::SharedKind: if (cast<SharedSymbol<ELFT>>(Sym)->needsCopy()) return Out<ELFT>::Bss; diff --git a/lld/ELF/SymbolTable.cpp b/lld/ELF/SymbolTable.cpp index 65b58bd800b..b4f9411ac49 100644 --- a/lld/ELF/SymbolTable.cpp +++ b/lld/ELF/SymbolTable.cpp @@ -322,13 +322,15 @@ static int compareDefined(Symbol *S, bool WasInserted, uint8_t Binding) { // 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 <class ELFT> +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<DefinedCommon>(S->body())) { + if (isa<DefinedCommon<ELFT>>(S->body())) { // Non-common symbols take precedence over common symbols. if (Config->WarnCommon) warning("common " + S->body()->getName() + " is overridden"); @@ -350,9 +352,10 @@ Symbol *SymbolTable<ELFT>::addCommon(StringRef N, uint64_t Size, int Cmp = compareDefined(S, WasInserted, Binding); if (Cmp > 0) { S->Binding = Binding; - replaceBody<DefinedCommon>(S, N, Size, Alignment, StOther, Type, File); + replaceBody<DefinedCommon<ELFT>>(S, N, Size, Alignment, StOther, Type, + File); } else if (Cmp == 0) { - auto *C = dyn_cast<DefinedCommon>(S->body()); + auto *C = dyn_cast<DefinedCommon<ELFT>>(S->body()); if (!C) { // Non-common symbols take precedence over common symbols. if (Config->WarnCommon) @@ -388,7 +391,7 @@ Symbol *SymbolTable<ELFT>::addRegular(StringRef Name, const Elf_Sym &Sym, insert(Name, Sym.getType(), Sym.getVisibility(), /*CanOmitFromDynSym*/ false, /*IsUsedInRegularObj*/ true, Section ? Section->getFile() : nullptr); - int Cmp = compareDefinedNonCommon(S, WasInserted, Sym.getBinding()); + int Cmp = compareDefinedNonCommon<ELFT>(S, WasInserted, Sym.getBinding()); if (Cmp > 0) replaceBody<DefinedRegular<ELFT>>(S, Name, Sym, Section); else if (Cmp == 0) @@ -404,7 +407,7 @@ Symbol *SymbolTable<ELFT>::addRegular(StringRef Name, uint8_t Binding, std::tie(S, WasInserted) = insert(Name, STT_NOTYPE, StOther & 3, /*CanOmitFromDynSym*/ false, /*IsUsedInRegularObj*/ true, nullptr); - int Cmp = compareDefinedNonCommon(S, WasInserted, Binding); + int Cmp = compareDefinedNonCommon<ELFT>(S, WasInserted, Binding); if (Cmp > 0) replaceBody<DefinedRegular<ELFT>>(S, Name, StOther); else if (Cmp == 0) @@ -421,7 +424,7 @@ Symbol *SymbolTable<ELFT>::addSynthetic(StringRef N, 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<ELFT>(S, WasInserted, STB_GLOBAL); if (Cmp > 0) replaceBody<DefinedSynthetic<ELFT>>(S, N, Value, Section); else if (Cmp == 0) @@ -459,8 +462,8 @@ Symbol *SymbolTable<ELFT>::addBitcode(StringRef Name, bool IsWeak, 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<ELFT>(S, WasInserted, + IsWeak ? STB_WEAK : STB_GLOBAL); if (Cmp > 0) replaceBody<DefinedBitcode>(S, Name, StOther, Type, F); else if (Cmp == 0) diff --git a/lld/ELF/Symbols.cpp b/lld/ELF/Symbols.cpp index 0a4805c7be4..6d7e7978c71 100644 --- a/lld/ELF/Symbols.cpp +++ b/lld/ELF/Symbols.cpp @@ -63,8 +63,10 @@ static typename ELFT::uint getSymVA(const SymbolBody &Body, return VA - Out<ELFT>::TlsPhdr->p_vaddr; return VA; } - case SymbolBody::DefinedCommonKind: - return Out<ELFT>::Bss->getVA() + cast<DefinedCommon>(Body).OffsetInBss; + case SymbolBody::DefinedCommonKind: { + auto &D = cast<DefinedCommon<ELFT>>(Body); + return D.Section->OutSec->getVA() + D.Section->OutSecOff + D.Offset; + } case SymbolBody::SharedKind: { auto &SS = cast<SharedSymbol<ELFT>>(Body); if (!SS.NeedsCopyOrPltAddr) @@ -175,7 +177,7 @@ template <class ELFT> typename ELFT::uint SymbolBody::getThunkVA() const { } template <class ELFT> typename ELFT::uint SymbolBody::getSize() const { - if (const auto *C = dyn_cast<DefinedCommon>(this)) + if (const auto *C = dyn_cast<DefinedCommon<ELFT>>(this)) return C->Size; if (const auto *DR = dyn_cast<DefinedRegular<ELFT>>(this)) return DR->Size; @@ -218,8 +220,10 @@ DefinedSynthetic<ELFT>::DefinedSynthetic(StringRef N, uintX_t Value, : 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 <class ELFT> +DefinedCommon<ELFT>::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<ELF32LE>; template class elf::DefinedSynthetic<ELF32BE>; template class elf::DefinedSynthetic<ELF64LE>; template class elf::DefinedSynthetic<ELF64BE>; + +template class elf::DefinedCommon<ELF32LE>; +template class elf::DefinedCommon<ELF32BE>; +template class elf::DefinedCommon<ELF64LE>; +template class elf::DefinedCommon<ELF64BE>; diff --git a/lld/ELF/Symbols.h b/lld/ELF/Symbols.h index 97235222635..f8b5f463ba2 100644 --- a/lld/ELF/Symbols.h +++ b/lld/ELF/Symbols.h @@ -167,7 +167,7 @@ public: BitcodeFile *file() { return (BitcodeFile *)this->File; } }; -class DefinedCommon : public Defined { +template <class ELFT> 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 @@ public: // 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<ELFT> *Section; }; // Regular defined symbols read from object file symbol tables. @@ -433,7 +436,8 @@ struct Symbol { // 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<llvm::object::ELF64LE>, + DefinedBitcode, DefinedCommon<llvm::object::ELF64LE>, + DefinedRegular<llvm::object::ELF64LE>, DefinedSynthetic<llvm::object::ELF64LE>, Undefined, SharedSymbol<llvm::object::ELF64LE>, LazyArchive, LazyObject> Body; diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index 99d9323d9d2..f8209e0ccf0 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -68,12 +68,11 @@ private: void writeSections(); void writeBuildId(); - void addCommonSymbols(std::vector<DefinedCommon *> &Syms); - std::unique_ptr<FileOutputBuffer> Buffer; BumpPtrAllocator Alloc; std::vector<OutputSectionBase<ELFT> *> OutputSections; + std::unique_ptr<CommonInputSection<ELFT>> CommonSection; OutputSectionFactory<ELFT> Factory; void addRelIpltSymbols(); @@ -223,9 +222,11 @@ template <class ELFT> void Writer<ELFT>::run() { copyLocalSymbols(); addReservedSymbols(); - OutputSections = ScriptConfig->DoLayout - ? Script<ELFT>::X->createSections(Factory) - : createSections(); + CommonSection = llvm::make_unique<CommonInputSection<ELFT>>(); + OutputSections = + ScriptConfig->DoLayout + ? Script<ELFT>::X->createSections(Factory, CommonSection.get()) + : createSections(); finalizeSections(); if (HasError) return; @@ -490,30 +491,6 @@ void PhdrEntry<ELFT>::add(OutputSectionBase<ELFT> *Sec) { H.p_align = std::max<typename ELFT::uint>(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 <class ELFT> -void Writer<ELFT>::addCommonSymbols(std::vector<DefinedCommon *> &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<ELFT>::Bss->getSize(); - for (DefinedCommon *C : Syms) { - Off = alignTo(Off, C->Alignment); - Out<ELFT>::Bss->updateAlignment(C->Alignment); - C->OffsetInBss = Off; - Off += C->Size; - } - - Out<ELFT>::Bss->setSize(Off); -} - template <class ELFT> static Symbol *addOptionalSynthetic(SymbolTable<ELFT> &Table, StringRef Name, OutputSectionBase<ELFT> *Sec, @@ -734,7 +711,6 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() { // Now that we have defined all possible symbols including linker- // synthesized ones. Visit all symbols to give the finishing touches. - std::vector<DefinedCommon *> CommonSymbols; for (Symbol *S : Symtab.getSymbols()) { SymbolBody *Body = S->body(); @@ -743,9 +719,6 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() { if (S->IsUsedInRegularObj && Body->isUndefined() && !S->isWeak()) reportUndefined<ELFT>(Symtab, Body); - if (auto *C = dyn_cast<DefinedCommon>(Body)) - CommonSymbols.push_back(C); - if (!includeInSymtab<ELFT>(*Body)) continue; if (Out<ELFT>::SymTab) @@ -763,7 +736,12 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() { 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) { + Out<ELFT>::Bss->addSection(CommonSection.get()); + Out<ELFT>::Bss->assignOffsets(); + } // So far we have added sections from input object files. // This function adds linker-created Out<ELFT>::* sections. diff --git a/lld/test/ELF/linkerscript/linkerscript-common.s b/lld/test/ELF/linkerscript/linkerscript-common.s new file mode 100644 index 00000000000..c04c129dabc --- /dev/null +++ b/lld/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 |