diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h --- a/lld/ELF/Config.h +++ b/lld/ELF/Config.h @@ -194,6 +194,7 @@ bool timeTraceEnabled; bool tocOptimize; bool undefinedVersion; + bool unique = false; bool useAndroidRelrTags = false; bool warnBackrefs; bool warnCommon; diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -967,6 +967,7 @@ config->splitStackAdjustSize = args::getInteger(args, OPT_split_stack_adjust_size, 16384); config->strip = getStrip(args); config->sysroot = args.getLastArgValue(OPT_sysroot); + config->unique = args.hasArg(OPT_unique); config->target1Rel = args.hasFlag(OPT_target1_rel, OPT_target1_abs, false); config->target2 = getTarget2(args); config->thinLTOCacheDir = args.getLastArgValue(OPT_thinlto_cache_dir); diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp --- a/lld/ELF/LinkerScript.cpp +++ b/lld/ELF/LinkerScript.cpp @@ -680,24 +680,27 @@ std::function add; add = [&](InputSectionBase *s) { - if (s->isLive() && !s->parent) { - orphanSections.push_back(s); - - StringRef name = getOutputSectionName(s); - if (OutputSection *sec = findByName(sectionCommands, name)) { - sec->recordSection(s); - } else { - if (OutputSection *os = addInputSec(map, s, name)) - v.push_back(os); - assert(isa(s) || - s->getOutputSection()->sectionIndex == UINT32_MAX); + if (s->isLive() && !s->parent) { + orphanSections.push_back(s); + + StringRef name = getOutputSectionName(s); + + if (config->unique) { + v.push_back(createSection(s, name)); + } else if (OutputSection *sec = findByName(sectionCommands, name)) { + sec->recordSection(s); + } else { + if (OutputSection *os = addInputSec(map, s, name)) + v.push_back(os); + assert(isa(s) || + s->getOutputSection()->sectionIndex == UINT32_MAX); + } } - } - if (config->relocatable) - for (InputSectionBase *depSec : s->dependentSections) - if (depSec->flags & SHF_LINK_ORDER) - add(depSec); + if (config->relocatable) + for (InputSectionBase *depSec : s->dependentSections) + if (depSec->flags & SHF_LINK_ORDER) + add(depSec); }; // For futher --emit-reloc handling code we need target output section diff --git a/lld/ELF/Options.td b/lld/ELF/Options.td --- a/lld/ELF/Options.td +++ b/lld/ELF/Options.td @@ -374,6 +374,8 @@ defm undefined_glob: Eq<"undefined-glob", "Force undefined symbol during linking">, MetaVarName<"">; +def unique: F<"unique">, HelpText<"Creates a separate output section for every orphan input section">; + defm unresolved_symbols: Eq<"unresolved-symbols", "Determine how to handle unresolved symbols">; diff --git a/lld/docs/ld.lld.1 b/lld/docs/ld.lld.1 --- a/lld/docs/ld.lld.1 +++ b/lld/docs/ld.lld.1 @@ -553,6 +553,8 @@ All symbols that match a given pattern are handled as if they were given as arguments of .Fl -undefined . +.It Fl -unique +Creates a separate output section for every orphan input section. .It Fl -unresolved-symbols Ns = Ns Ar value Determine how to handle unresolved symbols. .It Fl -use-android-relr-tags diff --git a/lld/test/ELF/unique-orphans.s b/lld/test/ELF/unique-orphans.s new file mode 100644 --- /dev/null +++ b/lld/test/ELF/unique-orphans.s @@ -0,0 +1,29 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o + +.section .foo,"a",@progbits,unique,1 +.byte 1 + +.section .foo,"a",@progbits,unique,2 +.byte 2 + +.section .foo,"a",@progbits,unique,3 +.byte 3 + +## We should have 3 instances of orphan section foo. +## Test with -r +# RUN: ld.lld %t.o -r -o %t.ro --unique +# RUN: llvm-readelf -S %t.ro | FileCheck %s +## Test for execuable link +# RUN: ld.lld %t.o -o %t.elf --unique +# RUN: llvm-readelf -S %t.elf | FileCheck %s + +# CHECK-COUNT-3: .foo +# CHECK-NOT: .foo + +## Test that --unique does not affect sections specified in output section descriptions. +# RUN: echo 'SECTIONS { .foo : { *(.foo) }}' > %t.script +# RUN: ld.lld %t.o -o %t2.elf -T %t.script --unique +# RUN: llvm-readelf -S %t2.elf | FileCheck --check-prefix UNIQUE_SCRIPT %s +# UNIQUE_SCRIPT: .foo +# UNIQUE_SCRIPT-NOT: .foo