PECOFF: make dumpbin tool happy.
authorRui Ueyama <ruiu@google.com>
Thu, 12 Feb 2015 02:50:05 +0000 (02:50 +0000)
committerRui Ueyama <ruiu@google.com>
Thu, 12 Feb 2015 02:50:05 +0000 (02:50 +0000)
The dumpbin tool in the MSVC toolchain cannot handle an executable created
by LLD if the executable contains a long section name.

In PE/COFF, a section name is stored to a section table entry. Because the
section name field in the table is only 8 byte long, a name longer than
that is stored to the string table and the offset in the string table is
stored to the section table entry instead.

In order to look up a string from the string table, tools need to handle
the symbol table, because the string table is defined as it immediately
follows the symbol table.

And seems the dumpbin doesn't like zero-length symbol table.

This patch teaches LLD how to emit a dummy symbol table. The dummy table
has one dummy entry in it.

llvm-svn: 228900

lld/lib/ReaderWriter/PECOFF/WriterPECOFF.cpp

index a77050a..099c370 100644 (file)
@@ -148,6 +148,7 @@ public:
   }
 
   void setNumberOfSections(uint32_t num) { _coffHeader.NumberOfSections = num; }
+  void setNumberOfSymbols(uint32_t num) { _coffHeader.NumberOfSymbols = num; }
 
   void setAddressOfEntryPoint(uint32_t address) {
     _peHeader.AddressOfEntryPoint = address;
@@ -186,13 +187,20 @@ public:
   }
 
   uint32_t addSectionName(StringRef sectionName) {
-    if (_stringTable.empty())
-      _stringTable.insert(_stringTable.begin(), 4, 0);
+    if (_stringTable.empty()) {
+      // The string table immediately follows the symbol table.
+      // We don't really need a symbol table, but some tools (e.g. dumpbin)
+      // don't like zero-length symbol table.
+      // Make room for the empty symbol slot, which occupies 18 byte.
+      // We also need to reserve 4 bytes for the string table header.
+      int size = sizeof(llvm::object::coff_symbol16) + 4;
+      _stringTable.insert(_stringTable.begin(), size, 0);
+    }
     uint32_t offset = _stringTable.size();
     _stringTable.insert(_stringTable.end(), sectionName.begin(),
                         sectionName.end());
     _stringTable.push_back('\0');
-    return offset;
+    return offset - sizeof(llvm::object::coff_symbol16);
   }
 
   uint64_t size() const override { return _stringTable.size(); }
@@ -200,7 +208,8 @@ public:
   void write(uint8_t *buffer) override {
     if (_stringTable.empty())
       return;
-    *reinterpret_cast<ulittle32_t *>(_stringTable.data()) = _stringTable.size();
+    char *off = _stringTable.data() + sizeof(llvm::object::coff_symbol16);
+    *reinterpret_cast<ulittle32_t *>(off) = _stringTable.size();
     std::memcpy(buffer, _stringTable.data(), _stringTable.size());
   }
 
@@ -1158,11 +1167,11 @@ void PECOFFWriter::build(const File &linkedFile) {
   }
 
   setImageSizeOnDisk();
-  // N.B. Currently released versions of dumpbin do not appropriately handle
-  // symbol tables which NumberOfSymbols set to zero but a non-zero
-  // PointerToSymbolTable.
-  if (stringTable->size())
+
+  if (stringTable->size()) {
     peHeader->setPointerToSymbolTable(stringTable->fileOffset());
+    peHeader->setNumberOfSymbols(1);
+  }
 
   for (std::unique_ptr<Chunk> &chunk : _chunks) {
     SectionChunk *section = dyn_cast<SectionChunk>(chunk.get());