Index: ELF/LinkerScript.h =================================================================== --- ELF/LinkerScript.h +++ ELF/LinkerScript.h @@ -140,14 +140,10 @@ bool shouldKeep(InputSectionBase *S); void assignAddresses(ArrayRef *> S); int compareSections(StringRef A, StringRef B); - void addScriptedSymbols(); bool hasPhdrsCommands(); uintX_t getOutputSectionSize(StringRef Name); private: - std::vector> - getSectionMap(); - std::vector *> getInputSections(const InputSectionDescription *); Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -43,6 +43,25 @@ ScriptConfiguration *elf::ScriptConfig; +template class SymbolT, class... ArgsT> +static void addSymbolToSymtab(SymbolAssignment *Cmd, ArgsT... Args) { + if (!Cmd || 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; + + // 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, Args...); + Sym->Visibility = Cmd->Hidden ? STV_HIDDEN : STV_DEFAULT; + Cmd->Sym = Sym->body(); +} + bool SymbolAssignment::classof(const BaseCommand *C) { return C->Kind == AssignmentKind; } @@ -74,21 +93,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)) @@ -117,18 +121,43 @@ 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 { @@ -153,16 +182,16 @@ SortKind Kind; }; +// Create output sections and symbols as listed in linker script. template void LinkerScript::createSections( std::vector *> *Out, OutputSectionFactory &Factory) { OutputSections = Out; + OutputSectionBuilder Builder(Factory, Out); - for (auto &P : getSectionMap()) { + auto Add = [&](StringRef OutputName, const InputSectionDescription *I) { std::vector *> Sections; - StringRef OutputName = P.first; - const InputSectionDescription *I = P.second; for (InputSectionBase *S : getInputSections(I)) { if (OutputName == "/DISCARD/") { S->Live = false; @@ -175,15 +204,28 @@ std::stable_sort(Sections.begin(), Sections.end(), SectionsSorter(I->Sort)); for (InputSectionBase *S : Sections) - addSection(Factory, *Out, 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, *Out, S, getOutputSectionName(S)); + Builder.addSection(getOutputSectionName(S), S); // Remove from the output all the sections which did not meet // the optional constraints. @@ -385,28 +427,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(); } @@ -482,7 +502,8 @@ void readInputFilePattern(InputSectionDescription *InCmd, bool Keep); void readInputSectionRules(InputSectionDescription *InCmd, bool Keep); unsigned readPhdrType(); - void readProvide(bool Hidden); + SymbolAssignment *readProvide(bool Hidden); + SymbolAssignment *readProvideOrAssignment(StringRef Tok); void readAlign(OutputSectionCommand *Cmd); void readSort(); @@ -683,16 +704,10 @@ expect("{"); while (!Error && !skip("}")) { StringRef Tok = next(); - if (peek() == "=" || peek() == "+=") { - readAssignment(Tok); - expect(";"); - } else if (Tok == "PROVIDE") { - readProvide(false); - } else if (Tok == "PROVIDE_HIDDEN") { - readProvide(true); - } else { + if (SymbolAssignment *Assignment = readProvideOrAssignment(Tok)) + Opt.Commands.emplace_back(Assignment); + else readOutputSectionDescription(Tok); - } } } @@ -822,15 +837,12 @@ } StringRef Tok = next(); - if (Tok == "PROVIDE") { - readProvide(false); - } else if (Tok == "PROVIDE_HIDDEN") { - readProvide(true); - } else if (Tok == "SORT") { + if (SymbolAssignment *Assignment = readProvideOrAssignment(Tok)) + Cmd->Commands.emplace_back(Assignment); + else if (Tok == "SORT") readSort(); - } else { + else setError("unknown command " + Tok); - } } Cmd->Phdrs = readOutputSectionPhdrs(); Cmd->Filler = readOutputSectionFiller(); @@ -855,13 +867,27 @@ return {static_cast(Value)}; } -void ScriptParser::readProvide(bool Hidden) { +SymbolAssignment *ScriptParser::readProvide(bool Hidden) { expect("("); SymbolAssignment *Cmd = readAssignment(next()); Cmd->Provide = true; Cmd->Hidden = Hidden; expect(")"); expect(";"); + 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) { @@ -914,9 +940,7 @@ Expr E = readExpr(); if (Op == "+=") E = [=](uint64_t Dot) { return getSymbolValue(Name, Dot) + E(Dot); }; - auto *Cmd = new SymbolAssignment(Name, E); - Opt.Commands.emplace_back(Cmd); - return Cmd; + return new SymbolAssignment(Name, E); } // This is an operator-precedence parser to parse a linker 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-provide-in-section.s =================================================================== --- test/ELF/linkerscript/linkerscript-provide-in-section.s +++ test/ELF/linkerscript/linkerscript-provide-in-section.s @@ -1,20 +0,0 @@ -# REQUIRES: x86 -# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t -# RUN: echo \ -# RUN: "SECTIONS { . = 1000; .blah : { PROVIDE(foo = .); } }" \ -# RUN: > %t.script -# RUN: ld.lld -o %t1 --script %t.script %t -shared -# RUN: llvm-objdump -t %t1 | FileCheck %s -# CHECK: 00000000000003e8 *ABS* 00000000 foo - -# RUN: echo \ -# RUN: "SECTIONS { . = 1000; .blah : { PROVIDE_HIDDEN(foo = .); } }" \ -# RUN: > %t2.script -# RUN: ld.lld -o %t2 --script %t2.script %t -shared -# RUN: llvm-objdump -t %t2 | FileCheck %s --check-prefix=HIDDEN -# HIDDEN: 00000000000003e8 *ABS* 00000000 .hidden foo - -.section .blah -.globl patatino -patatino: - movl $foo, %edx 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