Index: ELF/Config.h =================================================================== --- ELF/Config.h +++ ELF/Config.h @@ -36,6 +36,9 @@ // For --discard-{all,locals,none}. enum class DiscardPolicy { Default, All, Locals, None }; +// For --orphan-handling. +enum class OrphanHandlingPolicy { Place, Discard, Warn, Error }; + // For --strip-{all,debug}. enum class StripPolicy { None, All, Debug }; @@ -127,6 +130,7 @@ bool ZOrigin; bool ZRelro; DiscardPolicy Discard; + OrphanHandlingPolicy OrphanHandling; SortSectionPolicy SortSection; StripPolicy Strip = StripPolicy::None; UnresolvedPolicy UnresolvedSymbols; Index: ELF/Driver.cpp =================================================================== --- ELF/Driver.cpp +++ ELF/Driver.cpp @@ -407,6 +407,19 @@ return Ret; } +static OrphanHandlingPolicy getOrphanHandling(opt::InputArgList &Args) { + StringRef S = getString(Args, OPT_orphan_handling); + if (S == "discard") + return OrphanHandlingPolicy::Discard; + if (S == "warn") + return OrphanHandlingPolicy::Warn; + if (S == "error") + return OrphanHandlingPolicy::Error; + if (!S.empty() && S != "place") + error("unknown --orphan-handling mode: " + S); + return OrphanHandlingPolicy::Place; +} + static SortSectionPolicy getSortKind(opt::InputArgList &Args) { StringRef S = getString(Args, OPT_sort_section); if (S == "alignment") @@ -541,6 +554,8 @@ for (auto *Arg : Args.filtered(OPT_undefined)) Config->Undefined.push_back(Arg->getValue()); + Config->OrphanHandling = getOrphanHandling(Args); + Config->SortSection = getSortKind(Args); Config->UnresolvedSymbols = getUnresolvedSymbolOption(Args); Index: ELF/LinkerScript.h =================================================================== --- ELF/LinkerScript.h +++ ELF/LinkerScript.h @@ -198,6 +198,8 @@ std::vector *> *OutputSections; private: + void placeOrphans(OutputSectionFactory &Factory); + void computeInputSections(InputSectionDescription *); void addSection(OutputSectionFactory &Factory, Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -321,11 +321,32 @@ template void LinkerScript::createSections(OutputSectionFactory &Factory) { processCommands(Factory); - // Add orphan sections. - for (ObjectFile *F : Symtab::X->getObjectFiles()) - for (InputSectionBase *S : F->getSections()) - if (!isDiscarded(S) && !S->OutSec) + placeOrphans(Factory); +} + +template +void LinkerScript::placeOrphans(OutputSectionFactory &Factory) { + for (ObjectFile *F : Symtab::X->getObjectFiles()) { + for (InputSectionBase *S : F->getSections()) { + if (!isDiscarded(S) && !S->OutSec) { + if (Config->OrphanHandling == OrphanHandlingPolicy::Discard) { + discard({S}); + continue; + } + addSection(Factory, S, getOutputSectionName(S)); + if (Config->OrphanHandling == OrphanHandlingPolicy::Place) + continue; + + std::string Msg = "unplaced orphan section " + S->Name.str() + + " from " + getFilename(F); + if (Config->OrphanHandling == OrphanHandlingPolicy::Warn) + warning(Msg); + else + error(Msg); + } + } + } } // Sets value of a section-defined symbol. Two kinds of Index: ELF/Options.td =================================================================== --- ELF/Options.td +++ ELF/Options.td @@ -139,6 +139,9 @@ def oformat: Separate<["--"], "oformat">, MetaVarName<"">, HelpText<"Specify the binary format for the output object file">; +def orphan_handling: J<"orphan-handling=">, + HelpText<"Control how orphan sections are handled">; + def pie: F<"pie">, HelpText<"Create a position independent executable">; def print_gc_sections: F<"print-gc-sections">, Index: test/ELF/linkerscript/orphan-handling.s =================================================================== --- test/ELF/linkerscript/orphan-handling.s +++ test/ELF/linkerscript/orphan-handling.s @@ -0,0 +1,46 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o +# RUN: echo "SECTIONS { .foo.1 : { *(.foo.1) } }" > %t.script + +# RUN: ld.lld -o %t.out --script %t.script %t +# RUN: llvm-objdump -section-headers %t.out | FileCheck %s +# RUN: ld.lld --orphan-handling=place -o %t2.out --script %t.script %t +# RUN: llvm-objdump -section-headers %t2.out | FileCheck %s +# CHECK: .foo.1 +# CHECK: .foo.2 +# CHECK: .foo.3 + +# RUN: ld.lld --orphan-handling=discard -o %t3.out --script %t.script %t.o +# RUN: llvm-objdump -section-headers %t3.out | FileCheck %s --check-prefix=DISCARD +# DISCARD: .foo.1 +# DISCARD-NOT: .foo.2 +# DISCARD-NOT: .foo.3 + +# RUN: not ld.lld --orphan-handling=error -o %t4.out --script %t.script %t.o 2>&1 \ +# RUN: | FileCheck %s --check-prefix=ERROR +# ERROR: unplaced orphan section .text from {{.*}}.o +# ERROR: unplaced orphan section .foo.2 from {{.*}}.o +# ERROR: unplaced orphan section .foo.3 from {{.*}}.o + +# RUN: ld.lld --orphan-handling=warn -o %t5.out --script %t.script %t.o 2>&1 \ +# RUN: | FileCheck %s --check-prefix=WARN +# WARN: unplaced orphan section .text from {{.*}}.o +# WARN: unplaced orphan section .foo.2 from {{.*}}.o +# WARN: unplaced orphan section .foo.3 from {{.*}}.o + +# RUN: not ld.lld --orphan-handling=foo -o %t5.out --script %t.script %t.o 2>&1 \ +# RUN: | FileCheck %s --check-prefix=UNKNOWN +# UNKNOWN: unknown --orphan-handling mode: foo + +.text +.globl _start +_start: + +.section .foo.1,"a" + .quad 1 + +.section .foo.2,"a" + .quad 2 + +.section .foo.3,"a" + .quad 3