diff --git a/lld/ELF/LinkerScript.h b/lld/ELF/LinkerScript.h --- a/lld/ELF/LinkerScript.h +++ b/lld/ELF/LinkerScript.h @@ -227,7 +227,7 @@ }; struct InsertCommand { - StringRef name; + std::vector names; bool isAfter; StringRef where; }; diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp --- a/lld/ELF/LinkerScript.cpp +++ b/lld/ELF/LinkerScript.cpp @@ -251,30 +251,34 @@ // Process INSERT [AFTER|BEFORE] commands. For each command, we move the // specified output section to the designated place. void LinkerScript::processInsertCommands() { + std::vector moves; for (const InsertCommand &cmd : insertCommands) { - // If cmd.os is empty, it may have been discarded by - // adjustSectionsBeforeSorting(). We do not handle such output sections. - auto from = llvm::find_if(sectionCommands, [&](BaseCommand *base) { - return isa(base) && - cast(base)->name == cmd.name; - }); - if (from == sectionCommands.end()) - continue; - OutputSection *osec = cast(*from); - sectionCommands.erase(from); + for (StringRef name : cmd.names) { + // If base is empty, it may have been discarded by + // adjustSectionsBeforeSorting(). We do not handle such output sections. + auto from = llvm::find_if(sectionCommands, [&](BaseCommand *base) { + return isa(base) && + cast(base)->name == name; + }); + if (from == sectionCommands.end()) + continue; + moves.push_back(cast(*from)); + sectionCommands.erase(from); + } auto insertPos = llvm::find_if(sectionCommands, [&cmd](BaseCommand *base) { auto *to = dyn_cast(base); return to != nullptr && to->name == cmd.where; }); if (insertPos == sectionCommands.end()) { - error("unable to insert " + osec->name + + error("unable to insert " + cmd.names[0] + (cmd.isAfter ? " after " : " before ") + cmd.where); } else { if (cmd.isAfter) ++insertPos; - sectionCommands.insert(insertPos, osec); + sectionCommands.insert(insertPos, moves.begin(), moves.end()); } + moves.clear(); } } diff --git a/lld/ELF/ScriptParser.cpp b/lld/ELF/ScriptParser.cpp --- a/lld/ELF/ScriptParser.cpp +++ b/lld/ELF/ScriptParser.cpp @@ -596,9 +596,12 @@ else if (!consume("BEFORE")) setError("expected AFTER/BEFORE, but got '" + next() + "'"); StringRef where = next(); + std::vector names; for (BaseCommand *cmd : v) if (auto *os = dyn_cast(cmd)) - script->insertCommands.push_back({os->name, isAfter, where}); + names.push_back(os->name); + if (!names.empty()) + script->insertCommands.push_back({std::move(names), isAfter, where}); } void ScriptParser::readTarget() { diff --git a/lld/test/ELF/linkerscript/insert-multi.test b/lld/test/ELF/linkerscript/insert-multi.test new file mode 100644 --- /dev/null +++ b/lld/test/ELF/linkerscript/insert-multi.test @@ -0,0 +1,53 @@ +# REQUIRES: x86 +## Sections in an INSERT command are in a unit. Their order is preserved. + +# RUN: split-file %s %t +# RUN: llvm-mc -filetype=obj -triple=x86_64 %t/a.s -o %t/a.o +# RUN: ld.lld -T %t/a.lds %t/a.o -o %t1 +# RUN: llvm-readelf -S -l %t1 | FileCheck %s + +# CHECK: Name +# CHECK-NEXT: NULL +# CHECK-NEXT: text.3 +# CHECK-NEXT: text.4 +# CHECK-NEXT: text.5 +# CHECK-NEXT: .text +# CHECK-NEXT: .data +# CHECK-NEXT: text.6 +# CHECK-NEXT: text.7 +# CHECK-NEXT: text.8 +# CHECK-NEXT: text.0 +# CHECK-NEXT: text.1 +# CHECK-NEXT: text.2 + +#--- a.lds +SECTIONS { + text.0 : {} + text.1 : {} + text.2 : {} +} INSERT AFTER .data; + +SECTIONS { + text.3 : {} + text.4 : {} + text.5 : {} +} INSERT BEFORE .text; + +SECTIONS { + text.6 : {} + text.7 : {} + text.8 : {} +} INSERT AFTER .data; + +#--- a.s +.text; nop +.section text.0,"ax"; nop +.section text.1,"ax"; nop +.section text.2,"ax"; nop +.section text.3,"ax"; nop +.section text.4,"ax"; nop +.section text.5,"ax"; nop +.section text.6,"ax"; nop +.section text.7,"ax"; nop +.section text.8,"ax"; nop +.data; .byte 0