[lld] r309303 - [PDB] Write public symbol records and the publics hash table

Reid Kleckner via llvm-commits llvm-commits at lists.llvm.org
Thu Jul 27 11:25:59 PDT 2017


Author: rnk
Date: Thu Jul 27 11:25:59 2017
New Revision: 309303

URL: http://llvm.org/viewvc/llvm-project?rev=309303&view=rev
Log:
[PDB] Write public symbol records and the publics hash table

Summary:
MSVC link.exe records all external symbol names in the publics stream.
It provides similar functionality to an ELF .symtab.

Reviewers: zturner, ruiu

Subscribers: hiraditya, llvm-commits

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

Added:
    lld/trunk/test/COFF/pdb-publics-import.test
Modified:
    lld/trunk/COFF/PDB.cpp
    lld/trunk/COFF/SymbolTable.h
    lld/trunk/COFF/Symbols.cpp
    lld/trunk/COFF/Symbols.h
    lld/trunk/COFF/Writer.cpp
    lld/trunk/test/COFF/pdb-import-gc.yaml
    lld/trunk/test/COFF/pdb.test

Modified: lld/trunk/COFF/PDB.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/PDB.cpp?rev=309303&r1=309302&r2=309303&view=diff
==============================================================================
--- lld/trunk/COFF/PDB.cpp (original)
+++ lld/trunk/COFF/PDB.cpp Thu Jul 27 11:25:59 2017
@@ -13,6 +13,7 @@
 #include "Error.h"
 #include "SymbolTable.h"
 #include "Symbols.h"
+#include "Writer.h"
 #include "llvm/DebugInfo/CodeView/CVDebugRecord.h"
 #include "llvm/DebugInfo/CodeView/DebugSubsectionRecord.h"
 #include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
@@ -34,6 +35,7 @@
 #include "llvm/DebugInfo/PDB/Native/PDBFile.h"
 #include "llvm/DebugInfo/PDB/Native/PDBFileBuilder.h"
 #include "llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h"
+#include "llvm/DebugInfo/PDB/Native/PublicsStreamBuilder.h"
 #include "llvm/DebugInfo/PDB/Native/TpiHashing.h"
 #include "llvm/DebugInfo/PDB/Native/TpiStream.h"
 #include "llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h"
@@ -545,6 +547,23 @@ void PDBLinker::addObjFile(ObjFile *File
   }
 }
 
