[lld] b91905a - [lld-link] Support /map option, matching link.exe 's /map output format

Sylvain Audi via llvm-commits llvm-commits at lists.llvm.org
Tue Mar 24 06:49:35 PDT 2020


Author: Sylvain Audi
Date: 2020-03-24T09:48:00-04:00
New Revision: b91905a26378f03c9b56126207771829d89cdcb7

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

LOG: [lld-link] Support /map option, matching link.exe 's /map output format

Added support for /map and /map:[filepath].
The output was derived from Microsoft's Link.exe output when using that same option.
Note that /MAPINFO support was not added.

The previous implementation of MapFile.cpp/.h was meant for /lldmap, and was renamed to LLDMapFile.cpp/.h
MapFile.cpp/.h is now for /MAP
However, a small fix was added to lldmap, replacing a std::sort with std::stable_sort to enforce reproducibility.

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

Added: 
    lld/COFF/LLDMapFile.cpp
    lld/COFF/LLDMapFile.h
    lld/test/COFF/Inputs/map.yaml
    lld/test/COFF/map.test

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

Removed: 
    lld/test/COFF/lldmap.test


################################################################################
diff  --git a/lld/COFF/CMakeLists.txt b/lld/COFF/CMakeLists.txt
index 1d310f8419f5..4592ace373ef 100644
--- a/lld/COFF/CMakeLists.txt
+++ b/lld/COFF/CMakeLists.txt
@@ -14,6 +14,7 @@ add_lld_library(lldCOFF
   DriverUtils.cpp
   ICF.cpp
   InputFiles.cpp
+  LLDMapFile.cpp
   LTO.cpp
   MapFile.cpp
   MarkLive.cpp

diff  --git a/lld/COFF/Config.h b/lld/COFF/Config.h
index af86b6992272..e376ea51f133 100644
--- a/lld/COFF/Config.h
+++ b/lld/COFF/Config.h
@@ -182,6 +182,9 @@ struct Configuration {
   llvm::StringMap<int> order;
 
   // Used for /lldmap.
+  std::string lldmapFile;
+
+  // Used for /map.
   std::string mapFile;
 
   // Used for /thinlto-index-only:

diff  --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp
index 5320b8b83ce0..8b3ba1cdf24b 100644
--- a/lld/COFF/Driver.cpp
+++ b/lld/COFF/Driver.cpp
@@ -707,14 +707,15 @@ static unsigned parseDebugTypes(const opt::InputArgList &args) {
   return debugTypes;
 }
 
-static std::string getMapFile(const opt::InputArgList &args) {
-  auto *arg = args.getLastArg(OPT_lldmap, OPT_lldmap_file);
+static std::string getMapFile(const opt::InputArgList &args,
+                              opt::OptSpecifier os, opt::OptSpecifier osFile) {
+  auto *arg = args.getLastArg(os, osFile);
   if (!arg)
     return "";
-  if (arg->getOption().getID() == OPT_lldmap_file)
+  if (arg->getOption().getID() == osFile.getID())
     return arg->getValue();
 
-  assert(arg->getOption().getID() == OPT_lldmap);
+  assert(arg->getOption().getID() == os.getID());
   StringRef outFile = config->outputFile;
   return (outFile.substr(0, outFile.rfind('.')) + ".map").str();
 }
@@ -1564,7 +1565,14 @@ void LinkerDriver::link(ArrayRef<const char *> argsArr) {
   if (config->mingw || config->debugDwarf)
     config->warnLongSectionNames = false;
 
-  config->mapFile = getMapFile(args);
+  config->lldmapFile = getMapFile(args, OPT_lldmap, OPT_lldmap_file);
+  config->mapFile = getMapFile(args, OPT_map, OPT_map_file);
+
+  if (config->lldmapFile != "" && config->lldmapFile == config->mapFile) {
+    warn("/lldmap and /map have the same output file '" + config->mapFile +
+         "'.\n>>> ignoring /lldmap");
+    config->lldmapFile.clear();
+  }
 
   if (config->incremental && args.hasArg(OPT_profile)) {
     warn("ignoring '/incremental' due to '/profile' specification");

diff  --git a/lld/COFF/LLDMapFile.cpp b/lld/COFF/LLDMapFile.cpp
new file mode 100644
index 000000000000..0e069724f816
--- /dev/null
+++ b/lld/COFF/LLDMapFile.cpp
@@ -0,0 +1,123 @@
+//===- LLDMapFile.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 /lldmap option. It shows lists in order and
+// hierarchically the output sections, input sections, input files and
+// symbol:
+//
+//   Address  Size     Align Out     File    Symbol
+//   00201000 00000015     4 .text
+//   00201000 0000000e     4         test.o:(.text)
+//   0020100e 00000000     0                 local
+//   00201005 00000000     0                 f(int)
+//
+//===----------------------------------------------------------------------===//
+
+#include "LLDMapFile.h"
+#include "SymbolTable.h"
+#include "Symbols.h"
+#include "Writer.h"
+#include "lld/Common/ErrorHandler.h"
+#include "lld/Common/Threads.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace lld;
+using namespace lld::coff;
+
+using SymbolMapTy =
+    DenseMap<const SectionChunk *, SmallVector<DefinedRegular *, 4>>;
+
+static constexpr char indent8[] = "        ";          // 8 spaces
+static constexpr char indent16[] = "                "; // 16 spaces
+
+// Print out the first three columns of a line.
+static void writeHeader(raw_ostream &os, uint64_t addr, uint64_t size,
+                        uint64_t align) {
+  os << format("%08llx %08llx %5lld ", addr, size, align);
+}
+
+// Returns a list of all symbols that we want to print out.
+static std::vector<DefinedRegular *> getSymbols() {
+  std::vector<DefinedRegular *> v;
+  for (ObjFile *file : ObjFile::instances)
+    for (Symbol *b : file->getSymbols())
+      if (auto *sym = dyn_cast_or_null<DefinedRegular>(b))
+        if (sym && !sym->getCOFFSymbol().isSectionDefinition())
+          v.push_back(sym);
+  return v;
+}
+
+// Returns a map from sections to their symbols.
+static SymbolMapTy getSectionSyms(ArrayRef<DefinedRegular *> syms) {
+  SymbolMapTy ret;
+  for (DefinedRegular *s : syms)
+    ret[s->getChunk()].push_back(s);
+
+  // Sort symbols by address.
+  for (auto &it : ret) {
+    SmallVectorImpl<DefinedRegular *> &v = it.second;
+    std::stable_sort(v.begin(), v.end(), [](DefinedRegular *a, DefinedRegular *b) {
+      return a->getRVA() < b->getRVA();
+    });
+  }
+  return ret;
+}
+
+// Construct a map from symbols to their stringified representations.
+static DenseMap<DefinedRegular *, std::string>
+getSymbolStrings(ArrayRef<DefinedRegular *> syms) {
+  std::vector<std::string> str(syms.size());
+  parallelForEachN((size_t)0, syms.size(), [&](size_t i) {
+    raw_string_ostream os(str[i]);
+    writeHeader(os, syms[i]->getRVA(), 0, 0);
+    os << indent16 << toString(*syms[i]);
+  });
+
+  DenseMap<DefinedRegular *, std::string> ret;
+  for (size_t i = 0, e = syms.size(); i < e; ++i)
+    ret[syms[i]] = std::move(str[i]);
+  return ret;
+}
+
+void lld::coff::writeLLDMapFile(ArrayRef<OutputSection *> outputSections) {
+  if (config->lldmapFile.empty())
+    return;
+
+  std::error_code ec;
+  raw_fd_ostream os(config->lldmapFile, ec, sys::fs::OF_None);
+  if (ec)
+    fatal("cannot open " + config->lldmapFile + ": " + ec.message());
+
+  // Collect symbol info that we want to print out.
+  std::vector<DefinedRegular *> syms = getSymbols();
+  SymbolMapTy sectionSyms = getSectionSyms(syms);
+  DenseMap<DefinedRegular *, std::string> symStr = getSymbolStrings(syms);
+
+  // Print out the header line.
+  os << "Address  Size     Align Out     In      Symbol\n";
+
+  // Print out file contents.
+  for (OutputSection *sec : outputSections) {
+    writeHeader(os, sec->getRVA(), sec->getVirtualSize(), /*align=*/pageSize);
+    os << sec->name << '\n';
+
+    for (Chunk *c : sec->chunks) {
+      auto *sc = dyn_cast<SectionChunk>(c);
+      if (!sc)
+        continue;
+
+      writeHeader(os, sc->getRVA(), sc->getSize(), sc->getAlignment());
+      os << indent8 << sc->file->getName() << ":(" << sc->getSectionName()
+         << ")\n";
+      for (DefinedRegular *sym : sectionSyms[sc])
+        os << symStr[sym] << '\n';
+    }
+  }
+}

diff  --git a/lld/COFF/LLDMapFile.h b/lld/COFF/LLDMapFile.h
new file mode 100644
index 000000000000..b731293a8625
--- /dev/null
+++ b/lld/COFF/LLDMapFile.h
@@ -0,0 +1,21 @@
+//===- LLDMapFile.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_COFF_LLDMAPFILE_H
+#define LLD_COFF_LLDMAPFILE_H
+
+#include "llvm/ADT/ArrayRef.h"
+
+namespace lld {
+namespace coff {
+class OutputSection;
+void writeLLDMapFile(llvm::ArrayRef<OutputSection *> outputSections);
+}
+}
+
+#endif

diff  --git a/lld/COFF/MapFile.cpp b/lld/COFF/MapFile.cpp
index a80c553637aa..0958a79b1402 100644
--- a/lld/COFF/MapFile.cpp
+++ b/lld/COFF/MapFile.cpp
@@ -6,16 +6,25 @@
 //
 //===----------------------------------------------------------------------===//
 //
-// This file implements the /lldmap option. It shows lists in order and
-// hierarchically the output sections, input sections, input files and
-// symbol:
+// This file implements the /map option in the same format as link.exe
+// (based on observations)
 //
-//   Address  Size     Align Out     File    Symbol
-//   00201000 00000015     4 .text
-//   00201000 0000000e     4         test.o:(.text)
-//   0020100e 00000000     0                 local
-//   00201005 00000000     0                 f(int)
+// Header (program name, timestamp info, preferred load address)
 //
+// Section list (Start = Section index:Base address):
+// Start         Length     Name                   Class
+// 0001:00001000 00000015H .text                   CODE
+//
+// Symbols list:
+// Address        Publics by Value    Rva + Base          Lib:Object
+// 0001:00001000  main                 0000000140001000    main.obj
+// 0001:00001300  ?__scrt_common_main@@YAHXZ  0000000140001300 libcmt:exe_main.obj
+//
+// entry point at        0001:00000360
+//
+// Static symbols
+//
+// 0000:00000000  __guard_fids__       0000000140000000     libcmt : exe_main.obj
 //===----------------------------------------------------------------------===//
 
 #include "MapFile.h"
@@ -24,6 +33,8 @@
 #include "Writer.h"
 #include "lld/Common/ErrorHandler.h"
 #include "lld/Common/Threads.h"
+#include "lld/Common/Timer.h"
+#include "llvm/Support/Path.h"
 #include "llvm/Support/raw_ostream.h"
 
 using namespace llvm;
@@ -31,56 +42,160 @@ using namespace llvm::object;
 using namespace lld;
 using namespace lld::coff;
 
-using SymbolMapTy =
-    DenseMap<const SectionChunk *, SmallVector<DefinedRegular *, 4>>;
+static Timer totalMapTimer("MAP emission (Cumulative)", Timer::root());
+static Timer symbolGatherTimer("Gather symbols", totalMapTimer);
+static Timer symbolStringsTimer("Build symbol strings", totalMapTimer);
+static Timer writeTimer("Write to file", totalMapTimer);
 
-static constexpr char indent8[] = "        ";          // 8 spaces
-static constexpr char indent16[] = "                "; // 16 spaces
+// Print out the first two columns of a line.
+static void writeHeader(raw_ostream &os, uint32_t sec, uint64_t addr) {
+  os << format(" %04x:%08llx", sec, addr);
+}
 
-// Print out the first three columns of a line.
-static void writeHeader(raw_ostream &os, uint64_t addr, uint64_t size,
-                        uint64_t align) {
-  os << format("%08llx %08llx %5lld ", addr, size, align);
+// Write the time stamp with the format used by link.exe
+// It seems identical to strftime with "%c" on msvc build, but we need a
+// locale-agnostic version.
+static void writeFormattedTimestamp(raw_ostream &os, time_t tds) {
+  constexpr const char *const days[7] = {"Sun", "Mon", "Tue", "Wed",
+                                         "Thu", "Fri", "Sat"};
+  constexpr const char *const months[12] = {"Jan", "Feb", "Mar", "Apr",
+                                            "May", "Jun", "Jul", "Aug",
+                                            "Sep", "Oct", "Nov", "Dec"};
+  tm *time = localtime(&tds);
+  os << format("%s %s %2d %02d:%02d:%02d %d", days[time->tm_wday],
+               months[time->tm_mon], time->tm_mday, time->tm_hour, time->tm_min,
+               time->tm_sec, time->tm_year + 1900);
 }
 
-// Returns a list of all symbols that we want to print out.
-static std::vector<DefinedRegular *> getSymbols() {
-  std::vector<DefinedRegular *> v;
-  for (ObjFile *file : ObjFile::instances)
-    for (Symbol *b : file->getSymbols())
-      if (auto *sym = dyn_cast_or_null<DefinedRegular>(b))
-        if (sym && !sym->getCOFFSymbol().isSectionDefinition())
-          v.push_back(sym);
-  return v;
+static void sortUniqueSymbols(std::vector<Defined *> &syms) {
+  // Build helper vector
+  using SortEntry = std::pair<Defined *, size_t>;
+  std::vector<SortEntry> v;
+  v.resize(syms.size());
+  for (size_t i = 0, e = syms.size(); i < e; ++i)
+    v[i] = SortEntry(syms[i], i);
+
+  // Remove duplicate symbol pointers
+  parallelSort(v, std::less<SortEntry>());
+  auto end = std::unique(v.begin(), v.end(),
+                         [](const SortEntry &a, const SortEntry &b) {
+                           return a.first == b.first;
+                         });
+  v.erase(end, v.end());
+
+  // Sort by RVA then original order
+  parallelSort(v, [](const SortEntry &a, const SortEntry &b) {
+    // Add config->imageBase to avoid comparing "negative" RVAs.
+    // This can happen with symbols of Absolute kind
+    uint64_t rvaa = config->imageBase + a.first->getRVA();
+    uint64_t rvab = config->imageBase + b.first->getRVA();
+    return rvaa < rvab || (rvaa == rvab && a.second < b.second);
+  });
+
+  syms.resize(v.size());
+  for (size_t i = 0, e = v.size(); i < e; ++i)
+    syms[i] = v[i].first;
 }
 
-// Returns a map from sections to their symbols.
-static SymbolMapTy getSectionSyms(ArrayRef<DefinedRegular *> syms) {
-  SymbolMapTy ret;
-  for (DefinedRegular *s : syms)
-    ret[s->getChunk()].push_back(s);
-
-  // Sort symbols by address.
-  for (auto &it : ret) {
-    SmallVectorImpl<DefinedRegular *> &v = it.second;
-    std::sort(v.begin(), v.end(), [](DefinedRegular *a, DefinedRegular *b) {
-      return a->getRVA() < b->getRVA();
-    });
+// Returns the lists of all symbols that we want to print out.
+static void getSymbols(std::vector<Defined *> &syms,
+                       std::vector<Defined *> &staticSyms) {
+
+  for (ObjFile *file : ObjFile::instances)
+    for (Symbol *b : file->getSymbols()) {
+      if (!b || !b->isLive())
+        continue;
+      if (auto *sym = dyn_cast<DefinedCOFF>(b)) {
+        COFFSymbolRef symRef = sym->getCOFFSymbol();
+        if (!symRef.isSectionDefinition() &&
+            symRef.getStorageClass() != COFF::IMAGE_SYM_CLASS_LABEL) {
+          if (symRef.getStorageClass() == COFF::IMAGE_SYM_CLASS_STATIC)
+            staticSyms.push_back(sym);
+          else
+            syms.push_back(sym);
+        }
+      } else if (auto *sym = dyn_cast<Defined>(b)) {
+        syms.push_back(sym);
+      }
+    }
+
+  for (ImportFile *file : ImportFile::instances) {
+    if (!file->live)
+      continue;
+
+    if (!file->thunkSym)
+      continue;
+
+    if (!file->thunkLive)
+      continue;
+
+    if (auto *thunkSym = dyn_cast<Defined>(file->thunkSym))
+      syms.push_back(thunkSym);
+
+    if (auto *impSym = dyn_cast_or_null<Defined>(file->impSym))
+      syms.push_back(impSym);
   }
-  return ret;
+
+  sortUniqueSymbols(syms);
+  sortUniqueSymbols(staticSyms);
 }
 
 // Construct a map from symbols to their stringified representations.
-static DenseMap<DefinedRegular *, std::string>
-getSymbolStrings(ArrayRef<DefinedRegular *> syms) {
+static DenseMap<Defined *, std::string>
+getSymbolStrings(ArrayRef<Defined *> syms) {
   std::vector<std::string> str(syms.size());
   parallelForEachN((size_t)0, syms.size(), [&](size_t i) {
     raw_string_ostream os(str[i]);
-    writeHeader(os, syms[i]->getRVA(), 0, 0);
-    os << indent16 << toString(*syms[i]);
+    Defined *sym = syms[i];
+
+    uint16_t sectionIdx = 0;
+    uint64_t address = 0;
+    SmallString<128> fileDescr;
+
+    if (auto *absSym = dyn_cast<DefinedAbsolute>(sym)) {
+      address = absSym->getVA();
+      fileDescr = "<absolute>";
+    } else if (isa<DefinedSynthetic>(sym)) {
+      fileDescr = "<linker-defined>";
+    } else if (isa<DefinedCommon>(sym)) {
+      fileDescr = "<common>";
+    } else if (Chunk *chunk = sym->getChunk()) {
+      address = sym->getRVA();
+      if (OutputSection *sec = chunk->getOutputSection())
+        address -= sec->header.VirtualAddress;
+
+      sectionIdx = chunk->getOutputSectionIdx();
+
+      InputFile *file;
+      if (auto *impSym = dyn_cast<DefinedImportData>(sym))
+        file = impSym->file;
+      else if (auto *thunkSym = dyn_cast<DefinedImportThunk>(sym))
+        file = thunkSym->wrappedSym->file;
+      else
+        file = sym->getFile();
+
+      if (file) {
+        if (!file->parentName.empty()) {
+          fileDescr = sys::path::filename(file->parentName);
+          sys::path::replace_extension(fileDescr, "");
+          fileDescr += ":";
+        }
+        fileDescr += sys::path::filename(file->getName());
+      }
+    }
+    writeHeader(os, sectionIdx, address);
+    os << "       ";
+    os << left_justify(sym->getName(), 26);
+    os << " ";
+    os << format_hex_no_prefix((config->imageBase + sym->getRVA()), 16);
+    if (!fileDescr.empty()) {
+      os << "     "; // FIXME : Handle "f" and "i" flags sometimes generated
+                     // by link.exe in those spaces
+      os << fileDescr;
+    }
   });
 
-  DenseMap<DefinedRegular *, std::string> ret;
+  DenseMap<Defined *, std::string> ret;
   for (size_t i = 0, e = syms.size(); i < e; ++i)
     ret[syms[i]] = std::move(str[i]);
   return ret;
@@ -95,29 +210,113 @@ void lld::coff::writeMapFile(ArrayRef<OutputSection *> outputSections) {
   if (ec)
     fatal("cannot open " + config->mapFile + ": " + ec.message());
 
+  ScopedTimer t1(totalMapTimer);
+
   // Collect symbol info that we want to print out.
-  std::vector<DefinedRegular *> syms = getSymbols();
-  SymbolMapTy sectionSyms = getSectionSyms(syms);
-  DenseMap<DefinedRegular *, std::string> symStr = getSymbolStrings(syms);
+  ScopedTimer t2(symbolGatherTimer);
+  std::vector<Defined *> syms;
+  std::vector<Defined *> staticSyms;
+  getSymbols(syms, staticSyms);
+  t2.stop();
 
-  // Print out the header line.
-  os << "Address  Size     Align Out     In      Symbol\n";
+  ScopedTimer t3(symbolStringsTimer);
+  DenseMap<Defined *, std::string> symStr = getSymbolStrings(syms);
+  DenseMap<Defined *, std::string> staticSymStr = getSymbolStrings(staticSyms);
+  t3.stop();
 
-  // Print out file contents.
-  for (OutputSection *sec : outputSections) {
-    writeHeader(os, sec->getRVA(), sec->getVirtualSize(), /*align=*/pageSize);
-    os << sec->name << '\n';
+  ScopedTimer t4(writeTimer);
+  SmallString<128> AppName = sys::path::filename(config->outputFile);
+  sys::path::replace_extension(AppName, "");
 
+  // Print out the file header
+  os << " " << AppName << "\n";
+  os << "\n";
+
+  os << " Timestamp is " << format_hex_no_prefix(config->timestamp, 8) << " (";
+  if (config->repro) {
+    os << "Repro mode";
+  } else {
+    writeFormattedTimestamp(os, config->timestamp);
+  }
+  os << ")\n";
+
+  os << "\n";
+  os << " Preferred load address is "
+     << format_hex_no_prefix(config->imageBase, 16) << "\n";
+  os << "\n";
+
+  // Print out section table.
+  os << " Start         Length     Name                   Class\n";
+
+  for (OutputSection *sec : outputSections) {
+    // Merge display of chunks with same sectionName
+    std::vector<std::pair<SectionChunk *, SectionChunk *>> ChunkRanges;
     for (Chunk *c : sec->chunks) {
       auto *sc = dyn_cast<SectionChunk>(c);
       if (!sc)
         continue;
 
-      writeHeader(os, sc->getRVA(), sc->getSize(), sc->getAlignment());
-      os << indent8 << sc->file->getName() << ":(" << sc->getSectionName()
-         << ")\n";
-      for (DefinedRegular *sym : sectionSyms[sc])
-        os << symStr[sym] << '\n';
+      if (ChunkRanges.empty() ||
+          c->getSectionName() != ChunkRanges.back().first->getSectionName()) {
+        ChunkRanges.emplace_back(sc, sc);
+      } else {
+        ChunkRanges.back().second = sc;
+      }
+    }
+
+    const bool isCodeSection =
+        (sec->header.Characteristics & COFF::IMAGE_SCN_CNT_CODE) &&
+        (sec->header.Characteristics & COFF::IMAGE_SCN_MEM_READ) &&
+        (sec->header.Characteristics & COFF::IMAGE_SCN_MEM_EXECUTE);
+    StringRef SectionClass = (isCodeSection ? "CODE" : "DATA");
+
+    for (auto &cr : ChunkRanges) {
+      size_t size =
+          cr.second->getRVA() + cr.second->getSize() - cr.first->getRVA();
+
+      auto address = cr.first->getRVA() - sec->header.VirtualAddress;
+      writeHeader(os, sec->sectionIndex, address);
+      os << " " << format_hex_no_prefix(size, 8) << "H";
+      os << " " << left_justify(cr.first->getSectionName(), 23);
+      os << " " << SectionClass;
+      os << '\n';
+    }
+  }
+
+  // Print out the symbols table (without static symbols)
+  os << "\n";
+  os << "  Address         Publics by Value              Rva+Base"
+        "               Lib:Object\n";
+  os << "\n";
+  for (Defined *sym : syms)
+    os << symStr[sym] << '\n';
+
+  // Print out the entry point.
+  os << "\n";
+
+  uint16_t entrySecIndex = 0;
+  uint64_t entryAddress = 0;
+
+  if (!config->noEntry) {
+    Defined *entry = dyn_cast_or_null<Defined>(config->entry);
+    if (entry) {
+      Chunk *chunk = entry->getChunk();
+      entrySecIndex = chunk->getOutputSectionIdx();
+      entryAddress =
+          entry->getRVA() - chunk->getOutputSection()->header.VirtualAddress;
     }
   }
+  os << " entry point at         ";
+  os << format("%04x:%08llx", entrySecIndex, entryAddress);
+  os << "\n";
+
+  // Print out the static symbols
+  os << "\n";
+  os << " Static symbols\n";
+  os << "\n";
+  for (Defined *sym : staticSyms)
+    os << staticSymStr[sym] << '\n';
+
+  t4.stop();
+  t1.stop();
 }

diff  --git a/lld/COFF/Options.td b/lld/COFF/Options.td
index cea02e7a0042..72fe9ce8c118 100644
--- a/lld/COFF/Options.td
+++ b/lld/COFF/Options.td
@@ -226,6 +226,8 @@ defm threads: B<"threads",
 // Flags for debugging
 def lldmap : F<"lldmap">;
 def lldmap_file : Joined<["/", "-", "/?", "-?"], "lldmap:">;
+def map : F<"map">;
+def map_file : Joined<["/", "-", "/?", "-?"], "map:">;
 def show_timing : F<"time">;
 def summary : F<"summary">;
 

diff  --git a/lld/COFF/Writer.cpp b/lld/COFF/Writer.cpp
index 7e7aaafe18ed..d5e2b59027b4 100644
--- a/lld/COFF/Writer.cpp
+++ b/lld/COFF/Writer.cpp
@@ -10,6 +10,7 @@
 #include "Config.h"
 #include "DLL.h"
 #include "InputFiles.h"
+#include "LLDMapFile.h"
 #include "MapFile.h"
 #include "PDB.h"
 #include "SymbolTable.h"
@@ -633,6 +634,7 @@ void Writer::run() {
   }
   writeBuildId();
 
+  writeLLDMapFile(outputSections);
   writeMapFile(outputSections);
 
   if (errorCount())

diff  --git a/lld/test/COFF/Inputs/map.yaml b/lld/test/COFF/Inputs/map.yaml
new file mode 100644
index 000000000000..7a834344cc5b
--- /dev/null
+++ b/lld/test/COFF/Inputs/map.yaml
@@ -0,0 +1,60 @@
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: []
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     0000000000000000
+    Relocations:
+      - VirtualAddress:  0
+        SymbolName:      exportfn1
+        Type:            IMAGE_REL_AMD64_ADDR32NB
+      - VirtualAddress:  4
+        SymbolName:      exportfn2
+        Type:            IMAGE_REL_AMD64_ADDR32NB
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          8
+      NumberOfRelocations: 2
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            main
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            exportfn1
+    Value:           0
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            exportfn2
+    Value:           0
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            absolute
+    Value:           0x00000042
+    SectionNumber:   -1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+  - Name:            staticdef
+    Value:           0x00000043
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+...

diff  --git a/lld/test/COFF/lldmap.test b/lld/test/COFF/lldmap.test
deleted file mode 100644
index d705a16c6c2a..000000000000
--- a/lld/test/COFF/lldmap.test
+++ /dev/null
@@ -1,10 +0,0 @@
-# RUN: yaml2obj < %p/Inputs/ret42.yaml > %t.obj
-# RUN: lld-link /out:%t.exe /entry:main /lldmap:%T/foo.map %t.obj
-# RUN: FileCheck -strict-whitespace %s < %T/foo.map
-# RUN: lld-link /out:%T/bar.exe /entry:main /lldmap %t.obj
-# RUN: FileCheck -strict-whitespace %s < %T/bar.map
-
-# CHECK:      Address  Size     Align Out     In      Symbol
-# CHECK-NEXT: 00001000 00000006  4096 .text
-# CHECK-NEXT: 00001000 00000006    16         {{.*}}lldmap.test.tmp.obj:(.text$mn)
-# CHECK-NEXT: 00001000 00000000     0                 main

diff  --git a/lld/test/COFF/map.test b/lld/test/COFF/map.test
new file mode 100644
index 000000000000..0ec27fb33bdc
--- /dev/null
+++ b/lld/test/COFF/map.test
@@ -0,0 +1,40 @@
+# RUN: yaml2obj < %p/Inputs/export.yaml > %t-dll.obj
+# RUN: lld-link /out:%t.dll /dll %t-dll.obj /implib:%t-dll.lib \
+# RUN:   /export:exportfn1 /export:exportfn2
+# RUN: yaml2obj < %p/Inputs/map.yaml > %t.obj
+# RUN: lld-link /out:%t.exe /entry:main %t.obj %t-dll.lib /map:%T/foo.map  /lldmap
+# RUN: FileCheck -check-prefix=MAP -strict-whitespace %s < %T/foo.map
+# RUN: FileCheck -check-prefix=LLDMAP -strict-whitespace %s < %t.map
+# RUN: lld-link /out:%t.exe /entry:main %t.obj %t-dll.lib /map /lldmap:%T/foo-lld.map
+# RUN: FileCheck -check-prefix=MAP -strict-whitespace %s < %t.map
+# RUN: FileCheck -check-prefix=LLDMAP -strict-whitespace %s < %T/foo-lld.map
+
+# MAP: {{.*}}
+# MAP-EMPTY:
+# MAP-NEXT: Timestamp is {{.*}}
+# MAP-EMPTY:
+# MAP-NEXT: Preferred load address is 0000000140000000
+# MAP-EMPTY:
+# MAP-NEXT: Start         Length     Name                   Class
+# MAP-NEXT: 0001:00000000 00000008H .text                   CODE
+# MAP-EMPTY:
+# MAP-NEXT:  Address         Publics by Value              Rva+Base               Lib:Object
+# MAP-EMPTY:
+# MAP-NEXT: 0000:00000042       absolute                   0000000000000042     <absolute>
+# MAP-NEXT: 0001:00000000       main                       0000000140001000     map.test.tmp.obj
+# MAP-NEXT: 0001:00000010       exportfn1                  0000000140001010     map.test.tmp-dll:map.test.tmp.dll
+# MAP-NEXT: 0001:00000020       exportfn2                  0000000140001020     map.test.tmp-dll:map.test.tmp.dll
+# MAP-NEXT: 0002:00000040       __imp_exportfn1            0000000140002040     map.test.tmp-dll:map.test.tmp.dll
+# MAP-NEXT: 0002:00000048       __imp_exportfn2            0000000140002048     map.test.tmp-dll:map.test.tmp.dll
+# MAP-EMPTY:
+# MAP-NEXT: entry point at         0001:00000000
+# MAP-EMPTY:
+# MAP-NEXT: Static symbols
+# MAP-EMPTY:
+# MAP-NEXT: 0001:00000043       staticdef                  0000000140001043     map.test.tmp.obj
+
+
+# LLDMAP:      Address  Size     Align Out     In      Symbol
+# LLDMAP-NEXT: 00001000 00000026  4096 .text
+# LLDMAP-NEXT: 00001000 00000008     4         {{.*}}map.test.tmp.obj:(.text)
+# LLDMAP-NEXT: 00001000 00000000     0                 main


        


More information about the llvm-commits mailing list