Index: ELF/LinkerScript.h =================================================================== --- ELF/LinkerScript.h +++ ELF/LinkerScript.h @@ -10,6 +10,8 @@ #ifndef LLD_ELF_LINKER_SCRIPT_H #define LLD_ELF_LINKER_SCRIPT_H +#include "Symbols.h" +#include "SymbolTable.h" #include "lld/Core/LLVM.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/MapVector.h" @@ -40,7 +42,7 @@ // 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; @@ -81,6 +83,7 @@ bool shouldKeep(InputSectionBase *S); void assignAddresses(ArrayRef *> S); int compareSections(StringRef A, StringRef B); + void addScriptedSymbols(SymbolTable &Symtab); private: // "ScriptConfig" is a bit too long, so define a short name for it. @@ -89,6 +92,8 @@ int getSectionIndex(StringRef Name); uintX_t Dot; + + std::vector *> Symbols; }; // Variable template is a C++14 feature, so we can't template Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -223,12 +223,19 @@ // Assign addresses as instructed by linker script SECTIONS sub-commands. Dot = Out::ElfHeader->getSize() + Out::ProgramHeaders->getSize(); uintX_t MinVA = std::numeric_limits::max(); + uintX_t SymIndex = 0; 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: + Symbols[SymIndex++]->Value = evalExpr(Cmd.Expr, Dot); + continue; + default: + break; } // Find all the sections with required name. There can be more than @@ -298,6 +305,17 @@ return I < J ? -1 : 1; } +template +void LinkerScript::addScriptedSymbols(SymbolTable &Symtab) { + for (SectionsCommand &Cmd : Opt.Commands) { + if (Cmd.Kind == SymbolAssignmentKind) { + DefinedRegular *D = + Symtab.addAbsolute(Cmd.SectionName, STV_DEFAULT); + Symbols.push_back(D); + } + } +} + class elf::ScriptParser : public ScriptParserBase { typedef void (ScriptParser::*Handler)(); @@ -323,6 +341,8 @@ void readLocationCounterValue(); void readOutputSectionDescription(); + void readSymbolAssignment(); + void readSectionsCommandExpr(); const static StringMap Cmd; ScriptConfiguration &Opt = *ScriptConfig; @@ -488,6 +508,8 @@ StringRef Tok = peek(); if (Tok == ".") readLocationCounterValue(); + else if (peek(2) == "=") + readSymbolAssignment(); else readOutputSectionDescription(); } @@ -497,15 +519,7 @@ 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()) - error("error in location counter expression"); + readSectionsCommandExpr(); } void ScriptParser::readOutputSectionDescription() { @@ -547,6 +561,25 @@ } } +void ScriptParser::readSymbolAssignment() { + StringRef Name = next(); + expect("="); + Opt.Commands.push_back({SymbolAssignmentKind, {}, Name}); + readSectionsCommandExpr(); +} + +void ScriptParser::readSectionsCommandExpr() { + SectionsCommand &Cmd = Opt.Commands.back(); + while (!Error) { + StringRef Tok = next(); + if (Tok == ";") + break; + Cmd.Expr.push_back(Tok); + } + if (Cmd.Expr.empty()) + error("error in location counter expression"); +} + static bool isUnderSysroot(StringRef Path) { if (Config->Sysroot == "") return false; Index: ELF/ScriptParser.h =================================================================== --- ELF/ScriptParser.h +++ ELF/ScriptParser.h @@ -30,7 +30,7 @@ static StringRef skipSpace(StringRef S); bool atEOF(); StringRef next(); - StringRef peek(); + StringRef peek(int Lookahead = 1); bool skip(StringRef Tok); void expect(StringRef Expect); Index: ELF/ScriptParser.cpp =================================================================== --- ELF/ScriptParser.cpp +++ ELF/ScriptParser.cpp @@ -124,11 +124,17 @@ return Tokens[Pos++]; } -StringRef ScriptParserBase::peek() { - StringRef Tok = next(); - if (Error) - return ""; - --Pos; +StringRef ScriptParserBase::peek(int Lookahead) { + int Skipped = 0; + StringRef Tok; + for (; Skipped < Lookahead; Skipped++) { + Tok = next(); + if (Error || Tok.empty()) { + Tok = ""; + break; + } + } + Pos -= Skipped; return Tok; } Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -785,6 +785,9 @@ // 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(Symtab); if (!Out::EhFrame->empty()) { OutputSections.push_back(Out::EhFrame); Index: test/ELF/linkerscript-symbols.s =================================================================== --- test/ELF/linkerscript-symbols.s +++ test/ELF/linkerscript-symbols.s @@ -0,0 +1,12 @@ +# 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 +