From bfb4aa17915d4bea1e54b1ec6c8b4f183a9b5c3c Mon Sep 17 00:00:00 2001 From: Rui Ueyama Date: Sat, 30 May 2015 19:09:50 +0000 Subject: [PATCH] COFF: Support long section name. Section names were truncated to 8 bytes because the section table's name field is 8 byte long. This patch creates the string table to store long names. llvm-svn: 238661 --- lld/COFF/Writer.cpp | 57 +++++++++++++++++++++++++++++++---- lld/COFF/Writer.h | 10 +++++-- lld/test/COFF/long-section-name.test | 58 ++++++++++++++++++++++++++++++++++++ 3 files changed, 116 insertions(+), 9 deletions(-) create mode 100644 lld/test/COFF/long-section-name.test diff --git a/lld/COFF/Writer.cpp b/lld/COFF/Writer.cpp index 48cd72b..9b24368 100644 --- a/lld/COFF/Writer.cpp +++ b/lld/COFF/Writer.cpp @@ -18,13 +18,16 @@ #include "llvm/Support/FileOutputBuffer.h" #include "llvm/Support/raw_ostream.h" #include +#include #include #include #include using namespace llvm; -using namespace llvm::object; using namespace llvm::COFF; +using namespace llvm::object; +using namespace llvm::support; +using namespace llvm::support::endian; static const int PageSize = 4096; static const int FileAlignment = 512; @@ -41,7 +44,6 @@ namespace coff { OutputSection::OutputSection(StringRef N, uint32_t SI) : Name(N), SectionIndex(SI) { memset(&Header, 0, sizeof(Header)); - strncpy(Header.Name, Name.data(), std::min(Name.size(), size_t(8))); } void OutputSection::setRVA(uint64_t RVA) { @@ -77,6 +79,19 @@ void OutputSection::addPermissions(uint32_t C) { Header.Characteristics = Header.Characteristics | (C & PermMask); } +// Write the section header to a given buffer. +void OutputSection::writeHeader(uint8_t *Buf) { + auto *Hdr = reinterpret_cast(Buf); + *Hdr = Header; + if (StringTableOff) { + // 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()); + } +} + void Writer::markLive() { Entry = cast(Symtab->find(Config->EntryName)); Entry->markLive(); @@ -307,11 +322,41 @@ void Writer::writeHeader() { DataDirectory[IAT].Size = ImportAddressTableSize; } + // Section table + // Name field in the string table is 8 byte long. Longer names need + // to be written to the string table. First, construct string table. + std::vector Strtab; + for (std::unique_ptr &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 - coff_section *SectionTable = reinterpret_cast(Buf); - int Idx = 0; - for (std::unique_ptr &Sec : OutputSections) - SectionTable[Idx++] = Sec->getHeader(); + for (std::unique_ptr &Sec : OutputSections) { + Sec->writeHeader(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()) + return; + COFF->PointerToSymbolTable = Buf - Buffer->getBufferStart(); + COFF->NumberOfSymbols = 1; + auto *SymbolTable = reinterpret_cast(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. + write32le(Buf, Strtab.size() + 4); + memcpy(Buf + 4, Strtab.data(), Strtab.size()); } std::error_code Writer::openFile(StringRef Path) { diff --git a/lld/COFF/Writer.h b/lld/COFF/Writer.h index a8f12e5..429eb68 100644 --- a/lld/COFF/Writer.h +++ b/lld/COFF/Writer.h @@ -37,13 +37,12 @@ public: StringRef getName() { return Name; } uint64_t getSectionIndex() { return SectionIndex; } std::vector &getChunks() { return Chunks; } - - const llvm::object::coff_section getHeader() { return Header; } void addPermissions(uint32_t C); uint32_t getPermissions() { return Header.Characteristics & PermMask; } uint32_t getCharacteristics() { return Header.Characteristics; } uint64_t getRVA() { return Header.VirtualAddress; } uint64_t getFileOff() { return Header.PointerToRawData; } + void writeHeader(uint8_t *Buf); // Returns the size of this section in an executable memory image. // This may be smaller than the raw size (the raw size is multiple @@ -55,10 +54,15 @@ public: // Returns the size of the section in the output file. uint64_t getRawSize() { return Header.SizeOfRawData; } + // Set offset into the string table storing this section name. + // Used only when the name is longer than 8 bytes. + void setStringTableOff(uint32_t V) { StringTableOff = V; } + private: - llvm::object::coff_section Header; + coff_section Header; StringRef Name; uint32_t SectionIndex; + uint32_t StringTableOff = 0; std::vector Chunks; }; diff --git a/lld/test/COFF/long-section-name.test b/lld/test/COFF/long-section-name.test new file mode 100644 index 0000000..8158be3 --- /dev/null +++ b/lld/test/COFF/long-section-name.test @@ -0,0 +1,58 @@ +# RUN: yaml2obj %s > %t.obj +# RUN: lld -flavor link2 /out:%t.exe /subsystem:console %t.obj +# RUN: llvm-readobj -sections %t.exe | FileCheck %s + +--- +header: + Machine: IMAGE_FILE_MACHINE_I386 + Characteristics: [ ] +sections: + - Name: .text_long_section_name + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + Alignment: 4 + SectionData: B82A000000C3 + - Name: .data_long_section_name + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ] + Alignment: 4 + SectionData: "00" +symbols: + - Name: "@comp.id" + Value: 10394907 + SectionNumber: 65535 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + - Name: .text_long_section_name + 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: .data_long_section_name + Value: 0 + SectionNumber: 2 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 0 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 0 + - Name: mainCRTStartup + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_EXTERNAL +... + +# CHECK: Name: .data_long_section_name +# CHECK: Name: .text_long_section_name -- 2.7.4