[lld] r291990 - COFF: Change the /lldmap output format to be more like the ELF linker.

Peter Collingbourne via llvm-commits llvm-commits at lists.llvm.org
Fri Jan 13 19:14:46 PST 2017


Author: pcc
Date: Fri Jan 13 21:14:46 2017
New Revision: 291990

URL: http://llvm.org/viewvc/llvm-project?rev=291990&view=rev
Log:
COFF: Change the /lldmap output format to be more like the ELF linker.

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

Added:
    lld/trunk/COFF/MapFile.cpp
    lld/trunk/COFF/MapFile.h
Modified:
    lld/trunk/COFF/CMakeLists.txt
    lld/trunk/COFF/Chunks.h
    lld/trunk/COFF/Config.h
    lld/trunk/COFF/Driver.cpp
    lld/trunk/COFF/SymbolTable.cpp
    lld/trunk/COFF/SymbolTable.h
    lld/trunk/COFF/Writer.cpp
    lld/trunk/COFF/Writer.h
    lld/trunk/test/COFF/lldmap.test
    lld/trunk/test/COFF/lto-parallel.ll
    lld/trunk/test/COFF/weak-external.test
    lld/trunk/test/COFF/weak-external3.test

Modified: lld/trunk/COFF/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/CMakeLists.txt?rev=291990&r1=291989&r2=291990&view=diff
==============================================================================
--- lld/trunk/COFF/CMakeLists.txt (original)
+++ lld/trunk/COFF/CMakeLists.txt Fri Jan 13 21:14:46 2017
@@ -15,6 +15,7 @@ add_lld_library(lldCOFF
   ICF.cpp
   InputFiles.cpp
   Librarian.cpp
+  MapFile.cpp
   MarkLive.cpp
   ModuleDef.cpp
   PDB.cpp

Modified: lld/trunk/COFF/Chunks.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Chunks.h?rev=291990&r1=291989&r2=291990&view=diff
==============================================================================
--- lld/trunk/COFF/Chunks.h (original)
+++ lld/trunk/COFF/Chunks.h Fri Jan 13 21:14:46 2017
@@ -187,10 +187,10 @@ public:
 
   const coff_section *Header;
 
-private:
-  // A file this chunk was created from.
+  // The file that this chunk was created from.
   ObjectFile *File;
 
+private:
   StringRef SectionName;
   std::vector<SectionChunk *> AssocChildren;
   llvm::iterator_range<const coff_relocation *> Relocs;

Modified: lld/trunk/COFF/Config.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Config.h?rev=291990&r1=291989&r2=291990&view=diff
==============================================================================
--- lld/trunk/COFF/Config.h (original)
+++ lld/trunk/COFF/Config.h Fri Jan 13 21:14:46 2017
@@ -135,6 +135,9 @@ struct Configuration {
   // Used for /alternatename.
   std::map<StringRef, StringRef> AlternateNames;
 
+  // Used for /lldmap.
+  std::string MapFile;
+
   uint64_t ImageBase = -1;
   uint64_t StackReserve = 1024 * 1024;
   uint64_t StackCommit = 4096;

Modified: lld/trunk/COFF/Driver.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Driver.cpp?rev=291990&r1=291989&r2=291990&view=diff
==============================================================================
--- lld/trunk/COFF/Driver.cpp (original)
+++ lld/trunk/COFF/Driver.cpp Fri Jan 13 21:14:46 2017
@@ -658,6 +658,8 @@ void LinkerDriver::link(ArrayRef<const c
   Config->DumpPdb = Args.hasArg(OPT_dumppdb);
   Config->DebugPdb = Args.hasArg(OPT_debugpdb);
 
+  Config->MapFile = getMapFile(Args);
+
   // Create a list of input files. Files can be given as arguments
   // for /defaultlib option.
   std::vector<MemoryBufferRef> MBs;
@@ -846,17 +848,6 @@ void LinkerDriver::link(ArrayRef<const c
   // Write the result.
   writeResult(&Symtab);
 
-  // Create a symbol map file containing symbol VAs and their names
-  // to help debugging.
-  std::string MapFile = getMapFile(Args);
-  if (!MapFile.empty()) {
-    std::error_code EC;
-    raw_fd_ostream Out(MapFile, EC, OpenFlags::F_Text);
-    if (EC)
-      fatal(EC, "could not create the symbol map " + MapFile);
-    Symtab.printMap(Out);
-  }
-
   // Call exit to avoid calling destructors.
   exit(0);
 }

Added: lld/trunk/COFF/MapFile.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/MapFile.cpp?rev=291990&view=auto
==============================================================================
--- lld/trunk/COFF/MapFile.cpp (added)
+++ lld/trunk/COFF/MapFile.cpp Fri Jan 13 21:14:46 2017
@@ -0,0 +1,125 @@
+//===- MapFile.cpp --------------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// 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     In      File    Symbol
+// =================================================================
+// 00201000 00000015     4 .text
+// 00201000 0000000e     4         .text
+// 00201000 0000000e     4                 test.o
+// 0020100e 00000000     0                         local
+// 00201005 00000000     0                         f(int)
+//
+//===----------------------------------------------------------------------===//
+
+#include "MapFile.h"
+#include "Error.h"
+#include "Symbols.h"
+#include "Writer.h"
+
+#include "llvm/Support/FileUtilities.h"
+
+using namespace llvm;
+using namespace llvm::object;
+
+using namespace lld;
+using namespace lld::coff;
+
+static void writeOutSecLine(raw_fd_ostream &OS, uint64_t Address, uint64_t Size,
+                            uint64_t Align, StringRef Name) {
+  OS << format_hex_no_prefix(Address, 8) << ' '
+     << format_hex_no_prefix(Size, 8) << ' ' << format("%5x ", Align)
+     << left_justify(Name, 7);
+}
+
+static void writeInSecLine(raw_fd_ostream &OS, uint64_t Address, uint64_t Size,
+                           uint64_t Align, StringRef Name) {
+  // Pass an empty name to align the text to the correct column.
+  writeOutSecLine(OS, Address, Size, Align, "");
+  OS << ' ' << left_justify(Name, 7);
+}
+
+static void writeFileLine(raw_fd_ostream &OS, uint64_t Address, uint64_t Size,
+                          uint64_t Align, StringRef Name) {
+  // Pass an empty name to align the text to the correct column.
+  writeInSecLine(OS, Address, Size, Align, "");
+  OS << ' ' << left_justify(Name, 7);
+}
+
+static void writeSymbolLine(raw_fd_ostream &OS, uint64_t Address, uint64_t Size,
+                            StringRef Name) {
+  // Pass an empty name to align the text to the correct column.
+  writeFileLine(OS, Address, Size, 0, "");
+  OS << ' ' << left_justify(Name, 7);
+}
+
+static void writeSectionChunk(raw_fd_ostream &OS, const SectionChunk *SC,
+                              StringRef &PrevName) {
+  StringRef Name = SC->getSectionName();
+  if (Name != PrevName) {
+    writeInSecLine(OS, SC->getRVA(), SC->getSize(), SC->getAlign(), Name);
+    OS << '\n';
+    PrevName = Name;
+  }
+  coff::ObjectFile *File = SC->File;
+  if (!File)
+    return;
+  writeFileLine(OS, SC->getRVA(), SC->getSize(), SC->getAlign(),
+                toString(File));
+  OS << '\n';
+  ArrayRef<SymbolBody *> Syms = File->getSymbols();
+  for (SymbolBody *Sym : Syms) {
+    auto *DR = dyn_cast<DefinedRegular>(Sym);
+    if (!DR || DR->getChunk() != SC ||
+        DR->getCOFFSymbol().isSectionDefinition())
+      continue;
+    writeSymbolLine(OS, DR->getRVA(), SC->getSize(), toString(*Sym));
+    OS << '\n';
+  }
+}
+
+static void writeMapFile2(int FD,
+                          ArrayRef<OutputSection *> OutputSections) {
+  raw_fd_ostream OS(FD, true);
+  OS << left_justify("Address", 8) << ' ' << left_justify("Size", 8)
+     << ' ' << left_justify("Align", 5) << ' ' << left_justify("Out", 7) << ' '
+     << left_justify("In", 7) << ' ' << left_justify("File", 7) << " Symbol\n";
+  for (OutputSection *Sec : OutputSections) {
+    uint32_t VA = Sec->getRVA();
+    writeOutSecLine(OS, VA, Sec->getVirtualSize(), /*Align=*/PageSize,
+                    Sec->getName());
+    OS << '\n';
+    StringRef PrevName = "";
+    for (Chunk *C : Sec->getChunks())
+      if (const auto *SC = dyn_cast<SectionChunk>(C))
+        writeSectionChunk(OS, SC, PrevName);
+  }
+}
+
+void coff::writeMapFile(ArrayRef<OutputSection *> OutputSections) {
+  StringRef MapFile = Config->MapFile;
+  if (MapFile.empty())
+    return;
+
+  // Create new file in same directory but with random name.
+  SmallString<128> TempPath;
+  int FD;
+  std::error_code EC =
+      sys::fs::createUniqueFile(Twine(MapFile) + ".tmp%%%%%%%", FD, TempPath);
+  if (EC)
+    fatal(EC.message());
+  FileRemover RAII(TempPath);
+  writeMapFile2(FD, OutputSections);
+  EC = sys::fs::rename(TempPath, MapFile);
+  if (EC)
+    fatal(EC.message());
+}

Added: lld/trunk/COFF/MapFile.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/MapFile.h?rev=291990&view=auto
==============================================================================
--- lld/trunk/COFF/MapFile.h (added)
+++ lld/trunk/COFF/MapFile.h Fri Jan 13 21:14:46 2017
@@ -0,0 +1,22 @@
+//===- MapFile.h ------------------------------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_COFF_MAPFILE_H
+#define LLD_COFF_MAPFILE_H
+
+#include "llvm/ADT/ArrayRef.h"
+
+namespace lld {
+namespace coff {
+class OutputSection;
+void writeMapFile(llvm::ArrayRef<OutputSection *> OutputSections);
+}
+}
+
+#endif

Modified: lld/trunk/COFF/SymbolTable.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/SymbolTable.cpp?rev=291990&r1=291989&r2=291990&view=diff
==============================================================================
--- lld/trunk/COFF/SymbolTable.cpp (original)
+++ lld/trunk/COFF/SymbolTable.cpp Fri Jan 13 21:14:46 2017
@@ -345,17 +345,6 @@ SymbolBody *SymbolTable::addUndefined(St
   return addUndefined(Name, nullptr, false)->body();
 }
 
-void SymbolTable::printMap(llvm::raw_ostream &OS) {
-  for (ObjectFile *File : ObjectFiles) {
-    OS << toString(File) << ":\n";
-    for (SymbolBody *Body : File->getSymbols())
-      if (auto *R = dyn_cast<DefinedRegular>(Body))
-        if (R->getChunk()->isLive())
-          OS << Twine::utohexstr(Config->ImageBase + R->getRVA())
-             << " " << R->getName() << "\n";
-  }
-}
-
 void SymbolTable::addCombinedLTOObjects() {
   if (BitcodeFiles.empty())
     return;

Modified: lld/trunk/COFF/SymbolTable.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/SymbolTable.h?rev=291990&r1=291989&r2=291990&view=diff
==============================================================================
--- lld/trunk/COFF/SymbolTable.h (original)
+++ lld/trunk/COFF/SymbolTable.h Fri Jan 13 21:14:46 2017
@@ -69,9 +69,6 @@ public:
   void mangleMaybe(SymbolBody *B);
   StringRef findMangle(StringRef Name);
 
-  // Print a layout map to OS.
-  void printMap(llvm::raw_ostream &OS);
-
   // Build a set of COFF objects representing the combined contents of
   // BitcodeFiles and add them to the symbol table. Called after all files are
   // added and before the writer writes results to a file.

Modified: lld/trunk/COFF/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Writer.cpp?rev=291990&r1=291989&r2=291990&view=diff
==============================================================================
--- lld/trunk/COFF/Writer.cpp (original)
+++ lld/trunk/COFF/Writer.cpp Fri Jan 13 21:14:46 2017
@@ -12,6 +12,7 @@
 #include "DLL.h"
 #include "Error.h"
 #include "InputFiles.h"
+#include "MapFile.h"
 #include "Memory.h"
 #include "PDB.h"
 #include "SymbolTable.h"
@@ -39,7 +40,6 @@ using namespace llvm::support::endian;
 using namespace lld;
 using namespace lld::coff;
 
-static const int PageSize = 4096;
 static const int SectorSize = 512;
 static const int DOSStubSize = 64;
 static const int NumberfOfDataDirectory = 16;
@@ -163,51 +163,6 @@ namespace coff {
 
 void writeResult(SymbolTable *T) { Writer(T).run(); }
 
-// OutputSection represents a section in an output file. It's a
-// container of chunks. OutputSection and Chunk are 1:N relationship.
-// Chunks cannot belong to more than one OutputSections. The writer
-// creates multiple OutputSections and assign them unique,
-// non-overlapping file offsets and RVAs.
-class OutputSection {
-public:
-  OutputSection(StringRef N) : Name(N), Header({}) {}
-  void setRVA(uint64_t);
-  void setFileOffset(uint64_t);
-  void addChunk(Chunk *C);
-  StringRef getName() { return Name; }
-  std::vector<Chunk *> &getChunks() { return Chunks; }
-  void addPermissions(uint32_t C);
-  void setPermissions(uint32_t C);
-  uint32_t getPermissions() { return Header.Characteristics & PermMask; }
-  uint32_t getCharacteristics() { return Header.Characteristics; }
-  uint64_t getRVA() { return Header.VirtualAddress; }
-  uint64_t getFileOff() { return Header.PointerToRawData; }
-  void writeHeaderTo(uint8_t *Buf);
-
-  // Returns the size of this section in an executable memory image.
-  // This may be smaller than the raw size (the raw size is multiple
-  // of disk sector size, so there may be padding at end), or may be
-  // larger (if that's the case, the loader reserves spaces after end
-  // of raw data).
-  uint64_t getVirtualSize() { return Header.VirtualSize; }
-
-  // Returns the size of the section in the output file.
-  uint64_t getRawSize() { return Header.SizeOfRawData; }
-
-  // Set offset into the string table storing this section name.
-  // Used only when the name is longer than 8 bytes.
-  void setStringTableOff(uint32_t V) { StringTableOff = V; }
-
-  // N.B. The section index is one based.
-  uint32_t SectionIndex = 0;
-
-private:
-  StringRef Name;
-  coff_section Header;
-  uint32_t StringTableOff = 0;
-  std::vector<Chunk *> Chunks;
-};
-
 void OutputSection::setRVA(uint64_t RVA) {
   Header.VirtualAddress = RVA;
   for (Chunk *C : Chunks)
@@ -306,6 +261,8 @@ void Writer::run() {
   if (!Config->PDBPath.empty())
     createPDB(Config->PDBPath, Symtab, SectionTable, BuildId->DI);
 
+  writeMapFile(OutputSections);
+
   if (auto EC = Buffer->commit())
     fatal(EC, "failed to write the output file");
 }

Modified: lld/trunk/COFF/Writer.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Writer.h?rev=291990&r1=291989&r2=291990&view=diff
==============================================================================
--- lld/trunk/COFF/Writer.h (original)
+++ lld/trunk/COFF/Writer.h Fri Jan 13 21:14:46 2017
@@ -10,14 +10,65 @@
 #ifndef LLD_COFF_WRITER_H
 #define LLD_COFF_WRITER_H
 
+#include "Chunks.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Object/COFF.h"
+#include <cstdint>
 #include <vector>
 
 namespace lld {
 namespace coff {
 class SymbolTable;
 
+static const int PageSize = 4096;
+
 void writeResult(SymbolTable *T);
 
+// OutputSection represents a section in an output file. It's a
+// container of chunks. OutputSection and Chunk are 1:N relationship.
+// Chunks cannot belong to more than one OutputSections. The writer
+// creates multiple OutputSections and assign them unique,
+// non-overlapping file offsets and RVAs.
+class OutputSection {
+public:
+  OutputSection(llvm::StringRef N) : Name(N), Header({}) {}
+  void setRVA(uint64_t);
+  void setFileOffset(uint64_t);
+  void addChunk(Chunk *C);
+  llvm::StringRef getName() { return Name; }
+  std::vector<Chunk *> &getChunks() { return Chunks; }
+  void addPermissions(uint32_t C);
+  void setPermissions(uint32_t C);
+  uint32_t getPermissions() { return Header.Characteristics & PermMask; }
+  uint32_t getCharacteristics() { return Header.Characteristics; }
+  uint64_t getRVA() { return Header.VirtualAddress; }
+  uint64_t getFileOff() { return Header.PointerToRawData; }
+  void writeHeaderTo(uint8_t *Buf);
+
+  // Returns the size of this section in an executable memory image.
+  // This may be smaller than the raw size (the raw size is multiple
+  // of disk sector size, so there may be padding at end), or may be
+  // larger (if that's the case, the loader reserves spaces after end
+  // of raw data).
+  uint64_t getVirtualSize() { return Header.VirtualSize; }
+
+  // Returns the size of the section in the output file.
+  uint64_t getRawSize() { return Header.SizeOfRawData; }
+
+  // Set offset into the string table storing this section name.
+  // Used only when the name is longer than 8 bytes.
+  void setStringTableOff(uint32_t V) { StringTableOff = V; }
+
+  // N.B. The section index is one based.
+  uint32_t SectionIndex = 0;
+
+private:
+  llvm::StringRef Name;
+  llvm::object::coff_section Header;
+  uint32_t StringTableOff = 0;
+  std::vector<Chunk *> Chunks;
+};
+
 }
 }
 

Modified: lld/trunk/test/COFF/lldmap.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/COFF/lldmap.test?rev=291990&r1=291989&r2=291990&view=diff
==============================================================================
--- lld/trunk/test/COFF/lldmap.test (original)
+++ lld/trunk/test/COFF/lldmap.test Fri Jan 13 21:14:46 2017
@@ -4,7 +4,8 @@
 # RUN: lld-link /out:%T/bar.exe /entry:main /lldmap %t.obj
 # RUN: FileCheck %s < %T/bar.map
 
-# CHECK: .obj:
-# CHECK-NEXT: 140001000 .text$mn
-# CHECK-NEXT: 140001000 .data
-# CHECK-NEXT: 140001000 main
+# CHECK:      Address  Size     Align Out     In      File    Symbol
+# CHECK-NEXT: 00001000 00000006  1000 .text  
+# CHECK-NEXT: 00001000 00000006    10         .text$mn
+# CHECK-NEXT: 00001000 00000006    10                 {{.*}}lldmap.test.tmp.obj
+# CHECK-NEXT: 00001000 00000006     0                         main   

Modified: lld/trunk/test/COFF/lto-parallel.ll
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/COFF/lto-parallel.ll?rev=291990&r1=291989&r2=291990&view=diff
==============================================================================
--- lld/trunk/test/COFF/lto-parallel.ll (original)
+++ lld/trunk/test/COFF/lto-parallel.ll Fri Jan 13 21:14:46 2017
@@ -5,15 +5,15 @@
 target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
 target triple = "x86_64-pc-windows-msvc"
 
-; CHECK: <lto object>:
-; CHECK: foo
+; CHECK: <lto object>
+; CHECK-NEXT: foo
 define void @foo() {
   call void @bar()
   ret void
 }
 
-; CHECK: <lto object>:
-; CHECK: bar
+; CHECK: <lto object>
+; CHECK-NEXT: bar
 define void @bar() {
   call void @foo()
   ret void

Modified: lld/trunk/test/COFF/weak-external.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/COFF/weak-external.test?rev=291990&r1=291989&r2=291990&view=diff
==============================================================================
--- lld/trunk/test/COFF/weak-external.test (original)
+++ lld/trunk/test/COFF/weak-external.test Fri Jan 13 21:14:46 2017
@@ -4,9 +4,8 @@
 # RUN: lld-link /out:%t2.exe /entry:g /subsystem:console /lldmap:%t2.map %t.obj %t.lto.obj
 # RUN: FileCheck %s < %t2.map
 
-# CHECK: <lto object>:
-# CHECK-NOT: :
-# CHECK: {{ g$}}
+# CHECK: <lto object>
+# CHECK-NEXT: 0 g
 
 --- !COFF
 header:

Modified: lld/trunk/test/COFF/weak-external3.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/COFF/weak-external3.test?rev=291990&r1=291989&r2=291990&view=diff
==============================================================================
--- lld/trunk/test/COFF/weak-external3.test (original)
+++ lld/trunk/test/COFF/weak-external3.test Fri Jan 13 21:14:46 2017
@@ -5,13 +5,11 @@
 # RUN: lld-link /out:%t2.exe /entry:f /subsystem:console /lldmap:%t2.map %t.obj %t.lto.obj
 # RUN: FileCheck --check-prefix=CHECK2 %s < %t2.map
 
-# CHECK1: <lto object>:
-# CHECK1-NOT: :
-# CHECK1: {{ g$}}
+# CHECK1: <lto object>
+# CHECK1-NEXT: 0 g
 
-# CHECK2: weak-external3{{.*}}:
-# CHECK2-NOT: :
-# CHECK2: {{ f$}}
+# CHECK2: weak-external3.test.tmp.obj
+# CHECK2-NEXT: 0 f
 
 --- !COFF
 header:




More information about the llvm-commits mailing list