[ELF] Support for symbol assignment in linker scripts within SECTIONS {} block

llvm-svn: 275158
This commit is contained in:
Eugene Leviant 2016-07-12 06:39:48 +00:00
parent 425175934e
commit eda81a1b86
4 changed files with 73 additions and 19 deletions

View File

@ -20,6 +20,7 @@
#include "OutputSections.h" #include "OutputSections.h"
#include "ScriptParser.h" #include "ScriptParser.h"
#include "Strings.h" #include "Strings.h"
#include "Symbols.h"
#include "SymbolTable.h" #include "SymbolTable.h"
#include "Target.h" #include "Target.h"
#include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/StringSwitch.h"
@ -226,16 +227,25 @@ void LinkerScript<ELFT>::assignAddresses(
uintX_t ThreadBssOffset = 0; uintX_t ThreadBssOffset = 0;
for (SectionsCommand &Cmd : Opt.Commands) { for (SectionsCommand &Cmd : Opt.Commands) {
if (Cmd.Kind == ExprKind) { switch (Cmd.Kind) {
case ExprKind:
Dot = evalExpr(Cmd.Expr, Dot); Dot = evalExpr(Cmd.Expr, Dot);
continue; continue;
case SymbolAssignmentKind: {
auto *D =
cast<DefinedRegular<ELFT>>(Symtab<ELFT>::X->find(Cmd.Name));
D->Value = evalExpr(Cmd.Expr, Dot);
continue;
}
default:
break;
} }
// Find all the sections with required name. There can be more than // Find all the sections with required name. There can be more than
// ont section with such name, if the alignment, flags or type // ont section with such name, if the alignment, flags or type
// attribute differs. // attribute differs.
for (OutputSectionBase<ELFT> *Sec : Sections) { for (OutputSectionBase<ELFT> *Sec : Sections) {
if (Sec->getName() != Cmd.SectionName) if (Sec->getName() != Cmd.Name)
continue; continue;
if ((Sec->getFlags() & SHF_TLS) && Sec->getType() == SHT_NOBITS) { if ((Sec->getFlags() & SHF_TLS) && Sec->getType() == SHT_NOBITS) {
@ -283,7 +293,7 @@ int LinkerScript<ELFT>::getSectionIndex(StringRef Name) {
auto Begin = Opt.Commands.begin(); auto Begin = Opt.Commands.begin();
auto End = Opt.Commands.end(); auto End = Opt.Commands.end();
auto I = std::find_if(Begin, End, [&](SectionsCommand &N) { auto I = std::find_if(Begin, End, [&](SectionsCommand &N) {
return N.Kind == SectionKind && N.SectionName == Name; return N.Kind == SectionKind && N.Name == Name;
}); });
return I == End ? INT_MAX : (I - Begin); return I == End ? INT_MAX : (I - Begin);
} }
@ -299,6 +309,13 @@ int LinkerScript<ELFT>::compareSections(StringRef A, StringRef B) {
return I < J ? -1 : 1; return I < J ? -1 : 1;
} }
template <class ELFT>
void LinkerScript<ELFT>::addScriptedSymbols() {
for (SectionsCommand &Cmd : Opt.Commands)
if (Cmd.Kind == SymbolAssignmentKind)
Symtab<ELFT>::X->addAbsolute(Cmd.Name, STV_DEFAULT);
}
class elf::ScriptParser : public ScriptParserBase { class elf::ScriptParser : public ScriptParserBase {
typedef void (ScriptParser::*Handler)(); typedef void (ScriptParser::*Handler)();
@ -323,7 +340,9 @@ private:
void readSections(); void readSections();
void readLocationCounterValue(); void readLocationCounterValue();
void readOutputSectionDescription(); void readOutputSectionDescription(StringRef OutSec);
void readSymbolAssignment(StringRef Name);
std::vector<StringRef> readSectionsCommandExpr();
const static StringMap<Handler> Cmd; const static StringMap<Handler> Cmd;
ScriptConfiguration &Opt = *ScriptConfig; ScriptConfiguration &Opt = *ScriptConfig;
@ -487,30 +506,29 @@ void ScriptParser::readSections() {
expect("{"); expect("{");
while (!Error && !skip("}")) { while (!Error && !skip("}")) {
StringRef Tok = peek(); StringRef Tok = peek();
if (Tok == ".") if (Tok == ".") {
readLocationCounterValue(); readLocationCounterValue();
continue;
}
next();
if (peek() == "=")
readSymbolAssignment(Tok);
else else
readOutputSectionDescription(); readOutputSectionDescription(Tok);
} }
} }
void ScriptParser::readLocationCounterValue() { void ScriptParser::readLocationCounterValue() {
expect("."); expect(".");
expect("="); expect("=");
Opt.Commands.push_back({ExprKind, {}, ""}); std::vector<StringRef> Expr = readSectionsCommandExpr();
SectionsCommand &Cmd = Opt.Commands.back(); if (Expr.empty())
while (!Error) {
StringRef Tok = next();
if (Tok == ";")
break;
Cmd.Expr.push_back(Tok);
}
if (Cmd.Expr.empty())
error("error in location counter expression"); error("error in location counter expression");
else
Opt.Commands.push_back({ExprKind, std::move(Expr), ""});
} }
void ScriptParser::readOutputSectionDescription() { void ScriptParser::readOutputSectionDescription(StringRef OutSec) {
StringRef OutSec = next();
Opt.Commands.push_back({SectionKind, {}, OutSec}); Opt.Commands.push_back({SectionKind, {}, OutSec});
expect(":"); expect(":");
expect("{"); expect("{");
@ -548,6 +566,26 @@ void ScriptParser::readOutputSectionDescription() {
} }
} }
void ScriptParser::readSymbolAssignment(StringRef Name) {
expect("=");
std::vector<StringRef> Expr = readSectionsCommandExpr();
if (Expr.empty())
error("error in symbol assignment expression");
else
Opt.Commands.push_back({SymbolAssignmentKind, std::move(Expr), Name});
}
std::vector<StringRef> ScriptParser::readSectionsCommandExpr() {
std::vector<StringRef> Expr;
while (!Error) {
StringRef Tok = next();
if (Tok == ";")
break;
Expr.push_back(Tok);
}
return Expr;
}
static bool isUnderSysroot(StringRef Path) { static bool isUnderSysroot(StringRef Path) {
if (Config->Sysroot == "") if (Config->Sysroot == "")
return false; return false;

View File

@ -40,12 +40,12 @@ struct SectionRule {
// This enum represents what we can observe in SECTIONS tag of script: // This enum represents what we can observe in SECTIONS tag of script:
// ExprKind is a location counter change, like ". = . + 0x1000" // ExprKind is a location counter change, like ". = . + 0x1000"
// SectionKind is a description of output section, like ".data :..." // SectionKind is a description of output section, like ".data :..."
enum SectionsCommandKind { ExprKind, SectionKind }; enum SectionsCommandKind { ExprKind, SectionKind, SymbolAssignmentKind };
struct SectionsCommand { struct SectionsCommand {
SectionsCommandKind Kind; SectionsCommandKind Kind;
std::vector<StringRef> Expr; std::vector<StringRef> Expr;
StringRef SectionName; StringRef Name;
}; };
// ScriptConfiguration holds linker script parse results. // ScriptConfiguration holds linker script parse results.
@ -81,6 +81,7 @@ public:
bool shouldKeep(InputSectionBase<ELFT> *S); bool shouldKeep(InputSectionBase<ELFT> *S);
void assignAddresses(ArrayRef<OutputSectionBase<ELFT> *> S); void assignAddresses(ArrayRef<OutputSectionBase<ELFT> *> S);
int compareSections(StringRef A, StringRef B); int compareSections(StringRef A, StringRef B);
void addScriptedSymbols();
private: private:
// "ScriptConfig" is a bit too long, so define a short name for it. // "ScriptConfig" is a bit too long, so define a short name for it.

View File

@ -786,6 +786,10 @@ template <class ELFT> void Writer<ELFT>::createSections() {
// Define __rel[a]_iplt_{start,end} symbols if needed. // Define __rel[a]_iplt_{start,end} symbols if needed.
addRelIpltSymbols(); addRelIpltSymbols();
// Add scripted symbols with zero values now.
// Real values will be assigned later
Script<ELFT>::X->addScriptedSymbols();
if (!Out<ELFT>::EhFrame->empty()) { if (!Out<ELFT>::EhFrame->empty()) {
OutputSections.push_back(Out<ELFT>::EhFrame); OutputSections.push_back(Out<ELFT>::EhFrame);
Out<ELFT>::EhFrame->finalize(); Out<ELFT>::EhFrame->finalize();

View File

@ -0,0 +1,11 @@
# 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