[ELF] --cref: If -Map is specified, print to the map file
PR48282: This behavior matches GNU ld and gold.
Reviewed By: markj
Differential Revision: https://reviews.llvm.org/D114663
diff --git a/lld/ELF/MapFile.cpp b/lld/ELF/MapFile.cpp
index 7b8db00..0673580 100644
--- 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<Defined *> 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<Symbol *, SetVector<InputFile *>> 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/MapFile.h b/lld/ELF/MapFile.h
index 1b8c016..df54898 100644
--- 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/Options.td b/lld/ELF/Options.td
index 3bb358c..f9f9f54 100644
--- 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
index 423f989..07c5e23 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -565,9 +565,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/ReleaseNotes.rst b/lld/docs/ReleaseNotes.rst
index 9024599..a2456fc 100644
--- a/lld/docs/ReleaseNotes.rst
+++ b/lld/docs/ReleaseNotes.rst
@@ -31,6 +31,8 @@
* ``e_entry`` no longer falls back to the address of ``.text`` if the entry symbol does not exist.
Instead, a value of 0 will be written.
(`D110014 <https://reviews.llvm.org/D110014>`_)
+* If ``-Map`` is specified, ``--cref`` will be printted to the specified file.
+ (`D114663 <https://reviews.llvm.org/D114663>`_)
Architecture specific changes:
diff --git a/lld/docs/ld.lld.1 b/lld/docs/ld.lld.1
index 3bb3eb2..0422231 100644
--- 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
index 3098920..662a2ce 100644
--- 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: <internal>:(.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