[lld] ed8bff1 - [lld-macho] implement options -map

Jez Ng via llvm-commits llvm-commits at lists.llvm.org
Thu Mar 18 07:39:30 PDT 2021


Author: caoming.roy
Date: 2021-03-18T10:39:19-04:00
New Revision: ed8bff13dcaa123721e0117fb586c3124c03a421

URL: https://github.com/llvm/llvm-project/commit/ed8bff13dcaa123721e0117fb586c3124c03a421
DIFF: https://github.com/llvm/llvm-project/commit/ed8bff13dcaa123721e0117fb586c3124c03a421.diff

LOG: [lld-macho] implement options -map

Implement command-line options -map

Reviewed By: int3, #lld-macho

Differential Revision: https://reviews.llvm.org/D98323

Added: 
    lld/MachO/MapFile.cpp
    lld/MachO/MapFile.h
    lld/test/MachO/map-file.s

Modified: 
    lld/MachO/CMakeLists.txt
    lld/MachO/Config.h
    lld/MachO/Driver.cpp
    lld/MachO/Options.td
    lld/MachO/Writer.cpp

Removed: 
    


################################################################################
diff  --git a/lld/MachO/CMakeLists.txt b/lld/MachO/CMakeLists.txt
index 8eb3371580b7..16b372945d07 100644
--- a/lld/MachO/CMakeLists.txt
+++ b/lld/MachO/CMakeLists.txt
@@ -24,6 +24,7 @@ add_lld_library(lldMachO2
   Symbols.cpp
   SyntheticSections.cpp
   Target.cpp
+  MapFile.cpp
   Writer.cpp
 
   LINK_COMPONENTS

diff  --git a/lld/MachO/Config.h b/lld/MachO/Config.h
index 93c6a11c0808..611440185837 100644
--- a/lld/MachO/Config.h
+++ b/lld/MachO/Config.h
@@ -88,6 +88,7 @@ struct Configuration {
   uint32_t timeTraceGranularity;
   std::string progName;
   llvm::StringRef installName;
+  llvm::StringRef mapFile;
   llvm::StringRef outputFile;
   llvm::StringRef ltoObjPath;
   bool demangle = false;

diff  --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp
index 207dc4f36e6a..c85b72564213 100644
--- a/lld/MachO/Driver.cpp
+++ b/lld/MachO/Driver.cpp
@@ -826,6 +826,7 @@ bool macho::link(ArrayRef<const char *> argsArr, bool canExitEarly,
   for (const Arg *arg : args.filtered(OPT_U))
     symtab->addDynamicLookup(arg->getValue());
 
+  config->mapFile = args.getLastArgValue(OPT_map);
   config->outputFile = args.getLastArgValue(OPT_o, "a.out");
   config->headerPad = args::getHex(args, OPT_headerpad, /*Default=*/32);
   config->headerPadMaxInstallNames =

diff  --git a/lld/MachO/MapFile.cpp b/lld/MachO/MapFile.cpp
new file mode 100644
index 000000000000..e089136ee218
--- /dev/null
+++ b/lld/MachO/MapFile.cpp
@@ -0,0 +1,151 @@
+//===- MapFile.cpp --------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the -map option. It shows lists in order and
+// hierarchically the outputFile, arch, input files, output sections and
+// symbol:
+//
+// # Path: test
+// # Arch: x86_84
+// # Object files:
+// [  0] linker synthesized
+// [  1] a.o
+// # Sections:
+// # Address  Size      Segment  Section
+// 0x1000005C0  0x0000004C  __TEXT  __text
+// # Symbols:
+// # Address  File  Name
+// 0x1000005C0  [  1] _main
+//
+//===----------------------------------------------------------------------===//
+
+#include "MapFile.h"
+#include "Config.h"
+#include "InputFiles.h"
+#include "InputSection.h"
+#include "OutputSection.h"
+#include "OutputSegment.h"
+#include "Symbols.h"
+#include "Target.h"
+#include "llvm/Support/Parallel.h"
+
+using namespace llvm;
+using namespace llvm::sys;
+using namespace lld;
+using namespace lld::macho;
+
+using SymbolMapTy = DenseMap<const InputSection *, SmallVector<Defined *, 4>>;
+
+// Returns a map from sections to their symbols.
+static SymbolMapTy getSectionSyms(ArrayRef<Defined *> syms) {
+  SymbolMapTy ret;
+  for (Defined *dr : syms)
+    ret[dr->isec].push_back(dr);
+
+  // Sort symbols by address. We want to print out symbols in the
+  // order in the output file rather than the order they appeared
+  // in the input files.
+  for (auto &it : ret)
+    llvm::stable_sort(it.second, [](Defined *a, Defined *b) {
+      return a->getVA() < b->getVA();
+    });
+  return ret;
+}
+
+// Returns a list of all symbols that we want to print out.
+static std::vector<Defined *> getSymbols() {
+  std::vector<Defined *> v;
+  for (InputFile *file : inputFiles)
+    if (isa<ObjFile>(file))
+      for (Symbol *sym : file->symbols) {
+        if (sym == nullptr)
+          continue;
+        if (auto *d = dyn_cast<Defined>(sym))
+          if (d->isec && d->getFile() == file)
+            v.push_back(d);
+      }
+  return v;
+}
+
+// Construct a map from symbols to their stringified representations.
+// Demangling symbols (which is what toString() does) is slow, so
+// we do that in batch using parallel-for.
+static DenseMap<macho::Symbol *, std::string>
+getSymbolStrings(ArrayRef<Defined *> syms) {
+  std::vector<std::string> str(syms.size());
+  parallelForEachN(0, syms.size(), [&](size_t i) {
+    raw_string_ostream os(str[i]);
+    os << toString(*syms[i]);
+  });
+
+  DenseMap<macho::Symbol *, std::string> ret;
+  for (size_t i = 0, e = syms.size(); i < e; ++i)
+    ret[syms[i]] = std::move(str[i]);
+  return ret;
+}
+
+void macho::writeMapFile() {
+  if (config->mapFile.empty())
+    return;
+
+  // 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;
+  }
+
+  // Dump output path
+  os << format("# Path: %s\n", config->outputFile.str().c_str());
+
+  // Dump output architecure
+  os << format("# Arch: %s\n",
+               getArchitectureName(config->target.Arch).str().c_str());
+
+  // Dump table of object files
+  os << "# Object files:\n";
+  os << format("[%3u] %s\n", 0, (const char *)"linker synthesized");
+  uint32_t fileIndex = 1;
+  DenseMap<lld::macho::InputFile *, uint32_t> readerToFileOrdinal;
+  for (InputFile *file : inputFiles) {
+    if (isa<ObjFile>(file)) {
+      os << format("[%3u] %s\n", fileIndex, file->getName().str().c_str());
+      readerToFileOrdinal[file] = fileIndex++;
+    }
+  }
+
+  // Collect symbol info that we want to print out.
+  std::vector<Defined *> syms = getSymbols();
+  SymbolMapTy sectionSyms = getSectionSyms(syms);
+  DenseMap<lld::macho::Symbol *, std::string> symStr = getSymbolStrings(syms);
+
+  // Dump table of sections
+  os << "# Sections:\n";
+  os << "# Address\tSize    \tSegment\tSection\n";
+  for (OutputSegment *seg : outputSegments)
+    for (OutputSection *osec : seg->getSections()) {
+      if (osec->isHidden())
+        continue;
+
+      os << format("0x%08llX\t0x%08llX\t%s\t%s\n", osec->addr, osec->getSize(),
+                   seg->name.str().c_str(), osec->name.str().c_str());
+    }
+
+  // Dump table of symbols
+  os << "# Symbols:\n";
+  os << "# Address\t    File  Name\n";
+  for (InputSection *isec : inputSections) {
+    for (macho::Symbol *sym : sectionSyms[isec]) {
+      os << format("0x%08llX\t[%3u] %s\n", sym->getVA(),
+                   readerToFileOrdinal[sym->getFile()], symStr[sym].c_str());
+    }
+  }
+
+  // TODO: when we implement -dead_strip, we should dump dead stripped symbols
+}

diff  --git a/lld/MachO/MapFile.h b/lld/MachO/MapFile.h
new file mode 100644
index 000000000000..bf16ffdd0382
--- /dev/null
+++ b/lld/MachO/MapFile.h
@@ -0,0 +1,18 @@
+//===- MapFile.h ------------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_MACHO_MAPFILE_H
+#define LLD_MACHO_MAPFILE_H
+
+namespace lld {
+namespace macho {
+void writeMapFile();
+} // namespace macho
+} // namespace lld
+
+#endif

diff  --git a/lld/MachO/Options.td b/lld/MachO/Options.td
index 6af0d2c4152f..af8e44e73724 100644
--- a/lld/MachO/Options.td
+++ b/lld/MachO/Options.td
@@ -500,7 +500,6 @@ def order_file_statistics : Flag<["-"], "order_file_statistics">,
 def map : Separate<["-"], "map">,
      MetaVarName<"<path>">,
      HelpText<"Writes all symbols and their addresses to <path>">,
-     Flags<[HelpHidden]>,
      Group<grp_introspect>;
 def dependency_info : Separate<["-"], "dependency_info">,
      MetaVarName<"<path>">,

diff  --git a/lld/MachO/Writer.cpp b/lld/MachO/Writer.cpp
index 62f4eef19498..b2d316355807 100644
--- a/lld/MachO/Writer.cpp
+++ b/lld/MachO/Writer.cpp
@@ -10,6 +10,7 @@
 #include "Config.h"
 #include "InputFiles.h"
 #include "InputSection.h"
+#include "MapFile.h"
 #include "MergedOutputSection.h"
 #include "OutputSection.h"
 #include "OutputSegment.h"
@@ -926,6 +927,7 @@ void Writer::run() {
   createLoadCommands();
   finalizeAddressses();
   finalizeLinkEditSegment();
+  writeMapFile();
   openFile();
   if (errorCount())
     return;

diff  --git a/lld/test/MachO/map-file.s b/lld/test/MachO/map-file.s
new file mode 100644
index 000000000000..ac5fb93898d3
--- /dev/null
+++ b/lld/test/MachO/map-file.s
@@ -0,0 +1,50 @@
+# REQUIRES: x86
+# RUN: rm -rf %t; split-file %s %t
+# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/foo.s -o %t/foo.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/test.s -o %t/test.o
+
+# RUN: %lld -map %t/map %t/test.o %t/foo.o -o %t/test-map
+# RUN: llvm-objdump --syms --section-headers %t/test-map > %t/objdump
+# RUN: cat %t/objdump %t/map > %t/out
+# RUN: FileCheck %s < %t/out
+
+#--- foo.s
+.section __TEXT,obj
+.globl _foo
+_foo:
+
+#--- test.s
+.comm _number, 1
+.globl _main
+_main:
+  ret
+
+# CHECK:      Sections:
+# CHECK-NEXT: Idx  Name          Size           VMA           Type
+# CHECK-NEXT: 0    __text        {{[0-9a-f]+}}  [[#%x,TEXT:]] TEXT
+# CHECK-NEXT: 1    obj           {{[0-9a-f]+}}  [[#%x,DATA:]] DATA
+# CHECK-NEXT: 2    __common      {{[0-9a-f]+}}  [[#%x,BSS:]]  BSS
+
+# CHECK: SYMBOL TABLE:
+# CHECK-NEXT: [[#%x,MAIN:]]   g     F __TEXT,__text _main
+# CHECK-NEXT: [[#%x,NUMBER:]] g     O __DATA,__common _number
+# CHECK-NEXT: [[#%x,FOO:]]    g     O __TEXT,obj _foo
+
+# CHECK-NEXT: # Path: {{.*}}{{/|\\}}map-file.s.tmp/test-map
+# CHECK-NEXT: # Arch: x86_64
+# CHECK-NEXT: # Object files:
+# CHECK-NEXT: [  0] linker synthesized
+# CHECK-NEXT: [  1] {{.*}}{{/|\\}}map-file.s.tmp/test.o
+# CHECK-NEXT: [  2] {{.*}}{{/|\\}}map-file.s.tmp/foo.o
+
+# CHECK-NEXT: # Sections:
+# CHECK-NEXT: # Address    Size              Segment    Section
+# CHECK-NEXT: 0x[[#TEXT]]  0x{{[0-9a-f]+}}   __TEXT  __text
+# CHECK-NEXT: 0x[[#DATA]]  0x{{[0-9a-f]+}}   __TEXT  obj
+# CHECK-NEXT: 0x[[#BSS]]   0x{{[0-9a-f]+}}   __DATA  __common
+
+# CHECK-NEXT: # Symbols:
+# CHECK-NEXT: # Address        File  Name
+# CHECK-NEXT: 0x[[#NUMBER]]    [  1]  _number
+# CHECK-NEXT: 0x[[#MAIN]]      [  1]  _main
+# CHECK-NEXT: 0x[[#FOO]]       [  2]  _foo


        


More information about the llvm-commits mailing list