Index: lld/trunk/ELF/Config.h =================================================================== --- lld/trunk/ELF/Config.h +++ lld/trunk/ELF/Config.h @@ -113,6 +113,7 @@ bool BsymbolicFunctions; bool CheckSections; bool CompressDebugSections; + bool Cref; bool DefineCommon; bool Demangle = true; bool DisableVerify; Index: lld/trunk/ELF/Driver.cpp =================================================================== --- lld/trunk/ELF/Driver.cpp +++ lld/trunk/ELF/Driver.cpp @@ -618,6 +618,7 @@ 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); Index: lld/trunk/ELF/MapFile.h =================================================================== --- lld/trunk/ELF/MapFile.h +++ lld/trunk/ELF/MapFile.h @@ -13,6 +13,7 @@ namespace lld { namespace elf { void writeMapFile(); +void writeCrossReferenceTable(); } // namespace elf } // namespace lld Index: lld/trunk/ELF/MapFile.cpp =================================================================== --- lld/trunk/ELF/MapFile.cpp +++ lld/trunk/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 @@ } } } + +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> Map; + for (InputFile *File : ObjectFiles) { + for (Symbol *Sym : File->getSymbols()) { + if (isa(Sym)) + Map[Sym].insert(File); + if (auto *D = dyn_cast(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 &Files = KV.second; + + print(toString(*Sym), toString(Sym->File)); + for (InputFile *File : Files) + if (File != Sym->File) + print("", toString(File)); + } +} Index: lld/trunk/ELF/Options.td =================================================================== --- lld/trunk/ELF/Options.td +++ lld/trunk/ELF/Options.td @@ -75,6 +75,10 @@ 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 @@ // 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">; Index: lld/trunk/ELF/Writer.cpp =================================================================== --- lld/trunk/ELF/Writer.cpp +++ lld/trunk/ELF/Writer.cpp @@ -475,8 +475,9 @@ if (errorCount()) return; - // Handle -Map option. + // Handle -Map and -cref options. writeMapFile(); + writeCrossReferenceTable(); if (errorCount()) return; Index: lld/trunk/test/ELF/cref.s =================================================================== --- lld/trunk/test/ELF/cref.s +++ lld/trunk/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: Index: lld/trunk/test/ELF/silent-ignore.test =================================================================== --- lld/trunk/test/ELF/silent-ignore.test +++ lld/trunk/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 \