Skip to content

Commit

Permalink
[ELF] Support PROVIDE and PROVIDE_HIDDEN inside SECTIONS
Browse files Browse the repository at this point in the history
llvm-svn: 276398
  • Loading branch information
eleviant777 committed Jul 22, 2016
1 parent 2db00ce commit a31c91b
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 14 deletions.
59 changes: 48 additions & 11 deletions lld/ELF/LinkerScript.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@ void LinkerScript<ELFT>::dispatchAssignment(SymbolAssignment *Cmd) {
uint64_t Val = evalExpr(Cmd->Expr, Dot);
if (Cmd->Name == ".") {
Dot = Val;
} else {
} else if (!Cmd->Ignore) {
auto *D = cast<DefinedRegular<ELFT>>(Symtab<ELFT>::X->find(Cmd->Name));
D->Value = Val;
}
Expand Down Expand Up @@ -528,10 +528,19 @@ int LinkerScript<ELFT>::compareSections(StringRef A, StringRef B) {
}

template <class ELFT> void LinkerScript<ELFT>::addScriptedSymbols() {
for (const std::unique_ptr<BaseCommand> &Base : Opt.Commands)
if (auto *Cmd = dyn_cast<SymbolAssignment>(Base.get()))
if (Cmd->Name != "." && Symtab<ELFT>::X->find(Cmd->Name) == nullptr)
Symtab<ELFT>::X->addAbsolute(Cmd->Name, STV_DEFAULT);
for (const std::unique_ptr<BaseCommand> &Base : Opt.Commands) {
auto *Cmd = dyn_cast<SymbolAssignment>(Base.get());
if (!Cmd || Cmd->Name == ".")
continue;

if (Symtab<ELFT>::X->find(Cmd->Name) == nullptr)
Symtab<ELFT>::X->addAbsolute(Cmd->Name,
Cmd->Hidden ? STV_HIDDEN : STV_DEFAULT);
else
// Symbol already exists in symbol table. If it is provided
// then we can't override its value.
Cmd->Ignore = Cmd->Provide;
}
}

template <class ELFT> bool LinkerScript<ELFT>::hasPhdrsCommands() {
Expand Down Expand Up @@ -592,7 +601,8 @@ class elf::ScriptParser : public ScriptParserBase {
void readOutputSectionDescription(StringRef OutSec);
std::vector<StringRef> readOutputSectionPhdrs();
unsigned readPhdrType();
void readSymbolAssignment(StringRef Name);
void readProvide(bool Hidden);
SymbolAssignment *readSymbolAssignment(StringRef Name);
std::vector<StringRef> readSectionsCommandExpr();

const static StringMap<Handler> Cmd;
Expand Down Expand Up @@ -789,7 +799,11 @@ void ScriptParser::readSections() {
continue;
}
next();
if (peek() == "=")
if (Tok == "PROVIDE")
readProvide(false);
else if (Tok == "PROVIDE_HIDDEN")
readProvide(true);
else if (peek() == "=")
readSymbolAssignment(Tok);
else
readOutputSectionDescription(Tok);
Expand Down Expand Up @@ -855,19 +869,42 @@ void ScriptParser::readOutputSectionDescription(StringRef OutSec) {
}
}

void ScriptParser::readSymbolAssignment(StringRef Name) {
void ScriptParser::readProvide(bool Hidden) {
expect("(");
if (SymbolAssignment *Assignment = readSymbolAssignment(next())) {
Assignment->Provide = true;
Assignment->Hidden = Hidden;
}
expect(")");
expect(";");
}

SymbolAssignment *ScriptParser::readSymbolAssignment(StringRef Name) {
expect("=");
std::vector<StringRef> Expr = readSectionsCommandExpr();
if (Expr.empty())
if (Expr.empty()) {
error("error in symbol assignment expression");
else
} else {
Opt.Commands.push_back(llvm::make_unique<SymbolAssignment>(Name, Expr));
return static_cast<SymbolAssignment *>(Opt.Commands.back().get());
}
return nullptr;
}

// This function reads balanced expression until semicolon is seen.
std::vector<StringRef> ScriptParser::readSectionsCommandExpr() {
int Braces = 0;
std::vector<StringRef> Expr;
while (!Error) {
StringRef Tok = next();
StringRef Tok = peek();

if (Tok == "(")
Braces++;
else if (Tok == ")")
if (--Braces < 0)
break;

next();
if (Tok == ";")
break;
Expr.push_back(Tok);
Expand Down
4 changes: 4 additions & 0 deletions lld/ELF/LinkerScript.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ struct SymbolAssignment : BaseCommand {
static bool classof(const BaseCommand *C);
StringRef Name;
std::vector<StringRef> Expr;
bool Provide = false;
// Hidden and Ignore can be true, only if Provide is true
bool Hidden = false;
bool Ignore = false;
};

// Linker scripts allow additional constraints to be put on ouput sections.
Expand Down
2 changes: 1 addition & 1 deletion lld/test/ELF/linkerscript-locationcounter.s
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,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 { \
Expand Down
36 changes: 34 additions & 2 deletions lld/test/ELF/linkerscript-symbols.s
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit a31c91b

Please sign in to comment.