Index: lib/ReaderWriter/PECOFF/WriterPECOFF.cpp =================================================================== --- lib/ReaderWriter/PECOFF/WriterPECOFF.cpp +++ lib/ReaderWriter/PECOFF/WriterPECOFF.cpp @@ -68,6 +68,7 @@ enum Kind { kindHeader, kindSection, + kindStringTable, kindAtomChunk }; @@ -154,6 +155,10 @@ _peHeader.AddressOfEntryPoint = address; } + void setPointerToSymbolTable(uint32_t rva) { + _coffHeader.PointerToSymbolTable = rva; + } + private: llvm::object::coff_file_header _coffHeader; PEHeader _peHeader; @@ -174,6 +179,33 @@ std::vector _sections; }; +class StringTableChunk : public Chunk { +public: + StringTableChunk() : Chunk(kindStringTable) {} + static bool classof(const Chunk *c) { + return c->getKind() == kindStringTable; + } + uint32_t addSectionName(StringRef sectionName) { + if (_stringTable.empty()) + _stringTable.insert(_stringTable.begin(), 4, 0); + uint32_t offset = _stringTable.size(); + _stringTable.insert(_stringTable.end(), sectionName.begin(), + sectionName.end()); + _stringTable.push_back('\0'); + return offset; + } + uint64_t size() const override { return _stringTable.size(); } + void write(uint8_t *buffer) override { + if (_stringTable.empty()) + return; + *reinterpret_cast(_stringTable.data()) = _stringTable.size(); + std::memcpy(buffer, _stringTable.data(), _stringTable.size()); + } + +private: + std::vector _stringTable; +}; + class SectionChunk : public Chunk { public: uint64_t onDiskSize() const override { @@ -194,15 +226,20 @@ uint64_t getVirtualAddress() { return _virtualAddress; } virtual void setVirtualAddress(uint32_t rva) { _virtualAddress = rva; } + uint32_t getStringTableOffset() const { return _stringTableOffset; } + void setStringTableOffset(uint32_t offset) { _stringTableOffset = offset; } + protected: SectionChunk(Kind kind, StringRef sectionName, uint32_t characteristics) : Chunk(kind), _sectionName(sectionName), - _characteristics(characteristics), _virtualAddress(0) {} + _characteristics(characteristics), _virtualAddress(0), + _stringTableOffset(0) {} private: StringRef _sectionName; const uint32_t _characteristics; uint64_t _virtualAddress; + uint32_t _stringTableOffset; }; /// An AtomChunk represents a section containing atoms. @@ -753,15 +790,13 @@ SectionHeaderTableChunk::createSectionHeader(SectionChunk *chunk) { llvm::object::coff_section header; - // Section name must be equal to or less than 8 characters in the - // executable. Longer names will be truncated. StringRef sectionName = chunk->getSectionName(); - - // Name field must be NUL-padded. If the name is exactly 8 byte long, - // there's no terminating NUL. - std::memset(header.Name, 0, sizeof(header.Name)); - std::strncpy(header.Name, sectionName.data(), - std::min(sizeof(header.Name), sectionName.size())); + if (uint32_t stringTableOffset = chunk->getStringTableOffset()) { + sprintf(header.Name, "/%u", stringTableOffset); + } else { + std::memset(header.Name, 0, llvm::COFF::NameSize); + std::strncpy(header.Name, sectionName.data(), sectionName.size()); + } uint32_t characteristics = chunk->getCharacteristics(); header.VirtualSize = chunk->size(); @@ -875,7 +910,8 @@ void reorderSEHTableEntriesX64(uint8_t *bufferStart); void addChunk(Chunk *chunk); - void addSectionChunk(SectionChunk *chunk, SectionHeaderTableChunk *table); + void addSectionChunk(SectionChunk *chunk, SectionHeaderTableChunk *table, + StringTableChunk *stringTable); void setImageSizeOnDisk(); uint64_t calcSectionSize(llvm::COFF::SectionCharacteristics sectionType) const; @@ -976,10 +1012,12 @@ auto *peHeader = new PEHeaderChunk(_ctx); auto *dataDirectory = new DataDirectoryChunk(); auto *sectionTable = new SectionHeaderTableChunk(); + auto *stringTable = new StringTableChunk(); addChunk(dosStub); addChunk(peHeader); addChunk(dataDirectory); addChunk(sectionTable); + addChunk(stringTable); // Create sections and add the atoms to them. for (auto i : atoms) { @@ -987,7 +1025,7 @@ std::vector &contents = i.second; auto *section = new AtomChunk(_ctx, sectionName, contents); if (section->size() > 0) - addSectionChunk(section, sectionTable); + addSectionChunk(section, sectionTable, stringTable); } // Build atom to its RVA map. @@ -1001,7 +1039,7 @@ if (_ctx.getBaseRelocationEnabled()) { BaseRelocChunk *baseReloc = new BaseRelocChunk(_chunks, _ctx); if (baseReloc->size()) { - addSectionChunk(baseReloc, sectionTable); + addSectionChunk(baseReloc, sectionTable, stringTable); dataDirectory->setField(DataDirectoryIndex::BASE_RELOCATION_TABLE, baseReloc->getVirtualAddress(), baseReloc->size()); @@ -1009,6 +1047,8 @@ } setImageSizeOnDisk(); + if (stringTable->size()) + peHeader->setPointerToSymbolTable(stringTable->fileOffset()); for (std::unique_ptr &chunk : _chunks) { SectionChunk *section = dyn_cast(chunk.get()); @@ -1181,11 +1221,18 @@ } void PECOFFWriter::addSectionChunk(SectionChunk *chunk, - SectionHeaderTableChunk *table) { + SectionHeaderTableChunk *table, + StringTableChunk *stringTable) { _chunks.push_back(std::unique_ptr(chunk)); table->addSection(chunk); _numSections++; + StringRef sectionName = chunk->getSectionName(); + if (sectionName.size() > llvm::COFF::NameSize) { + uint32_t stringTableOffset = stringTable->addSectionName(sectionName); + chunk->setStringTableOffset(stringTableOffset); + } + // Compute and set the starting address of sections when loaded in // memory. They are different from positions on disk because sections need // to be sector-aligned on disk but page-aligned in memory. Index: test/pecoff/long-section-name.test =================================================================== --- test/pecoff/long-section-name.test +++ test/pecoff/long-section-name.test @@ -4,4 +4,4 @@ # RUN: /merge:.text=.longsectionname -- %t.obj # RUN: llvm-readobj -sections %t.exe | FileCheck %s -CHECK: Name: .longsec (2E 6C 6F 6E 67 73 65 63) +CHECK: Name: .longsectionname (2F 34 00 00 00 00 00 00)