Index: ELF/LinkerScript.h =================================================================== --- ELF/LinkerScript.h +++ ELF/LinkerScript.h @@ -145,16 +145,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,35 @@ 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 void addSymbolToSymtab(SymbolAssignment &Cmd, ArgsT... Args) { + if (Cmd.Name == ".") + return; + + // 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; + + Symbol *Sym = + addSymbolToSymtabAux(Cmd.Name, std::forward(Args)...); + + Sym->Visibility = Cmd.Hidden ? STV_HIDDEN : STV_DEFAULT; + Cmd.Sym = Sym->body(); +} + bool SymbolAssignment::classof(const BaseCommand *C) { return C->Kind == AssignmentKind; } @@ -78,21 +107,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 +135,42 @@ 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 { +// 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.push_back(Cmd); } + void flushSymbols(); + +private: + OutputSectionFactory &Factory; + std::vector *> *OutputSections; + OutputSectionBase *Current = nullptr; + std::vector PendingSymbols; +}; +} + 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 (SymbolAssignment *Cmd : PendingSymbols) + addSymbolToSymtab(*Cmd, Cmd->Expression(Current->getSize()), Current); + PendingSymbols.clear(); } template struct SectionsSorter { @@ -160,33 +198,43 @@ 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->Sort != SortKind::None) std::stable_sort(Sections.begin(), Sections.end(), SectionsSorter(Cmd->Sort)); - 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. @@ -392,28 +440,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(); } @@ -490,6 +516,7 @@ InputSectionDescription *readInputSectionRules(); unsigned readPhdrType(); SymbolAssignment *readProvide(bool Hidden); + SymbolAssignment *readProvideOrAssignment(StringRef Tok); Expr readAlign(); void readSort(); Expr readAssert(); @@ -691,18 +718,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); } @@ -844,11 +865,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(); @@ -885,6 +909,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 @@ -81,7 +81,6 @@ virtual void finalize() {} virtual void finalizePieces() {} - virtual void assignOffsets() {} virtual void writeTo(uint8_t *Buf) {} virtual ~OutputSectionBase() = default; @@ -349,8 +348,10 @@ void sortCtorsDtors(); void writeTo(uint8_t *Buf) override; void finalize() override; - void assignOffsets() override; std::vector *> Sections; + +private: + void assignOffsets(); }; template Index: ELF/OutputSections.cpp =================================================================== --- ELF/OutputSections.cpp +++ ELF/OutputSections.cpp @@ -842,6 +842,9 @@ Sections.push_back(S); S->OutSec = this; this->updateAlignment(S->Alignment); + uintX_t Off = alignTo(this->Header.sh_size, S->Alignment); + S->OutSecOff = Off; + this->Header.sh_size = Off + S->getSize(); } // If an input string is in the form of "foo.N" where N is a number, @@ -860,7 +863,7 @@ // This function is called after we sort input sections // and scan relocations to setup sections' offsets. template void OutputSection::assignOffsets() { - uintX_t Off = this->Header.sh_size; + uintX_t Off = 0; for (InputSection *S : Sections) { Off = alignTo(Off, S->Alignment); S->OutSecOff = Off; @@ -886,7 +889,9 @@ std::stable_sort(V.begin(), V.end(), Comp); Sections.clear(); for (Pair &P : V) - Sections.push_back(P.second); + addSection(P.second); + + assignOffsets(); } // Returns true if S matches /Filename.?\.o$/. @@ -947,6 +952,7 @@ // Read the comment above. template void OutputSection::sortCtorsDtors() { std::stable_sort(Sections.begin(), Sections.end(), compCtors); + assignOffsets(); } static void fill(uint8_t *Buf, size_t Size, ArrayRef A) { 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 @@ -230,6 +230,9 @@ copyLocalSymbols(); addReservedSymbols(); + if (Target->NeedsThunks) + forEachRelSec(createThunks); + CommonInputSection Common(getCommonSymbols()); CommonInputSection::X = &Common; @@ -697,21 +700,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); @@ -745,10 +738,8 @@ // If linker script processor hasn't added common symbol section yet, // then add it to .bss now. - if (!CommonInputSection::X->OutSec) { + if (!CommonInputSection::X->OutSec) Out::Bss->addSection(CommonInputSection::X); - 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-symbols-synthetic.s =================================================================== --- test/ELF/linkerscript/linkerscript-symbols-synthetic.s +++ test/ELF/linkerscript/linkerscript-symbols-synthetic.s @@ -0,0 +1,29 @@ +# 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 { .foo : { \ +# RUN: begin_foo = .; \ +# RUN: *(.foo) \ +# RUN: end_foo = .; \ +# RUN: begin_bar = .; \ +# RUN: *(.bar) \ +# RUN: end_bar = .; } }" > %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: 0000000000000128 .foo 00000000 begin_bar +# SIMPLE-NEXT: 000000000000012c .foo 00000000 end_bar + +.global _start +_start: + nop + +.section .foo,"a" + .quad 0 + +.section .bar,"a" + .long 0