[lld] r241689 - COFF: Emit a symbol table if /debug is specified

David Majnemer david.majnemer at gmail.com
Wed Jul 8 09:37:51 PDT 2015


Author: majnemer
Date: Wed Jul  8 11:37:50 2015
New Revision: 241689

URL: http://llvm.org/viewvc/llvm-project?rev=241689&view=rev
Log:
COFF: Emit a symbol table if /debug is specified

Providing a symbol table in the executable is quite useful when
debugging a fully-linked executable without having to reconstruct one
from DWARF.

Differential Revision: http://reviews.llvm.org/D11023

Added:
    lld/trunk/test/COFF/symtab.test
Modified:
    lld/trunk/COFF/Chunks.cpp
    lld/trunk/COFF/InputFiles.cpp
    lld/trunk/COFF/Writer.cpp
    lld/trunk/COFF/Writer.h
    lld/trunk/test/COFF/long-section-name.test

Modified: lld/trunk/COFF/Chunks.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Chunks.cpp?rev=241689&r1=241688&r2=241689&view=diff
==============================================================================
--- lld/trunk/COFF/Chunks.cpp (original)
+++ lld/trunk/COFF/Chunks.cpp Wed Jul  8 11:37:50 2015
@@ -60,7 +60,7 @@ void SectionChunk::applyRelX64(uint8_t *
   case IMAGE_REL_AMD64_REL32_3:  add32(Off, S - P - 7); break;
   case IMAGE_REL_AMD64_REL32_4:  add32(Off, S - P - 8); break;
   case IMAGE_REL_AMD64_REL32_5:  add32(Off, S - P - 9); break;
-  case IMAGE_REL_AMD64_SECTION:  add16(Off, Out->getSectionIndex() + 1); break;
+  case IMAGE_REL_AMD64_SECTION:  add16(Off, Out->SectionIndex); break;
   case IMAGE_REL_AMD64_SECREL:   add32(Off, S - Out->getRVA()); break;
   default:
     llvm::report_fatal_error("Unsupported relocation type");
@@ -74,7 +74,7 @@ void SectionChunk::applyRelX86(uint8_t *
   case IMAGE_REL_I386_DIR32:    add32(Off, S + Config->ImageBase); break;
   case IMAGE_REL_I386_DIR32NB:  add32(Off, S); break;
   case IMAGE_REL_I386_REL32:    add32(Off, S - P - 4); break;
-  case IMAGE_REL_I386_SECTION:  add16(Off, Out->getSectionIndex() + 1); break;
+  case IMAGE_REL_I386_SECTION:  add16(Off, Out->SectionIndex); break;
   case IMAGE_REL_I386_SECREL:   add32(Off, S - Out->getRVA()); break;
   default:
     llvm::report_fatal_error("Unsupported relocation type");

Modified: lld/trunk/COFF/InputFiles.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/InputFiles.cpp?rev=241689&r1=241688&r2=241689&view=diff
==============================================================================
--- lld/trunk/COFF/InputFiles.cpp (original)
+++ lld/trunk/COFF/InputFiles.cpp Wed Jul  8 11:37:50 2015
@@ -141,7 +141,8 @@ std::error_code ObjectFile::initializeCh
       Directives = std::string((const char *)Data.data(), Data.size());
       continue;
     }
-    if (Name.startswith(".debug"))
+    // We want to preserve DWARF debug sections only when /debug is on.
+    if (!Config->Debug && Name.startswith(".debug"))
       continue;
     if (Sec->Characteristics & llvm::COFF::IMAGE_SCN_LNK_REMOVE)
       continue;

Modified: lld/trunk/COFF/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Writer.cpp?rev=241689&r1=241688&r2=241689&view=diff
==============================================================================
--- lld/trunk/COFF/Writer.cpp (original)
+++ lld/trunk/COFF/Writer.cpp Wed Jul  8 11:37:50 2015
@@ -50,6 +50,7 @@ std::error_code Writer::write(StringRef
     createSection(".reloc");
   assignAddresses();
   removeEmptySections();
+  createSymbolAndStringTable();
   if (auto EC = openFile(OutputPath))
     return EC;
   if (Is64) {
@@ -104,8 +105,9 @@ void OutputSection::writeHeaderTo(uint8_
     // If name is too long, write offset into the string table as a name.
     sprintf(Hdr->Name, "/%d", StringTableOff);
   } else {
-    assert(Name.size() <= COFF::NameSize);
-    strncpy(Hdr->Name, Name.data(), Name.size());
+    assert(!Config->Debug || Name.size() <= COFF::NameSize);
+    strncpy(Hdr->Name, Name.data(),
+            std::min(Name.size(), (size_t)COFF::NameSize));
   }
 }
 
@@ -200,8 +202,7 @@ void Writer::createSections() {
     StringRef Name = getOutputSection(Pair.first);
     OutputSection *&Sec = Sections[Name];
     if (!Sec) {
-      size_t SectIdx = OutputSections.size();
-      Sec = new (CAlloc.Allocate()) OutputSection(Name, SectIdx);
+      Sec = new (CAlloc.Allocate()) OutputSection(Name);
       OutputSections.push_back(Sec);
     }
     std::vector<Chunk *> &Chunks = Pair.second;
@@ -280,6 +281,75 @@ void Writer::removeEmptySections() {
   OutputSections.erase(
       std::remove_if(OutputSections.begin(), OutputSections.end(), IsEmpty),
       OutputSections.end());
+  uint32_t Idx = 1;
+  for (OutputSection *Sec : OutputSections)
+    Sec->SectionIndex = Idx++;
+}
+
+size_t Writer::addEntryToStringTable(StringRef Str) {
+  assert(Str.size() > COFF::NameSize);
+  size_t OffsetOfEntry = Strtab.size() + 4; // +4 for the size field
+  Strtab.insert(Strtab.end(), Str.begin(), Str.end());
+  Strtab.push_back('\0');
+  return OffsetOfEntry;
+}
+
+void Writer::createSymbolAndStringTable() {
+  if (!Config->Debug)
+    return;
+  // Name field in the section table is 8 byte long. Longer names need
+  // to be written to the string table. First, construct string table.
+  for (OutputSection *Sec : OutputSections) {
+    StringRef Name = Sec->getName();
+    if (Name.size() <= COFF::NameSize)
+      continue;
+    Sec->setStringTableOff(addEntryToStringTable(Name));
+  }
+  for (ObjectFile *File : Symtab->ObjectFiles) {
+    for (SymbolBody *B : File->getSymbols()) {
+      auto *D = dyn_cast<DefinedRegular>(B);
+      if (!D || !D->isLive())
+        continue;
+      uint64_t RVA = D->getRVA();
+      OutputSection *SymSec = nullptr;
+      for (OutputSection *Sec : OutputSections) {
+        if (Sec->getRVA() > RVA)
+          break;
+        SymSec = Sec;
+      }
+      uint64_t SectionRVA = SymSec->getRVA();
+      uint64_t SymbolValue = RVA - SectionRVA;
+
+      StringRef Name = D->getName();
+      coff_symbol16 Sym;
+      if (Name.size() > COFF::NameSize) {
+        Sym.Name.Offset.Zeroes = 0;
+        Sym.Name.Offset.Offset = addEntryToStringTable(Name);
+      } else {
+        memset(Sym.Name.ShortName, 0, COFF::NameSize);
+        memcpy(Sym.Name.ShortName, Name.data(), Name.size());
+      }
+
+      Sym.Value = SymbolValue;
+      Sym.SectionNumber = SymSec->SectionIndex;
+      Sym.StorageClass = IMAGE_SYM_CLASS_NULL;
+      Sym.NumberOfAuxSymbols = 0;
+      OutputSymtab.push_back(Sym);
+    }
+  }
+  OutputSection *LastSection = OutputSections.back();
+  // We position the symbol table to be adjacent to the end of the last section.
+  uint64_t FileOff =
+      LastSection->getFileOff() +
+      RoundUpToAlignment(LastSection->getRawSize(), FileAlignment);
+  if (!OutputSymtab.empty()) {
+    PointerToSymbolTable = FileOff;
+    FileOff += OutputSymtab.size() * sizeof(coff_symbol16);
+  }
+  if (!Strtab.empty())
+    FileOff += Strtab.size() + 4;
+  FileSize = SizeOfHeaders +
+             RoundUpToAlignment(FileOff - SizeOfHeaders, FileAlignment);
 }
 
 // Visits all sections to assign incremental, non-overlapping RVAs and
@@ -430,39 +500,25 @@ template <typename PEHeaderTy> void Writ
     }
   }
 
-  // Section table
-  // Name field in the section table is 8 byte long. Longer names need
-  // to be written to the string table. First, construct string table.
-  std::vector<char> Strtab;
-  for (OutputSection *Sec : OutputSections) {
-    StringRef Name = Sec->getName();
-    if (Name.size() <= COFF::NameSize)
-      continue;
-    Sec->setStringTableOff(Strtab.size() + 4); // +4 for the size field
-    Strtab.insert(Strtab.end(), Name.begin(), Name.end());
-    Strtab.push_back('\0');
-  }
-
   // Write section table
   for (OutputSection *Sec : OutputSections) {
     Sec->writeHeaderTo(Buf);
     Buf += sizeof(coff_section);
   }
 
-  // Write string table if we need to. The string table immediately
-  // follows the symbol table, so we create a dummy symbol table
-  // first. The symbol table contains one dummy symbol.
-  if (Strtab.empty())
+  if (OutputSymtab.empty())
     return;
-  COFF->PointerToSymbolTable = Buf - Buffer->getBufferStart();
-  COFF->NumberOfSymbols = 1;
-  auto *SymbolTable = reinterpret_cast<coff_symbol16 *>(Buf);
-  Buf += sizeof(*SymbolTable);
-  // (Set 4 to make the dummy symbol point to the first string table
-  // entry, so that tools to print out symbols don't read NUL bytes.)
-  SymbolTable->Name.Offset.Offset = 4;
-  // Then create the symbol table. The first 4 bytes is length
-  // including itself.
+
+  COFF->PointerToSymbolTable = PointerToSymbolTable;
+  uint32_t NumberOfSymbols = OutputSymtab.size();
+  COFF->NumberOfSymbols = NumberOfSymbols;
+  auto *SymbolTable = reinterpret_cast<coff_symbol16 *>(
+      Buffer->getBufferStart() + COFF->PointerToSymbolTable);
+  for (size_t I = 0; I != NumberOfSymbols; ++I)
+    SymbolTable[I] = OutputSymtab[I];
+  // Create the string table, it follows immediately after the symbol table.
+  // The first 4 bytes is length including itself.
+  Buf = reinterpret_cast<uint8_t *>(&SymbolTable[NumberOfSymbols]);
   write32le(Buf, Strtab.size() + 4);
   memcpy(Buf + 4, Strtab.data(), Strtab.size());
 }
