summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lld/ELF/Config.h1
-rw-r--r--lld/ELF/Driver.cpp1
-rw-r--r--lld/ELF/Options.td3
-rw-r--r--lld/ELF/Writer.cpp14
-rw-r--r--lld/test/ELF/gc-sections-print.s23
5 files changed, 41 insertions, 1 deletions
diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h
index 4aee5a5cb10..299a0df1858 100644
--- a/lld/ELF/Config.h
+++ b/lld/ELF/Config.h
@@ -58,6 +58,7 @@ struct Configuration {
bool Mips64EL = false;
bool NoInhibitExec;
bool NoUndefined;
+ bool PrintGcSections;
bool Shared;
bool Static = false;
bool StripAll;
diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp
index b515ddc7bc3..2f1cf9be4df 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -163,6 +163,7 @@ void LinkerDriver::createFiles(opt::InputArgList &Args) {
Config->GcSections = Args.hasArg(OPT_gc_sections);
Config->NoInhibitExec = Args.hasArg(OPT_noinhibit_exec);
Config->NoUndefined = Args.hasArg(OPT_no_undefined);
+ Config->PrintGcSections = Args.hasArg(OPT_print_gc_sections);
Config->Shared = Args.hasArg(OPT_shared);
Config->StripAll = Args.hasArg(OPT_strip_all);
Config->Verbose = Args.hasArg(OPT_verbose);
diff --git a/lld/ELF/Options.td b/lld/ELF/Options.td
index 6a95e2b92fd..bfa87ac9fbc 100644
--- a/lld/ELF/Options.td
+++ b/lld/ELF/Options.td
@@ -79,6 +79,9 @@ def no_undefined : Flag<["--"], "no-undefined">,
def o : Separate<["-"], "o">, MetaVarName<"<path>">,
HelpText<"Path to file to write output">;
+def print_gc_sections: Flag<["--"], "print-gc-sections">,
+ HelpText<"List removed unused sections">;
+
def rpath : Separate<["-"], "rpath">,
HelpText<"Add a DT_RUNPATH to the output">;
diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index 465dc68a3c0..1a86881c5b4 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -16,6 +16,7 @@
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/FileOutputBuffer.h"
+#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/StringSaver.h"
using namespace llvm;
@@ -532,6 +533,15 @@ StringRef Writer<ELFT>::getOutputSectionName(StringRef S) const {
}
template <class ELFT>
+void reportDiscarded(InputSectionBase<ELFT> *IS,
+ const std::unique_ptr<ObjectFile<ELFT>> &File) {
+ if (!Config->PrintGcSections || !IS || IS->isLive())
+ return;
+ llvm::errs() << "removing unused section from '" << IS->getSectionName()
+ << "' in file '" << File->getName() << "'\n";
+}
+
+template <class ELFT>
bool Writer<ELFT>::isDiscarded(InputSectionBase<ELFT> *IS) const {
if (!IS || !IS->isLive() || IS == &InputSection<ELFT>::Discarded)
return true;
@@ -564,8 +574,10 @@ template <class ELFT> void Writer<ELFT>::createSections() {
for (const std::unique_ptr<ObjectFile<ELFT>> &F : Symtab.getObjectFiles()) {
for (InputSectionBase<ELFT> *C : F->getSections()) {
- if (isDiscarded(C))
+ if (isDiscarded(C)) {
+ reportDiscarded(C, F);
continue;
+ }
const Elf_Shdr *H = C->getSectionHdr();
uintX_t OutFlags = H->sh_flags & ~SHF_GROUP;
// For SHF_MERGE we create different output sections for each sh_entsize.
diff --git a/lld/test/ELF/gc-sections-print.s b/lld/test/ELF/gc-sections-print.s
new file mode 100644
index 00000000000..59177a65367
--- /dev/null
+++ b/lld/test/ELF/gc-sections-print.s
@@ -0,0 +1,23 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: ld.lld %t --gc-sections --print-gc-sections -o %t2 2>&1 | FileCheck -check-prefix=PRINT %s
+
+# PRINT: removing unused section from '.text.x' in file
+# PRINT-NEXT: removing unused section from '.text.y' in file
+
+.globl _start
+.protected a, x, y
+_start:
+ call a
+
+.section .text.a,"ax",@progbits
+a:
+ nop
+
+.section .text.x,"ax",@progbits
+x:
+ nop
+
+.section .text.y,"ax",@progbits
+y:
+ nop
OpenPOWER on IntegriCloud