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/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