@@ -540,8 +596,7 @@ OutputSection *Writer::createSection(Str
                        .Default(0);
   if (!Perms)
     llvm_unreachable("unknown section name");
-  size_t SectIdx = OutputSections.size();
-  auto Sec = new (CAlloc.Allocate()) OutputSection(Name, SectIdx);
+  auto Sec = new (CAlloc.Allocate()) OutputSection(Name);
   Sec->addPermissions(Perms);
   OutputSections.push_back(Sec);
   return Sec;

Modified: lld/trunk/COFF/Writer.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Writer.h?rev=241689&r1=241688&r2=241689&view=diff
==============================================================================
--- lld/trunk/COFF/Writer.h (original)
+++ lld/trunk/COFF/Writer.h Wed Jul  8 11:37:50 2015
@@ -34,13 +34,11 @@ void doICF(const std::vector<Chunk *> &C
 // non-overlapping file offsets and RVAs.
 class OutputSection {
 public:
-  OutputSection(StringRef N, uint32_t SI)
-      : Name(N), SectionIndex(SI), Header({}) {}
+  OutputSection(StringRef N) : Name(N), Header({}) {}
   void setRVA(uint64_t);
   void setFileOffset(uint64_t);
   void addChunk(Chunk *C);
   StringRef getName() { return Name; }
-  uint64_t getSectionIndex() { return SectionIndex; }
   std::vector<Chunk *> &getChunks() { return Chunks; }
   void addPermissions(uint32_t C);
   uint32_t getPermissions() { return Header.Characteristics & PermMask; }
@@ -63,9 +61,11 @@ public:
   // 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;
-  uint32_t SectionIndex;
   coff_section Header;
   uint32_t StringTableOff = 0;
   std::vector<Chunk *> Chunks;
@@ -86,6 +86,8 @@ private:
   void createExportTable();
   void assignAddresses();
   void removeEmptySections();
+  void createSymbolAndStringTable();
+  size_t addEntryToStringTable(StringRef Str);
   std::error_code openFile(StringRef OutputPath);
   template <typename PEHeaderTy> void writeHeader();
   void writeSections();
@@ -105,12 +107,15 @@ private:
   llvm::SpecificBumpPtrAllocator<OutputSection> CAlloc;
   llvm::SpecificBumpPtrAllocator<BaserelChunk> BAlloc;
   std::vector<OutputSection *> OutputSections;
+  std::vector<char> Strtab;
+  std::vector<llvm::object::coff_symbol16> OutputSymtab;
   IdataContents Idata;
   DelayLoadContents DelayIdata;
   EdataContents Edata;
 
   bool Is64;
   uint64_t FileSize;
+  uint32_t PointerToSymbolTable = 0;
   uint64_t SizeOfImage;
   uint64_t SizeOfHeaders;
 

Modified: lld/trunk/test/COFF/long-section-name.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/COFF/long-section-name.test?rev=241689&r1=241688&r2=241689&view=diff
==============================================================================
--- lld/trunk/test/COFF/long-section-name.test (original)
+++ lld/trunk/test/COFF/long-section-name.test Wed Jul  8 11:37:50 2015
@@ -1,5 +1,5 @@
 # RUN: yaml2obj < %s > %t.obj
-# RUN: lld -flavor link2 /out:%t.exe /entry:main %t.obj
+# RUN: lld -flavor link2 /debug /out:%t.exe /entry:main %t.obj
 # RUN: llvm-readobj -sections %t.exe | FileCheck %s
 
 # CHECK: Name: .data_long_section_name

Added: lld/trunk/test/COFF/symtab.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/COFF/symtab.test?rev=241689&view=auto
==============================================================================
--- lld/trunk/test/COFF/symtab.test (added)
+++ lld/trunk/test/COFF/symtab.test Wed Jul  8 11:37:50 2015
@@ -0,0 +1,84 @@
+# RUN: yaml2obj < %s > %t.obj
+# RUN: lld -flavor link2 /debug /out:%t.exe /entry:main %t.obj
+# RUN: llvm-readobj -symbols %t.exe | FileCheck %s
+
+# CHECK:      Symbols [
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: .text
+# CHECK-NEXT:     Value: 0
+# CHECK-NEXT:     Section: .text
+# CHECK-NEXT:     BaseType: Null (0x0)
+# CHECK-NEXT:     ComplexType: Null (0x0)
+# CHECK-NEXT:     StorageClass: Null (0x0)
+# CHECK-NEXT:     AuxSymbolCount: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: f
+# CHECK-NEXT:     Value: 2
+# CHECK-NEXT:     Section: .text
+# CHECK-NEXT:     BaseType: Null (0x0)
+# CHECK-NEXT:     ComplexType: Null (0x0)
+# CHECK-NEXT:     StorageClass: Null (0x0)
+# CHECK-NEXT:     AuxSymbolCount: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: g
+# CHECK-NEXT:     Value: 4
+# CHECK-NEXT:     Section: .text
+# CHECK-NEXT:     BaseType: Null (0x0)
+# CHECK-NEXT:     ComplexType: Null (0x0)
+# CHECK-NEXT:     StorageClass: Null (0x0)
+# CHECK-NEXT:     AuxSymbolCount: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: main
+# CHECK-NEXT:     Value: 0
+# CHECK-NEXT:     Section: .text
+# CHECK-NEXT:     BaseType: Null (0x0)
+# CHECK-NEXT:     ComplexType: Null (0x0)
+# CHECK-NEXT:     StorageClass: Null (0x0)
+# CHECK-NEXT:     AuxSymbolCount: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+
+---
+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:     B82A00
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          6
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            f
+    Value:           2
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            g
+    Value:           4
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            main
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...





More information about the llvm-commits mailing list