diff --git a/lld/COFF/Writer.cpp b/lld/COFF/Writer.cpp --- a/lld/COFF/Writer.cpp +++ b/lld/COFF/Writer.cpp @@ -24,6 +24,7 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringSet.h" #include "llvm/ADT/StringSwitch.h" +#include "llvm/MC/StringTableBuilder.h" #include "llvm/Support/BinaryStreamReader.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Endian.h" @@ -195,7 +196,9 @@ // The writer writes a SymbolTable result to a file. class Writer { public: - Writer(COFFLinkerContext &c) : buffer(errorHandler().outputBuffer), ctx(c) {} + Writer(COFFLinkerContext &c) + : buffer(errorHandler().outputBuffer), + strtab(StringTableBuilder::WinCOFF), ctx(c) {} void run(); private: @@ -240,7 +243,6 @@ PartialSection *findPartialSection(StringRef name, uint32_t outChars); llvm::Optional createSymbol(Defined *d); - size_t addEntryToStringTable(StringRef str); OutputSection *findSection(StringRef name); void addBaserels(); @@ -250,7 +252,7 @@ std::unique_ptr &buffer; std::map partialSections; - std::vector strtab; + StringTableBuilder strtab; std::vector outputSymtab; IdataContents idata; Chunk *importTableStart = nullptr; @@ -1120,14 +1122,6 @@ sc->setOutputSectionIdx(mc->getOutputSectionIdx()); } -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 Writer::createSymbol(Defined *def) { coff_symbol16 sym; switch (def->kind()) { @@ -1164,7 +1158,8 @@ StringRef name = def->getName(); if (name.size() > COFF::NameSize) { sym.Name.Offset.Zeroes = 0; - sym.Name.Offset.Offset = addEntryToStringTable(name); + sym.Name.Offset.Offset = 0; // Filled in later + strtab.add(name); } else { memset(sym.Name.ShortName, 0, COFF::NameSize); memcpy(sym.Name.ShortName, name.data(), name.size()); @@ -1191,6 +1186,7 @@ // solution where discardable sections have long names preserved and // non-discardable sections have their names truncated, to ensure that any // section which is mapped at runtime also has its name mapped at runtime. + std::vector longNameSections; for (OutputSection *sec : ctx.outputSections) { if (sec->name.size() <= COFF::NameSize) continue; @@ -1201,9 +1197,12 @@ " is longer than 8 characters and will use a non-standard string " "table"); } - sec->setStringTableOff(addEntryToStringTable(sec->name)); + + strtab.add(sec->name); + longNameSections.push_back(sec); } + std::vector> longNameSymbols; if (config->debugDwarf || config->debugSymtab) { for (ObjFile *file : ctx.objFileInstances) { for (Symbol *b : file->getSymbols()) { @@ -1218,20 +1217,33 @@ continue; } - if (Optional sym = createSymbol(d)) + if (Optional sym = createSymbol(d)) { outputSymtab.push_back(*sym); + if (d->getName().size() > COFF::NameSize) + longNameSymbols.push_back({outputSymtab.size() - 1, d->getName()}); + } } } } - if (outputSymtab.empty() && strtab.empty()) + strtab.finalize(); + + for (OutputSection *sec : longNameSections) + sec->setStringTableOff(strtab.getOffset(sec->name)); + + for (auto P : longNameSymbols) { + coff_symbol16 &sym = outputSymtab[P.first]; + sym.Name.Offset.Offset = strtab.getOffset(P.second); + } + + if (outputSymtab.empty() && strtab.getSize() <= 4) return; // We position the symbol table to be adjacent to the end of the last section. uint64_t fileOff = fileSize; pointerToSymbolTable = fileOff; fileOff += outputSymtab.size() * sizeof(coff_symbol16); - fileOff += 4 + strtab.size(); + fileOff += strtab.getSize(); fileSize = alignTo(fileOff, config->fileAlign); } @@ -1506,7 +1518,7 @@ sectionTable = ArrayRef( buf - ctx.outputSections.size() * sizeof(coff_section), buf); - if (outputSymtab.empty() && strtab.empty()) + if (outputSymtab.empty() && strtab.getSize() <= 4) return; coff->PointerToSymbolTable = pointerToSymbolTable; @@ -1519,9 +1531,7 @@ // Create the string table, it follows immediately after the symbol table. // The first 4 bytes is length including itself. buf = reinterpret_cast(&symbolTable[numberOfSymbols]); - write32le(buf, strtab.size() + 4); - if (!strtab.empty()) - memcpy(buf + 4, strtab.data(), strtab.size()); + strtab.write(buf); } void Writer::openFile(StringRef path) {