Index: ELF/InputSection.h =================================================================== --- ELF/InputSection.h +++ ELF/InputSection.h @@ -48,7 +48,7 @@ SmallVector Uncompressed; public: - enum Kind { Regular, EHFrame, Merge, MipsReginfo, MipsOptions }; + enum Kind { Regular, EHFrame, Merge, MipsReginfo, MipsOptions, Layout }; Kind SectionKind; InputSectionBase() : Repl(this) {} Index: ELF/InputSection.cpp =================================================================== --- ELF/InputSection.cpp +++ ELF/InputSection.cpp @@ -71,6 +71,7 @@ typename ELFT::uint InputSectionBase::getOffset(uintX_t Offset) const { switch (SectionKind) { case Regular: + case Layout: return cast>(this)->OutSecOff + Offset; case EHFrame: // The file crtbeginT.o has relocations pointing to the start of an empty @@ -129,7 +130,7 @@ template bool InputSection::classof(const InputSectionBase *S) { - return S->SectionKind == Base::Regular; + return S->SectionKind == Base::Regular || S->SectionKind == Base::Layout; } template Index: ELF/LinkerScript.h =================================================================== --- ELF/LinkerScript.h +++ ELF/LinkerScript.h @@ -146,16 +146,12 @@ bool shouldKeep(InputSectionBase *S); void assignAddresses(); int compareSections(StringRef A, StringRef B); - void addScriptedSymbols(); bool hasPhdrsCommands(); uintX_t getOutputSectionSize(StringRef Name); std::vector *> *OutputSections; private: - std::vector> - getSectionMap(); - std::vector *> getInputSections(const InputSectionDescription *); Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -43,6 +43,36 @@ ScriptConfiguration *elf::ScriptConfig; +template +static Symbol *addSymbolToSymtabAux(StringRef Name, uint8_t StOther) { + return Symtab::X->addRegular(Name, STB_GLOBAL, StOther); +} + +template +static Symbol *addSymbolToSymtabAux(StringRef Name, typename ELFT::uint Value, + OutputSectionBase *Section) { + return Symtab::X->addSynthetic(Name, Section, Value); +} + +template +static bool addSymbolToSymtab(SymbolAssignment &Cmd, ArgsT... Args) { + if (Cmd.Name == ".") + return false; + + // If a symbol was in PROVIDE(), define it only when it is an + // undefined symbol. + SymbolBody *B = Symtab::X->find(Cmd.Name); + if (Cmd.Provide && !(B && B->isUndefined())) + return false; + + Symbol *Sym = + addSymbolToSymtabAux(Cmd.Name, std::forward(Args)...); + + Sym->Visibility = Cmd.Hidden ? STV_HIDDEN : STV_DEFAULT; + Cmd.Sym = Sym->body(); + return true; +} + bool SymbolAssignment::classof(const BaseCommand *C) { return C->Kind == AssignmentKind; } @@ -78,21 +108,6 @@ return false; } -// Create a vector of (, ). -template -std::vector> -LinkerScript::getSectionMap() { - std::vector> Ret; - - for (const std::unique_ptr &Base1 : Opt.Commands) - if (auto *Cmd1 = dyn_cast(Base1.get())) - for (const std::unique_ptr &Base2 : Cmd1->Commands) - if (auto *Cmd2 = dyn_cast(Base2.get())) - Ret.emplace_back(Cmd1->Name, Cmd2); - - return Ret; -} - static bool fileMatches(const InputSectionDescription *Desc, StringRef Filename) { if (!globMatch(Desc->FilePattern, Filename)) @@ -121,18 +136,92 @@ return Ret; } -// Add input section to output section. If there is no output section yet, -// then create it and add to output section list. +namespace { +template class LayoutInputSection : public InputSection { +public: + LayoutInputSection(SymbolAssignment *Cmd); + static bool classof(const InputSectionBase *S); + SymbolAssignment *Cmd; + +private: + typename ELFT::Shdr Hdr; +}; + +// Helper class, which builds output section list, also +// creating symbol sections, when needed +template class OutputSectionBuilder { +public: + OutputSectionBuilder(OutputSectionFactory &F, + std::vector *> *Out) + : Factory(F), OutputSections(Out) {} + + void addSection(StringRef OutputName, InputSectionBase *I); + void addSymbol(SymbolAssignment *Cmd) { + PendingSymbols.emplace_back(new LayoutInputSection(Cmd)); + } + void flushSymbols(); + void finalize(); + +private: + OutputSectionFactory &Factory; + std::vector *> *OutputSections; + OutputSectionBase *Current = nullptr; + std::vector>> PendingSymbols; + static std::vector>> OwningSections; +}; + +template +std::vector>> + OutputSectionBuilder::OwningSections; +} + +template static T *zero(T *Val) { + memset(Val, 0, sizeof(*Val)); + return Val; +} + +template +LayoutInputSection::LayoutInputSection(SymbolAssignment *Cmd) + : InputSection(nullptr, zero(&Hdr)), Cmd(Cmd) { + this->Live = true; + this->SectionKind = InputSectionBase::Layout; + Hdr.sh_type = SHT_NOBITS; +} + +template +bool LayoutInputSection::classof(const InputSectionBase *S) { + return S->SectionKind == InputSectionBase::Layout; +} + template -static void addSection(OutputSectionFactory &Factory, - std::vector *> &Out, - InputSectionBase *C, StringRef Name) { - OutputSectionBase *Sec; +void OutputSectionBuilder::addSection(StringRef OutputName, + InputSectionBase *C) { bool IsNew; - std::tie(Sec, IsNew) = Factory.create(C, Name); + std::tie(Current, IsNew) = Factory.create(C, OutputName); if (IsNew) - Out.push_back(Sec); - Sec->addSection(C); + OutputSections->push_back(Current); + flushSymbols(); + Current->addSection(C); +} + +template void OutputSectionBuilder::flushSymbols() { + for (std::unique_ptr> &I : PendingSymbols) + if (I->Cmd->Name == "." || addSymbolToSymtab(*I->Cmd, 0, Current)) { + Current->addSection(I.get()); + OwningSections.push_back(std::move(I)); + } + + PendingSymbols.clear(); +} + +template void OutputSectionBuilder::finalize() { + // Assign offsets to all sections which don't contain symbols + for (OutputSectionBase *S : *OutputSections) + if (llvm::find_if(OwningSections, + [&](std::unique_ptr> &L) { + return L->OutSec == S; + }) == OwningSections.end()) + S->assignOffsets(); } template @@ -160,40 +249,51 @@ template void LinkerScript::createSections( OutputSectionFactory &Factory) { - for (auto &P : getSectionMap()) { - StringRef OutputName = P.first; - const InputSectionDescription *Cmd = P.second; - std::vector *> Sections = getInputSections(Cmd); + OutputSectionBuilder Builder(Factory, OutputSections); + auto Add = [&](StringRef OutputName, const InputSectionDescription *Cmd) { + std::vector *> Sections = getInputSections(Cmd); if (OutputName == "/DISCARD/") { for (InputSectionBase *S : Sections) { S->Live = false; reportDiscarded(S); } - continue; + return; } - if (Cmd->SortInner) std::stable_sort(Sections.begin(), Sections.end(), getComparator(Cmd->SortInner)); if (Cmd->SortOuter) std::stable_sort(Sections.begin(), Sections.end(), getComparator(Cmd->SortOuter)); - for (InputSectionBase *S : Sections) - addSection(Factory, *OutputSections, S, OutputName); - } + Builder.addSection(OutputName, S); + }; + + for (const std::unique_ptr &Base1 : Opt.Commands) + if (auto *Cmd = dyn_cast(Base1.get())) { + for (const std::unique_ptr &Base2 : Cmd->Commands) + if (auto *Assignment = dyn_cast(Base2.get())) + Builder.addSymbol(Assignment); + else + Add(Cmd->Name, cast(Base2.get())); + + Builder.flushSymbols(); + } else if (auto *Cmd2 = dyn_cast(Base1.get())) { + addSymbolToSymtab(*Cmd2, STV_DEFAULT); + } // Add all other input sections, which are not listed in script. for (const std::unique_ptr> &F : Symtab::X->getObjectFiles()) for (InputSectionBase *S : F->getSections()) if (!isDiscarded(S) && !S->OutSec) - addSection(Factory, *OutputSections, S, getOutputSectionName(S)); + Builder.addSection(getOutputSectionName(S), S); // Remove from the output all the sections which did not meet // the optional constraints. filter(); + Builder.finalize(); } template @@ -224,6 +324,36 @@ } } +template void assignOffsets(OutputSectionBase *Sec) { + // Non-zero size means we have assigned offsets earlier in + // OutputSectionBuilder::finalize + if (Sec->getSize()) + return; + + typedef typename ELFT::uint uintX_t; + uintX_t Off = 0; + unsigned SecIdx = 0; + + while (InputSectionBase *Base = Sec->getSection(SecIdx++)) { + if (LayoutInputSection *L = + dyn_cast>(Base)) { + uintX_t Value = L->Cmd->Expression(Sec->getVA() + Off) - Sec->getVA(); + if (L->Cmd->Name == ".") + Off = Value; + else + cast>(L->Cmd->Sym)->Value = Value; + } else { + InputSection *I = cast>(Base); + Off = alignTo(Off, I->Alignment); + I->OutSecOff = Off; + Off += I->getSize(); + } + // Update section size, so that SIZEOF works correctly in the case below: + // .foo { ... a = SIZEOF(.foo) ... } + Sec->setSize(Off); + } +} + template void LinkerScript::assignAddresses() { ArrayRef *> Sections = *OutputSections; // Orphan sections are sections present in the input files which @@ -275,6 +405,7 @@ uintX_t TVA = Dot + ThreadBssOffset; TVA = alignTo(TVA, Sec->getAlignment()); Sec->setVA(TVA); + assignOffsets(Sec); ThreadBssOffset = TVA - Dot + Sec->getSize(); continue; } @@ -282,6 +413,7 @@ if (Sec->getFlags() & SHF_ALLOC) { Dot = alignTo(Dot, Sec->getAlignment()); Sec->setVA(Dot); + assignOffsets(Sec); MinVA = std::min(MinVA, Dot); Dot += Sec->getSize(); continue; @@ -395,28 +527,6 @@ return I < J ? -1 : 1; } -// Add symbols defined by linker scripts. -template void LinkerScript::addScriptedSymbols() { - for (const std::unique_ptr &Base : Opt.Commands) { - auto *Cmd = dyn_cast(Base.get()); - if (!Cmd || Cmd->Name == ".") - continue; - - // If a symbol was in PROVIDE(), define it only when it is an - // undefined symbol. - SymbolBody *B = Symtab::X->find(Cmd->Name); - if (Cmd->Provide && !(B && B->isUndefined())) - continue; - - // Define an absolute symbol. The symbol value will be assigned later. - // (At this point, we don't know the final address yet.) - Symbol *Sym = Symtab::X->addUndefined(Cmd->Name); - replaceBody>(Sym, Cmd->Name, STV_DEFAULT); - Sym->Visibility = Cmd->Hidden ? STV_HIDDEN : STV_DEFAULT; - Cmd->Sym = Sym->body(); - } -} - template bool LinkerScript::hasPhdrsCommands() { return !Opt.PhdrsCommands.empty(); } @@ -494,6 +604,7 @@ unsigned readPhdrType(); SortKind readSortKind(); SymbolAssignment *readProvide(bool Hidden); + SymbolAssignment *readProvideOrAssignment(StringRef Tok); Expr readAlign(); void readSort(); Expr readAssert(); @@ -683,18 +794,12 @@ expect("{"); while (!Error && !skip("}")) { StringRef Tok = next(); - BaseCommand *Cmd; - if (peek() == "=" || peek() == "+=") { - Cmd = readAssignment(Tok); - expect(";"); - } else if (Tok == "PROVIDE") { - Cmd = readProvide(false); - } else if (Tok == "PROVIDE_HIDDEN") { - Cmd = readProvide(true); - } else if (Tok == "ASSERT") { - Cmd = new AssertCommand(readAssert()); - } else { - Cmd = readOutputSectionDescription(Tok); + BaseCommand *Cmd = readProvideOrAssignment(Tok); + if (!Cmd) { + if (Tok == "ASSERT") + Cmd = new AssertCommand(readAssert()); + else + Cmd = readOutputSectionDescription(Tok); } Opt.Commands.emplace_back(Cmd); } @@ -831,11 +936,14 @@ Cmd->Commands.emplace_back(readInputSectionDescription()); continue; } - if (skip("SORT")) { + + StringRef Tok = next(); + if (SymbolAssignment *Assignment = readProvideOrAssignment(Tok)) + Cmd->Commands.emplace_back(Assignment); + else if (Tok == "SORT") readSort(); - continue; - } - setError("unknown command " + peek()); + else + setError("unknown command " + Tok); } Cmd->Phdrs = readOutputSectionPhdrs(); Cmd->Filler = readOutputSectionFiller(); @@ -872,6 +980,19 @@ return Cmd; } +SymbolAssignment *ScriptParser::readProvideOrAssignment(StringRef Tok) { + SymbolAssignment *Cmd = nullptr; + if (peek() == "=" || peek() == "+=") { + Cmd = readAssignment(Tok); + expect(";"); + } else if (Tok == "PROVIDE") { + Cmd = readProvide(false); + } else if (Tok == "PROVIDE_HIDDEN") { + Cmd = readProvide(true); + } + return Cmd; +} + static uint64_t getSymbolValue(StringRef S, uint64_t Dot) { if (S == ".") return Dot; Index: ELF/OutputSections.h =================================================================== --- ELF/OutputSections.h +++ ELF/OutputSections.h @@ -58,6 +58,7 @@ StringRef getName() { return Name; } virtual void addSection(InputSectionBase *C) {} + virtual InputSectionBase *getSection(unsigned Idx) { return nullptr; } unsigned SectionIndex; @@ -343,6 +344,7 @@ typedef typename ELFT::uint uintX_t; OutputSection(StringRef Name, uint32_t Type, uintX_t Flags); void addSection(InputSectionBase *C) override; + InputSectionBase *getSection(unsigned Idx) override; void sortInitFini(); void sortCtorsDtors(); void writeTo(uint8_t *Buf) override; Index: ELF/OutputSections.cpp =================================================================== --- ELF/OutputSections.cpp +++ ELF/OutputSections.cpp @@ -845,6 +845,11 @@ this->updateAlignment(S->Alignment); } +template +InputSectionBase *OutputSection::getSection(unsigned Idx) { + return Sections.size() > Idx ? Sections[Idx] : nullptr; +} + // If an input string is in the form of "foo.N" where N is a number, // return N. Otherwise, returns 65536, which is one greater than the // lowest priority. @@ -1762,6 +1767,8 @@ case InputSectionBase::MipsOptions: Sec = new MipsOptionsOutputSection(); break; + case InputSectionBase::Layout: + llvm_unreachable("Invalid section type"); } OwningSections.emplace_back(Sec); return {Sec, true}; Index: ELF/Symbols.cpp =================================================================== --- ELF/Symbols.cpp +++ ELF/Symbols.cpp @@ -58,7 +58,7 @@ Offset += Addend; Addend = 0; } - uintX_t VA = SC->OutSec->getVA() + SC->getOffset(Offset); + uintX_t VA = (SC->OutSec ? SC->OutSec->getVA() : 0) + SC->getOffset(Offset); if (D.isTls()) return VA - Out::TlsPhdr->p_vaddr; return VA; Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -238,6 +238,9 @@ copyLocalSymbols(); addReservedSymbols(); + if (Target->NeedsThunks) + forEachRelSec(createThunks); + CommonInputSection Common(getCommonSymbols()); CommonInputSection::X = &Common; @@ -659,6 +662,14 @@ Sec->addSection(C); } } + + sortInitFini(findSection(".init_array")); + sortInitFini(findSection(".fini_array")); + sortCtorsDtors(findSection(".ctors")); + sortCtorsDtors(findSection(".dtors")); + + for (OutputSectionBase *Sec : OutputSections) + Sec->assignOffsets(); } // Create output section objects and add them to OutputSections. @@ -667,12 +678,6 @@ Out::InitArray = findSection(".init_array"); Out::FiniArray = findSection(".fini_array"); - // Sort section contents for __attribute__((init_priority(N)). - sortInitFini(Out::InitArray); - sortInitFini(Out::FiniArray); - sortCtorsDtors(findSection(".ctors")); - sortCtorsDtors(findSection(".dtors")); - // The linker needs to define SECNAME_start, SECNAME_end and SECNAME_stop // symbols for sections, so that the runtime can get the start and end // addresses of each section by section name. Add such symbols. @@ -692,21 +697,11 @@ // Define __rel[a]_iplt_{start,end} symbols if needed. addRelIpltSymbols(); - // Add scripted symbols with zero values now. - // Real values will be assigned later - Script::X->addScriptedSymbols(); - if (!Out::EhFrame->empty()) { OutputSections.push_back(Out::EhFrame); Out::EhFrame->finalize(); } - if (Target->NeedsThunks) - forEachRelSec(createThunks); - - for (OutputSectionBase *Sec : OutputSections) - Sec->assignOffsets(); - // Scan relocations. This must be done after every symbol is declared so that // we can correctly decide if a dynamic relocation is needed. forEachRelSec(scanRelocations); Index: test/ELF/linkerscript/linkerscript-symbols-synthetic.s =================================================================== --- test/ELF/linkerscript/linkerscript-symbols-synthetic.s +++ test/ELF/linkerscript/linkerscript-symbols-synthetic.s @@ -0,0 +1,38 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t + +# Simple symbol assignment within input section list. The '.' symbol +# is not location counter but offset from the beginning of output +# section .foo +# RUN: echo "SECTIONS { \ +# RUN: .foo : { \ +# RUN: begin_foo = .; \ +# RUN: *(.foo) \ +# RUN: end_foo = .; \ +# RUN: size_foo_1 = SIZEOF(.foo); \ +# RUN: . = ALIGN(0x1000); \ +# RUN: begin_bar = .; \ +# RUN: *(.bar) \ +# RUN: end_bar = .; \ +# RUN: size_foo_2 = SIZEOF(.foo); \ +# RUN: } \ +# RUN: size_foo_3 = SIZEOF(.foo); }" > %t.script +# RUN: ld.lld -o %t1 --script %t.script %t +# RUN: llvm-objdump -t %t1 | FileCheck --check-prefix=SIMPLE %s +# SIMPLE: 0000000000000120 .foo 00000000 begin_foo +# SIMPLE-NEXT: 0000000000000128 .foo 00000000 end_foo +# SIMPLE-NEXT: 0000000000000008 .foo 00000000 size_foo_1 +# SIMPLE-NEXT: 0000000000001000 .foo 00000000 begin_bar +# SIMPLE-NEXT: 0000000000001004 .foo 00000000 end_bar +# SIMPLE-NEXT: 0000000000000ee4 .foo 00000000 size_foo_2 +# SIMPLE-NEXT: 0000000000000ee4 *ABS* 00000000 size_foo_3 + +.global _start +_start: + nop + +.section .foo,"a" + .quad 0 + +.section .bar,"a" + .long 0