#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;
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) {
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();
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) {
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
// 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;
};
--- /dev/null
+# 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