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
This commit is contained in:
Rui Ueyama 2015-05-30 19:09:50 +00:00
parent 86f218e7ec
commit bfb4aa1791
3 changed files with 116 additions and 9 deletions

View File

@ -18,13 +18,16 @@
#include "llvm/Support/FileOutputBuffer.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <cstdio>
#include <functional>
#include <map>
#include <utility>
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<coff_section *>(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<Defined>(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<char> Strtab;
for (std::unique_ptr<OutputSection> &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<coff_section *>(Buf);
int Idx = 0;
for (std::unique_ptr<OutputSection> &Sec : OutputSections)
SectionTable[Idx++] = Sec->getHeader();
for (std::unique_ptr<OutputSection> &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<coff_symbol16 *>(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) {

View File

@ -37,13 +37,12 @@ public:
StringRef getName() { return Name; }
uint64_t getSectionIndex() { return SectionIndex; }
std::vector<Chunk *> &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<Chunk *> Chunks;
};

View File

@ -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