summaryrefslogtreecommitdiffstats
path: root/lld/COFF/Writer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lld/COFF/Writer.cpp')
-rw-r--r--lld/COFF/Writer.cpp128
1 files changed, 106 insertions, 22 deletions
diff --git a/lld/COFF/Writer.cpp b/lld/COFF/Writer.cpp
index afdacdef135..f071fd2e2bf 100644
--- a/lld/COFF/Writer.cpp
+++ b/lld/COFF/Writer.cpp
@@ -118,7 +118,7 @@ private:
void createExportTable();
void assignAddresses();
void removeEmptySections();
- void createStringTable();
+ void createSymbolAndStringTable();
void openFile(StringRef OutputPath);
template <typename PEHeaderTy> void writeHeader();
void createSEHTable(OutputSection *RData);
@@ -127,6 +127,9 @@ private:
void writeBuildId();
void sortExceptionTable();
+ llvm::Optional<coff_symbol16> createSymbol(Defined *D);
+ size_t addEntryToStringTable(StringRef Str);
+
OutputSection *findSection(StringRef Name);
OutputSection *createSection(StringRef Name);
void addBaserels(OutputSection *Dest);
@@ -151,7 +154,7 @@ private:
ArrayRef<uint8_t> SectionTable;
uint64_t FileSize;
- uint32_t PointerToStringTable = 0;
+ uint32_t PointerToSymbolTable = 0;
uint64_t SizeOfImage;
uint64_t SizeOfHeaders;
};
@@ -290,7 +293,7 @@ void Writer::run() {
assignAddresses();
removeEmptySections();
setSectionPermissions();
- createStringTable();
+ createSymbolAndStringTable();
// We must do this before opening the output file, as it depends on being able
// to read the contents of the existing output file.
@@ -467,7 +470,69 @@ void Writer::removeEmptySections() {
Sec->SectionIndex = Idx++;
}
-void Writer::createStringTable() {
+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;
+}
+
+Optional<coff_symbol16> Writer::createSymbol(Defined *Def) {
+ // Relative symbols are unrepresentable in a COFF symbol table.
+ if (isa<DefinedSynthetic>(Def))
+ return None;
+
+ // 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;
+ StringRef Name = Def->getName();
+ 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());
+ }
+
+ if (auto *D = dyn_cast<DefinedCOFF>(Def)) {
+ COFFSymbolRef Ref = D->getCOFFSymbol();
+ Sym.Type = Ref.getType();
+ Sym.StorageClass = Ref.getStorageClass();
+ } else {
+ Sym.Type = IMAGE_SYM_TYPE_NULL;
+ Sym.StorageClass = IMAGE_SYM_CLASS_EXTERNAL;
+ }
+ Sym.NumberOfAuxSymbols = 0;
+
+ switch (Def->kind()) {
+ case Symbol::DefinedAbsoluteKind:
+ Sym.Value = Def->getRVA();
+ Sym.SectionNumber = IMAGE_SYM_ABSOLUTE;
+ break;
+ default: {
+ uint64_t RVA = Def->getRVA();
+ OutputSection *Sec = nullptr;
+ for (OutputSection *S : OutputSections) {
+ if (S->getRVA() > RVA)
+ break;
+ Sec = S;
+ }
+ Sym.Value = RVA - Sec->getRVA();
+ Sym.SectionNumber = Sec->SectionIndex;
+ break;
+ }
+ }
+ return Sym;
+}
+
+void Writer::createSymbolAndStringTable() {
// 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) {
@@ -481,19 +546,34 @@ void Writer::createStringTable() {
// to libunwind.
if ((Sec->getPermissions() & IMAGE_SCN_MEM_DISCARDABLE) == 0)
continue;
- Sec->setStringTableOff(Strtab.size() + 4); // +4 for the size field
- Strtab.insert(Strtab.end(), Name.begin(), Name.end());
- Strtab.push_back('\0');
+ Sec->setStringTableOff(addEntryToStringTable(Name));
+ }
+
+ if (Config->DebugDwarf) {
+ for (ObjFile *File : ObjFile::Instances) {
+ for (Symbol *B : File->getSymbols()) {
+ auto *D = dyn_cast_or_null<Defined>(B);
+ if (!D || D->WrittenToSymtab)
+ continue;
+ D->WrittenToSymtab = true;
+
+ if (Optional<coff_symbol16> Sym = createSymbol(D))
+ OutputSymtab.push_back(*Sym);
+ }
+ }
}
- if (Strtab.empty())
+ if (OutputSymtab.empty() && Strtab.empty())
return;
OutputSection *LastSection = OutputSections.back();
- // We position the string table to be adjacent to the end of the last section.
- PointerToStringTable = LastSection->getFileOff() +
- alignTo(LastSection->getRawSize(), SectorSize);
- FileSize = alignTo(PointerToStringTable + Strtab.size() + 4, SectorSize);
+ // We position the symbol table to be adjacent to the end of the last section.
+ uint64_t FileOff = LastSection->getFileOff() +
+ alignTo(LastSection->getRawSize(), SectorSize);
+ PointerToSymbolTable = FileOff;
+ FileOff += OutputSymtab.size() * sizeof(coff_symbol16);
+ FileOff += 4 + Strtab.size();
+ FileSize = alignTo(FileOff, SectorSize);
}
// Visits all sections to assign incremental, non-overlapping RVAs and
@@ -680,18 +760,22 @@ template <typename PEHeaderTy> void Writer::writeHeader() {
SectionTable = ArrayRef<uint8_t>(
Buf - OutputSections.size() * sizeof(coff_section), Buf);
- // The string table normally follows the symbol table, but because we always
- // emit an empty symbol table, the string table appears at the location of the
- // symbol table.
- COFF->PointerToSymbolTable = PointerToStringTable;
- COFF->NumberOfSymbols = 0;
- if (Strtab.empty())
+ if (OutputSymtab.empty() && Strtab.empty())
return;
- auto *StringTable = Buffer->getBufferStart() + PointerToStringTable;
- // Create the string table. The first 4 bytes is length including itself.
- write32le(StringTable, Strtab.size() + 4);
- memcpy(StringTable + 4, Strtab.data(), Strtab.size());
+ 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);
+ if (!Strtab.empty())
+ memcpy(Buf + 4, Strtab.data(), Strtab.size());
}
void Writer::openFile(StringRef Path) {
OpenPOWER on IntegriCloud