[ELF] - Support "INSERT AFTER" statement.

This implements INSERT AFTER in a following way:

During reading scripts it collects all insert statements.
After we done and read all files it inserts statements into script commands list.

With that:
* Rest of code does know nothing about INSERT.
* Approach is straightforward and have no visible limitations.
* It is also easy to support INSERT BEFORE (was seen in clang code once).
* Should work for PR35877 and similar cases.

Cons:
* It assumes we have "main" scripts that describes sections.

Differential revision: https://reviews.llvm.org/D43468

llvm-svn: 327003
This commit is contained in:
George Rimar 2018-03-08 14:54:38 +00:00
parent 9003b3b76d
commit 9e2c8a9db1
7 changed files with 87 additions and 1 deletions

View File

@ -1087,6 +1087,10 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
if (errorCount())
return;
// Now when we read all script files, we want to finalize order of linker
// script commands, which can be not yet final because of INSERT commands.
Script->processInsertCommands();
// We want to declare linker script's symbols early,
// so that we can version them.
// They also might be exported if referenced by DSOs.

View File

@ -203,6 +203,26 @@ static void declareSymbol(SymbolAssignment *Cmd) {
Cmd->Provide = false;
}
// This method is used to handle INSERT AFTER statement. Here we rebuild
// the list of script commands to mix sections inserted into.
void LinkerScript::processInsertCommands() {
std::vector<BaseCommand *> V;
for (BaseCommand *Base : SectionCommands) {
V.push_back(Base);
if (auto *Cmd = dyn_cast<OutputSection>(Base)) {
std::vector<BaseCommand *> &W = InsertAfterCommands[Cmd->Name];
V.insert(V.end(), W.begin(), W.end());
W.clear();
}
}
for (std::pair<StringRef, std::vector<BaseCommand *>> &P :
InsertAfterCommands)
if (!P.second.empty())
error("unable to INSERT AFTER " + P.first + ": section not defined");
SectionCommands = std::move(V);
}
// Symbols defined in script should not be inlined by LTO. At the same time
// we don't know their final values until late stages of link. Here we scan
// over symbol assignment commands and create placeholder symbols if needed.

View File

@ -267,6 +267,9 @@ public:
void processSectionCommands();
void declareSymbols();
// Used to handle INSERT AFTER statements.
void processInsertCommands();
// SECTIONS command list.
std::vector<BaseCommand *> SectionCommands;
@ -285,6 +288,10 @@ public:
// A list of symbols referenced by the script.
std::vector<llvm::StringRef> ReferencedSymbols;
// Used to implement INSERT AFTER. Contains commands that need
// to be inserted into SECTIONS commands list.
llvm::DenseMap<StringRef, std::vector<BaseCommand *>> InsertAfterCommands;
};
extern LinkerScript *Script;

View File

@ -436,6 +436,7 @@ void ScriptParser::readSections() {
Config->SingleRoRx = true;
expect("{");
std::vector<BaseCommand *> V;
while (!errorCount() && !consume("}")) {
StringRef Tok = next();
BaseCommand *Cmd = readProvideOrAssignment(Tok);
@ -445,8 +446,18 @@ void ScriptParser::readSections() {
else
Cmd = readOutputSectionDescription(Tok);
}
Script->SectionCommands.push_back(Cmd);
V.push_back(Cmd);
}
if (!atEOF() && consume("INSERT")) {
consume("AFTER");
std::vector<BaseCommand *> &Dest = Script->InsertAfterCommands[next()];
Dest.insert(Dest.end(), V.begin(), V.end());
return;
}
Script->SectionCommands.insert(Script->SectionCommands.end(), V.begin(),
V.end());
}
static int precedence(StringRef Op) {

View File

@ -0,0 +1,11 @@
.section .foo.text,"ax"
.quad 0
.section .foo.data,"aw"
.quad 0
.section .text.1,"ax"
.quad 0
.section .data.1,"aw"
.quad 0

View File

@ -0,0 +1,4 @@
SECTIONS {
.text : { *(.text.*) }
.data : { *(.data.*) }
}

View File

@ -0,0 +1,29 @@
# REQUIRES: x86
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/insert-after.s -o %t1.o
## Main linker script contains .text and .data sections. Here
## we check that can use INSERT AFTER to insert sections .foo.data
## and .foo.text at the right places.
SECTIONS {
.foo.data : { *(.foo.data) }
} INSERT AFTER .data;
SECTIONS {
.foo.text : { *(.foo.text) }
} INSERT AFTER .text;
# RUN: ld.lld %t1.o -o %t1 --script %p/Inputs/insert-after.script --script %s
# RUN: llvm-objdump -section-headers %t1 | FileCheck %s
# CHECK: Sections:
# CHECK-NEXT: Idx Name Size Address Type
# CHECK-NEXT: 0 00000000 0000000000000000
# CHECK-NEXT: 1 .text 00000008 0000000000000000 TEXT DATA
# CHECK-NEXT: 2 .foo.text 00000008 0000000000000008 TEXT DATA
# CHECK-NEXT: 3 .data 00000008 0000000000000010 DATA
# CHECK-NEXT: 4 .foo.data 00000008 0000000000000018 DATA
# RUN: not ld.lld %t1.o -o %t1 --script %s 2>&1 \
# RUN: | FileCheck %s --check-prefix=ERR
# ERR-DAG: error: unable to INSERT AFTER .text: section not defined
# ERR-DAG: error: unable to INSERT AFTER .data: section not defined