diff --git a/lld/ELF/MapFile.h b/lld/ELF/MapFile.h --- a/lld/ELF/MapFile.h +++ b/lld/ELF/MapFile.h @@ -11,9 +11,8 @@ namespace lld { namespace elf { -void writeMapFile(); +void writeMapAndCref(); void writeWhyExtract(); -void writeCrossReferenceTable(); void writeArchiveStats(); } // namespace elf } // namespace lld diff --git a/lld/ELF/MapFile.cpp b/lld/ELF/MapFile.cpp --- a/lld/ELF/MapFile.cpp +++ b/lld/ELF/MapFile.cpp @@ -139,20 +139,7 @@ } } -void elf::writeMapFile() { - if (config->mapFile.empty()) - return; - - llvm::TimeTraceScope timeScope("Write map file"); - - // Open a map file for writing. - std::error_code ec; - raw_fd_ostream os(config->mapFile, ec, sys::fs::OF_None); - if (ec) { - error("cannot open " + config->mapFile + ": " + ec.message()); - return; - } - +static void writeMapFile(raw_fd_ostream &os) { // Collect symbol info that we want to print out. std::vector syms = getSymbols(); SymbolMapTy sectionSyms = getSectionSyms(syms); @@ -235,10 +222,6 @@ } } -static void print(StringRef a, StringRef b) { - lld::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 @@ -250,10 +233,7 @@ // // In this case, strlen is defined by libc.so.6 and used by other two // files. -void elf::writeCrossReferenceTable() { - if (!config->cref) - return; - +static void writeCref(raw_fd_ostream &os) { // Collect symbols and files. MapVector> map; for (InputFile *file : objectFiles) { @@ -266,8 +246,12 @@ } } - // Print out a header. - lld::outs() << "Cross Reference Table\n\n"; + auto print = [&](StringRef a, StringRef b) { + os << left_justify(a, 49) << ' ' << b << '\n'; + }; + + // Print a blank line and a header. The format matches GNU ld. + os << "\nCross Reference Table\n\n"; print("Symbol", "File"); // Print out a table. @@ -282,6 +266,27 @@ } } +void elf::writeMapAndCref() { + if (config->mapFile.empty() && !config->cref) + return; + + llvm::TimeTraceScope timeScope("Write map file"); + + // Open a map file for writing. + std::error_code ec; + StringRef mapFile = config->mapFile.empty() ? "-" : config->mapFile; + raw_fd_ostream os(mapFile, ec, sys::fs::OF_None); + if (ec) { + error("cannot open " + mapFile + ": " + ec.message()); + return; + } + + if (!config->mapFile.empty()) + writeMapFile(os); + if (config->cref) + writeCref(os); +} + void elf::writeArchiveStats() { if (config->printArchiveStats.empty()) return; diff --git a/lld/ELF/Options.td b/lld/ELF/Options.td --- a/lld/ELF/Options.td +++ b/lld/ELF/Options.td @@ -129,7 +129,8 @@ HelpText<"Use colors in diagnostics (default: auto)">, MetaVarName<"[auto,always,never]">; -def cref: FF<"cref">, HelpText<"Output cross reference table">; +def cref: FF<"cref">, + HelpText<"Output cross reference table. If -Map is specified, print to the map file">; defm define_common: B<"define-common", "Assign space to common symbols", diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -562,9 +562,8 @@ // --print-archive-stats=. Dump them before checkSections() because the files // may be useful in case checkSections() or openFile() fails, for example, due // to an erroneous file size. - writeMapFile(); + writeMapAndCref(); writeWhyExtract(); - writeCrossReferenceTable(); writeArchiveStats(); if (config->checkSections) diff --git a/lld/docs/ld.lld.1 b/lld/docs/ld.lld.1 --- a/lld/docs/ld.lld.1 +++ b/lld/docs/ld.lld.1 @@ -141,7 +141,9 @@ .Fl O2 to set the compression level to 6. .It Fl -cref -Output cross reference table. +Output cross reference table. If +.Fl Map +is specified, print to the map file. .It Fl -define-common , Fl d Assign space to common symbols. .It Fl -defsym Ns = Ns Ar symbol Ns = Ns Ar expression diff --git a/lld/test/ELF/cref.s b/lld/test/ELF/cref.s --- a/lld/test/ELF/cref.s +++ b/lld/test/ELF/cref.s @@ -9,7 +9,14 @@ // RUN: ld.lld -shared -o %t1.so %t1.o // RUN: ld.lld -o /dev/null %t1.so %t2.o %t3.o %t.a --gc-sections --cref | FileCheck -strict-whitespace %s -// CHECK: Symbol File +/// If -Map is specified, print to the map file. +// RUN: ld.lld -o /dev/null %t1.so %t2.o %t3.o %t.a --gc-sections -Map=%t.map --cref +// RUN: FileCheck --input-file=%t.map %s --check-prefix=CHECK2 + +// CHECK: {{^$}} +// CHECK-NEXT: Cross Reference Table +// CHECK-EMPTY: +// CHECK-NEXT: Symbol File // CHECK-NEXT: foo {{.*}}1.so // CHECK-NEXT: {{.*}}2.o // CHECK-NEXT: {{.*}}3.o @@ -21,6 +28,14 @@ // CHECK-NEXT: {{.*}}3.o // CHECK-NOT: discarded +// CHECK2: VMA LMA Size Align Out In Symbol +// CHECK2: .strtab +// CHECK2-NEXT: :(.strtab) + +/// There is a blank line before the "Cross Reference Table" header. +// CHECK2-EMPTY: +// CHECK2-NEXT: Cross Reference Table + .global _start, foo, bar, baz, discarded _start: call foo