diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp index 6baa8ce271cf..f25d6d400f9f 100644 --- a/lld/ELF/LinkerScript.cpp +++ b/lld/ELF/LinkerScript.cpp @@ -20,6 +20,7 @@ #include "OutputSections.h" #include "ScriptParser.h" #include "Strings.h" +#include "Symbols.h" #include "SymbolTable.h" #include "Target.h" #include "llvm/ADT/StringSwitch.h" @@ -226,16 +227,25 @@ void LinkerScript::assignAddresses( uintX_t ThreadBssOffset = 0; for (SectionsCommand &Cmd : Opt.Commands) { - if (Cmd.Kind == ExprKind) { + switch (Cmd.Kind) { + case ExprKind: Dot = evalExpr(Cmd.Expr, Dot); continue; + case SymbolAssignmentKind: { + auto *D = + cast>(Symtab::X->find(Cmd.Name)); + D->Value = evalExpr(Cmd.Expr, Dot); + continue; + } + default: + break; } // Find all the sections with required name. There can be more than // ont section with such name, if the alignment, flags or type // attribute differs. for (OutputSectionBase *Sec : Sections) { - if (Sec->getName() != Cmd.SectionName) + if (Sec->getName() != Cmd.Name) continue; if ((Sec->getFlags() & SHF_TLS) && Sec->getType() == SHT_NOBITS) { @@ -283,7 +293,7 @@ int LinkerScript::getSectionIndex(StringRef Name) { auto Begin = Opt.Commands.begin(); auto End = Opt.Commands.end(); auto I = std::find_if(Begin, End, [&](SectionsCommand &N) { - return N.Kind == SectionKind && N.SectionName == Name; + return N.Kind == SectionKind && N.Name == Name; }); return I == End ? INT_MAX : (I - Begin); } @@ -299,6 +309,13 @@ int LinkerScript::compareSections(StringRef A, StringRef B) { return I < J ? -1 : 1; } +template +void LinkerScript::addScriptedSymbols() { + for (SectionsCommand &Cmd : Opt.Commands) + if (Cmd.Kind == SymbolAssignmentKind) + Symtab::X->addAbsolute(Cmd.Name, STV_DEFAULT); +} + class elf::ScriptParser : public ScriptParserBase { typedef void (ScriptParser::*Handler)(); @@ -323,7 +340,9 @@ private: void readSections(); void readLocationCounterValue(); - void readOutputSectionDescription(); + void readOutputSectionDescription(StringRef OutSec); + void readSymbolAssignment(StringRef Name); + std::vector readSectionsCommandExpr(); const static StringMap Cmd; ScriptConfiguration &Opt = *ScriptConfig; @@ -487,30 +506,29 @@ void ScriptParser::readSections() { expect("{"); while (!Error && !skip("}")) { StringRef Tok = peek(); - if (Tok == ".") + if (Tok == ".") { readLocationCounterValue(); + continue; + } + next(); + if (peek() == "=") + readSymbolAssignment(Tok); else - readOutputSectionDescription(); + readOutputSectionDescription(Tok); } } void ScriptParser::readLocationCounterValue() { expect("."); expect("="); - Opt.Commands.push_back({ExprKind, {}, ""}); - SectionsCommand &Cmd = Opt.Commands.back(); - while (!Error) { - StringRef Tok = next(); - if (Tok == ";") - break; - Cmd.Expr.push_back(Tok); - } - if (Cmd.Expr.empty()) + std::vector Expr = readSectionsCommandExpr(); + if (Expr.empty()) error("error in location counter expression"); + else + Opt.Commands.push_back({ExprKind, std::move(Expr), ""}); } -void ScriptParser::readOutputSectionDescription() { - StringRef OutSec = next(); +void ScriptParser::readOutputSectionDescription(StringRef OutSec) { Opt.Commands.push_back({SectionKind, {}, OutSec}); expect(":"); expect("{"); @@ -548,6 +566,26 @@ void ScriptParser::readOutputSectionDescription() { } } +void ScriptParser::readSymbolAssignment(StringRef Name) { + expect("="); + std::vector Expr = readSectionsCommandExpr(); + if (Expr.empty()) + error("error in symbol assignment expression"); + else + Opt.Commands.push_back({SymbolAssignmentKind, std::move(Expr), Name}); +} + +std::vector ScriptParser::readSectionsCommandExpr() { + std::vector Expr; + while (!Error) { + StringRef Tok = next(); + if (Tok == ";") + break; + Expr.push_back(Tok); + } + return Expr; +} + static bool isUnderSysroot(StringRef Path) { if (Config->Sysroot == "") return false; diff --git a/lld/ELF/LinkerScript.h b/lld/ELF/LinkerScript.h index 95f9f1359030..b515c1890097 100644 --- a/lld/ELF/LinkerScript.h +++ b/lld/ELF/LinkerScript.h @@ -40,12 +40,12 @@ struct SectionRule { // This enum represents what we can observe in SECTIONS tag of script: // ExprKind is a location counter change, like ". = . + 0x1000" // SectionKind is a description of output section, like ".data :..." -enum SectionsCommandKind { ExprKind, SectionKind }; +enum SectionsCommandKind { ExprKind, SectionKind, SymbolAssignmentKind }; struct SectionsCommand { SectionsCommandKind Kind; std::vector Expr; - StringRef SectionName; + StringRef Name; }; // ScriptConfiguration holds linker script parse results. @@ -81,6 +81,7 @@ public: bool shouldKeep(InputSectionBase *S); void assignAddresses(ArrayRef *> S); int compareSections(StringRef A, StringRef B); + void addScriptedSymbols(); private: // "ScriptConfig" is a bit too long, so define a short name for it. diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index cf58ab895715..329753183820 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -786,6 +786,10 @@ template void Writer::createSections() { // 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(); diff --git a/lld/test/ELF/linkerscript-symbols.s b/lld/test/ELF/linkerscript-symbols.s new file mode 100644 index 000000000000..1fcd4e8a8481 --- /dev/null +++ b/lld/test/ELF/linkerscript-symbols.s @@ -0,0 +1,11 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t + +# RUN: echo "SECTIONS {.text : {*(.text.*)} text_end = .;}" > %t.script +# RUN: ld.lld -o %t1 --script %t.script %t +# RUN: llvm-objdump -t %t1 | FileCheck %s +# CHECK: 0000000000000121 *ABS* 00000000 text_end + +.global _start +_start: + nop