summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRui Ueyama <ruiu@google.com>2018-03-14 20:29:45 +0000
committerRui Ueyama <ruiu@google.com>2018-03-14 20:29:45 +0000
commitdb46a62e2bc56697347ccb681dc673b7e276d3ce (patch)
tree1c8d3fb7b2d5e86ab61efa3c533a488864dd8c08
parent115b0673b67fe826cee1bc7a145c324ec41c2140 (diff)
downloadbcm5719-llvm-db46a62e2bc56697347ccb681dc673b7e276d3ce.tar.gz
bcm5719-llvm-db46a62e2bc56697347ccb681dc673b7e276d3ce.zip
Implement --cref.
This is an option to print out a table of symbols and filenames. The output format of this option is the same as GNU, so that it can be processed by the same scripts as before after migrating from GNU to lld. This option is mildly useful; we can live without it. But it is pretty convenient sometimes, and it can be implemented in 50 lines of code, so I think lld should support this option. Differential Revision: https://reviews.llvm.org/D44336 llvm-svn: 327565
-rw-r--r--lld/ELF/Config.h1
-rw-r--r--lld/ELF/Driver.cpp1
-rw-r--r--lld/ELF/MapFile.cpp49
-rw-r--r--lld/ELF/MapFile.h1
-rw-r--r--lld/ELF/Options.td5
-rw-r--r--lld/ELF/Writer.cpp3
-rw-r--r--lld/test/ELF/cref.s26
-rw-r--r--lld/test/ELF/silent-ignore.test1
8 files changed, 84 insertions, 3 deletions
diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h
index 193a520ff67..2007992eaa2 100644
--- a/lld/ELF/Config.h
+++ b/lld/ELF/Config.h
@@ -113,6 +113,7 @@ struct Configuration {
bool BsymbolicFunctions;
bool CheckSections;
bool CompressDebugSections;
+ bool Cref;
bool DefineCommon;
bool Demangle = true;
bool DisableVerify;
diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp
index 4b83292040d..54529e06015 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -618,6 +618,7 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) {
Args.hasFlag(OPT_check_sections, OPT_no_check_sections, true);
Config->Chroot = Args.getLastArgValue(OPT_chroot);
Config->CompressDebugSections = getCompressDebugSections(Args);
+ Config->Cref = Args.hasFlag(OPT_cref, OPT_no_cref, false);
Config->DefineCommon = Args.hasFlag(OPT_define_common, OPT_no_define_common,
!Args.hasArg(OPT_relocatable));
Config->Demangle = Args.hasFlag(OPT_demangle, OPT_no_demangle, true);
diff --git a/lld/ELF/MapFile.cpp b/lld/ELF/MapFile.cpp
index 1887e8b264e..b8d4007968d 100644
--- a/lld/ELF/MapFile.cpp
+++ b/lld/ELF/MapFile.cpp
@@ -28,6 +28,8 @@
#include "SyntheticSections.h"
#include "lld/Common/Strings.h"
#include "lld/Common/Threads.h"
+#include "llvm/ADT/MapVector.h"
+#include "llvm/ADT/SetVector.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
@@ -146,3 +148,50 @@ void elf::writeMapFile() {
}
}
}
+
+static void print(StringRef A, StringRef B) {
+ outs() << left_justify(A, 49) << " " << B << "\n";
+}
+
+// Output a cross reference table to stdout. This is for --cref.
+//
+// For each global symbol, we print out a file that defines the symbol
+// followed by files that uses that symbol. Here is an example.
+//
+// strlen /lib/x86_64-linux-gnu/libc.so.6
+// tools/lld/tools/lld/CMakeFiles/lld.dir/lld.cpp.o
+// lib/libLLVMSupport.a(PrettyStackTrace.cpp.o)
+//
+// In this case, strlen is defined by libc.so.6 and used by other two
+// files.
+void elf::writeCrossReferenceTable() {
+ if (!Config->Cref)
+ return;
+
+ // Collect symbols and files.
+ MapVector<Symbol *, SetVector<InputFile *>> Map;
+ for (InputFile *File : ObjectFiles) {
+ for (Symbol *Sym : File->getSymbols()) {
+ if (isa<SharedSymbol>(Sym))
+ Map[Sym].insert(File);
+ if (auto *D = dyn_cast<Defined>(Sym))
+ if (!D->isLocal() && (!D->Section || D->Section->Live))
+ Map[D].insert(File);
+ }
+ }
+
+ // Print out a header.
+ outs() << "Cross Reference Table\n\n";
+ print("Symbol", "File");
+
+ // Print out a table.
+ for (auto KV : Map) {
+ Symbol *Sym = KV.first;
+ SetVector<InputFile *> &Files = KV.second;
+
+ print(toString(*Sym), toString(Sym->File));
+ for (InputFile *File : Files)
+ if (File != Sym->File)
+ print("", toString(File));
+ }
+}
diff --git a/lld/ELF/MapFile.h b/lld/ELF/MapFile.h
index 2d93e26d4cf..0282425888b 100644
--- a/lld/ELF/MapFile.h
+++ b/lld/ELF/MapFile.h
@@ -13,6 +13,7 @@
namespace lld {
namespace elf {
void writeMapFile();
+void writeCrossReferenceTable();
} // namespace elf
} // namespace lld
diff --git a/lld/ELF/Options.td b/lld/ELF/Options.td
index 40b996e07d1..82a2a1c1188 100644
--- a/lld/ELF/Options.td
+++ b/lld/ELF/Options.td
@@ -75,6 +75,10 @@ def color_diagnostics: F<"color-diagnostics">,
def color_diagnostics_eq: J<"color-diagnostics=">,
HelpText<"Use colors in diagnostics">;
+defm cref: B<"cref",
+ "Output cross reference table",
+ "Do not output cross reference table">;
+
defm define_common: B<"define-common",
"Assign space to common symbols",
"Do not assign space to common symbols">;
@@ -420,7 +424,6 @@ defm plugin: Eq<"plugin">;
// Options listed below are silently ignored for now for compatibility.
def allow_shlib_undefined: F<"allow-shlib-undefined">;
-def cref: F<"cref">;
def detect_odr_violations: F<"detect-odr-violations">;
def g: Flag<["-"], "g">;
def long_plt: F<"long-plt">;
diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index fc292d6f461..2490d1d5aec 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -475,8 +475,9 @@ template <class ELFT> void Writer<ELFT>::run() {
if (errorCount())
return;
- // Handle -Map option.
+ // Handle -Map and -cref options.
writeMapFile();
+ writeCrossReferenceTable();
if (errorCount())
return;
diff --git a/lld/test/ELF/cref.s b/lld/test/ELF/cref.s
new file mode 100644
index 00000000000..01516fa0eb2
--- /dev/null
+++ b/lld/test/ELF/cref.s
@@ -0,0 +1,26 @@
+// REQUIRES: x86
+
+// RUN: echo '.global foo; foo:' | llvm-mc -filetype=obj -triple=x86_64-pc-linux - -o %t1.o
+// RUN: echo '.global foo, bar; bar:' | llvm-mc -filetype=obj -triple=x86_64-pc-linux - -o %t2.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t3.o
+// RUN: ld.lld -shared -o %t1.so %t1.o -gc-sections
+// RUN: ld.lld -o /dev/null %t1.so %t2.o %t3.o -cref | FileCheck -strict-whitespace %s
+
+// CHECK: Symbol File
+// CHECK-NEXT: bar {{.*}}2.o
+// CHECK-NEXT: {{.*}}3.o
+// CHECK-NEXT: foo {{.*}}1.so
+// CHECK-NEXT: {{.*}}2.o
+// CHECK-NEXT: {{.*}}3.o
+// CHECK-NEXT: _start {{.*}}3.o
+// CHECK-NEXT: baz {{.*}}3.o
+
+.global _start, foo, bar, baz
+_start:
+ call foo
+ call bar
+localsym:
+baz:
+
+.section .text.a,"ax",@progbits
+discarded:
diff --git a/lld/test/ELF/silent-ignore.test b/lld/test/ELF/silent-ignore.test
index 6655754ace5..adfc2442d4e 100644
--- a/lld/test/ELF/silent-ignore.test
+++ b/lld/test/ELF/silent-ignore.test
@@ -1,6 +1,5 @@
RUN: ld.lld --version \
RUN: -allow-shlib-undefined \
-RUN: -cref \
RUN: -g \
RUN: -no-add-needed \
RUN: -no-allow-shlib-undefined \
OpenPOWER on IntegriCloud