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 @@ -684,13 +684,18 @@ orphanSections.push_back(s); StringRef name = getOutputSectionName(s); - if (OutputSection *sec = findByName(sectionCommands, name)) { - sec->recordSection(s); + + if (config->unique) { + v.push_back(createSection(s, name)); } else { - if (OutputSection *os = addInputSec(map, s, name)) - v.push_back(os); - assert(isa(s) || - s->getOutputSection()->sectionIndex == UINT32_MAX); + 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); + } } } 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,9 @@ 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/test/ELF/Inputs/unique-orphans.s b/lld/test/ELF/Inputs/unique-orphans.s new file mode 100644 --- /dev/null +++ b/lld/test/ELF/Inputs/unique-orphans.s @@ -0,0 +1,16 @@ + .text + .section .text.bar_2,"ax",@progbits + .globl bar_2 + .type bar_2,@function +bar_2: + callq foo + retq +.Lfunc_end0: + .size bar_2, .Lfunc_end0-bar_2 + + .section .text.foo,"ax",@progbits + .type foo,@function +foo: + retq +.Lfunc_end1: + .size foo, .Lfunc_end1-foo \ No newline at end of file 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,33 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/unique-orphans.s -o %t2.o + + .text + .section .text.bar,"ax",@progbits + .globl bar + .type bar,@function +bar: + callq foo + retq +.Lfunc_end0: + .size bar, .Lfunc_end0-bar + + .section .text.foo,"ax",@progbits + .type foo,@function +foo: + retq +.Lfunc_end1: + .size foo, .Lfunc_end1-foo + +# We should have 2 instance of orphan section .text.foo +# RUN: ld.lld %t1.o %t2.o -r -o %t3.ro --unique +# RUN: objdump -h %t3.ro | FileCheck --check-prefix UNIQUE %s +# UNIQUE-COUNT-2: .text.foo +# UNIQUE-NOT: .text.foo + +# Check that the orphan section .text.foo has been merged +# RUN: ld.lld %t1.o %t2.o -r -o %t3.ro +# RUN: objdump -h %t3.ro | FileCheck %s +# CHECK-COUNT-1: .text.foo +# CHECK-NOT: .text.foo