diff options
| -rw-r--r-- | lld/ELF/Driver.cpp | 4 | ||||
| -rw-r--r-- | lld/ELF/LinkerScript.cpp | 20 | ||||
| -rw-r--r-- | lld/ELF/LinkerScript.h | 7 | ||||
| -rw-r--r-- | lld/ELF/ScriptParser.cpp | 13 | ||||
| -rw-r--r-- | lld/test/ELF/linkerscript/Inputs/insert-after.s | 11 | ||||
| -rw-r--r-- | lld/test/ELF/linkerscript/Inputs/insert-after.script | 4 | ||||
| -rw-r--r-- | lld/test/ELF/linkerscript/insert-after.test | 29 |
7 files changed, 87 insertions, 1 deletions
diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp index ebfab486c01..9f32e6aab3c 100644 --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -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. diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp index 6b7f8ed2216..e4b3bc99210 100644 --- a/lld/ELF/LinkerScript.cpp +++ b/lld/ELF/LinkerScript.cpp @@ -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. diff --git a/lld/ELF/LinkerScript.h b/lld/ELF/LinkerScript.h index 4eddafa4996..fe5d6d8ef6f 100644 --- a/lld/ELF/LinkerScript.h +++ b/lld/ELF/LinkerScript.h @@ -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; diff --git a/lld/ELF/ScriptParser.cpp b/lld/ELF/ScriptParser.cpp index c68c25ad615..29dec116ce8 100644 --- a/lld/ELF/ScriptParser.cpp +++ b/lld/ELF/ScriptParser.cpp @@ -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) { diff --git a/lld/test/ELF/linkerscript/Inputs/insert-after.s b/lld/test/ELF/linkerscript/Inputs/insert-after.s new file mode 100644 index 00000000000..88a6044cc96 --- /dev/null +++ b/lld/test/ELF/linkerscript/Inputs/insert-after.s @@ -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 diff --git a/lld/test/ELF/linkerscript/Inputs/insert-after.script b/lld/test/ELF/linkerscript/Inputs/insert-after.script new file mode 100644 index 00000000000..cb95878bc5c --- /dev/null +++ b/lld/test/ELF/linkerscript/Inputs/insert-after.script @@ -0,0 +1,4 @@ +SECTIONS { + .text : { *(.text.*) } + .data : { *(.data.*) } +} diff --git a/lld/test/ELF/linkerscript/insert-after.test b/lld/test/ELF/linkerscript/insert-after.test new file mode 100644 index 00000000000..2da0e296aa0 --- /dev/null +++ b/lld/test/ELF/linkerscript/insert-after.test @@ -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 |

