Index: ELF/LinkerScript.h =================================================================== --- ELF/LinkerScript.h +++ ELF/LinkerScript.h @@ -40,12 +40,12 @@ // 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 @@ 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. Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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::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; Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -786,6 +786,10 @@ // 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-symbols.s =================================================================== --- test/ELF/linkerscript-symbols.s +++ 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