Index: ELF/Driver.cpp =================================================================== --- ELF/Driver.cpp +++ ELF/Driver.cpp @@ -1104,6 +1104,10 @@ if (!Config->Relocatable) addReservedSymbols(); + // 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. Script->declareSymbols(); Index: ELF/LinkerScript.h =================================================================== --- ELF/LinkerScript.h +++ ELF/LinkerScript.h @@ -267,6 +267,9 @@ void processSectionCommands(); void declareSymbols(); + // Used to handle INSERT AFTER statements. + void processInsertCommands(); + // SECTIONS command list. std::vector SectionCommands; @@ -285,6 +288,10 @@ // A list of symbols referenced by the script. std::vector ReferencedSymbols; + + // Used to implement INSERT AFTER. Contains commands that needs + // to be inserted into SECTIONS commands list. + llvm::DenseMap> PendingInserts; }; extern LinkerScript *Script; Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -165,6 +165,23 @@ Cmd->Sym = cast(Sym); } +void LinkerScript::processInsertCommands() { + std::vector V; + for (BaseCommand *Base : SectionCommands) { + V.push_back(Base); + if (auto *Cmd = dyn_cast(Base)) { + std::vector &InsertV = PendingInserts[Cmd->Name]; + V.insert(V.end(), InsertV.begin(), InsertV.end()); + InsertV.clear(); + } + } + for (std::pair> &P : PendingInserts) + if (!P.second.empty()) + error("unable to INSERT AFTER " + P.first + ": section not defined"); + + SectionCommands.swap(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. Index: ELF/ScriptParser.cpp =================================================================== --- ELF/ScriptParser.cpp +++ ELF/ScriptParser.cpp @@ -446,6 +446,7 @@ Config->SingleRoRx = true; expect("{"); + std::vector V; while (!errorCount() && !consume("}")) { StringRef Tok = next(); BaseCommand *Cmd = readProvideOrAssignment(Tok); @@ -455,8 +456,18 @@ else Cmd = readOutputSectionDescription(Tok); } - Script->SectionCommands.push_back(Cmd); + V.push_back(Cmd); } + + if (atEOF() || !consume("INSERT")) { + Script->SectionCommands.insert(Script->SectionCommands.end(), V.begin(), + V.end()); + return; + } + + consume("AFTER"); + std::vector &Dest = Script->PendingInserts[next()]; + Dest.insert(Dest.end(), V.begin(), V.end()); } static int precedence(StringRef Op) { Index: test/ELF/insert-after.s =================================================================== --- test/ELF/insert-after.s +++ test/ELF/insert-after.s @@ -0,0 +1,41 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o + +# RUN: echo "SECTIONS { \ +# RUN: .foo.data : { *(.foo.data) } \ +# RUN: } INSERT AFTER .data; \ +# RUN: SECTIONS { \ +# RUN: .foo.text : { *(.foo.text) } \ +# RUN: } INSERT AFTER .text;" > %tinsert.script + +# RUN: echo "SECTIONS { \ +# RUN: .text : { *(.text.*) } \ +# RUN: .data : { *(.data.*) } \ +# RUN: }" > %tmain.script + +# RUN: ld.lld %t1.o -o %t1 --script %tinsert.script %tmain.script +# 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 %tinsert.script 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 + +.section .foo.text,"ax" +.quad 0 + +.section .foo.data,"aw" +.quad 0 + +.section .text.foo,"ax" +.quad 0 + +.section .data.foo,"aw" +.quad 0