Index: ELF/LinkerScript.h =================================================================== --- ELF/LinkerScript.h +++ ELF/LinkerScript.h @@ -58,6 +58,9 @@ // Hidden and Ignore can be true, only if Provide is true bool Hidden = false; bool Ignore = false; + // Value of symbol. For synthetic symbols it hold offset from the + // beginning of its output section. + uint64_t Value = 0; }; // Linker scripts allow additional constraints to be put on ouput sections. @@ -129,13 +132,11 @@ bool shouldKeep(InputSectionBase *S); void assignAddresses(ArrayRef *> S); int compareSections(StringRef A, StringRef B); - void addScriptedSymbols(); bool hasPhdrsCommands(); + void addSyntheticSymbols(); private: - std::vector> - getSectionMap(); - + void addAbsoluteSymbols(); std::vector *> getInputSections(const InputSectionDescription *); @@ -151,6 +152,7 @@ void dispatchAssignment(SymbolAssignment *Cmd); uintX_t Dot; + std::vector>> Synthetics; }; // Variable template is a C++14 feature, so we can't template Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -43,6 +43,26 @@ ScriptConfiguration *elf::ScriptConfig; +namespace { +template class SymbolInputSection : public InputSection { +public: + SymbolInputSection(SymbolAssignment *A); + + SymbolAssignment *Cmd; + +private: + typename ELFT::Shdr Hdr; +}; +} + +template +SymbolInputSection::SymbolInputSection(SymbolAssignment *A) + : InputSection(nullptr, &Hdr), Cmd(A) { + Hdr.sh_size = 0; + Hdr.sh_type = SHT_NOBITS; + Hdr.sh_addralign = 1; +} + bool SymbolAssignment::classof(const BaseCommand *C) { return C->Kind == AssignmentKind; } @@ -74,24 +94,6 @@ return false; } -// Create a vector of (, ). -// For example, if a returned vector contains (".text" (".foo.*" ".bar.*")), -// input sections start with ".foo." or ".bar." should be added to -// ".text" section. -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; -} - // Returns input sections filtered by given glob patterns. template std::vector *> @@ -113,22 +115,33 @@ std::vector *> LinkerScript::createSections(OutputSectionFactory &Factory) { std::vector *> Ret; + std::vector PendingSymbols; + OutputSectionBase *Current; + + // Add pending symbols to current output section and clear pending state. + auto AddPendingSyms = [&]() { + for (SymbolAssignment *Assignment : PendingSymbols) { + std::unique_ptr> SymSec( + new SymbolInputSection(Assignment)); + Current->addSection(SymSec.get()); + Synthetics.push_back(std::move(SymSec)); + } + PendingSymbols.clear(); + }; // Add input section to output section. If there is no output section yet, // then create it and add to output section list. auto Add = [&](InputSectionBase *C, StringRef Name) { - OutputSectionBase *Sec; bool IsNew; - std::tie(Sec, IsNew) = Factory.create(C, Name); + std::tie(Current, IsNew) = Factory.create(C, Name); if (IsNew) - Ret.push_back(Sec); - Sec->addSection(C); + Ret.push_back(Current); + AddPendingSyms(); + Current->addSection(C); }; - for (auto &P : getSectionMap()) { - StringRef OutputName = P.first; - const InputSectionDescription *I = P.second; - for (InputSectionBase *S : getInputSections(I)) { + auto AddMultiple = [&](StringRef OutputName, InputSectionDescription *In) { + for (InputSectionBase *S : getInputSections(In)) { if (OutputName == "/DISCARD/") { S->Live = false; reportDiscarded(S); @@ -136,7 +149,18 @@ } Add(S, OutputName); } - } + }; + + 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())) + PendingSymbols.push_back(Assignment); + else + AddMultiple(Cmd->Name, cast(Base2.get())); + + AddPendingSyms(); + } // Add all other input sections, which are not listed in script. for (const std::unique_ptr> &F : @@ -145,6 +169,9 @@ if (!isDiscarded(S) && !S->OutSec) Add(S, getOutputSectionName(S)); + // Add all absolute symbols + addAbsoluteSymbols(); + // Remove from the output all the sections which did not meet // the optional constraints. return filter(Ret); @@ -357,22 +384,36 @@ return I < J ? -1 : 1; } -template void LinkerScript::addScriptedSymbols() { - for (const std::unique_ptr &Base : Opt.Commands) { +template void LinkerScript::addAbsoluteSymbols() { + for (std::unique_ptr &Base : Opt.Commands) { auto *Cmd = dyn_cast(Base.get()); - if (!Cmd || Cmd->Name == ".") - continue; + if (Cmd && Cmd->Name != ".") { + SymbolBody *B = Symtab::X->find(Cmd->Name); + if ((!B && !Cmd->Provide) || (B && B->isUndefined())) + Symtab::X->addAbsolute(Cmd->Name, + Cmd->Hidden ? STV_HIDDEN : STV_DEFAULT); + + else + // Symbol already exists in symbol table. If it is provided + // then we can't override its value. + Cmd->Ignore = Cmd->Provide; + } + } +} - SymbolBody *B = Symtab::X->find(Cmd->Name); - // The semantic of PROVIDE is that of introducing a symbol only if - // it's not defined and there's at least a reference to it. - if ((!B && !Cmd->Provide) || (B && B->isUndefined())) - Symtab::X->addAbsolute(Cmd->Name, - Cmd->Hidden ? STV_HIDDEN : STV_DEFAULT); - else +template void LinkerScript::addSyntheticSymbols() { + for (std::unique_ptr> &I : Synthetics) { + auto *SS = cast>(I.get()); + SymbolBody *B = Symtab::X->find(SS->Cmd->Name); + if ((!B && !SS->Cmd->Provide) || (B && B->isUndefined())) { + Symbol *S = Symtab::X->addSynthetic( + SS->Cmd->Name, SS->OutSec, SS->Cmd->Expression(SS->OutSecOff)); + S->Visibility = SS->Cmd->Hidden ? STV_HIDDEN : STV_DEFAULT; + } else { // Symbol already exists in symbol table. If it is provided // then we can't override its value. - Cmd->Ignore = Cmd->Provide; + SS->Cmd->Ignore = SS->Cmd->Provide; + } } } @@ -436,11 +477,11 @@ void readSearchDir(); void readSections(); - SymbolAssignment *readAssignment(StringRef Name); + std::unique_ptr readAssignment(StringRef Name); void readOutputSectionDescription(StringRef OutSec); std::vector readOutputSectionPhdrs(); unsigned readPhdrType(); - void readProvide(bool Hidden); + std::unique_ptr readProvide(bool Hidden); void readAlign(OutputSectionCommand *Cmd); Expr readExpr(); @@ -638,16 +679,19 @@ expect("{"); while (!Error && !skip("}")) { StringRef Tok = next(); + std::unique_ptr Assignment; if (peek() == "=") { - readAssignment(Tok); + Assignment = readAssignment(Tok); expect(";"); } else if (Tok == "PROVIDE") { - readProvide(false); + Assignment = readProvide(false); } else if (Tok == "PROVIDE_HIDDEN") { - readProvide(true); + Assignment = readProvide(true); } else { readOutputSectionDescription(Tok); } + if (Assignment) + Opt.Commands.push_back(std::move(Assignment)); } } @@ -702,8 +746,9 @@ } void ScriptParser::readOutputSectionDescription(StringRef OutSec) { - OutputSectionCommand *Cmd = new OutputSectionCommand(OutSec); - Opt.Commands.emplace_back(Cmd); + std::unique_ptr Cmd = + llvm::make_unique(OutSec); + size_t NumSymbols = 0; // Read an address expression. // https://sourceware.org/binutils/docs/ld/Output-Section-Address.html#Output-Section-Address @@ -713,7 +758,7 @@ expect(":"); if (skip("ALIGN")) - readAlign(Cmd); + readAlign(Cmd.get()); // Parse constraints. if (skip("ONLY_IF_RO")) @@ -724,6 +769,7 @@ while (!Error && !skip("}")) { StringRef Tok = next(); + std::unique_ptr Assignment; if (Tok == "*") { auto *InCmd = new InputSectionDescription(); Cmd->Commands.emplace_back(InCmd); @@ -731,14 +777,21 @@ while (!Error && !skip(")")) InCmd->Patterns.push_back(next()); } else if (Tok == "KEEP") { - readKeep(Cmd); + readKeep(Cmd.get()); } else if (Tok == "PROVIDE") { - readProvide(false); + Assignment = readProvide(false); } else if (Tok == "PROVIDE_HIDDEN") { - readProvide(true); + Assignment = readProvide(true); + } else if (peek() == "=") { + Assignment = readAssignment(Tok); + expect(";"); } else { setError("unknown command " + Tok); } + if (Assignment) { + Cmd->Commands.push_back(std::move(Assignment)); + NumSymbols++; + } } Cmd->Phdrs = readOutputSectionPhdrs(); @@ -752,24 +805,33 @@ Cmd->Filler = parseHex(Tok); next(); } + + // Check if output section contains any input sections. + if (Cmd->Commands.size() > NumSymbols) + Opt.Commands.push_back(std::move(Cmd)); + else + // The section definition contains only symbols or nothing at all. + // Make all symbols global and discard the section. + std::move(Cmd->Commands.begin(), Cmd->Commands.end(), + std::back_inserter(Opt.Commands)); } -void ScriptParser::readProvide(bool Hidden) { +std::unique_ptr ScriptParser::readProvide(bool Hidden) { expect("("); - if (SymbolAssignment *Assignment = readAssignment(next())) { + std::unique_ptr Assignment = readAssignment(next()); + if (Assignment) { Assignment->Provide = true; Assignment->Hidden = Hidden; } expect(")"); expect(";"); + + return Assignment; } -SymbolAssignment *ScriptParser::readAssignment(StringRef Name) { +std::unique_ptr ScriptParser::readAssignment(StringRef Name) { expect("="); - Expr E = readExpr(); - auto *Cmd = new SymbolAssignment(Name, E); - Opt.Commands.emplace_back(Cmd); - return Cmd; + return llvm::make_unique(Name, readExpr()); } // This is an operator-precedence parser to parse a linker Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -722,10 +722,6 @@ // 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(); @@ -737,6 +733,9 @@ for (OutputSectionBase *Sec : OutputSections) Sec->assignOffsets(); + // Should be called after assignOffsets(). + Script::X->addSyntheticSymbols(); + // 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,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