[ELF] - Implement --orphan-handling option.
authorGeorge Rimar <grimar@accesssoftek.com>
Wed, 25 Oct 2017 15:20:30 +0000 (15:20 +0000)
committerGeorge Rimar <grimar@accesssoftek.com>
Wed, 25 Oct 2017 15:20:30 +0000 (15:20 +0000)
It is PR34946.

Spec (http://man7.org/linux/man-pages/man1/ld.1.html) tells about
--orphan-handling=MODE, option where MODE can be one of four:
"place", "discard", "warn", "error".
Currently we already report orphans when -verbose given,
what becomes excessive with option implemented.

Patch stops reporting orphans when -versbose is given,
and support "place", "warn" and "error" modes.
It is not yet clear that "discard" mode is useful so it is not supported.

Differential revision: https://reviews.llvm.org/D39000

llvm-svn: 316583

lld/ELF/Config.h
lld/ELF/Driver.cpp
lld/ELF/LinkerScript.cpp
lld/ELF/Options.td
lld/test/ELF/linkerscript/orphan-report.s

index d753af7..8da6d4c 100644 (file)
@@ -46,6 +46,9 @@ enum class StripPolicy { None, All, Debug };
 // For --unresolved-symbols.
 enum class UnresolvedPolicy { ReportError, Warn, Ignore, IgnoreAll };
 
+// For --orphan-handling.
+enum class OrphanHandlingPolicy { Place, Warn, Error };
+
 // For --sort-section and linkerscript sorting rules.
 enum class SortSectionPolicy { Default, None, Alignment, Name, Priority };
 
@@ -155,6 +158,7 @@ struct Configuration {
   bool ExitEarly;
   bool ZWxneeded;
   DiscardPolicy Discard;
+  OrphanHandlingPolicy OrphanHandling;
   SortSectionPolicy SortSection;
   StripPolicy Strip;
   UnresolvedPolicy UnresolvedSymbols;
index 73bc3c3..5ffc877 100644 (file)
@@ -554,6 +554,17 @@ static SortSectionPolicy getSortSection(opt::InputArgList &Args) {
   return SortSectionPolicy::Default;
 }
 
+static OrphanHandlingPolicy getOrphanHandling(opt::InputArgList &Args) {
+  StringRef S = Args.getLastArgValue(OPT_orphan_handling, "place");
+  if (S == "warn")
+    return OrphanHandlingPolicy::Warn;
+  if (S == "error")
+    return OrphanHandlingPolicy::Error;
+  if (S != "place")
+    error("unknown --orphan-handling mode: " + S);
+  return OrphanHandlingPolicy::Place;
+}
+
 // Parse --build-id or --build-id=<style>. We handle "tree" as a
 // synonym for "sha1" because all our hash functions including
 // -build-id=sha1 are actually tree hashes for performance reasons.
@@ -656,6 +667,7 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) {
   Config->OptRemarksFilename = Args.getLastArgValue(OPT_opt_remarks_filename);
   Config->OptRemarksWithHotness = Args.hasArg(OPT_opt_remarks_with_hotness);
   Config->Optimize = getInteger(Args, OPT_O, 1);
+  Config->OrphanHandling = getOrphanHandling(Args);
   Config->OutputFile = Args.getLastArgValue(OPT_o);
   Config->Pie = Args.hasFlag(OPT_pie, OPT_nopie, false);
   Config->PrintGcSections = Args.hasArg(OPT_print_gc_sections);
index ff7b9f1..1f25de7 100644 (file)
@@ -457,6 +457,13 @@ static OutputSection *findByName(ArrayRef<BaseCommand *> Vec,
   return nullptr;
 }
 
+static void reportOrphan(InputSectionBase *IS, StringRef Name) {
+  if (Config->OrphanHandling == OrphanHandlingPolicy::Error)
+    error(toString(IS) + " is being placed in '" + Name + "'");
+  else if (Config->OrphanHandling == OrphanHandlingPolicy::Warn)
+    warn(toString(IS) + " is being placed in '" + Name + "'");
+}
+
 // Add sections that didn't match any sections command.
 void LinkerScript::addOrphanSections(OutputSectionFactory &Factory) {
   unsigned End = SectionCommands.size();
@@ -466,7 +473,7 @@ void LinkerScript::addOrphanSections(OutputSectionFactory &Factory) {
       continue;
 
     StringRef Name = getOutputSectionName(S->Name);
-    log(toString(S) + " is being placed in '" + Name + "'");
+    reportOrphan(S, Name);
 
     if (OutputSection *Sec =
             findByName(makeArrayRef(SectionCommands).slice(0, End), Name)) {
index 316c116..6596f97 100644 (file)
@@ -219,6 +219,9 @@ def oformat: Separate<["--"], "oformat">, MetaVarName<"<format>">,
 def omagic: Flag<["--"], "omagic">, MetaVarName<"<magic>">,
   HelpText<"Set the text and data sections to be readable and writable">;
 
+defm orphan_handling: Eq<"orphan-handling">, 
+  HelpText<"Control how orphan sections are handled when linker script used">;
+
 def pie: F<"pie">, HelpText<"Create a position independent executable">;
 
 def print_gc_sections: F<"print-gc-sections">,
index a5a179d..241857b 100644 (file)
@@ -1,31 +1,51 @@
 # REQUIRES: x86
 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
 # RUN: echo "SECTIONS { .text : { *(.text.1) } }" > %t.script
-# RUN: ld.lld --hash-style=sysv -shared -o %t.out --script %t.script %t.o --verbose | FileCheck %s
 
-# CHECK:      {{.*}}.o:(.text) is being placed in '.text'
-# CHECK-NEXT: {{.*}}.o:(.text.2) is being placed in '.text'
-# CHECK-NEXT: <internal>:(.comment) is being placed in '.comment'
-# CHECK-NEXT: <internal>:(.bss) is being placed in '.bss'
-# CHECK-NEXT: <internal>:(.bss.rel.ro) is being placed in '.bss.rel.ro'
-# CHECK-NEXT: <internal>:(.dynsym) is being placed in '.dynsym'
-# CHECK-NEXT: <internal>:(.gnu.version) is being placed in '.gnu.version'
-# CHECK-NEXT: <internal>:(.gnu.version_r) is being placed in '.gnu.version_r'
-# CHECK-NEXT: <internal>:(.hash) is being placed in '.hash'
-# CHECK-NEXT: <internal>:(.dynamic) is being placed in '.dynamic'
-# CHECK-NEXT: <internal>:(.dynstr) is being placed in '.dynstr'
-# CHECK-NEXT: <internal>:(.rela.dyn) is being placed in '.rela.dyn'
-# CHECK-NEXT: <internal>:(.got) is being placed in '.got'
-# CHECK-NEXT: <internal>:(.got.plt) is being placed in '.got.plt'
-# CHECK-NEXT: <internal>:(.got.plt) is being placed in '.got.plt'
-# CHECK-NEXT: <internal>:(.rela.plt) is being placed in '.rela.plt'
-# CHECK-NEXT: <internal>:(.rela.plt) is being placed in '.rela.plt'
-# CHECK-NEXT: <internal>:(.plt) is being placed in '.plt'
-# CHECK-NEXT: <internal>:(.plt) is being placed in '.plt'
-# CHECK-NEXT: <internal>:(.eh_frame) is being placed in '.eh_frame'
-# CHECK-NEXT: <internal>:(.symtab) is being placed in '.symtab'
-# CHECK-NEXT: <internal>:(.shstrtab) is being placed in '.shstrtab'
-# CHECK-NEXT: <internal>:(.strtab) is being placed in '.strtab'
+## Check we do not report orphans by default even with -verbose.
+# RUN: ld.lld -shared -o %t.out --script %t.script %t.o 2>&1 -verbose \
+# RUN:   | FileCheck %s --check-prefix=DEFAULT
+# DEFAULT-NOT: placed
+
+## Check --orphan-handling=place has the same behavior as default.
+# RUN: ld.lld -shared --orphan-handling=place -o %t.out --script %t.script \
+# RUN:   %t.o 2>&1 -verbose  -error-limit=0 | FileCheck %s --check-prefix=DEFAULT
+
+## Check --orphan-handling=error reports errors about orphans.
+# RUN: not ld.lld -shared --orphan-handling=error -o %t.out --script %t.script \
+# RUN:   %t.o 2>&1 -verbose  -error-limit=0 | FileCheck %s --check-prefix=REPORT
+# REPORT:      {{.*}}.o:(.text) is being placed in '.text'
+# REPORT-NEXT: {{.*}}.o:(.text.2) is being placed in '.text'
+# REPORT-NEXT: <internal>:(.comment) is being placed in '.comment'
+# REPORT-NEXT: <internal>:(.bss) is being placed in '.bss'
+# REPORT-NEXT: <internal>:(.bss.rel.ro) is being placed in '.bss.rel.ro'
+# REPORT-NEXT: <internal>:(.dynsym) is being placed in '.dynsym'
+# REPORT-NEXT: <internal>:(.gnu.version) is being placed in '.gnu.version'
+# REPORT-NEXT: <internal>:(.gnu.version_r) is being placed in '.gnu.version_r'
+# REPORT-NEXT: <internal>:(.gnu.hash) is being placed in '.gnu.hash'
+# REPORT-NEXT: <internal>:(.hash) is being placed in '.hash'
+# REPORT-NEXT: <internal>:(.dynamic) is being placed in '.dynamic'
+# REPORT-NEXT: <internal>:(.dynstr) is being placed in '.dynstr'
+# REPORT-NEXT: <internal>:(.rela.dyn) is being placed in '.rela.dyn'
+# REPORT-NEXT: <internal>:(.got) is being placed in '.got'
+# REPORT-NEXT: <internal>:(.got.plt) is being placed in '.got.plt'
+# REPORT-NEXT: <internal>:(.got.plt) is being placed in '.got.plt'
+# REPORT-NEXT: <internal>:(.rela.plt) is being placed in '.rela.plt'
+# REPORT-NEXT: <internal>:(.rela.plt) is being placed in '.rela.plt'
+# REPORT-NEXT: <internal>:(.plt) is being placed in '.plt'
+# REPORT-NEXT: <internal>:(.plt) is being placed in '.plt'
+# REPORT-NEXT: <internal>:(.eh_frame) is being placed in '.eh_frame'
+# REPORT-NEXT: <internal>:(.symtab) is being placed in '.symtab'
+# REPORT-NEXT: <internal>:(.shstrtab) is being placed in '.shstrtab'
+# REPORT-NEXT: <internal>:(.strtab) is being placed in '.strtab'
+
+## Check --orphan-handling=warn reports warnings about orphans.
+# RUN: ld.lld -shared --orphan-handling=warn -o %t.out --script %t.script \
+# RUN:   %t.o 2>&1 -verbose | FileCheck %s --check-prefix=REPORT
+
+# RUN: not ld.lld --orphan-handling=foo -o %t.out --script %t.script %t.o 2>&1 \
+# RUN:   | FileCheck %s --check-prefix=UNKNOWN
+# UNKNOWN: unknown --orphan-handling mode: foo
 
 .section .text.1,"a"
  nop