+static PublicSym32 createPublic(Defined *Def) {
+  PublicSym32 Pub(SymbolKind::S_PUB32);
+  Pub.Name = Def->getName();
+  if (auto *D = dyn_cast<DefinedCOFF>(Def)) {
+    if (D->getCOFFSymbol().isFunctionDefinition())
+      Pub.Flags = PublicSymFlags::Function;
+  } else if (isa<DefinedImportThunk>(Def)) {
+    Pub.Flags = PublicSymFlags::Function;
+  }
+
+  OutputSection *OS = Def->getChunk()->getOutputSection();
+  assert(OS && "all publics should be in final image");
+  Pub.Offset = Def->getRVA() - OS->getRVA();
+  Pub.Segment = OS->SectionIndex;
+  return Pub;
+}
+
 // Add all object files to the PDB. Merge .debug$T sections into IpiData and
 // TpiData.
 void PDBLinker::addObjectsToPDB() {
@@ -559,12 +578,25 @@ void PDBLinker::addObjectsToPDB() {
   // Construct IPI stream contents.
   addTypeInfo(Builder.getIpiBuilder(), IDTable);
 
-  // Add public and symbol records stream.
+  // Compute the public symbols.
+  std::vector<PublicSym32> Publics;
+  Symtab->forEachSymbol([&Publics](Symbol *S) {
+    // Only emit defined, live symbols that have a chunk.
+    auto *Def = dyn_cast<Defined>(S->body());
+    if (Def && Def->isLive() && Def->getChunk())
+      Publics.push_back(createPublic(Def));
+  });
 
-  // For now we don't actually write any thing useful to the publics stream, but
-  // the act of "getting" it also creates it lazily so that we write an empty
-  // stream.
-  (void)Builder.getPublicsBuilder();
+  if (!Publics.empty()) {
+    // Sort the public symbols and add them to the stream.
+    std::sort(Publics.begin(), Publics.end(),
+              [](const PublicSym32 &L, const PublicSym32 &R) {
+                return L.Name < R.Name;
+              });
+    auto &PublicsBuilder = Builder.getPublicsBuilder();
+    for (const PublicSym32 &Pub : Publics)
+      PublicsBuilder.addPublicSymbol(Pub);
+  }
 }
 
 static void addLinkerModuleSymbols(StringRef Path,

Modified: lld/trunk/COFF/SymbolTable.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/SymbolTable.h?rev=309303&r1=309302&r2=309303&view=diff
==============================================================================
--- lld/trunk/COFF/SymbolTable.h (original)
+++ lld/trunk/COFF/SymbolTable.h Thu Jul 27 11:25:59 2017
@@ -99,6 +99,12 @@ public:
   // A list of chunks which to be added to .rdata.
   std::vector<Chunk *> LocalImportChunks;
 
+  // Iterates symbols in non-determinstic hash table order.
+  template <typename T> void forEachSymbol(T Callback) {
+    for (auto &Pair : Symtab)
+      Callback(Pair.second);
+  }
+
 private:
   std::pair<Symbol *, bool> insert(StringRef Name);
   StringRef findByPrefix(StringRef Prefix);

Modified: lld/trunk/COFF/Symbols.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Symbols.cpp?rev=309303&r1=309302&r2=309303&view=diff
==============================================================================
--- lld/trunk/COFF/Symbols.cpp (original)
+++ lld/trunk/COFF/Symbols.cpp Thu Jul 27 11:25:59 2017
@@ -52,6 +52,17 @@ InputFile *SymbolBody::getFile() {
   return nullptr;
 }
 
+bool SymbolBody::isLive() const {
+  if (auto *R = dyn_cast<DefinedRegular>(this))
+    return R->getChunk()->isLive();
+  if (auto *Imp = dyn_cast<DefinedImportData>(this))
+    return Imp->File->Live;
+  if (auto *Imp = dyn_cast<DefinedImportThunk>(this))
+    return Imp->WrappedSym->File->Live;
+  // Assume any other kind of symbol is live.
+  return true;
+}
+
 COFFSymbolRef DefinedCOFF::getCOFFSymbol() {
   size_t SymSize = cast<ObjFile>(File)->getCOFFObj()->getSymbolTableEntrySize();
   if (SymSize == sizeof(coff_symbol16))

Modified: lld/trunk/COFF/Symbols.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Symbols.h?rev=309303&r1=309302&r2=309303&view=diff
==============================================================================
--- lld/trunk/COFF/Symbols.h (original)
+++ lld/trunk/COFF/Symbols.h Thu Jul 27 11:25:59 2017
@@ -70,6 +70,10 @@ public:
   // Returns the file from which this symbol was created.
   InputFile *getFile();
 
+  // Indicates that this symbol will be included in the final image. Only valid
+  // after calling markLive.
+  bool isLive() const;
+
   Symbol *symbol();
   const Symbol *symbol() const {
     return const_cast<SymbolBody *>(this)->symbol();
@@ -155,10 +159,10 @@ public:
     return S->kind() == DefinedRegularKind;
   }
 
-  uint64_t getRVA() { return (*Data)->getRVA() + Sym->Value; }
-  bool isCOMDAT() { return IsCOMDAT; }
-  SectionChunk *getChunk() { return *Data; }
-  uint32_t getValue() { return Sym->Value; }
+  uint64_t getRVA() const { return (*Data)->getRVA() + Sym->Value; }
+  bool isCOMDAT() const { return IsCOMDAT; }
+  SectionChunk *getChunk() const { return *Data; }
+  uint32_t getValue() const { return Sym->Value; }
 
 private:
   SectionChunk **Data;

Modified: lld/trunk/COFF/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Writer.cpp?rev=309303&r1=309302&r2=309303&view=diff
==============================================================================
--- lld/trunk/COFF/Writer.cpp (original)
+++ lld/trunk/COFF/Writer.cpp Thu Jul 27 11:25:59 2017
@@ -432,19 +432,12 @@ Optional<coff_symbol16> Writer::createSy
   if (isa<DefinedSynthetic>(Def))
     return None;
 
-  if (auto *D = dyn_cast<DefinedRegular>(Def)) {
-    // Don't write dead symbols or symbols in codeview sections to the symbol
-    // table.
-    if (!D->getChunk()->isLive() || D->getChunk()->isCodeView())
-      return None;
-  }
-
-  if (auto *Sym = dyn_cast<DefinedImportData>(Def))
-    if (!Sym->File->Live)
-      return None;
-
-  if (auto *Sym = dyn_cast<DefinedImportThunk>(Def))
-    if (!Sym->WrappedSym->File->Live)
+  // Don't write dead symbols or symbols in codeview sections to the symbol
+  // table.
+  if (!Def->isLive())
+    return None;
+  if (auto *D = dyn_cast<DefinedRegular>(Def))
+    if (D->getChunk()->isCodeView())
       return None;
 
   coff_symbol16 Sym;

Modified: lld/trunk/test/COFF/pdb-import-gc.yaml
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/COFF/pdb-import-gc.yaml?rev=309303&r1=309302&r2=309303&view=diff
==============================================================================
--- lld/trunk/test/COFF/pdb-import-gc.yaml (original)
+++ lld/trunk/test/COFF/pdb-import-gc.yaml Thu Jul 27 11:25:59 2017
@@ -1,7 +1,7 @@
 # RUN: yaml2obj %s -o %t.obj
 # RUN: lld-link %t.obj %S/Inputs/pdb-import-gc.lib -debug -entry:main \
 # RUN:          -nodefaultlib -debug -out:%t.exe -pdb:%t.pdb
-# RUN: llvm-pdbutil dump -symbols %t.pdb | FileCheck %s
+# RUN: llvm-pdbutil dump -publics -symbols %t.pdb | FileCheck %s
 
 # This tests the case where an __imp_ chunk is discarded by linker GC. The debug
 # info may refer to the __imp_ symbol still.

Added: lld/trunk/test/COFF/pdb-publics-import.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/COFF/pdb-publics-import.test?rev=309303&view=auto
==============================================================================
--- lld/trunk/test/COFF/pdb-publics-import.test (added)
+++ lld/trunk/test/COFF/pdb-publics-import.test Thu Jul 27 11:25:59 2017
@@ -0,0 +1,23 @@
+Make a DLL that exports a few functions, then make a DLL with PDBs that imports
+them. Check that the __imp_ pointer and the generated thunks appear in the
+publics stream.
+
+RUN: yaml2obj < %p/Inputs/export.yaml > %t1.obj
+RUN: lld-link /out:%t1.dll /dll %t1.obj /implib:%t1.lib \
+RUN:   /export:exportfn1 /export:exportfn2
+RUN: yaml2obj < %p/Inputs/import.yaml > %t2.obj
+RUN: lld-link /out:%t2.exe /pdb:%t2.pdb /debug /entry:main %t2.obj %t1.lib
+RUN: llvm-pdbutil dump %t2.pdb -publics | FileCheck %s
+
+CHECK:                             Public Symbols
+CHECK-NEXT: ============================================================
+CHECK-NEXT:      112 | S_PUB32 [size = 20] `main`
+CHECK-NEXT:            flags = function, addr = 0001:0000
+CHECK-NEXT:       64 | S_PUB32 [size = 24] `exportfn1`
+CHECK-NEXT:            flags = function, addr = 0001:0016
+CHECK-NEXT:       88 | S_PUB32 [size = 24] `exportfn2`
+CHECK-NEXT:            flags = function, addr = 0001:0032
+CHECK-NEXT:       32 | S_PUB32 [size = 32] `__imp_exportfn2`
+CHECK-NEXT:            flags = none, addr = 0003:0072
+CHECK-NEXT:        0 | S_PUB32 [size = 32] `__imp_exportfn1`
+CHECK-NEXT:            flags = none, addr = 0003:0064

Modified: lld/trunk/test/COFF/pdb.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/COFF/pdb.test?rev=309303&r1=309302&r2=309303&view=diff
==============================================================================
--- lld/trunk/test/COFF/pdb.test (original)
+++ lld/trunk/test/COFF/pdb.test Thu Jul 27 11:25:59 2017
@@ -7,7 +7,8 @@
 # RUN:   -dbi-stream -ipi-stream -tpi-stream %t.pdb | FileCheck %s
 
 # RUN: llvm-pdbutil dump -modules -section-map -section-contribs \
-# RUN:   -types -ids -type-extras -id-extras %t.pdb | FileCheck -check-prefix RAW %s
+# RUN:   -publics -public-extras -types -ids -type-extras -id-extras %t.pdb \
+# RUN:   | FileCheck -check-prefix RAW %s
 
 # CHECK:      MSF:
 # CHECK-NEXT:   SuperBlock:
@@ -171,6 +172,22 @@ RAW-NEXT:            0x1003: `C:\vs14\VC
 RAW-NEXT:            0x100A: `ret42-sub.c`
 RAW-NEXT:            0x1008: `D:\b\vc140.pdb`
 RAW-NEXT:            0x1006: ` -I"C:\Program Files (x86)\Windows Kits\8.1\include\um" -I"C:\Program Files (x86)\Windows Kits\8.1\include\winrt" -TC -X`
+RAW:                            Public Symbols
+RAW-NEXT:============================================================
+RAW-NEXT:      20 | S_PUB32 [size = 20] `main`
+RAW-NEXT:           flags = function, addr = 0002:0000
+RAW-NEXT:       0 | S_PUB32 [size = 20] `foo`
+RAW-NEXT:           flags = function, addr = 0002:0016
+RAW-NOT: S_PUB32
+RAW-NEXT:  Hash Records
+RAW-NEXT:    off = 21, refcnt = 1
+RAW-NEXT:    off = 1, refcnt = 1
+RAW-NEXT:  Hash Buckets
+RAW-NEXT:    0x00000000
+RAW-NEXT:    0x0000000c
+RAW-NEXT:  Address Map
+RAW-NEXT:    off = 20
+RAW-NEXT:    off = 0
 RAW:                        Section Contributions
 RAW-NEXT: ============================================================
 RAW-NEXT:   SC  | mod = 0, 65535:1288, size = 14, data crc = 0, reloc crc = 0




More information about the llvm-commits mailing list