[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