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
This commit is contained in:
Rui Ueyama 2018-03-14 20:29:45 +00:00
parent 115b0673b6
commit db46a62e2b
8 changed files with 84 additions and 3 deletions

View File

@ -113,6 +113,7 @@ struct Configuration {
bool BsymbolicFunctions;
bool CheckSections;
bool CompressDebugSections;
bool Cref;
bool DefineCommon;
bool Demangle = true;
bool DisableVerify;

View File

@ -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);

View File

@ -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));
}
}

View File

@ -13,6 +13,7 @@
namespace lld {
namespace elf {
void writeMapFile();
void writeCrossReferenceTable();
} // namespace elf
} // namespace lld

View File

@ -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">;

View File

@ -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;

26
lld/test/ELF/cref.s Normal file
View File

@ -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:

View File

@ -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 \