Index: ELF/LinkerScript.h =================================================================== --- ELF/LinkerScript.h +++ ELF/LinkerScript.h @@ -57,12 +57,17 @@ int Kind; }; +enum class SymbolProvision { Create, Provide, ProvideHidden, Ignore }; + struct SymbolAssignment : BaseCommand { - SymbolAssignment(StringRef Name, std::vector &Expr) - : BaseCommand(AssignmentKind), Name(Name), Expr(std::move(Expr)) {} + SymbolAssignment(StringRef Name, std::vector &Expr, + SymbolProvision Provision = SymbolProvision::Create) + : BaseCommand(AssignmentKind), Name(Name), Expr(std::move(Expr)), + Provision(Provision) {} static bool classof(const BaseCommand *C); StringRef Name; std::vector Expr; + SymbolProvision Provision; }; struct OutputSectionCommand : BaseCommand { Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -278,10 +278,9 @@ for (const std::unique_ptr &Base : Opt.Commands) { if (auto *Cmd = dyn_cast(Base.get())) { uint64_t Val = evalExpr(Cmd->Expr, Dot); - if (Cmd->Name == ".") { - + if (Cmd->Name == ".") Dot = Val; - } else { + else if (Cmd->Provision != SymbolProvision::Ignore) { auto *D = cast>(Symtab::X->find(Cmd->Name)); D->Value = Val; } @@ -450,8 +449,15 @@ template void LinkerScript::addScriptedSymbols() { for (const std::unique_ptr &Base : Opt.Commands) if (auto *Cmd = dyn_cast(Base.get())) - if (Cmd->Name != "." && Symtab::X->find(Cmd->Name) == nullptr) - Symtab::X->addAbsolute(Cmd->Name, STV_DEFAULT); + if (Cmd->Name != ".") { + if (Symtab::X->find(Cmd->Name) == nullptr) + Symtab::X->addAbsolute( + Cmd->Name, Cmd->Provision == SymbolProvision::ProvideHidden + ? STV_HIDDEN + : STV_DEFAULT); + else if (Cmd->Provision != SymbolProvision::Create) + Cmd->Provision = SymbolProvision::Ignore; + } } template bool LinkerScript::hasPhdrsCommands() { @@ -512,7 +518,8 @@ void readOutputSectionDescription(StringRef OutSec); std::vector readOutputSectionPhdrs(); unsigned readPhdrType(); - void readSymbolAssignment(StringRef Name); + void readProvideBody(SymbolProvision Provision); + void readSymbolAssignment(StringRef Name, SymbolProvision Provision); std::vector readSectionsCommandExpr(); const static StringMap Cmd; @@ -709,8 +716,12 @@ continue; } next(); - if (peek() == "=") - readSymbolAssignment(Tok); + if (Tok == "PROVIDE") + readProvideBody(SymbolProvision::Provide); + else if (Tok == "PROVIDE_HIDDEN") + readProvideBody(SymbolProvision::ProvideHidden); + else if (peek() == "=") + readSymbolAssignment(Tok, SymbolProvision::Create); else readOutputSectionDescription(Tok); } @@ -766,19 +777,34 @@ } } -void ScriptParser::readSymbolAssignment(StringRef Name) { +void ScriptParser::readProvideBody(SymbolProvision Provision) { + expect("("); + readSymbolAssignment(next(), Provision); + expect(")"); + expect(";"); +} + +void ScriptParser::readSymbolAssignment(StringRef Name, + SymbolProvision Provision) { expect("="); std::vector Expr = readSectionsCommandExpr(); if (Expr.empty()) error("error in symbol assignment expression"); else - Opt.Commands.push_back(llvm::make_unique(Name, Expr)); + Opt.Commands.push_back( + llvm::make_unique(Name, Expr, Provision)); } std::vector ScriptParser::readSectionsCommandExpr() { + int Braces = 0; std::vector Expr; while (!Error) { - StringRef Tok = next(); + StringRef Tok = peek(); + Braces += (Tok == "("); + Braces -= (Tok == ")"); + if (Braces < 0) + break; + next(); if (Tok == ";") break; Expr.push_back(Tok); Index: test/ELF/linkerscript-locationcounter.s =================================================================== --- test/ELF/linkerscript-locationcounter.s +++ test/ELF/linkerscript-locationcounter.s @@ -267,7 +267,7 @@ # RUN: }" > %t.script # RUN: not ld.lld %t --script %t.script -o %t2 2>&1 | \ # RUN: FileCheck --check-prefix=BRACKETERR2 %s -# BRACKETERR2: stray token: ) +# BRACKETERR2: expected, but got * ## Empty expression. # RUN: echo "SECTIONS { \ Index: test/ELF/linkerscript-symbols.s =================================================================== --- test/ELF/linkerscript-symbols.s +++ test/ELF/linkerscript-symbols.s @@ -1,11 +1,43 @@ # REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t +# Simple symbol assignment. Should raise conflict in case we +# have duplicates in any input section, but currently simply +# replaces the value. # 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 +# RUN: llvm-objdump -t %t1 | FileCheck --check-prefix=SIMPLE %s +# SIMPLE: 0000000000000121 *ABS* 00000000 text_end + +# Provide new symbol. The value should be 1, like set in PROVIDE() +# RUN: echo "SECTIONS { PROVIDE(newsym = 1);}" > %t.script +# RUN: ld.lld -o %t1 --script %t.script %t +# RUN: llvm-objdump -t %t1 | FileCheck --check-prefix=PROVIDE1 %s +# PROVIDE1: 0000000000000001 *ABS* 00000000 newsym + +# Provide new symbol (hidden). The value should be 1 +# RUN: echo "SECTIONS { PROVIDE_HIDDEN(newsym = 1);}" > %t.script +# RUN: ld.lld -o %t1 --script %t.script %t +# RUN: llvm-objdump -t %t1 | FileCheck --check-prefix=HIDDEN1 %s +# HIDDEN1: 0000000000000001 *ABS* 00000000 .hidden newsym + +# Provide existing symbol. The value should be 0, even though we +# have value of 1 in PROVIDE() +# RUN: echo "SECTIONS { PROVIDE(somesym = 1);}" > %t.script +# RUN: ld.lld -o %t1 --script %t.script %t +# RUN: llvm-objdump -t %t1 | FileCheck --check-prefix=PROVIDE2 %s +# PROVIDE2: 0000000000000000 *ABS* 00000000 somesym + +# Provide existing symbol. The value should be 0, even though we +# have value of 1 in PROVIDE(). Visibility should not change +# RUN: echo "SECTIONS { PROVIDE(somesym = 1);}" > %t.script +# RUN: ld.lld -o %t1 --script %t.script %t +# RUN: llvm-objdump -t %t1 | FileCheck --check-prefix=HIDDEN2 %s +# HIDDEN2: 0000000000000000 *ABS* 00000000 somesym .global _start _start: nop + +.global somesym +somesym=0