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. @@ -127,11 +130,12 @@ bool shouldKeep(InputSectionBase *S); void assignAddresses(ArrayRef *> S); int compareSections(StringRef A, StringRef B); - void addScriptedSymbols(); + void addScriptedSymbols(ArrayRef *> S); bool hasPhdrsCommands(); private: - std::vector>> getSectionMap(); + void visitInputs( + const std::function &V); std::vector *> getInputSections(ArrayRef Patterns); Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -74,22 +74,14 @@ 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; +template +void LinkerScript::visitInputs( + const std::function &V) { 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->Patterns); - - return Ret; + if (auto *Cmd = dyn_cast(Base1.get())) + for (const std::unique_ptr &Base2 : Cmd->Commands) + V(Cmd, Base2.get()); } // Returns input sections filtered by given glob patterns. @@ -109,6 +101,7 @@ std::vector *> LinkerScript::createSections(OutputSectionFactory &Factory) { std::vector *> Ret; + uintX_t SectionOffset; // Add input section to output section. If there is no output section yet, // then create it and add to output section list. @@ -116,15 +109,23 @@ OutputSectionBase *Sec; bool IsNew; std::tie(Sec, IsNew) = Factory.create(C, Name); - if (IsNew) + if (IsNew) { + SectionOffset = 0; Ret.push_back(Sec); + } Sec->addSection(C); + // Calculate value of 'Dot' within output section. + // It will be used to calculate symbol value in cases like this: + // .foo : { *(.foo.*) end_foo = .; } + SectionOffset = alignTo(SectionOffset, C->Alignment); + SectionOffset += C->getSize(); }; - for (auto &P : getSectionMap()) { - StringRef OutputName = P.first; - ArrayRef InputPatterns = P.second; - for (InputSectionBase *S : getInputSections(InputPatterns)) { + // Add 1 or more input sections given output section name and input + // section description + auto AddMultiple = [&](StringRef OutputName, InputSectionDescription *Cmd) { + + for (InputSectionBase *S : getInputSections(Cmd->Patterns)) { if (OutputName == "/DISCARD/") { S->Live = false; reportDiscarded(S); @@ -132,7 +133,15 @@ } Add(S, OutputName); } - } + }; + + // Apply visitor for all possible input kinds + visitInputs([&](OutputSectionCommand *Out, BaseCommand *In) { + if (InputSectionDescription *Cmd = dyn_cast(In)) + AddMultiple(Out->Name, Cmd); + else if (SymbolAssignment *Cmd = dyn_cast(In)) + Cmd->Value = In == Out->Commands.front().get() ? 0 : SectionOffset; + }); // Add all other input sections, which are not listed in script. for (const std::unique_ptr> &F : @@ -349,22 +358,51 @@ return I < J ? -1 : 1; } -template void LinkerScript::addScriptedSymbols() { - for (const std::unique_ptr &Base : Opt.Commands) { - auto *Cmd = dyn_cast(Base.get()); +template +void LinkerScript::addScriptedSymbols( + ArrayRef *> OutputSections) { + + auto AddSym = [](BaseCommand *Base, OutputSectionBase *OutSec) { + auto *Cmd = dyn_cast(Base); if (!Cmd || Cmd->Name == ".") - continue; + return; 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 + if ((!B && !Cmd->Provide) || (B && B->isUndefined())) { + if (OutSec) { + Symbol *Synthetic = Symtab::X->addSynthetic(Cmd->Name, OutSec, + Cmd->Expression(Cmd->Value)); + Synthetic->Visibility = Cmd->Hidden ? STV_HIDDEN : STV_DEFAULT; + + } else { + 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; + } + }; + + for (const std::unique_ptr &Base : Opt.Commands) + AddSym(Base.get(), nullptr); + + for (OutputSectionBase *Sec : OutputSections) { + auto ItCmd = + llvm::find_if(Opt.Commands, [&](std::unique_ptr &Base) { + OutputSectionCommand *Cmd = + dyn_cast(Base.get()); + return Cmd && Cmd->Name == Sec->getName(); + }); + + if (ItCmd != Opt.Commands.end()) { + OutputSectionCommand *OutSecCmd = + static_cast((*ItCmd).get()); + for (std::unique_ptr &Cmd : OutSecCmd->Commands) + AddSym(Cmd.get(), Sec); + } } } @@ -427,11 +465,11 @@ void readSearchDir(); void readSections(); - SymbolAssignment *readAssignment(StringRef Name); void readOutputSectionDescription(StringRef OutSec); std::vector readOutputSectionPhdrs(); unsigned readPhdrType(); - void readProvide(bool Hidden); + std::unique_ptr readProvide(bool Hidden); + std::unique_ptr readAssignment(StringRef Name); Expr readExpr(); Expr readExpr1(Expr Lhs, int MinPrec); @@ -623,21 +661,25 @@ expect(")"); } + void ScriptParser::readSections() { Opt.DoLayout = true; 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)); } } @@ -690,6 +732,7 @@ while (!Error && !skip("}")) { StringRef Tok = next(); + std::unique_ptr Assignment; if (Tok == "*") { auto *InCmd = new InputSectionDescription(); Cmd->Commands.emplace_back(InCmd); @@ -699,12 +742,17 @@ } 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 { setError("unknown command " + Tok); } + if (Assignment) + Cmd->Commands.push_back(std::move(Assignment)); } Cmd->Phdrs = readOutputSectionPhdrs(); @@ -720,22 +768,22 @@ } } -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 @@ -724,7 +724,7 @@ // Add scripted symbols with zero values now. // Real values will be assigned later - Script::X->addScriptedSymbols(); + Script::X->addScriptedSymbols(OutputSections); if (!Out::EhFrame->empty()) { OutputSections.push_back(Out::EhFrame); 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 @@ -3,18 +3,18 @@ # RUN: echo \ # RUN: "SECTIONS { . = 1000; .blah : { PROVIDE(foo = .); } }" \ # RUN: > %t.script -# RUN: ld.lld -o %t1 --script %t.script %t -shared +# RUN: ld.lld -o %t1 --script %t.script %t # RUN: llvm-objdump -t %t1 | FileCheck %s -# CHECK: 00000000000003e8 *ABS* 00000000 foo +# CHECK: 00000000000003e8 .blah 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: ld.lld -o %t2 --script %t2.script %t # RUN: llvm-objdump -t %t2 | FileCheck %s --check-prefix=HIDDEN -# HIDDEN: 00000000000003e8 *ABS* 00000000 .hidden foo +# HIDDEN: 00000000000003e8 .blah 00000000 .hidden foo -.section .blah -.globl patatino -patatino: +.section .blah, "a" +.globl _start +_start: 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,30 @@ +# 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 +