Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -593,7 +593,7 @@ void readSearchDir(); void readSections(); - SymbolAssignment *readAssignment(StringRef Name); + SymbolAssignment *readAssignment(StringRef Name, bool DotAvail); OutputSectionCommand *readOutputSectionDescription(StringRef OutSec); std::vector readOutputSectionFiller(); std::vector readOutputSectionPhdrs(); @@ -602,16 +602,16 @@ InputSectionDescription *readInputSectionRules(); unsigned readPhdrType(); SortKind readSortKind(); - SymbolAssignment *readProvideHidden(bool Provide, bool Hidden); - SymbolAssignment *readProvideOrAssignment(StringRef Tok); + SymbolAssignment *readProvideHidden(bool Provide, bool Hidden, bool DotAvail); + SymbolAssignment *readProvideOrAssignment(StringRef Tok, bool DotAvail); Expr readAlign(); void readSort(); Expr readAssert(); - Expr readExpr(); - Expr readExpr1(Expr Lhs, int MinPrec); - Expr readPrimary(); - Expr readTernary(Expr Cond); + Expr readExpr(bool DotAvail = true); + Expr readExpr1(Expr Lhs, int MinPrec, bool DotAvail = true); + Expr readPrimary(bool DotAvail = true); + Expr readTernary(Expr Cond, bool DotAvail = true); const static StringMap Cmd; ScriptConfiguration &Opt = *ScriptConfig; @@ -636,10 +636,15 @@ void ScriptParser::run() { while (!atEOF()) { StringRef Tok = next(); - if (Handler Fn = Cmd.lookup(Tok)) + if (Handler Fn = Cmd.lookup(Tok)) { (this->*Fn)(); - else - setError("unknown directive: " + Tok); + } else { + SymbolAssignment *Cmd = readProvideOrAssignment(Tok, false); + if (Cmd) + Opt.Commands.emplace_back(Cmd); + else + setError("unknown directive: " + Tok); + } } } @@ -793,7 +798,7 @@ expect("{"); while (!Error && !skip("}")) { StringRef Tok = next(); - BaseCommand *Cmd = readProvideOrAssignment(Tok); + BaseCommand *Cmd = readProvideOrAssignment(Tok, true); if (!Cmd) { if (Tok == "ASSERT") Cmd = new AssertCommand(readAssert()); @@ -937,7 +942,7 @@ } StringRef Tok = next(); - if (SymbolAssignment *Assignment = readProvideOrAssignment(Tok)) + if (SymbolAssignment *Assignment = readProvideOrAssignment(Tok, true)) Cmd->Commands.emplace_back(Assignment); else if (Tok == "SORT") readSort(); @@ -969,9 +974,10 @@ return { uint8_t(V >> 24), uint8_t(V >> 16), uint8_t(V >> 8), uint8_t(V) }; } -SymbolAssignment *ScriptParser::readProvideHidden(bool Provide, bool Hidden) { +SymbolAssignment * +ScriptParser::readProvideHidden(bool Provide, bool Hidden, bool DotAvail) { expect("("); - SymbolAssignment *Cmd = readAssignment(next()); + SymbolAssignment *Cmd = readAssignment(next(), DotAvail); Cmd->Provide = Provide; Cmd->Hidden = Hidden; expect(")"); @@ -979,17 +985,18 @@ return Cmd; } -SymbolAssignment *ScriptParser::readProvideOrAssignment(StringRef Tok) { +SymbolAssignment * +ScriptParser::readProvideOrAssignment(StringRef Tok, bool DotAvail) { SymbolAssignment *Cmd = nullptr; if (peek() == "=" || peek() == "+=") { - Cmd = readAssignment(Tok); + Cmd = readAssignment(Tok, DotAvail); expect(";"); } else if (Tok == "PROVIDE") { - Cmd = readProvideHidden(true, false); + Cmd = readProvideHidden(true, false, DotAvail); } else if (Tok == "HIDDEN") { - Cmd = readProvideHidden(false, true); + Cmd = readProvideHidden(false, true, DotAvail); } else if (Tok == "PROVIDE_HIDDEN") { - Cmd = readProvideHidden(true, true); + Cmd = readProvideHidden(true, true, DotAvail); } return Cmd; } @@ -1052,10 +1059,12 @@ } } -SymbolAssignment *ScriptParser::readAssignment(StringRef Name) { +SymbolAssignment *ScriptParser::readAssignment(StringRef Name, bool DotAvail) { StringRef Op = next(); assert(Op == "=" || Op == "+="); - Expr E = readExpr(); + if (Name == "." && !DotAvail) + setError("invalid reference to dot symbol"); + Expr E = readExpr(DotAvail); if (Op == "+=") E = [=](uint64_t Dot) { return getSymbolValue(Name, Dot) + E(Dot); }; return new SymbolAssignment(Name, E); @@ -1063,7 +1072,9 @@ // This is an operator-precedence parser to parse a linker // script expression. -Expr ScriptParser::readExpr() { return readExpr1(readPrimary(), 0); } +Expr ScriptParser::readExpr(bool DotAvail) { + return readExpr1(readPrimary(DotAvail), 0, DotAvail); +} static Expr combine(StringRef Op, Expr L, Expr R) { if (Op == "*") @@ -1101,16 +1112,16 @@ // This is a part of the operator-precedence parser. This function // assumes that the remaining token stream starts with an operator. -Expr ScriptParser::readExpr1(Expr Lhs, int MinPrec) { +Expr ScriptParser::readExpr1(Expr Lhs, int MinPrec, bool DotAvail) { while (!atEOF() && !Error) { // Read an operator and an expression. StringRef Op1 = peek(); if (Op1 == "?") - return readTernary(Lhs); + return readTernary(Lhs, DotAvail); if (precedence(Op1) < MinPrec) break; next(); - Expr Rhs = readPrimary(); + Expr Rhs = readPrimary(DotAvail); // Evaluate the remaining part of the expression first if the // next operator has greater precedence than the previous one. @@ -1120,7 +1131,7 @@ StringRef Op2 = peek(); if (precedence(Op2) <= precedence(Op1)) break; - Rhs = readExpr1(Rhs, precedence(Op2)); + Rhs = readExpr1(Rhs, precedence(Op2), DotAvail); } Lhs = combine(Op1, Lhs, Rhs); @@ -1135,11 +1146,11 @@ return 0; } -Expr ScriptParser::readPrimary() { +Expr ScriptParser::readPrimary(bool DotAvail) { StringRef Tok = next(); if (Tok == "(") { - Expr E = readExpr(); + Expr E = readExpr(DotAvail); expect(")"); return E; } @@ -1181,7 +1192,7 @@ expect("("); expect("."); expect(")"); - return [](uint64_t Dot) { return Dot; }; + return [](uint64_t Dot) { return getSymbolValue(".", Dot); }; } // GNU linkers implements more complicated logic to handle // DATA_SEGMENT_RELRO_END. We instead ignore the arguments and just align to @@ -1208,16 +1219,18 @@ if (Tok.getAsInteger(0, V)) { if (Tok != "." && !isValidCIdentifier(Tok)) setError("malformed number: " + Tok); + else if (Tok == "." && !DotAvail) + setError("invalid reference to dot symbol"); return [=](uint64_t Dot) { return getSymbolValue(Tok, Dot); }; } return [=](uint64_t Dot) { return V; }; } -Expr ScriptParser::readTernary(Expr Cond) { +Expr ScriptParser::readTernary(Expr Cond, bool DotAvail) { next(); - Expr L = readExpr(); + Expr L = readExpr(DotAvail); expect(":"); - Expr R = readExpr(); + Expr R = readExpr(DotAvail); return [=](uint64_t Dot) { return Cond(Dot) ? L(Dot) : R(Dot); }; } Index: test/ELF/invalid-linkerscript.test =================================================================== --- test/ELF/invalid-linkerscript.test +++ test/ELF/invalid-linkerscript.test @@ -15,7 +15,7 @@ # RUN: echo foobar > %t1 # RUN: not ld.lld %t1 no-such-file 2>&1 | FileCheck -check-prefix=ERR1 %s -# ERR1: unknown directive: foobar +# ERR1: unexpected EOF # ERR1: cannot open no-such-file: # RUN: echo "foo \"bar" > %t2 Index: test/ELF/linkerscript/linkerscript-symbols.s =================================================================== --- test/ELF/linkerscript/linkerscript-symbols.s +++ test/ELF/linkerscript/linkerscript-symbols.s @@ -41,6 +41,32 @@ # RUN: llvm-objdump -t %t1 | FileCheck --check-prefix=HIDDEN3 %s # HIDDEN3: 0000000000000001 *ABS* 00000000 .hidden newsym +# The symbol is not referenced. Don't provide it. +# RUN: echo "PROVIDE(newsym = 1);" > %t.script +# RUN: ld.lld -o %t1 --script %t.script %t +# RUN: llvm-objdump -t %t1 | FileCheck --check-prefix=PROVIDE4 %s +# PROVIDE4-NOT: 0000000000000001 *ABS* 00000000 newsym + +# The symbol is not referenced. Don't provide it. +# RUN: echo "PROVIDE_HIDDEN(newsym = 1);" > %t.script +# RUN: ld.lld -o %t1 --script %t.script %t +# RUN: llvm-objdump -t %t1 | FileCheck --check-prefix=HIDDEN4 %s +# HIDDEN4-NOT: 0000000000000001 *ABS* 00000000 .hidden newsym + +# Provide existing symbol. The value should be 0, even though we +# have value of 1 in PROVIDE() +# RUN: echo "PROVIDE(somesym = 1);" > %t.script +# RUN: ld.lld -o %t1 --script %t.script %t +# RUN: llvm-objdump -t %t1 | FileCheck --check-prefix=PROVIDE5 %s +# PROVIDE5: 0000000000000000 *ABS* 00000000 somesym + +# Provide existing symbol. The value should be 0, even though we +# have value of 1 in PROVIDE_HIDDEN(). Visibility should not change +# RUN: echo "PROVIDE_HIDDEN(somesym = 1);" > %t.script +# RUN: ld.lld -o %t1 --script %t.script %t +# RUN: llvm-objdump -t %t1 | FileCheck --check-prefix=HIDDEN5 %s +# HIDDEN5: 0000000000000000 *ABS* 00000000 somesym + .global _start _start: nop