PECOFF: Use the string table for long section names in EXEs/DLLs
Normally, PE files have section names of eight characters or less. However, this is problematic for DWARF because DWARF section names are things like .debug_aranges. Instead of truncating the section name, redirect the section name into the string table. Differential Revision: http://reviews.llvm.org/D6104 llvm-svn: 221212
This commit is contained in:
parent
9907d0a3c2
commit
4eb0a3fd25
|
@ -65,6 +65,7 @@ public:
|
||||||
enum Kind {
|
enum Kind {
|
||||||
kindHeader,
|
kindHeader,
|
||||||
kindSection,
|
kindSection,
|
||||||
|
kindStringTable,
|
||||||
kindAtomChunk
|
kindAtomChunk
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -151,6 +152,10 @@ public:
|
||||||
_peHeader.AddressOfEntryPoint = address;
|
_peHeader.AddressOfEntryPoint = address;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setPointerToSymbolTable(uint32_t rva) {
|
||||||
|
_coffHeader.PointerToSymbolTable = rva;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
llvm::object::coff_file_header _coffHeader;
|
llvm::object::coff_file_header _coffHeader;
|
||||||
PEHeader _peHeader;
|
PEHeader _peHeader;
|
||||||
|
@ -171,6 +176,37 @@ private:
|
||||||
std::vector<SectionChunk *> _sections;
|
std::vector<SectionChunk *> _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<ulittle32_t *>(_stringTable.data()) = _stringTable.size();
|
||||||
|
std::memcpy(buffer, _stringTable.data(), _stringTable.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<char> _stringTable;
|
||||||
|
};
|
||||||
|
|
||||||
class SectionChunk : public Chunk {
|
class SectionChunk : public Chunk {
|
||||||
public:
|
public:
|
||||||
uint64_t onDiskSize() const override {
|
uint64_t onDiskSize() const override {
|
||||||
|
@ -191,15 +227,20 @@ public:
|
||||||
uint64_t getVirtualAddress() { return _virtualAddress; }
|
uint64_t getVirtualAddress() { return _virtualAddress; }
|
||||||
virtual void setVirtualAddress(uint32_t rva) { _virtualAddress = rva; }
|
virtual void setVirtualAddress(uint32_t rva) { _virtualAddress = rva; }
|
||||||
|
|
||||||
|
uint32_t getStringTableOffset() const { return _stringTableOffset; }
|
||||||
|
void setStringTableOffset(uint32_t offset) { _stringTableOffset = offset; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
SectionChunk(Kind kind, StringRef sectionName, uint32_t characteristics)
|
SectionChunk(Kind kind, StringRef sectionName, uint32_t characteristics)
|
||||||
: Chunk(kind), _sectionName(sectionName),
|
: Chunk(kind), _sectionName(sectionName),
|
||||||
_characteristics(characteristics), _virtualAddress(0) {}
|
_characteristics(characteristics), _virtualAddress(0),
|
||||||
|
_stringTableOffset(0) {}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
StringRef _sectionName;
|
StringRef _sectionName;
|
||||||
const uint32_t _characteristics;
|
const uint32_t _characteristics;
|
||||||
uint64_t _virtualAddress;
|
uint64_t _virtualAddress;
|
||||||
|
uint32_t _stringTableOffset;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// An AtomChunk represents a section containing atoms.
|
/// An AtomChunk represents a section containing atoms.
|
||||||
|
@ -750,15 +791,15 @@ llvm::object::coff_section
|
||||||
SectionHeaderTableChunk::createSectionHeader(SectionChunk *chunk) {
|
SectionHeaderTableChunk::createSectionHeader(SectionChunk *chunk) {
|
||||||
llvm::object::coff_section header;
|
llvm::object::coff_section header;
|
||||||
|
|
||||||
// Section name must be equal to or less than 8 characters in the
|
// We have extended the COFF specification by allowing section names to be
|
||||||
// executable. Longer names will be truncated.
|
// greater than eight characters. We achieve this by adding the section names
|
||||||
|
// to the string table. Binutils' linker, ld, performs the same trick.
|
||||||
StringRef sectionName = chunk->getSectionName();
|
StringRef sectionName = chunk->getSectionName();
|
||||||
|
std::memset(header.Name, 0, llvm::COFF::NameSize);
|
||||||
// Name field must be NUL-padded. If the name is exactly 8 byte long,
|
if (uint32_t stringTableOffset = chunk->getStringTableOffset())
|
||||||
// there's no terminating NUL.
|
sprintf(header.Name, "/%u", stringTableOffset);
|
||||||
std::memset(header.Name, 0, sizeof(header.Name));
|
else
|
||||||
std::strncpy(header.Name, sectionName.data(),
|
std::strncpy(header.Name, sectionName.data(), sectionName.size());
|
||||||
std::min(sizeof(header.Name), sectionName.size()));
|
|
||||||
|
|
||||||
uint32_t characteristics = chunk->getCharacteristics();
|
uint32_t characteristics = chunk->getCharacteristics();
|
||||||
header.VirtualSize = chunk->size();
|
header.VirtualSize = chunk->size();
|
||||||
|
@ -873,7 +914,8 @@ private:
|
||||||
|
|
||||||
void addChunk(Chunk *chunk);
|
void addChunk(Chunk *chunk);
|
||||||
void addSectionChunk(std::unique_ptr<SectionChunk> chunk,
|
void addSectionChunk(std::unique_ptr<SectionChunk> chunk,
|
||||||
SectionHeaderTableChunk *table);
|
SectionHeaderTableChunk *table,
|
||||||
|
StringTableChunk *stringTable);
|
||||||
void setImageSizeOnDisk();
|
void setImageSizeOnDisk();
|
||||||
uint64_t
|
uint64_t
|
||||||
calcSectionSize(llvm::COFF::SectionCharacteristics sectionType) const;
|
calcSectionSize(llvm::COFF::SectionCharacteristics sectionType) const;
|
||||||
|
@ -974,10 +1016,12 @@ void PECOFFWriter::build(const File &linkedFile) {
|
||||||
auto *peHeader = new PEHeaderChunk<PEHeader>(_ctx);
|
auto *peHeader = new PEHeaderChunk<PEHeader>(_ctx);
|
||||||
auto *dataDirectory = new DataDirectoryChunk();
|
auto *dataDirectory = new DataDirectoryChunk();
|
||||||
auto *sectionTable = new SectionHeaderTableChunk();
|
auto *sectionTable = new SectionHeaderTableChunk();
|
||||||
|
auto *stringTable = new StringTableChunk();
|
||||||
addChunk(dosStub);
|
addChunk(dosStub);
|
||||||
addChunk(peHeader);
|
addChunk(peHeader);
|
||||||
addChunk(dataDirectory);
|
addChunk(dataDirectory);
|
||||||
addChunk(sectionTable);
|
addChunk(sectionTable);
|
||||||
|
addChunk(stringTable);
|
||||||
|
|
||||||
// Create sections and add the atoms to them.
|
// Create sections and add the atoms to them.
|
||||||
for (auto i : atoms) {
|
for (auto i : atoms) {
|
||||||
|
@ -986,7 +1030,7 @@ void PECOFFWriter::build(const File &linkedFile) {
|
||||||
std::unique_ptr<SectionChunk> section(
|
std::unique_ptr<SectionChunk> section(
|
||||||
new AtomChunk(_ctx, sectionName, contents));
|
new AtomChunk(_ctx, sectionName, contents));
|
||||||
if (section->size() > 0)
|
if (section->size() > 0)
|
||||||
addSectionChunk(std::move(section), sectionTable);
|
addSectionChunk(std::move(section), sectionTable, stringTable);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build atom to its RVA map.
|
// Build atom to its RVA map.
|
||||||
|
@ -1001,13 +1045,18 @@ void PECOFFWriter::build(const File &linkedFile) {
|
||||||
std::unique_ptr<SectionChunk> baseReloc(new BaseRelocChunk(_chunks, _ctx));
|
std::unique_ptr<SectionChunk> baseReloc(new BaseRelocChunk(_chunks, _ctx));
|
||||||
if (baseReloc->size()) {
|
if (baseReloc->size()) {
|
||||||
SectionChunk &ref = *baseReloc;
|
SectionChunk &ref = *baseReloc;
|
||||||
addSectionChunk(std::move(baseReloc), sectionTable);
|
addSectionChunk(std::move(baseReloc), sectionTable, stringTable);
|
||||||
dataDirectory->setField(DataDirectoryIndex::BASE_RELOCATION_TABLE,
|
dataDirectory->setField(DataDirectoryIndex::BASE_RELOCATION_TABLE,
|
||||||
ref.getVirtualAddress(), ref.size());
|
ref.getVirtualAddress(), ref.size());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setImageSizeOnDisk();
|
setImageSizeOnDisk();
|
||||||
|
// N.B. Currently released versions of dumpbin do not appropriately handle
|
||||||
|
// symbol tables which NumberOfSymbols set to zero but a non-zero
|
||||||
|
// PointerToSymbolTable.
|
||||||
|
if (stringTable->size())
|
||||||
|
peHeader->setPointerToSymbolTable(stringTable->fileOffset());
|
||||||
|
|
||||||
for (std::unique_ptr<Chunk> &chunk : _chunks) {
|
for (std::unique_ptr<Chunk> &chunk : _chunks) {
|
||||||
SectionChunk *section = dyn_cast<SectionChunk>(chunk.get());
|
SectionChunk *section = dyn_cast<SectionChunk>(chunk.get());
|
||||||
|
@ -1180,12 +1229,19 @@ void PECOFFWriter::addChunk(Chunk *chunk) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void PECOFFWriter::addSectionChunk(std::unique_ptr<SectionChunk> chunk,
|
void PECOFFWriter::addSectionChunk(std::unique_ptr<SectionChunk> chunk,
|
||||||
SectionHeaderTableChunk *table) {
|
SectionHeaderTableChunk *table,
|
||||||
|
StringTableChunk *stringTable) {
|
||||||
SectionChunk &ref = *chunk;
|
SectionChunk &ref = *chunk;
|
||||||
_chunks.push_back(std::move(chunk));
|
_chunks.push_back(std::move(chunk));
|
||||||
table->addSection(&ref);
|
table->addSection(&ref);
|
||||||
_numSections++;
|
_numSections++;
|
||||||
|
|
||||||
|
StringRef sectionName = ref.getSectionName();
|
||||||
|
if (sectionName.size() > llvm::COFF::NameSize) {
|
||||||
|
uint32_t stringTableOffset = stringTable->addSectionName(sectionName);
|
||||||
|
ref.setStringTableOffset(stringTableOffset);
|
||||||
|
}
|
||||||
|
|
||||||
// Compute and set the starting address of sections when loaded in
|
// Compute and set the starting address of sections when loaded in
|
||||||
// memory. They are different from positions on disk because sections need
|
// memory. They are different from positions on disk because sections need
|
||||||
// to be sector-aligned on disk but page-aligned in memory.
|
// to be sector-aligned on disk but page-aligned in memory.
|
||||||
|
|
|
@ -4,4 +4,4 @@
|
||||||
# RUN: /merge:.text=.longsectionname -- %t.obj
|
# RUN: /merge:.text=.longsectionname -- %t.obj
|
||||||
# RUN: llvm-readobj -sections %t.exe | FileCheck %s
|
# 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)
|
||||||
|
|
Loading…
Reference in New Issue