Index: ELF/LinkerScript.h =================================================================== --- ELF/LinkerScript.h +++ ELF/LinkerScript.h @@ -129,13 +129,10 @@ bool shouldKeep(InputSectionBase *S); void assignAddresses(ArrayRef *> S); int compareSections(StringRef A, StringRef B); - void addScriptedSymbols(); bool hasPhdrsCommands(); private: - std::vector> - getSectionMap(); - + void addAbsoluteSymbols(); std::vector *> getInputSections(const InputSectionDescription *); @@ -151,6 +148,9 @@ void dispatchAssignment(SymbolAssignment *Cmd); uintX_t Dot; + + // Relative symbol sections. + std::vector>> RSS; }; // 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,48 @@ ScriptConfiguration *elf::ScriptConfig; +template static inline T *zero(T *val) { + return static_cast(memset(val, 0, sizeof(*val))); +} + +namespace { +template class SymbolInputSection : public InputSection { +public: + SymbolInputSection(SymbolAssignment *A); + void calculateSymbolValue(); + +private: + SymbolAssignment *Cmd; + DefinedRegular *Regular; + typename ELFT::Shdr Hdr; +}; +} + +template +SymbolInputSection::SymbolInputSection(SymbolAssignment *A) + : InputSection(nullptr, zero(&Hdr)), Cmd(A) { + + // This section should never be written. + Hdr.sh_type = SHT_NOBITS; + + SymbolBody *B = Symtab::X->find(Cmd->Name); + if ((!B && !Cmd->Provide) || (B && B->isUndefined())) { + typename ELFT::Sym Sym = {}; + Sym.setBindingAndType(STB_GLOBAL, STT_NOTYPE); + Sym.setVisibility(Cmd->Hidden ? STV_HIDDEN : STV_DEFAULT); + Regular = cast>( + Symtab::X->addRegular(Cmd->Name, Sym, this)->body()); + } else { + Regular = dyn_cast>(B); + } +} + +template void SymbolInputSection::calculateSymbolValue() { + if (Regular) + // OutSecOff is added to value in getSymVA(). + Regular->Value = Cmd->Expression(this->OutSecOff) - this->OutSecOff; +} + bool SymbolAssignment::classof(const BaseCommand *C) { return C->Kind == AssignmentKind; } @@ -74,24 +116,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 +137,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()); + RSS.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 +171,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 +191,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); @@ -251,6 +300,11 @@ } } + // Set relative symbol values. + for (std::unique_ptr> &IS : RSS) + if (auto *SS = cast>(IS.get())) + SS->calculateSymbolValue(); + // ELF and Program headers need to be right before the first section in // memory. Set their addresses accordingly. MinVA = alignDown(MinVA - Out::ElfHeader->getSize() - @@ -357,22 +411,20 @@ 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; - - 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 - // Symbol already exists in symbol table. If it is provided - // then we can't override its value. - Cmd->Ignore = Cmd->Provide; + 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; + } } } @@ -436,11 +488,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); void readSort(); @@ -639,16 +691,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)); } } @@ -731,6 +786,7 @@ while (!Error && !skip("}")) { StringRef Tok = next(); + std::unique_ptr Assignment; if (Tok == "*") { auto *InCmd = new InputSectionDescription(); Cmd->Commands.emplace_back(InCmd); @@ -740,14 +796,19 @@ } else if (Tok == "KEEP") { readKeep(Cmd); } 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 if (Tok == "SORT") { readSort(); } else { setError("unknown command " + Tok); } + if (Assignment) + Cmd->Commands.push_back(std::move(Assignment)); } Cmd->Phdrs = readOutputSectionPhdrs(); @@ -763,22 +824,20 @@ } } -void ScriptParser::readProvide(bool Hidden) { +std::unique_ptr ScriptParser::readProvide(bool Hidden) { expect("("); - if (SymbolAssignment *Assignment = readAssignment(next())) { - Assignment->Provide = true; - Assignment->Hidden = Hidden; - } + std::unique_ptr Assignment = readAssignment(next()); + 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 @@ -713,10 +713,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(); 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