diff options
Diffstat (limited to 'lld/COFF/Writer.cpp')
-rw-r--r-- | lld/COFF/Writer.cpp | 128 |
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) { |