Index: ELF/OutputSections.h =================================================================== --- ELF/OutputSections.h +++ ELF/OutputSections.h @@ -101,6 +101,7 @@ std::string MemoryRegionName; std::string LMARegionName; bool Noload = false; + StringRef InsertAfter; template <class ELFT> void finalize(); template <class ELFT> void writeTo(uint8_t *Buf); Index: ELF/ScriptParser.cpp =================================================================== --- ELF/ScriptParser.cpp +++ ELF/ScriptParser.cpp @@ -457,6 +457,15 @@ } Script->SectionCommands.push_back(Cmd); } + + if (consume("INSERT")) { + expect("AFTER"); + StringRef After = next(); + for (BaseCommand *Base : Script->SectionCommands) { + auto *Sec = cast<OutputSection>(Base); + Sec->InsertAfter = After; + } + } } static int precedence(StringRef Op) { Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -1109,6 +1109,30 @@ // after another commands. For the details, look at shouldSkip // function. + // For handling "INSERT AFTER" we make all inserted sections to be orphans, + // because according to specification insertion point is as for oprhan + // sections. + for (BaseCommand *&Base : Script->SectionCommands) + if (auto *Sec = dyn_cast<OutputSection>(Base)) + if (!Sec->InsertAfter.empty()) + Sec->SectionIndex = INT_MAX; + + // We assuming that sections inserted with "INSERT AFTER" are not referencing + // each other for simplivity, so just placing them to the end and let orphans + // heuristic code do all job about placing them after already created + // sections. + std::stable_sort(Script->SectionCommands.begin(), + Script->SectionCommands.end(), + [](const BaseCommand *ACmd, const BaseCommand *BCmd) { + auto *SecA = dyn_cast<OutputSection>(ACmd); + auto *SecB = dyn_cast<OutputSection>(BCmd); + if (!SecA || !SecB) + return false; + if (SecA->InsertAfter.empty() == SecB->InsertAfter.empty()) + return false; + return SecA->InsertAfter.empty(); + }); + auto I = Script->SectionCommands.begin(); auto E = Script->SectionCommands.end(); auto NonScriptI = std::find_if(I, E, [](BaseCommand *Base) { @@ -1143,9 +1167,9 @@ }); std::rotate(Pos, NonScriptI, End); NonScriptI = End; - } + } - Script->adjustSectionsAfterSorting(); + Script->adjustSectionsAfterSorting(); } static bool compareByFilePosition(InputSection *A, InputSection *B) { Index: test/ELF/linkerscript/insert-after.s =================================================================== --- test/ELF/linkerscript/insert-after.s +++ test/ELF/linkerscript/insert-after.s @@ -0,0 +1,36 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o +# RUN: echo "SECTIONS { \ +# RUN: .bar1 : { __start_bar1 = .; *(.foo1) __end_bar1 = .; } \ +# RUN: } INSERT AFTER .data; \ +# RUN: SECTIONS { \ +# RUN: .bar2 : { __start_bar2 = .; *(.foo2) __end_bar2 = .; } \ +# RUN: } INSERT AFTER .text;" > %t.script + +# RUN: ld.lld %t1.o -o %t1 --script %t.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 00000001 0000000000000000 TEXT DATA +# CHECK-NEXT: 2 .bar2 00000008 0000000000000001 TEXT DATA +# CHECK-NEXT: 3 .data 00000008 0000000000000009 DATA +# CHECK-NEXT: 4 .bar1 00000008 0000000000000011 DATA +# CHECK-NEXT: 5 .comment 00000008 0000000000000000 +# CHECK-NEXT: 6 .symtab 00000090 0000000000000000 +# CHECK-NEXT: 7 .shstrtab 0000003c 0000000000000000 +# CHECK-NEXT: 8 .strtab 00000038 0000000000000000 + +.global _start +_start: + nop + +.section .data,"aw" +.quad 0 + +.section .foo1,"aw" +.quad 1 + +.section .foo2,"ax" +.quad 1