Index: ELF/LinkerScript.h =================================================================== --- ELF/LinkerScript.h +++ ELF/LinkerScript.h @@ -38,28 +38,22 @@ class InputSectionBase; class SectionBase; +struct ExprValue { + SectionBase *Sec; + uint64_t Val; + bool ForceAbsolute; + + ExprValue(SectionBase *Sec, uint64_t Val) + : Sec(Sec), Val(Val), ForceAbsolute(false) {} + ExprValue(uint64_t Val) : ExprValue(nullptr, Val) {} + bool isAbsolute() const { return ForceAbsolute || Sec == nullptr; } + uint64_t getValue() const; +}; + // This represents an expression in the linker script. // ScriptParser::readExpr reads an expression and returns an Expr. -// Later, we evaluate the expression by calling the function -// with the value of special context variable ".". -struct Expr { - std::function Val; - std::function IsAbsolute; - - // If expression is section-relative the function below is used - // to get the output section pointer. - std::function Section; - - uint64_t operator()() const { return Val(); } - operator bool() const { return (bool)Val; } - - Expr(std::function Val, std::function IsAbsolute, - std::function Section) - : Val(Val), IsAbsolute(IsAbsolute), Section(Section) {} - template - Expr(T V) : Expr(V, [] { return true; }, [] { return nullptr; }) {} - Expr() : Expr(nullptr) {} -}; +// Later, we evaluate the expression by calling the function. +typedef std::function Expr; // Parses a linker script. Calling this function updates // Config and ScriptConfig. @@ -209,14 +203,13 @@ protected: ~LinkerScriptBase() = default; OutputSection *Aether; + bool ErrorOnMissingSection = false; public: virtual uint64_t getHeaderSize() = 0; - virtual uint64_t getSymbolValue(const Twine &Loc, StringRef S) = 0; - uint64_t getDot() { return getSymbolValue("", "."); } + virtual ExprValue getSymbolValue(const Twine &Loc, StringRef S) = 0; + uint64_t getDot() { return getSymbolValue("", ".").getValue(); } virtual bool isDefined(StringRef S) = 0; - virtual bool isAbsolute(StringRef S) = 0; - virtual OutputSection *getSymbolSection(StringRef S) = 0; virtual OutputSection *getOutputSection(const Twine &Loc, StringRef S) = 0; virtual uint64_t getOutputSectionSize(StringRef S) = 0; }; @@ -267,10 +260,8 @@ void assignAddresses(std::vector &Phdrs); bool hasPhdrsCommands(); uint64_t getHeaderSize() override; - uint64_t getSymbolValue(const Twine &Loc, StringRef S) override; + ExprValue getSymbolValue(const Twine &Loc, StringRef S) override; bool isDefined(StringRef S) override; - bool isAbsolute(StringRef S) override; - OutputSection *getSymbolSection(StringRef S) override; OutputSection *getOutputSection(const Twine &Loc, StringRef S) override; uint64_t getOutputSectionSize(StringRef S) override; Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -53,6 +53,60 @@ using namespace lld; using namespace lld::elf; +uint64_t ExprValue::getValue() const { + if (Sec) + return Sec->getOffset(Val) + Sec->getOutputSection()->Addr; + return Val; +} + +static ExprValue operator+(ExprValue A, ExprValue B) { + return {A.Sec, A.Val + B.getValue()}; +} +static ExprValue operator-(ExprValue A, ExprValue B) { + return {A.Sec, A.Val - B.getValue()}; +} +static ExprValue operator*(ExprValue A, ExprValue B) { + return A.getValue() * B.getValue(); +} +static ExprValue operator/(ExprValue A, ExprValue B) { + if (uint64_t BV = B.getValue()) + return A.getValue() / BV; + error("division by zero"); + return 0; +} +static ExprValue operator<<(ExprValue A, ExprValue B) { + return A.getValue() << B.getValue(); +} +static ExprValue operator>>(ExprValue A, ExprValue B) { + return A.getValue() >> B.getValue(); +} +static ExprValue operator<(ExprValue A, ExprValue B) { + return A.getValue() < B.getValue(); +} +static ExprValue operator>(ExprValue A, ExprValue B) { + return A.getValue() > B.getValue(); +} +static ExprValue operator>=(ExprValue A, ExprValue B) { + return A.getValue() >= B.getValue(); +} +static ExprValue operator<=(ExprValue A, ExprValue B) { + return A.getValue() <= B.getValue(); +} +static ExprValue operator==(ExprValue A, ExprValue B) { + return A.getValue() == B.getValue(); +} +static ExprValue operator!=(ExprValue A, ExprValue B) { + return A.getValue() != B.getValue(); +} +static ExprValue operator&(ExprValue A, ExprValue B) { + return A.getValue() & B.getValue(); +} +static ExprValue operator|(ExprValue A, ExprValue B) { + return A.getValue() | B.getValue(); +} +static ExprValue operator~(ExprValue A) { return ~A.getValue(); } +static ExprValue operator-(ExprValue A) { return -A.getValue(); } + LinkerScriptBase *elf::ScriptBase; ScriptConfiguration *elf::ScriptConfig; @@ -63,8 +117,8 @@ Cmd->Name, /*Type*/ 0, Visibility, /*CanOmitFromDynSym*/ false, /*File*/ nullptr); Sym->Binding = STB_GLOBAL; - SectionBase *Sec = - Cmd->Expression.IsAbsolute() ? nullptr : Cmd->Expression.Section(); + ExprValue Value = Cmd->Expression(); + SectionBase *Sec = Value.isAbsolute() ? nullptr : Value.Sec; replaceBody(Sym, Cmd->Name, /*IsLocal=*/false, Visibility, STT_NOTYPE, 0, 0, Sec, nullptr); return Sym->body(); @@ -81,7 +135,7 @@ template void LinkerScript::setDot(Expr E, const Twine &Loc, bool InSec) { - uintX_t Val = E(); + uintX_t Val = E().getValue(); if (Val < Dot) { if (InSec) error(Loc + ": unable to move location counter backward for: " + @@ -109,12 +163,15 @@ return; auto *Sym = cast(Cmd->Sym); - Sym->Value = Cmd->Expression(); - if (!Cmd->Expression.IsAbsolute()) { - Sym->Section = Cmd->Expression.Section(); - if (auto *Sec = dyn_cast_or_null(Sym->Section)) - if (Sec->Flags & SHF_ALLOC) - Sym->Value -= Sec->Addr; + ExprValue V = Cmd->Expression(); + if (V.isAbsolute()) { + Sym->Value = V.getValue(); + } else { + Sym->Section = V.Sec; + if (Sym->Section->Flags & SHF_ALLOC) + Sym->Value = V.Val; + else + Sym->Value = V.getValue(); } } @@ -368,7 +425,7 @@ // is given, input sections are aligned to that value, whether the // given value is larger or smaller than the original section alignment. if (Cmd->SubalignExpr) { - uint32_t Subalign = Cmd->SubalignExpr(); + uint32_t Subalign = Cmd->SubalignExpr().getValue(); for (InputSectionBase *S : V) S->Alignment = Subalign; } @@ -549,7 +606,7 @@ void LinkerScript::assignOffsets(OutputSectionCommand *Cmd) { if (Cmd->LMAExpr) { uintX_t D = Dot; - LMAOffset = [=] { return Cmd->LMAExpr() - D; }; + LMAOffset = [=] { return Cmd->LMAExpr().getValue() - D; }; } OutputSection *Sec = findSection(Cmd->Name, *OutputSections); if (!Sec) @@ -560,7 +617,7 @@ // Handle align (e.g. ".foo : ALIGN(16) { ... }"). if (Cmd->AlignExpr) - Sec->updateAlignment(Cmd->AlignExpr()); + Sec->updateAlignment(Cmd->AlignExpr().getValue()); // Try and find an appropriate memory region to assign offsets in. CurMemRegion = findMemoryRegion(Cmd, Sec); @@ -766,6 +823,7 @@ void LinkerScript::assignAddresses(std::vector &Phdrs) { // Assign addresses as instructed by linker script SECTIONS sub-commands. Dot = 0; + ErrorOnMissingSection = true; switchTo(Aether); for (const std::unique_ptr &Base : Opt.Commands) { @@ -810,7 +868,7 @@ Phdr.add(Out::ProgramHeaders); if (Cmd.LMAExpr) { - Phdr.p_paddr = Cmd.LMAExpr(); + Phdr.p_paddr = Cmd.LMAExpr().getValue(); Phdr.HasLMA = true; } } @@ -878,7 +936,8 @@ auto *Cmd = dyn_cast(Opt.Commands[I].get()); for (const std::unique_ptr &Base : Cmd->Commands) if (auto *Data = dyn_cast(Base.get())) - writeInt(Buf + Data->Offset, Data->Expression(), Data->Size); + writeInt(Buf + Data->Offset, Data->Expression().getValue(), + Data->Size); } template bool LinkerScript::hasLMA(StringRef Name) { @@ -914,7 +973,8 @@ if (Sec->Name == Name) return Sec; - error(Loc + ": undefined section " + Name); + if (ErrorOnMissingSection) + error(Loc + ": undefined section " + Name); return &FakeSec; } @@ -937,11 +997,15 @@ } template -uint64_t LinkerScript::getSymbolValue(const Twine &Loc, StringRef S) { +ExprValue LinkerScript::getSymbolValue(const Twine &Loc, StringRef S) { if (S == ".") - return Dot; - if (SymbolBody *B = Symtab::X->find(S)) - return B->getVA(); + return {CurOutSec, Dot - CurOutSec->Addr}; + if (SymbolBody *B = Symtab::X->find(S)) { + if (auto *D = dyn_cast(B)) + return {D->Section, D->Value}; + auto *C = cast(B); + return {In::Common, C->Offset}; + } error(Loc + ": symbol not found: " + S); return 0; } @@ -950,24 +1014,6 @@ return Symtab::X->find(S) != nullptr; } -template bool LinkerScript::isAbsolute(StringRef S) { - if (S == ".") - return false; - SymbolBody *Sym = Symtab::X->find(S); - auto *DR = dyn_cast_or_null(Sym); - return DR && !DR->Section; -} - -// Gets section symbol belongs to. Symbol "." doesn't belong to any -// specific section but isn't absolute at the same time, so we try -// to find suitable section for it as well. -template -OutputSection *LinkerScript::getSymbolSection(StringRef S) { - if (SymbolBody *Sym = Symtab::X->find(S)) - return Sym->getOutputSection(); - return CurOutSec; -} - // Returns indices of ELF headers containing specific section, identified // by Name. Each index is a zero based number of ELF header listed within // PHDRS {} script block. @@ -1283,7 +1329,7 @@ expect("("); // Passing 0 for the value of dot is a bit of a hack. It means that // we accept expressions like ".|1". - PhdrCmd.Flags = readExpr()(); + PhdrCmd.Flags = readExpr()().getValue(); expect(")"); } else setError("unexpected header attribute: " + Tok); @@ -1449,7 +1495,7 @@ StringRef Msg = unquote(next()); expect(")"); return [=] { - if (!E()) + if (!E().getValue()) error(Msg); return ScriptBase->getDot(); }; @@ -1580,8 +1626,12 @@ Expr E; assert(Op == "=" || Op == "+="); if (consume("ABSOLUTE")) { - E = readExpr(); - E.IsAbsolute = [] { return true; }; + Expr Inner = readExpr(); + E = [=] { + ExprValue I = Inner(); + I.ForceAbsolute = true; + return I; + }; } else { E = readExpr(); } @@ -1605,28 +1655,15 @@ } static Expr combine(StringRef Op, Expr L, Expr R) { - auto IsAbs = [=] { return L.IsAbsolute() && R.IsAbsolute(); }; - auto GetOutSec = [=] { - SectionBase *S = L.Section(); - return S ? S : R.Section(); - }; - if (Op == "*") return [=] { return L() * R(); }; if (Op == "/") { - return [=]() -> uint64_t { - uint64_t RHS = R(); - if (RHS == 0) { - error("division by zero"); - return 0; - } - return L() / RHS; - }; + return [=] { return L() / R(); }; } if (Op == "+") - return {[=] { return L() + R(); }, IsAbs, GetOutSec}; + return {[=] { return L() + R(); }}; if (Op == "-") - return {[=] { return L() - R(); }, IsAbs, GetOutSec}; + return {[=] { return L() - R(); }}; if (Op == "<<") return [=] { return L() << R(); }; if (Op == ">>") @@ -1762,9 +1799,9 @@ // https://sourceware.org/binutils/docs/ld/Builtin-Functions.html. if (Tok == "ADDR") { StringRef Name = readParenLiteral(); - return {[=] { return ScriptBase->getOutputSection(Location, Name)->Addr; }, - [=] { return false; }, - [=] { return ScriptBase->getOutputSection(Location, Name); }}; + return [=]() -> ExprValue { + return {ScriptBase->getOutputSection(Location, Name), 0}; + }; } if (Tok == "LOADADDR") { StringRef Name = readParenLiteral(); @@ -1779,10 +1816,10 @@ if (consume(",")) { Expr E2 = readExpr(); expect(")"); - return [=] { return alignTo(E(), E2()); }; + return [=] { return alignTo(E().getValue(), E2().getValue()); }; } expect(")"); - return [=] { return alignTo(ScriptBase->getDot(), E()); }; + return [=] { return alignTo(ScriptBase->getDot(), E().getValue()); }; } if (Tok == "CONSTANT") { StringRef Name = readParenLiteral(); @@ -1806,13 +1843,13 @@ expect(","); readExpr(); expect(")"); - return [=] { return alignTo(ScriptBase->getDot(), E()); }; + return [=] { return alignTo(ScriptBase->getDot(), E().getValue()); }; } if (Tok == "DATA_SEGMENT_END") { expect("("); expect("."); expect(")"); - return []() { return ScriptBase->getDot(); }; + return [] { return ScriptBase->getDot(); }; } // GNU linkers implements more complicated logic to handle // DATA_SEGMENT_RELRO_END. We instead ignore the arguments and just align to @@ -1823,7 +1860,7 @@ expect(","); readExpr(); expect(")"); - return []() { return alignTo(ScriptBase->getDot(), Target->PageSize); }; + return [] { return alignTo(ScriptBase->getDot(), Target->PageSize); }; } if (Tok == "SIZEOF") { StringRef Name = readParenLiteral(); @@ -1845,16 +1882,14 @@ // Tok is a symbol name. if (Tok != "." && !isValidCIdentifier(Tok)) setError("malformed number: " + Tok); - return {[=] { return ScriptBase->getSymbolValue(Location, Tok); }, - [=] { return ScriptBase->isAbsolute(Tok); }, - [=] { return ScriptBase->getSymbolSection(Tok); }}; + return [=] { return ScriptBase->getSymbolValue(Location, Tok); }; } Expr ScriptParser::readTernary(Expr Cond) { Expr L = readExpr(); expect(":"); Expr R = readExpr(); - return [=] { return Cond() ? L() : R(); }; + return [=] { return Cond().getValue() ? L() : R(); }; } Expr ScriptParser::readParenExpr() { Index: test/ELF/linkerscript/obj-symbol-value.s =================================================================== --- /dev/null +++ test/ELF/linkerscript/obj-symbol-value.s @@ -0,0 +1,19 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: echo "SECTIONS { foo = bar; .bar : { *(.bar*) } }" > %t.script +# RUN: ld.lld %t.o --script %t.script -o %t.so -shared +# RUN: llvm-readobj -t %t.so | FileCheck %s + +# CHECK: Symbol { +# CHECK: Name: bar +# CHECK-NEXT: Value: 0x[[VAL:.*]] +# CHECK: Name: foo +# CHECK-NEXT: Value: 0x[[VAL]] + +.section .bar.1, "a" +.quad 0 + +.section .bar.2, "a" +.quad 0 +.global bar +bar: