Index: ELF/LinkerScript.h =================================================================== --- ELF/LinkerScript.h +++ ELF/LinkerScript.h @@ -55,6 +55,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. @@ -123,7 +126,7 @@ bool shouldKeep(InputSectionBase *S); void assignAddresses(ArrayRef *> S); int compareSections(StringRef A, StringRef B); - void addScriptedSymbols(); + void addScriptedSymbols(ArrayRef *> S); std::vector createPhdrs(ArrayRef *> S); bool hasPhdrsCommands(); Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -263,6 +263,7 @@ typedef const std::unique_ptr> ObjectFile; std::vector *> Result; DenseSet *> Removed; + uintX_t SecOff; // Add input section to output section. If there is no output section yet, // then create it and add to output section list. @@ -283,6 +284,11 @@ return; } 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 = .; } + SecOff = alignTo(SecOff, C->Alignment); + SecOff += C->getSize(); }; // Select input sections matching rule and add them to corresponding @@ -293,10 +299,15 @@ if (!OutCmd) continue; + SecOff = 0; for (const std::unique_ptr &Cmd : OutCmd->Commands) { auto *InCmd = dyn_cast(Cmd.get()); - if (!InCmd) + if (!InCmd) { + if (SymbolAssignment *Assignment = + dyn_cast(Cmd.get())) + Assignment->Value = SecOff; continue; + } for (ObjectFile &F : Symtab::X->getObjectFiles()) { for (InputSectionBase *S : F->getSections()) { @@ -527,19 +538,47 @@ 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; - if (Symtab::X->find(Cmd->Name) == nullptr) - Symtab::X->addAbsolute(Cmd->Name, - Cmd->Hidden ? STV_HIDDEN : STV_DEFAULT); - else + if (Symtab::X->find(Cmd->Name) == nullptr) { + if (OutSec) + Symtab::X->addSynthetic(Cmd->Name, OutSec, + evalExpr(Cmd->Expr, Cmd->Value)); + 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); + } } } @@ -601,8 +640,8 @@ void readOutputSectionDescription(StringRef OutSec); std::vector readOutputSectionPhdrs(); unsigned readPhdrType(); - void readProvide(bool Hidden); - SymbolAssignment *readSymbolAssignment(StringRef Name); + std::unique_ptr readProvide(bool Hidden); + std::unique_ptr readSymbolAssignment(StringRef Name); std::vector readSectionsCommandExpr(); const static StringMap Cmd; @@ -799,14 +838,19 @@ continue; } next(); + + std::unique_ptr Assignment; if (Tok == "PROVIDE") - readProvide(false); + Assignment = readProvide(false); else if (Tok == "PROVIDE_HIDDEN") - readProvide(true); + Assignment = readProvide(true); else if (peek() == "=") - readSymbolAssignment(Tok); + Assignment = readSymbolAssignment(Tok); else readOutputSectionDescription(Tok); + + if (Assignment) + Opt.Commands.push_back(std::move(Assignment)); } } @@ -851,6 +895,9 @@ InCmd->Patterns.push_back(next()); } expect(")"); + } else if (std::unique_ptr Assignment = + readSymbolAssignment(Tok)) { + Cmd->Commands.push_back(std::move(Assignment)); } else { setError("unknown command " + Tok); } @@ -869,25 +916,29 @@ } } -void ScriptParser::readProvide(bool Hidden) { +std::unique_ptr ScriptParser::readProvide(bool Hidden) { expect("("); - if (SymbolAssignment *Assignment = readSymbolAssignment(next())) { + std::unique_ptr Assignment = readSymbolAssignment(next()); + if (Assignment) { Assignment->Provide = true; Assignment->Hidden = Hidden; } expect(")"); expect(";"); + + return Assignment; } -SymbolAssignment *ScriptParser::readSymbolAssignment(StringRef Name) { +std::unique_ptr +ScriptParser::readSymbolAssignment(StringRef Name) { expect("="); std::vector Expr = readSectionsCommandExpr(); - if (Expr.empty()) { + + if (Expr.empty()) error("error in symbol assignment expression"); - } else { - Opt.Commands.push_back(llvm::make_unique(Name, Expr)); - return static_cast(Opt.Commands.back().get()); - } + else + return llvm::make_unique(Name, Expr); + return nullptr; } Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -726,7 +726,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-symbols-synthetic.s =================================================================== --- test/ELF/linkerscript-symbols-synthetic.s +++ test/ELF/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 .hidden begin_foo +# SIMPLE-NEXT: 0000000000000128 .foo 00000000 .hidden end_foo +# SIMPLE-NEXT: 0000000000000128 .foo 00000000 .hidden begin_bar +# SIMPLE-NEXT: 000000000000012c .foo 00000000 .hidden end_bar + +.global _start +_start: + nop + +.section .foo,"a" + .quad 0 + +.section .bar,"a" + .long 0 +