mirror of
https://github.com/corda/corda.git
synced 2025-01-01 02:36:44 +00:00
refactor binaryToObject to allow more flexibilty (in particular, allowing arbitrary symbols per object)
This commit is contained in:
parent
ca9b5b2f59
commit
661f6c28a8
19
makefile
19
makefile
@ -236,7 +236,6 @@ ifeq ($(arch),powerpc)
|
||||
|
||||
ifneq ($(platform),darwin)
|
||||
ifneq ($(arch),$(build-arch))
|
||||
converter-cflags += -DOPPOSITE_ENDIAN
|
||||
cxx = powerpc-linux-gnu-g++
|
||||
cc = powerpc-linux-gnu-gcc
|
||||
ar = powerpc-linux-gnu-ar
|
||||
@ -342,10 +341,6 @@ ifeq ($(platform),darwin)
|
||||
lflags += $(flags)
|
||||
endif
|
||||
|
||||
ifeq ($(build-arch),powerpc)
|
||||
converter-cflags += -DBIG_ENDIAN
|
||||
endif
|
||||
|
||||
ifeq ($(arch),powerpc)
|
||||
openjdk-extra-cflags += -arch ppc -mmacosx-version-min=${OSX_SDK_VERSION}
|
||||
cflags += -arch ppc -mmacosx-version-min=${OSX_SDK_VERSION}
|
||||
@ -428,6 +423,7 @@ endif
|
||||
|
||||
ifeq ($(mode),debug)
|
||||
optimization-cflags = -O0 -g3
|
||||
converter-cflags += -O0 -g3
|
||||
strip = :
|
||||
endif
|
||||
ifeq ($(mode),debug-fast)
|
||||
@ -606,9 +602,6 @@ driver-object = $(build)/main.o
|
||||
driver-dynamic-objects = \
|
||||
$(build)/main-dynamic.o
|
||||
|
||||
gdb-plugin-object = $(build)/gdb-plugin.o
|
||||
gdb-plugin-source = $(src)/gdb-plugin.cpp
|
||||
|
||||
boot-source = $(src)/boot.cpp
|
||||
boot-object = $(build)/boot.o
|
||||
|
||||
@ -623,7 +616,10 @@ generator-objects = \
|
||||
$(call generator-cpp-objects,$(generator-sources),$(src),$(build))
|
||||
generator = $(build)/generator
|
||||
|
||||
converter-depends = $(src)/binaryToObject/tools.h
|
||||
converter-depends = \
|
||||
$(src)/binaryToObject/tools.h \
|
||||
$(src)/binaryToObject/endianness.h
|
||||
|
||||
|
||||
converter-sources = \
|
||||
$(src)/binaryToObject/main.cpp \
|
||||
@ -826,9 +822,6 @@ $(heapwalk-objects): $(build)/%.o: $(src)/%.cpp $(vm-depends)
|
||||
$(driver-object): $(driver-source)
|
||||
$(compile-object)
|
||||
|
||||
$(gdb-plugin-object): $(gdb-plugin-source)
|
||||
$(compile-object)
|
||||
|
||||
$(build)/main-dynamic.o: $(driver-source)
|
||||
@echo "compiling $(@)"
|
||||
@mkdir -p $(dir $(@))
|
||||
@ -846,7 +839,7 @@ $(converter-objects): $(build)/binaryToObject/%.o: $(src)/binaryToObject/%.cpp $
|
||||
$(build-cxx) $(converter-cflags) -c $(<) -o $(@)
|
||||
|
||||
$(converter): $(converter-objects)
|
||||
$(build-cc) $(^) -o $(@)
|
||||
$(build-cc) $(^) -g -o $(@)
|
||||
|
||||
$(build)/classpath.jar: $(classpath-dep) $(classpath-jar-dep)
|
||||
@echo "creating $(@)"
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "endianness.h"
|
||||
|
||||
@ -119,6 +120,39 @@ using avian::endian::Endianness;
|
||||
#define V4 Endianness<TargetLittleEndian>::v4
|
||||
#define VANY Endianness<TargetLittleEndian>::vAny
|
||||
|
||||
|
||||
unsigned getElfPlatform(PlatformInfo::Architecture arch) {
|
||||
switch(arch) {
|
||||
case PlatformInfo::x86_64:
|
||||
return EM_X86_64;
|
||||
case PlatformInfo::x86:
|
||||
return EM_386;
|
||||
case PlatformInfo::Arm:
|
||||
return EM_ARM;
|
||||
case PlatformInfo::PowerPC:
|
||||
return EM_PPC;
|
||||
}
|
||||
return ~0;
|
||||
}
|
||||
|
||||
const char* getSectionName(unsigned accessFlags, unsigned& sectionFlags) {
|
||||
sectionFlags = SHF_ALLOC;
|
||||
if (accessFlags & Platform::Writable) {
|
||||
if (accessFlags & Platform::Executable) {
|
||||
sectionFlags |= SHF_WRITE | SHF_EXECINSTR;
|
||||
return ".rwx";
|
||||
} else {
|
||||
sectionFlags |= SHF_WRITE;
|
||||
return ".data";
|
||||
}
|
||||
} else if (accessFlags & Platform::Executable) {
|
||||
sectionFlags |= SHF_EXECINSTR;
|
||||
return ".text";
|
||||
} else {
|
||||
return ".rodata";
|
||||
}
|
||||
}
|
||||
|
||||
template<class AddrTy, bool TargetLittleEndian = true>
|
||||
class ElfPlatform : public Platform {
|
||||
public:
|
||||
@ -158,240 +192,182 @@ public:
|
||||
|
||||
typedef Symbol_Ty<AddrTy> Symbol;
|
||||
|
||||
class ElfObjectWriter : public ObjectWriter {
|
||||
static const unsigned Encoding = TargetLittleEndian ? ELFDATA2LSB : ELFDATA2MSB;
|
||||
|
||||
const unsigned machine;
|
||||
|
||||
ElfPlatform(PlatformInfo::Architecture arch):
|
||||
Platform(PlatformInfo(PlatformInfo::Linux, arch)),
|
||||
machine(getElfPlatform(arch)) {}
|
||||
|
||||
class FileWriter {
|
||||
public:
|
||||
unsigned sectionCount;
|
||||
unsigned sectionStringTableSectionNumber;
|
||||
|
||||
PlatformInfo::Architecture arch;
|
||||
OutputStream* out;
|
||||
AddrTy dataOffset;
|
||||
|
||||
ElfObjectWriter(PlatformInfo::Architecture arch, OutputStream* out):
|
||||
arch(arch),
|
||||
out(out) {}
|
||||
FileHeader header;
|
||||
StringTable strings;
|
||||
|
||||
void writeObject(const uint8_t* data, unsigned size,
|
||||
const char* startName, const char* endName,
|
||||
const char* sectionName, unsigned sectionFlags,
|
||||
unsigned alignment, int machine, int encoding)
|
||||
FileWriter(unsigned machine):
|
||||
sectionCount(0),
|
||||
dataOffset(sizeof(FileHeader))
|
||||
{
|
||||
const unsigned sectionCount = 5;
|
||||
const unsigned symbolCount = 2;
|
||||
|
||||
const unsigned sectionNameLength = strlen(sectionName) + 1;
|
||||
const unsigned startNameLength = strlen(startName) + 1;
|
||||
const unsigned endNameLength = strlen(endName) + 1;
|
||||
|
||||
const char* const sectionStringTableName = ".shstrtab";
|
||||
const char* const stringTableName = ".strtab";
|
||||
const char* const symbolTableName = ".symtab";
|
||||
|
||||
const unsigned sectionStringTableNameLength
|
||||
= strlen(sectionStringTableName) + 1;
|
||||
const unsigned stringTableNameLength = strlen(stringTableName) + 1;
|
||||
const unsigned symbolTableNameLength = strlen(symbolTableName) + 1;
|
||||
|
||||
const unsigned nullStringOffset = 0;
|
||||
|
||||
const unsigned sectionStringTableNameOffset = nullStringOffset + 1;
|
||||
const unsigned stringTableNameOffset
|
||||
= sectionStringTableNameOffset + sectionStringTableNameLength;
|
||||
const unsigned symbolTableNameOffset
|
||||
= stringTableNameOffset + stringTableNameLength;
|
||||
const unsigned sectionNameOffset
|
||||
= symbolTableNameOffset + symbolTableNameLength;
|
||||
const unsigned sectionStringTableLength
|
||||
= sectionNameOffset + sectionNameLength;
|
||||
|
||||
const unsigned startNameOffset = nullStringOffset + 1;
|
||||
const unsigned endNameOffset = startNameOffset + startNameLength;
|
||||
const unsigned stringTableLength = endNameOffset + endNameLength;
|
||||
|
||||
const unsigned bodySectionNumber = 1;
|
||||
const unsigned sectionStringTableSectionNumber = 2;
|
||||
const unsigned stringTableSectionNumber = 3;
|
||||
|
||||
FileHeader fileHeader;
|
||||
memset(&fileHeader, 0, sizeof(FileHeader));
|
||||
fileHeader.e_ident[EI_MAG0] = V1(ELFMAG0);
|
||||
fileHeader.e_ident[EI_MAG1] = V1(ELFMAG1);
|
||||
fileHeader.e_ident[EI_MAG2] = V1(ELFMAG2);
|
||||
fileHeader.e_ident[EI_MAG3] = V1(ELFMAG3);
|
||||
fileHeader.e_ident[EI_CLASS] = V1(Class);
|
||||
fileHeader.e_ident[EI_DATA] = V1(encoding);
|
||||
fileHeader.e_ident[EI_VERSION] = V1(EV_CURRENT);
|
||||
fileHeader.e_ident[EI_OSABI] = V1(OSABI);
|
||||
fileHeader.e_ident[EI_ABIVERSION] = V1(0);
|
||||
fileHeader.e_type = V2(ET_REL);
|
||||
fileHeader.e_machine = V2(machine);
|
||||
fileHeader.e_version = V4(EV_CURRENT);
|
||||
fileHeader.e_entry = VANY(static_cast<AddrTy>(0));
|
||||
fileHeader.e_phoff = VANY(static_cast<AddrTy>(0));
|
||||
fileHeader.e_shoff = VANY(static_cast<AddrTy>(sizeof(FileHeader)));
|
||||
fileHeader.e_flags = V4(machine == EM_ARM ? 0x04000000 : 0);
|
||||
fileHeader.e_ehsize = V2(sizeof(FileHeader));
|
||||
fileHeader.e_phentsize = V2(0);
|
||||
fileHeader.e_phnum = V2(0);
|
||||
fileHeader.e_shentsize = V2(sizeof(SectionHeader));
|
||||
fileHeader.e_shnum = V2(sectionCount);
|
||||
fileHeader.e_shstrndx = V2(sectionStringTableSectionNumber);
|
||||
|
||||
SectionHeader nullSection;
|
||||
memset(&nullSection, 0, sizeof(SectionHeader));
|
||||
|
||||
SectionHeader bodySection;
|
||||
bodySection.sh_name = V4(sectionNameOffset);
|
||||
bodySection.sh_type = V4(SHT_PROGBITS);
|
||||
bodySection.sh_flags = VANY(static_cast<AddrTy>(sectionFlags));
|
||||
bodySection.sh_addr = VANY(static_cast<AddrTy>(0));
|
||||
unsigned bodySectionOffset
|
||||
= sizeof(FileHeader) + (sizeof(SectionHeader) * sectionCount);
|
||||
bodySection.sh_offset = VANY(static_cast<AddrTy>(bodySectionOffset));
|
||||
unsigned bodySectionSize = size;
|
||||
bodySection.sh_size = VANY(static_cast<AddrTy>(bodySectionSize));
|
||||
bodySection.sh_link = V4(0);
|
||||
bodySection.sh_info = V4(0);
|
||||
bodySection.sh_addralign = VANY(static_cast<AddrTy>(alignment));
|
||||
bodySection.sh_entsize = VANY(static_cast<AddrTy>(0));
|
||||
|
||||
SectionHeader sectionStringTableSection;
|
||||
sectionStringTableSection.sh_name = V4(sectionStringTableNameOffset);
|
||||
sectionStringTableSection.sh_type = V4(SHT_STRTAB);
|
||||
sectionStringTableSection.sh_flags = VANY(static_cast<AddrTy>(0));
|
||||
sectionStringTableSection.sh_addr = VANY(static_cast<AddrTy>(0));
|
||||
unsigned sectionStringTableSectionOffset
|
||||
= bodySectionOffset + bodySectionSize;
|
||||
sectionStringTableSection.sh_offset = VANY(static_cast<AddrTy>(sectionStringTableSectionOffset));
|
||||
unsigned sectionStringTableSectionSize = sectionStringTableLength;
|
||||
sectionStringTableSection.sh_size = VANY(static_cast<AddrTy>(sectionStringTableSectionSize));
|
||||
sectionStringTableSection.sh_link = V4(0);
|
||||
sectionStringTableSection.sh_info = V4(0);
|
||||
sectionStringTableSection.sh_addralign = VANY(static_cast<AddrTy>(1));
|
||||
sectionStringTableSection.sh_entsize = VANY(static_cast<AddrTy>(0));
|
||||
|
||||
SectionHeader stringTableSection;
|
||||
stringTableSection.sh_name = V4(stringTableNameOffset);
|
||||
stringTableSection.sh_type = V4(SHT_STRTAB);
|
||||
stringTableSection.sh_flags = VANY(static_cast<AddrTy>(0));
|
||||
stringTableSection.sh_addr = VANY(static_cast<AddrTy>(0));
|
||||
unsigned stringTableSectionOffset
|
||||
= sectionStringTableSectionOffset + sectionStringTableSectionSize;
|
||||
stringTableSection.sh_offset = VANY(static_cast<AddrTy>(stringTableSectionOffset));
|
||||
unsigned stringTableSectionSize = stringTableLength;
|
||||
stringTableSection.sh_size = VANY(static_cast<AddrTy>(stringTableSectionSize));
|
||||
stringTableSection.sh_link = V4(0);
|
||||
stringTableSection.sh_info = V4(0);
|
||||
stringTableSection.sh_addralign = VANY(static_cast<AddrTy>(1));
|
||||
stringTableSection.sh_entsize = VANY(static_cast<AddrTy>(0));
|
||||
|
||||
SectionHeader symbolTableSection;
|
||||
symbolTableSection.sh_name = V4(symbolTableNameOffset);
|
||||
symbolTableSection.sh_type = V4(SHT_SYMTAB);
|
||||
symbolTableSection.sh_flags = VANY(static_cast<AddrTy>(0));
|
||||
symbolTableSection.sh_addr = VANY(static_cast<AddrTy>(0));
|
||||
unsigned symbolTableSectionOffset
|
||||
= stringTableSectionOffset + stringTableSectionSize;
|
||||
symbolTableSection.sh_offset = VANY(static_cast<AddrTy>(symbolTableSectionOffset));
|
||||
unsigned symbolTableSectionSize = sizeof(Symbol) * symbolCount;
|
||||
symbolTableSection.sh_size = VANY(static_cast<AddrTy>(symbolTableSectionSize));
|
||||
symbolTableSection.sh_link = V4(stringTableSectionNumber);
|
||||
symbolTableSection.sh_info = V4(0);
|
||||
symbolTableSection.sh_addralign = VANY(static_cast<AddrTy>(Elf::BytesPerWord));
|
||||
symbolTableSection.sh_entsize = VANY(static_cast<AddrTy>(sizeof(Symbol)));
|
||||
|
||||
Symbol startSymbol;
|
||||
startSymbol.st_name = V4(startNameOffset);
|
||||
startSymbol.st_value = VANY(static_cast<AddrTy>(0));
|
||||
startSymbol.st_size = VANY(static_cast<AddrTy>(0));
|
||||
startSymbol.st_info = V1(SYMBOL_INFO(STB_GLOBAL, STT_NOTYPE));
|
||||
startSymbol.st_other = V1(STV_DEFAULT);
|
||||
startSymbol.st_shndx = V2(bodySectionNumber);
|
||||
|
||||
Symbol endSymbol;
|
||||
endSymbol.st_name = V4(endNameOffset);
|
||||
endSymbol.st_value = VANY(static_cast<AddrTy>(size));
|
||||
endSymbol.st_size = VANY(static_cast<AddrTy>(0));
|
||||
endSymbol.st_info = V1(SYMBOL_INFO(STB_GLOBAL, STT_NOTYPE));
|
||||
endSymbol.st_other = V1(STV_DEFAULT);
|
||||
endSymbol.st_shndx = V2(bodySectionNumber);
|
||||
|
||||
out->writeChunk(&fileHeader, sizeof(fileHeader));
|
||||
out->writeChunk(&nullSection, sizeof(nullSection));
|
||||
out->writeChunk(&bodySection, sizeof(bodySection));
|
||||
out->writeChunk(§ionStringTableSection, sizeof(sectionStringTableSection));
|
||||
out->writeChunk(&stringTableSection, sizeof(stringTableSection));
|
||||
out->writeChunk(&symbolTableSection, sizeof(symbolTableSection));
|
||||
|
||||
out->writeChunk(data, size);
|
||||
|
||||
out->write(0);
|
||||
out->writeChunk(sectionStringTableName, sectionStringTableNameLength);
|
||||
out->writeChunk(stringTableName, stringTableNameLength);
|
||||
out->writeChunk(symbolTableName, symbolTableNameLength);
|
||||
out->writeChunk(sectionName, sectionNameLength);
|
||||
|
||||
out->write(0);
|
||||
out->writeChunk(startName, startNameLength);
|
||||
out->writeChunk(endName, endNameLength);
|
||||
|
||||
out->writeChunk(&startSymbol, sizeof(startSymbol));
|
||||
out->writeChunk(&endSymbol, sizeof(endSymbol));
|
||||
memset(&header, 0, sizeof(FileHeader));
|
||||
header.e_ident[EI_MAG0] = V1(ELFMAG0);
|
||||
header.e_ident[EI_MAG1] = V1(ELFMAG1);
|
||||
header.e_ident[EI_MAG2] = V1(ELFMAG2);
|
||||
header.e_ident[EI_MAG3] = V1(ELFMAG3);
|
||||
header.e_ident[EI_CLASS] = V1(Class);
|
||||
header.e_ident[EI_DATA] = V1(Encoding);
|
||||
header.e_ident[EI_VERSION] = V1(EV_CURRENT);
|
||||
header.e_ident[EI_OSABI] = V1(OSABI);
|
||||
header.e_ident[EI_ABIVERSION] = V1(0);
|
||||
header.e_type = V2(ET_REL);
|
||||
header.e_machine = V2(machine);
|
||||
header.e_version = V4(EV_CURRENT);
|
||||
header.e_entry = VANY(static_cast<AddrTy>(0));
|
||||
header.e_phoff = VANY(static_cast<AddrTy>(0));
|
||||
header.e_shoff = VANY(static_cast<AddrTy>(sizeof(FileHeader)));
|
||||
header.e_flags = V4(machine == EM_ARM ? 0x04000000 : 0);
|
||||
header.e_ehsize = V2(sizeof(FileHeader));
|
||||
header.e_phentsize = V2(0);
|
||||
header.e_phnum = V2(0);
|
||||
header.e_shentsize = V2(sizeof(SectionHeader));
|
||||
}
|
||||
|
||||
virtual bool write(uint8_t* data, size_t size,
|
||||
const char* startName, const char* endName,
|
||||
unsigned alignment, unsigned accessFlags)
|
||||
{
|
||||
int machine;
|
||||
int encoding;
|
||||
if (arch == PlatformInfo::x86_64) {
|
||||
machine = EM_X86_64;
|
||||
encoding = ELFDATA2LSB;
|
||||
} else if (arch == PlatformInfo::x86) {
|
||||
machine = EM_386;
|
||||
encoding = ELFDATA2LSB;
|
||||
} else if (arch == PlatformInfo::Arm) {
|
||||
machine = EM_ARM;
|
||||
encoding = ELFDATA2LSB;
|
||||
} else if (arch == PlatformInfo::PowerPC) {
|
||||
machine = EM_PPC;
|
||||
encoding = ELFDATA2MSB;
|
||||
} else {
|
||||
fprintf(stderr, "unsupported architecture: %s\n", arch);
|
||||
return false;
|
||||
}
|
||||
|
||||
const char* sectionName;
|
||||
unsigned sectionFlags = SHF_ALLOC;
|
||||
if (accessFlags & Writable) {
|
||||
if (accessFlags & Executable) {
|
||||
sectionName = ".rwx";
|
||||
sectionFlags |= SHF_WRITE | SHF_EXECINSTR;
|
||||
} else {
|
||||
sectionName = ".data";
|
||||
sectionFlags |= SHF_WRITE;
|
||||
}
|
||||
} else if (accessFlags & Executable) {
|
||||
sectionName = ".text";
|
||||
sectionFlags |= SHF_EXECINSTR;
|
||||
} else {
|
||||
sectionName = ".rodata";
|
||||
}
|
||||
|
||||
writeObject(data, size, startName, endName, sectionName, sectionFlags,
|
||||
alignment, machine, encoding);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void dispose() {
|
||||
delete this;
|
||||
void writeHeader(OutputStream* out) {
|
||||
header.e_shnum = V2(sectionCount);
|
||||
header.e_shstrndx = V2(sectionStringTableSectionNumber);
|
||||
out->writeChunk(&header, sizeof(FileHeader));
|
||||
}
|
||||
};
|
||||
|
||||
ElfPlatform(PlatformInfo::Architecture arch):
|
||||
Platform(PlatformInfo(PlatformInfo::Linux, arch)) {}
|
||||
class SectionWriter {
|
||||
public:
|
||||
FileWriter& file;
|
||||
String name;
|
||||
SectionHeader header;
|
||||
const size_t* dataSize;
|
||||
const uint8_t* const* data;
|
||||
|
||||
virtual ObjectWriter* makeObjectWriter(OutputStream* out) {
|
||||
return new ElfObjectWriter(info.arch, out);
|
||||
SectionWriter(FileWriter& file):
|
||||
file(file),
|
||||
name(""),
|
||||
data(0),
|
||||
dataSize(0)
|
||||
{
|
||||
memset(&header, 0, sizeof(SectionHeader));
|
||||
file.sectionCount++;
|
||||
file.dataOffset += sizeof(SectionHeader);
|
||||
size_t nameOffset = file.strings.add(name);
|
||||
header.sh_name = V4(nameOffset);
|
||||
}
|
||||
|
||||
SectionWriter(
|
||||
FileWriter& file,
|
||||
const char* chname,
|
||||
unsigned type,
|
||||
AddrTy flags,
|
||||
unsigned alignment,
|
||||
AddrTy addr,
|
||||
const uint8_t* const* data,
|
||||
size_t* dataSize,
|
||||
size_t entsize = 0,
|
||||
unsigned link = 0):
|
||||
|
||||
file(file),
|
||||
name(chname),
|
||||
data(data),
|
||||
dataSize(dataSize)
|
||||
{
|
||||
if(strcmp(chname, ".shstrtab") == 0) {
|
||||
file.sectionStringTableSectionNumber = file.sectionCount;
|
||||
}
|
||||
file.sectionCount++;
|
||||
file.dataOffset += sizeof(SectionHeader);
|
||||
size_t nameOffset = file.strings.add(name);
|
||||
|
||||
header.sh_name = V4(nameOffset);
|
||||
header.sh_type = V4(type);
|
||||
header.sh_flags = VANY(flags);
|
||||
header.sh_addr = VANY(addr);
|
||||
// header.sh_offset = VANY(static_cast<AddrTy>(bodySectionOffset));
|
||||
// header.sh_size = VANY(static_cast<AddrTy>(*dataSize));
|
||||
header.sh_link = V4(link);
|
||||
header.sh_info = V4(0);
|
||||
header.sh_addralign = VANY(static_cast<AddrTy>(alignment));
|
||||
header.sh_entsize = VANY(static_cast<AddrTy>(entsize));
|
||||
}
|
||||
|
||||
void writeHeader(OutputStream* out) {
|
||||
if(dataSize) {
|
||||
header.sh_offset = VANY(file.dataOffset);
|
||||
header.sh_size = VANY(static_cast<AddrTy>(*dataSize));
|
||||
file.dataOffset += *dataSize;
|
||||
}
|
||||
|
||||
out->writeChunk(&header, sizeof(SectionHeader));
|
||||
}
|
||||
|
||||
void writeData(OutputStream* out) {
|
||||
if(data) {
|
||||
out->writeChunk(*data, *dataSize);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
virtual bool writeObject(OutputStream* out, Slice<SymbolInfo> symbols, Slice<const uint8_t> data, unsigned accessFlags, unsigned alignment) {
|
||||
|
||||
unsigned sectionFlags;
|
||||
const char* sectionName = getSectionName(accessFlags, sectionFlags);
|
||||
|
||||
StringTable symbolStringTable;
|
||||
Buffer symbolTable;
|
||||
|
||||
FileWriter file(machine);
|
||||
|
||||
const int bodySectionNumber = 1;
|
||||
const int stringTableSectionNumber = 3;
|
||||
|
||||
SectionWriter sections[] = {
|
||||
SectionWriter(file), // null section
|
||||
SectionWriter(file, sectionName, SHT_PROGBITS, sectionFlags, alignment, 0, &data.items, &data.count), // body section
|
||||
SectionWriter(file, ".shstrtab", SHT_STRTAB, 0, 1, 0, &file.strings.data, &file.strings.length),
|
||||
SectionWriter(file, ".strtab", SHT_STRTAB, 0, 1, 0, &symbolStringTable.data, &symbolStringTable.length),
|
||||
SectionWriter(file, ".symtab", SHT_SYMTAB, 0, 8, 0, &symbolTable.data, &symbolTable.length, sizeof(Symbol), stringTableSectionNumber)
|
||||
};
|
||||
|
||||
// for some reason, string tables require a null first element...
|
||||
symbolStringTable.add("");
|
||||
|
||||
for(SymbolInfo* sym = symbols.begin(); sym != symbols.end(); sym++) {
|
||||
size_t nameOffset = symbolStringTable.add(sym->name);
|
||||
|
||||
Symbol symbolStruct;
|
||||
symbolStruct.st_name = V4(nameOffset);
|
||||
symbolStruct.st_value = VANY(static_cast<AddrTy>(sym->addr));
|
||||
symbolStruct.st_size = VANY(static_cast<AddrTy>(0));
|
||||
symbolStruct.st_info = V1(SYMBOL_INFO(STB_GLOBAL, STT_NOTYPE));
|
||||
symbolStruct.st_other = V1(STV_DEFAULT);
|
||||
symbolStruct.st_shndx = V2(bodySectionNumber);
|
||||
symbolTable.write(&symbolStruct, sizeof(Symbol));
|
||||
}
|
||||
|
||||
file.writeHeader(out);
|
||||
|
||||
for(int i = 0; i < file.sectionCount; i++) {
|
||||
sections[i].writeHeader(out);
|
||||
}
|
||||
|
||||
for(int i = 0; i < file.sectionCount; i++) {
|
||||
sections[i].writeData(out);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -15,11 +15,12 @@ namespace avian {
|
||||
|
||||
namespace endian {
|
||||
|
||||
#ifndef BIG_ENDIAN
|
||||
const bool LittleEndian = true;
|
||||
#else
|
||||
const bool LittleEndian = false;
|
||||
#endif
|
||||
static union {
|
||||
uint32_t i;
|
||||
char c[4];
|
||||
} _DetectEndianness = {1};
|
||||
|
||||
const bool LittleEndian = _DetectEndianness.c[0] == 1;
|
||||
|
||||
template<bool TargetLittleEndian>
|
||||
class Endianness {
|
||||
@ -57,13 +58,13 @@ public:
|
||||
return v;
|
||||
} else {
|
||||
return
|
||||
((static_cast<uint64_t>(v) >> 56) & UINT64_C(0x00000000000000FF)) |
|
||||
((static_cast<uint64_t>(v) >> 40) & UINT64_C(0x000000000000FF00)) |
|
||||
((static_cast<uint64_t>(v) >> 24) & UINT64_C(0x0000000000FF0000)) |
|
||||
((static_cast<uint64_t>(v) >> 8) & UINT64_C(0x00000000FF000000)) |
|
||||
((static_cast<uint64_t>(v) << 8) & UINT64_C(0x000000FF00000000)) |
|
||||
((static_cast<uint64_t>(v) << 24) & UINT64_C(0x0000FF0000000000)) |
|
||||
((static_cast<uint64_t>(v) << 40) & UINT64_C(0x00FF000000000000)) |
|
||||
((static_cast<uint64_t>(v) >> 56) & (static_cast<uint64_t>(0xff) << 0)) |
|
||||
((static_cast<uint64_t>(v) >> 40) & (static_cast<uint64_t>(0xff) << 8)) |
|
||||
((static_cast<uint64_t>(v) >> 24) & (static_cast<uint64_t>(0xff) << 16)) |
|
||||
((static_cast<uint64_t>(v) >> 8) & (static_cast<uint64_t>(0xff) << 24)) |
|
||||
((static_cast<uint64_t>(v) << 8) & (static_cast<uint64_t>(0xff) << 32)) |
|
||||
((static_cast<uint64_t>(v) << 24) & (static_cast<uint64_t>(0xff) << 40)) |
|
||||
((static_cast<uint64_t>(v) << 40) & (static_cast<uint64_t>(0xff) << 48)) |
|
||||
((static_cast<uint64_t>(v) << 56));
|
||||
}
|
||||
}
|
||||
|
@ -56,6 +56,14 @@ using avian::endian::Endianness;
|
||||
#define V4 Endianness<TargetLittleEndian>::v4
|
||||
#define VANY Endianness<TargetLittleEndian>::vAny
|
||||
|
||||
inline unsigned
|
||||
log(unsigned n)
|
||||
{
|
||||
unsigned r = 0;
|
||||
for (unsigned i = 1; i < n; ++r) i <<= 1;
|
||||
return r;
|
||||
}
|
||||
|
||||
template<class AddrTy, bool TargetLittleEndian = true>
|
||||
class MachOPlatform : public Platform {
|
||||
public:
|
||||
@ -132,200 +140,151 @@ public:
|
||||
return (n + (BytesPerWord - 1)) & ~(BytesPerWord - 1);
|
||||
}
|
||||
|
||||
static inline unsigned
|
||||
log(unsigned n)
|
||||
{
|
||||
unsigned r = 0;
|
||||
for (unsigned i = 1; i < n; ++r) i <<= 1;
|
||||
return r;
|
||||
virtual bool writeObject(OutputStream* out, Slice<SymbolInfo> symbols, Slice<const uint8_t> data, unsigned accessFlags, unsigned alignment) {
|
||||
cpu_type_t cpuType;
|
||||
cpu_subtype_t cpuSubType;
|
||||
switch(info.arch) {
|
||||
case PlatformInfo::x86_64:
|
||||
cpuType = CPU_TYPE_X86_64;
|
||||
cpuSubType = CPU_SUBTYPE_X86_64_ALL;
|
||||
break;
|
||||
case PlatformInfo::x86:
|
||||
cpuType = CPU_TYPE_I386;
|
||||
cpuSubType = CPU_SUBTYPE_I386_ALL;
|
||||
break;
|
||||
case PlatformInfo::PowerPC:
|
||||
cpuType = CPU_TYPE_POWERPC;
|
||||
cpuSubType = CPU_SUBTYPE_POWERPC_ALL;
|
||||
break;
|
||||
case PlatformInfo::Arm:
|
||||
cpuType = CPU_TYPE_ARM;
|
||||
cpuSubType = CPU_SUBTYPE_ARM_V7;
|
||||
default:
|
||||
// should never happen (see MachOPlatform declarations at bottom)
|
||||
fprintf(stderr, "unsupported architecture: %d\n", info.arch);
|
||||
return false;
|
||||
}
|
||||
|
||||
const char* segmentName;
|
||||
const char* sectionName;
|
||||
if (accessFlags & Writable) {
|
||||
if (accessFlags & Executable) {
|
||||
segmentName = "__RWX";
|
||||
sectionName = "__rwx";
|
||||
} else {
|
||||
segmentName = "__DATA";
|
||||
sectionName = "__data";
|
||||
}
|
||||
} else {
|
||||
segmentName = "__TEXT";
|
||||
sectionName = "__text";
|
||||
}
|
||||
|
||||
FileHeader header = {
|
||||
V4(Magic), // magic
|
||||
V4(cpuType),
|
||||
V4(cpuSubType),
|
||||
V4(MH_OBJECT), // filetype,
|
||||
V4(2), // ncmds
|
||||
V4(sizeof(SegmentCommand)
|
||||
+ sizeof(Section)
|
||||
+ sizeof(SymtabCommand)), // sizeofcmds
|
||||
V4(0) // flags
|
||||
};
|
||||
|
||||
AddrTy finalSize = pad(data.count);
|
||||
|
||||
SegmentCommand segment = {
|
||||
V4(Segment), // cmd
|
||||
V4(sizeof(SegmentCommand) + sizeof(Section)), // cmdsize
|
||||
"", // segname
|
||||
VANY(static_cast<AddrTy>(0)), // vmaddr
|
||||
VANY(static_cast<AddrTy>(finalSize)), // vmsize
|
||||
VANY(static_cast<AddrTy>(sizeof(FileHeader)
|
||||
+ sizeof(SegmentCommand)
|
||||
+ sizeof(Section)
|
||||
+ sizeof(SymtabCommand))), // fileoff
|
||||
VANY(static_cast<AddrTy>(finalSize)), // filesize
|
||||
V4(7), // maxprot
|
||||
V4(7), // initprot
|
||||
V4(1), // nsects
|
||||
V4(0) // flags
|
||||
};
|
||||
|
||||
strncpy(segment.segname, segmentName, sizeof(segment.segname));
|
||||
|
||||
Section sect = {
|
||||
"", // sectname
|
||||
"", // segname
|
||||
VANY(static_cast<AddrTy>(0)), // addr
|
||||
VANY(static_cast<AddrTy>(finalSize)), // size
|
||||
V4(sizeof(FileHeader)
|
||||
+ sizeof(SegmentCommand)
|
||||
+ sizeof(Section)
|
||||
+ sizeof(SymtabCommand)), // offset
|
||||
V4(log(alignment)), // align
|
||||
V4(0), // reloff
|
||||
V4(0), // nreloc
|
||||
V4(S_REGULAR), // flags
|
||||
V4(0), // reserved1
|
||||
V4(0), // reserved2
|
||||
};
|
||||
|
||||
strncpy(sect.segname, segmentName, sizeof(sect.segname));
|
||||
strncpy(sect.sectname, sectionName, sizeof(sect.sectname));
|
||||
|
||||
StringTable strings;
|
||||
strings.add("");
|
||||
Buffer symbolList;
|
||||
|
||||
for(SymbolInfo* sym = symbols.begin(); sym != symbols.end(); sym++) {
|
||||
unsigned offset = strings.length;
|
||||
strings.write("_", 1);
|
||||
strings.add(sym->name);
|
||||
NList symbol = {
|
||||
V4(offset), // n_un
|
||||
V1(N_SECT | N_EXT), // n_type
|
||||
V1(1), // n_sect
|
||||
V2(0), // n_desc
|
||||
VANY(static_cast<AddrTy>(sym->addr)) // n_value
|
||||
};
|
||||
symbolList.write(&symbol, sizeof(NList));
|
||||
}
|
||||
|
||||
SymtabCommand symbolTable = {
|
||||
V4(LC_SYMTAB), // cmd
|
||||
V4(sizeof(SymtabCommand)), // cmdsize
|
||||
V4(sizeof(FileHeader)
|
||||
+ sizeof(SegmentCommand)
|
||||
+ sizeof(Section)
|
||||
+ sizeof(SymtabCommand)
|
||||
+ finalSize), // symoff
|
||||
V4(symbols.count), // nsyms
|
||||
V4(sizeof(FileHeader)
|
||||
+ sizeof(SegmentCommand)
|
||||
+ sizeof(Section)
|
||||
+ sizeof(SymtabCommand)
|
||||
+ finalSize
|
||||
+ (sizeof(NList) * symbols.count)), // stroff
|
||||
V4(strings.length), // strsize
|
||||
};
|
||||
|
||||
out->writeChunk(&header, sizeof(header));
|
||||
out->writeChunk(&segment, sizeof(segment));
|
||||
out->writeChunk(§, sizeof(sect));
|
||||
out->writeChunk(&symbolTable, sizeof(symbolTable));
|
||||
|
||||
out->writeChunk(data.items, data.count);
|
||||
out->writeRepeat(0, finalSize - data.count);
|
||||
|
||||
out->writeChunk(symbolList.data, symbolList.length);
|
||||
|
||||
out->writeChunk(strings.data, strings.length);
|
||||
}
|
||||
|
||||
class MachOObjectWriter : public ObjectWriter {
|
||||
public:
|
||||
|
||||
PlatformInfo::Architecture arch;
|
||||
OutputStream* out;
|
||||
|
||||
MachOObjectWriter(PlatformInfo::Architecture arch, OutputStream* out):
|
||||
arch(arch),
|
||||
out(out) {}
|
||||
|
||||
void writeObject(const uint8_t* data, unsigned size,
|
||||
const char* startName, const char* endName,
|
||||
const char* segmentName, const char* sectionName,
|
||||
unsigned alignment, cpu_type_t cpuType, cpu_subtype_t cpuSubType)
|
||||
{
|
||||
unsigned startNameLength = strlen(startName) + 1;
|
||||
unsigned endNameLength = strlen(endName) + 1;
|
||||
|
||||
FileHeader header = {
|
||||
V4(Magic), // magic
|
||||
V4(cpuType),
|
||||
V4(cpuSubType),
|
||||
V4(MH_OBJECT), // filetype,
|
||||
V4(2), // ncmds
|
||||
V4(sizeof(SegmentCommand)
|
||||
+ sizeof(Section)
|
||||
+ sizeof(SymtabCommand)), // sizeofcmds
|
||||
V4(0) // flags
|
||||
};
|
||||
|
||||
SegmentCommand segment = {
|
||||
V4(Segment), // cmd
|
||||
V4(sizeof(SegmentCommand) + sizeof(Section)), // cmdsize
|
||||
"", // segname
|
||||
VANY(static_cast<AddrTy>(0)), // vmaddr
|
||||
VANY(static_cast<AddrTy>(pad(size))), // vmsize
|
||||
VANY(static_cast<AddrTy>(sizeof(FileHeader)
|
||||
+ sizeof(SegmentCommand)
|
||||
+ sizeof(Section)
|
||||
+ sizeof(SymtabCommand))), // fileoff
|
||||
VANY(static_cast<AddrTy>(pad(size))), // filesize
|
||||
V4(7), // maxprot
|
||||
V4(7), // initprot
|
||||
V4(1), // nsects
|
||||
V4(0) // flags
|
||||
};
|
||||
|
||||
strncpy(segment.segname, segmentName, sizeof(segment.segname));
|
||||
|
||||
Section sect = {
|
||||
"", // sectname
|
||||
"", // segname
|
||||
VANY(static_cast<AddrTy>(0)), // addr
|
||||
VANY(static_cast<AddrTy>(pad(size))), // size
|
||||
V4(sizeof(FileHeader)
|
||||
+ sizeof(SegmentCommand)
|
||||
+ sizeof(Section)
|
||||
+ sizeof(SymtabCommand)), // offset
|
||||
V4(log(alignment)), // align
|
||||
V4(0), // reloff
|
||||
V4(0), // nreloc
|
||||
V4(S_REGULAR), // flags
|
||||
V4(0), // reserved1
|
||||
V4(0), // reserved2
|
||||
};
|
||||
|
||||
strncpy(sect.segname, segmentName, sizeof(sect.segname));
|
||||
strncpy(sect.sectname, sectionName, sizeof(sect.sectname));
|
||||
|
||||
SymtabCommand symbolTable = {
|
||||
V4(LC_SYMTAB), // cmd
|
||||
V4(sizeof(SymtabCommand)), // cmdsize
|
||||
V4(sizeof(FileHeader)
|
||||
+ sizeof(SegmentCommand)
|
||||
+ sizeof(Section)
|
||||
+ sizeof(SymtabCommand)
|
||||
+ pad(size)), // symoff
|
||||
V4(2), // nsyms
|
||||
V4(sizeof(FileHeader)
|
||||
+ sizeof(SegmentCommand)
|
||||
+ sizeof(Section)
|
||||
+ sizeof(SymtabCommand)
|
||||
+ pad(size)
|
||||
+ (sizeof(NList) * 2)), // stroff
|
||||
V4(1 + startNameLength + endNameLength), // strsize
|
||||
};
|
||||
|
||||
NList symbolList[] = {
|
||||
{
|
||||
V4(1), // n_un
|
||||
V1(N_SECT | N_EXT), // n_type
|
||||
V1(1), // n_sect
|
||||
V2(0), // n_desc
|
||||
VANY(static_cast<AddrTy>(0)) // n_value
|
||||
},
|
||||
{
|
||||
V4(1 + startNameLength), // n_un
|
||||
V1(N_SECT | N_EXT), // n_type
|
||||
V1(1), // n_sect
|
||||
V2(0), // n_desc
|
||||
VANY(static_cast<AddrTy>(size)) // n_value
|
||||
}
|
||||
};
|
||||
|
||||
out->writeChunk(&header, sizeof(header));
|
||||
out->writeChunk(&segment, sizeof(segment));
|
||||
out->writeChunk(§, sizeof(sect));
|
||||
out->writeChunk(&symbolTable, sizeof(symbolTable));
|
||||
|
||||
out->writeChunk(data, size);
|
||||
out->writeRepeat(0, pad(size) - size);
|
||||
|
||||
out->writeChunk(&symbolList, sizeof(symbolList));
|
||||
|
||||
out->write(0);
|
||||
|
||||
out->writeChunk(startName, startNameLength);
|
||||
out->writeChunk(endName, endNameLength);
|
||||
}
|
||||
|
||||
virtual bool write(uint8_t* data, size_t size,
|
||||
const char* startName, const char* endName,
|
||||
unsigned alignment, unsigned accessFlags)
|
||||
{
|
||||
|
||||
cpu_type_t cpuType;
|
||||
cpu_subtype_t cpuSubType;
|
||||
if (arch == PlatformInfo::x86_64) {
|
||||
cpuType = CPU_TYPE_X86_64;
|
||||
cpuSubType = CPU_SUBTYPE_X86_64_ALL;
|
||||
} else if (arch == PlatformInfo::x86) {
|
||||
cpuType = CPU_TYPE_I386;
|
||||
cpuSubType = CPU_SUBTYPE_I386_ALL;
|
||||
} else if (arch == PlatformInfo::PowerPC) {
|
||||
cpuType = CPU_TYPE_POWERPC;
|
||||
cpuSubType = CPU_SUBTYPE_POWERPC_ALL;
|
||||
} else if (arch == PlatformInfo::Arm) {
|
||||
cpuType = CPU_TYPE_ARM;
|
||||
cpuSubType = CPU_SUBTYPE_ARM_V7;
|
||||
} else {
|
||||
fprintf(stderr, "unsupported architecture: %d\n", arch);
|
||||
return false;
|
||||
}
|
||||
|
||||
const char* segmentName;
|
||||
const char* sectionName;
|
||||
if (accessFlags & Writable) {
|
||||
if (accessFlags & Executable) {
|
||||
segmentName = "__RWX";
|
||||
sectionName = "__rwx";
|
||||
} else {
|
||||
segmentName = "__DATA";
|
||||
sectionName = "__data";
|
||||
}
|
||||
} else {
|
||||
segmentName = "__TEXT";
|
||||
sectionName = "__text";
|
||||
}
|
||||
|
||||
unsigned startNameLength = strlen(startName);
|
||||
char myStartName[startNameLength + 2];
|
||||
myStartName[0] = '_';
|
||||
memcpy(myStartName + 1, startName, startNameLength + 1);
|
||||
|
||||
unsigned endNameLength = strlen(endName);
|
||||
char myEndName[endNameLength + 2];
|
||||
myEndName[0] = '_';
|
||||
memcpy(myEndName + 1, endName, endNameLength + 1);
|
||||
|
||||
writeObject(data, size, myStartName, myEndName, segmentName,
|
||||
sectionName, alignment, cpuType, cpuSubType);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void dispose() {
|
||||
delete this;
|
||||
}
|
||||
};
|
||||
|
||||
MachOPlatform(PlatformInfo::Architecture arch):
|
||||
Platform(PlatformInfo(PlatformInfo::Darwin, arch)) {}
|
||||
|
||||
virtual ObjectWriter* makeObjectWriter(OutputStream* out) {
|
||||
return new MachOObjectWriter(info.arch, out);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
MachOPlatform<uint32_t> darwinx86Platform(PlatformInfo::x86);
|
||||
|
@ -33,18 +33,14 @@ void* operator new(size_t size) {
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
void operator delete(void* mem) {
|
||||
if(mem) {
|
||||
free(mem);
|
||||
}
|
||||
}
|
||||
void operator delete(void* mem) { abort(); }
|
||||
|
||||
namespace {
|
||||
|
||||
using namespace avian::tools;
|
||||
|
||||
bool
|
||||
writeObject(uint8_t* data, unsigned size, OutputStream* out, const char* startName,
|
||||
writeObject(uint8_t* data, size_t size, OutputStream* out, const char* startName,
|
||||
const char* endName, const char* os,
|
||||
const char* architecture, unsigned alignment, bool writable,
|
||||
bool executable)
|
||||
@ -56,14 +52,16 @@ writeObject(uint8_t* data, unsigned size, OutputStream* out, const char* startNa
|
||||
return false;
|
||||
}
|
||||
|
||||
ObjectWriter* writer = platform->makeObjectWriter(out);
|
||||
SymbolInfo symbols[2];
|
||||
symbols[0].name = startName;
|
||||
symbols[0].addr = 0;
|
||||
symbols[1].name = endName;
|
||||
symbols[1].addr = size;
|
||||
|
||||
bool success = writer->write(data, size, startName, endName, alignment,
|
||||
ObjectWriter::Readable | (writable ? ObjectWriter::Writable : 0) | (executable ? ObjectWriter::Executable : 0));
|
||||
unsigned accessFlags = (writable ? Platform::Writable : 0) | (executable ? Platform::Executable : 0);
|
||||
|
||||
writer->dispose();
|
||||
return platform->writeObject(out, Slice<SymbolInfo>(symbols, 2), Slice<const uint8_t>(data, size), accessFlags, alignment);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "tools.h"
|
||||
|
||||
@ -81,169 +82,193 @@ pad(unsigned n)
|
||||
|
||||
using namespace avian::tools;
|
||||
|
||||
void
|
||||
writeObject(const uint8_t* data, unsigned size, OutputStream* out,
|
||||
const char* startName, const char* endName,
|
||||
const char* sectionName, int machine, int machineMask,
|
||||
int sectionMask)
|
||||
{
|
||||
const unsigned sectionCount = 1;
|
||||
const unsigned symbolCount = 2;
|
||||
|
||||
const unsigned sectionNumber = 1;
|
||||
|
||||
const unsigned startNameLength = strlen(startName) + 1;
|
||||
const unsigned endNameLength = strlen(endName) + 1;
|
||||
|
||||
const unsigned startNameOffset = 4;
|
||||
const unsigned endNameOffset = startNameOffset + startNameLength;
|
||||
|
||||
IMAGE_FILE_HEADER fileHeader = {
|
||||
machine, // Machine
|
||||
sectionCount, // NumberOfSections
|
||||
0, // TimeDateStamp
|
||||
sizeof(IMAGE_FILE_HEADER)
|
||||
+ sizeof(IMAGE_SECTION_HEADER)
|
||||
+ pad(size), // PointerToSymbolTable
|
||||
symbolCount, // NumberOfSymbols
|
||||
0, // SizeOfOptionalHeader
|
||||
IMAGE_FILE_RELOCS_STRIPPED
|
||||
| IMAGE_FILE_LINE_NUMS_STRIPPED
|
||||
| machineMask // Characteristics
|
||||
};
|
||||
|
||||
IMAGE_SECTION_HEADER sectionHeader = {
|
||||
"", // Name
|
||||
0, // PhysicalAddress
|
||||
0, // VirtualAddress
|
||||
pad(size), // SizeOfRawData
|
||||
sizeof(IMAGE_FILE_HEADER)
|
||||
+ sizeof(IMAGE_SECTION_HEADER), // PointerToRawData
|
||||
0, // PointerToRelocations
|
||||
0, // PointerToLinenumbers
|
||||
0, // NumberOfRelocations
|
||||
0, // NumberOfLinenumbers
|
||||
sectionMask // Characteristics
|
||||
};
|
||||
|
||||
strncpy(reinterpret_cast<char*>(sectionHeader.Name), sectionName,
|
||||
sizeof(sectionHeader.Name));
|
||||
|
||||
IMAGE_SYMBOL startSymbol = {
|
||||
{ 0 }, // Name
|
||||
0, // Value
|
||||
sectionNumber, // SectionNumber
|
||||
0, // Type
|
||||
2, // StorageClass
|
||||
0, // NumberOfAuxSymbols
|
||||
};
|
||||
startSymbol.N.Name.Long = startNameOffset;
|
||||
|
||||
IMAGE_SYMBOL endSymbol = {
|
||||
{ 0 }, // Name
|
||||
size, // Value
|
||||
sectionNumber, // SectionNumber
|
||||
0, // Type
|
||||
2, // StorageClass
|
||||
0, // NumberOfAuxSymbols
|
||||
};
|
||||
endSymbol.N.Name.Long = endNameOffset;
|
||||
|
||||
out->writeChunk(&fileHeader, sizeof(fileHeader));
|
||||
out->writeChunk(§ionHeader, sizeof(sectionHeader));
|
||||
|
||||
out->writeChunk(data, size);
|
||||
out->writeRepeat(0, pad(size) - size);
|
||||
|
||||
out->writeChunk(&startSymbol, sizeof(startSymbol));
|
||||
out->writeChunk(&endSymbol, sizeof(endSymbol));
|
||||
|
||||
uint32_t symbolTableSize = endNameOffset + endNameLength;
|
||||
out->writeChunk(&symbolTableSize, 4);
|
||||
|
||||
out->writeChunk(startName, startNameLength);
|
||||
out->writeChunk(endName, endNameLength);
|
||||
}
|
||||
|
||||
template<unsigned BytesPerWord>
|
||||
class WindowsPlatform : public Platform {
|
||||
public:
|
||||
|
||||
class PEObjectWriter : public ObjectWriter {
|
||||
|
||||
class FileWriter {
|
||||
public:
|
||||
unsigned sectionCount;
|
||||
unsigned symbolCount;
|
||||
unsigned dataStart;
|
||||
unsigned dataOffset;
|
||||
|
||||
OutputStream* out;
|
||||
IMAGE_FILE_HEADER header;
|
||||
|
||||
PEObjectWriter(OutputStream* out):
|
||||
out(out) {}
|
||||
StringTable strings;
|
||||
Buffer symbols;
|
||||
|
||||
virtual bool write(uint8_t* data, size_t size,
|
||||
const char* startName, const char* endName,
|
||||
unsigned alignment, unsigned accessFlags)
|
||||
FileWriter(unsigned machine, unsigned machineMask, unsigned symbolCount):
|
||||
sectionCount(0),
|
||||
symbolCount(symbolCount),
|
||||
dataStart(sizeof(IMAGE_FILE_HEADER)),
|
||||
dataOffset(0)
|
||||
{
|
||||
int machine;
|
||||
int machineMask;
|
||||
|
||||
if (BytesPerWord == 8) {
|
||||
machine = IMAGE_FILE_MACHINE_AMD64;
|
||||
machineMask = 0;
|
||||
} else { // if (BytesPerWord == 8)
|
||||
machine = IMAGE_FILE_MACHINE_I386;
|
||||
machineMask = IMAGE_FILE_32BIT_MACHINE;
|
||||
}
|
||||
|
||||
int sectionMask;
|
||||
switch (alignment) {
|
||||
case 0:
|
||||
case 1:
|
||||
sectionMask = IMAGE_SCN_ALIGN_1BYTES;
|
||||
break;
|
||||
case 2:
|
||||
sectionMask = IMAGE_SCN_ALIGN_2BYTES;
|
||||
break;
|
||||
case 4:
|
||||
sectionMask = IMAGE_SCN_ALIGN_4BYTES;
|
||||
break;
|
||||
case 8:
|
||||
sectionMask = IMAGE_SCN_ALIGN_8BYTES;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "unsupported alignment: %d\n", alignment);
|
||||
return false;
|
||||
}
|
||||
|
||||
sectionMask |= IMAGE_SCN_MEM_READ;
|
||||
|
||||
const char* sectionName;
|
||||
if (accessFlags & ObjectWriter::Writable) {
|
||||
if (accessFlags & ObjectWriter::Executable) {
|
||||
sectionName = ".rwx";
|
||||
sectionMask |= IMAGE_SCN_MEM_WRITE
|
||||
| IMAGE_SCN_MEM_EXECUTE
|
||||
| IMAGE_SCN_CNT_CODE;
|
||||
} else {
|
||||
sectionName = ".data";
|
||||
sectionMask |= IMAGE_SCN_MEM_WRITE;
|
||||
}
|
||||
} else {
|
||||
sectionName = ".text";
|
||||
sectionMask |= IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_CNT_CODE;
|
||||
}
|
||||
|
||||
writeObject(data, size, out, startName, endName, sectionName, machine,
|
||||
machineMask, sectionMask);
|
||||
|
||||
return true;
|
||||
header.Machine = machine;
|
||||
// header.NumberOfSections = sectionCount;
|
||||
header.TimeDateStamp = 0;
|
||||
// header.PointerToSymbolTable = sizeof(IMAGE_FILE_HEADER)
|
||||
// + sizeof(IMAGE_SECTION_HEADER)
|
||||
// + pad(size);
|
||||
// header.NumberOfSymbols = symbolCount;
|
||||
header.SizeOfOptionalHeader = 0;
|
||||
header.Characteristics = IMAGE_FILE_RELOCS_STRIPPED
|
||||
| IMAGE_FILE_LINE_NUMS_STRIPPED
|
||||
| machineMask;
|
||||
}
|
||||
|
||||
virtual void dispose() {
|
||||
delete this;
|
||||
void writeHeader(OutputStream* out) {
|
||||
header.NumberOfSections = sectionCount;
|
||||
header.PointerToSymbolTable = dataStart + dataOffset;
|
||||
printf("symbol table start: 0x%x\n", header.PointerToSymbolTable);
|
||||
dataOffset = pad(dataOffset + symbolCount * sizeof(IMAGE_SYMBOL));
|
||||
printf("string table start: 0x%x\n", dataStart + dataOffset);
|
||||
header.NumberOfSymbols = symbolCount;
|
||||
out->writeChunk(&header, sizeof(IMAGE_FILE_HEADER));
|
||||
}
|
||||
|
||||
void addSymbol(String name, unsigned addr, unsigned sectionNumber, unsigned type, unsigned storageClass) {
|
||||
unsigned nameOffset = strings.add(name);
|
||||
IMAGE_SYMBOL symbol = {
|
||||
{ 0 }, // Name
|
||||
addr, // Value
|
||||
sectionNumber, // SectionNumber
|
||||
type, // Type
|
||||
storageClass, // StorageClass
|
||||
0, // NumberOfAuxSymbols
|
||||
};
|
||||
symbol.N.Name.Long = nameOffset+4;
|
||||
symbols.write(&symbol, sizeof(IMAGE_SYMBOL));
|
||||
}
|
||||
|
||||
void writeData(OutputStream* out) {
|
||||
out->writeChunk(symbols.data, symbols.length);
|
||||
uint32_t size = strings.length + 4;
|
||||
out->writeChunk(&size, 4);
|
||||
out->writeChunk(strings.data, strings.length);
|
||||
}
|
||||
};
|
||||
|
||||
class SectionWriter {
|
||||
public:
|
||||
FileWriter& file;
|
||||
IMAGE_SECTION_HEADER header;
|
||||
size_t dataSize;
|
||||
size_t finalSize;
|
||||
const uint8_t* data;
|
||||
unsigned dataOffset;
|
||||
|
||||
SectionWriter(
|
||||
FileWriter& file,
|
||||
const char* name,
|
||||
unsigned sectionMask,
|
||||
const uint8_t* data,
|
||||
size_t dataSize):
|
||||
|
||||
file(file),
|
||||
data(data),
|
||||
dataSize(dataSize),
|
||||
finalSize(pad(dataSize))
|
||||
{
|
||||
file.sectionCount++;
|
||||
file.dataStart += sizeof(IMAGE_SECTION_HEADER);
|
||||
strcpy(reinterpret_cast<char*>(header.Name), name);
|
||||
header.Misc.VirtualSize = 0;
|
||||
header.SizeOfRawData = finalSize;
|
||||
// header.PointerToRawData = file.dataOffset;
|
||||
dataOffset = file.dataOffset;
|
||||
file.dataOffset += finalSize;
|
||||
header.PointerToRelocations = 0;
|
||||
header.PointerToLinenumbers = 0;
|
||||
header.NumberOfRelocations = 0;
|
||||
header.NumberOfLinenumbers = 0;
|
||||
header.Characteristics = sectionMask;
|
||||
}
|
||||
|
||||
void writeHeader(OutputStream* out) {
|
||||
header.PointerToRawData = dataOffset + file.dataStart;
|
||||
printf("section %s: data at 0x%x, ending at 0x%x\n", header.Name, header.PointerToRawData, header.PointerToRawData + header.SizeOfRawData);
|
||||
out->writeChunk(&header, sizeof(IMAGE_SECTION_HEADER));
|
||||
}
|
||||
|
||||
void writeData(OutputStream* out) {
|
||||
out->writeChunk(data, dataSize);
|
||||
out->writeRepeat(0, finalSize - dataSize);
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
virtual ObjectWriter* makeObjectWriter(OutputStream* out) {
|
||||
return new PEObjectWriter(out);
|
||||
virtual bool writeObject(OutputStream* out, Slice<SymbolInfo> symbols, Slice<const uint8_t> data, unsigned accessFlags, unsigned alignment) {
|
||||
|
||||
int machine;
|
||||
int machineMask;
|
||||
|
||||
if (BytesPerWord == 8) {
|
||||
machine = IMAGE_FILE_MACHINE_AMD64;
|
||||
machineMask = 0;
|
||||
} else { // if (BytesPerWord == 8)
|
||||
machine = IMAGE_FILE_MACHINE_I386;
|
||||
machineMask = IMAGE_FILE_32BIT_MACHINE;
|
||||
}
|
||||
|
||||
int sectionMask;
|
||||
switch (alignment) {
|
||||
case 0:
|
||||
case 1:
|
||||
sectionMask = IMAGE_SCN_ALIGN_1BYTES;
|
||||
break;
|
||||
case 2:
|
||||
sectionMask = IMAGE_SCN_ALIGN_2BYTES;
|
||||
break;
|
||||
case 4:
|
||||
sectionMask = IMAGE_SCN_ALIGN_4BYTES;
|
||||
break;
|
||||
case 8:
|
||||
sectionMask = IMAGE_SCN_ALIGN_8BYTES;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "unsupported alignment: %d\n", alignment);
|
||||
return false;
|
||||
}
|
||||
|
||||
sectionMask |= IMAGE_SCN_MEM_READ;
|
||||
|
||||
const char* sectionName;
|
||||
if (accessFlags & Platform::Writable) {
|
||||
if (accessFlags & Platform::Executable) {
|
||||
sectionName = ".rwx";
|
||||
sectionMask |= IMAGE_SCN_MEM_WRITE
|
||||
| IMAGE_SCN_MEM_EXECUTE
|
||||
| IMAGE_SCN_CNT_CODE;
|
||||
} else {
|
||||
sectionName = ".data";
|
||||
sectionMask |= IMAGE_SCN_MEM_WRITE;
|
||||
}
|
||||
} else {
|
||||
sectionName = ".text";
|
||||
sectionMask |= IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_CNT_CODE;
|
||||
}
|
||||
|
||||
FileWriter file(machine, machineMask, symbols.count);
|
||||
|
||||
SectionWriter section(file, sectionName, sectionMask, data.items, data.count);
|
||||
|
||||
file.writeHeader(out);
|
||||
|
||||
for(SymbolInfo* sym = symbols.begin(); sym != symbols.end(); sym++) {
|
||||
file.addSymbol(sym->name, sym->addr, 1, 0, 2);
|
||||
}
|
||||
|
||||
section.writeHeader(out);
|
||||
|
||||
section.writeData(out);
|
||||
|
||||
file.writeData(out);
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
WindowsPlatform():
|
||||
@ -253,4 +278,4 @@ public:
|
||||
WindowsPlatform<4> windows32Platform;
|
||||
WindowsPlatform<8> windows64Platform;
|
||||
|
||||
}
|
||||
} // namespace
|
||||
|
@ -19,6 +19,38 @@ namespace avian {
|
||||
|
||||
namespace tools {
|
||||
|
||||
String::String(const char* text):
|
||||
text(text),
|
||||
length(strlen(text)) {}
|
||||
|
||||
Buffer::Buffer():
|
||||
capacity(100),
|
||||
length(0),
|
||||
data((uint8_t*)malloc(capacity)) {}
|
||||
|
||||
Buffer::~Buffer() {
|
||||
free(data);
|
||||
}
|
||||
|
||||
void Buffer::ensure(size_t more) {
|
||||
if(length + more > capacity) {
|
||||
capacity = capacity * 2 + more;
|
||||
data = (uint8_t*)realloc(data, capacity);
|
||||
}
|
||||
}
|
||||
|
||||
void Buffer::write(const void* d, size_t size) {
|
||||
ensure(size);
|
||||
memcpy(data + length, d, size);
|
||||
length += size;
|
||||
}
|
||||
|
||||
unsigned StringTable::add(String str) {
|
||||
unsigned offset = Buffer::length;
|
||||
Buffer::write(str.text, str.length + 1);
|
||||
return offset;
|
||||
}
|
||||
|
||||
void OutputStream::write(uint8_t byte) {
|
||||
writeChunk(&byte, 1);
|
||||
}
|
||||
|
@ -35,20 +35,62 @@ public:
|
||||
virtual void write(uint8_t byte);
|
||||
};
|
||||
|
||||
class ObjectWriter {
|
||||
class String {
|
||||
public:
|
||||
const char* text;
|
||||
size_t length;
|
||||
|
||||
enum AccessFlags {
|
||||
Readable = 1 << 0,
|
||||
Writable = 1 << 1,
|
||||
Executable = 1 << 2
|
||||
};
|
||||
String(const char* text);
|
||||
};
|
||||
|
||||
virtual bool write(uint8_t* data, size_t size,
|
||||
const char* startName, const char* endName,
|
||||
unsigned alignment, unsigned accessFlags) = 0;
|
||||
class SymbolInfo {
|
||||
public:
|
||||
unsigned addr;
|
||||
String name;
|
||||
|
||||
virtual void dispose() = 0;
|
||||
inline SymbolInfo(uint64_t addr, const char* name):
|
||||
addr(addr),
|
||||
name(name) {}
|
||||
|
||||
inline SymbolInfo():
|
||||
name("") {}
|
||||
};
|
||||
|
||||
class Buffer {
|
||||
public:
|
||||
size_t capacity;
|
||||
size_t length;
|
||||
uint8_t* data;
|
||||
|
||||
Buffer();
|
||||
~Buffer();
|
||||
|
||||
void ensure(size_t more);
|
||||
void write(const void* d, size_t size);
|
||||
};
|
||||
|
||||
class StringTable : public Buffer {
|
||||
public:
|
||||
unsigned add(String str);
|
||||
};
|
||||
|
||||
template<class T>
|
||||
class Slice {
|
||||
public:
|
||||
T* items;
|
||||
size_t count;
|
||||
|
||||
inline Slice(T* items, size_t count):
|
||||
items(items),
|
||||
count(count) {}
|
||||
|
||||
inline T* begin() {
|
||||
return items;
|
||||
}
|
||||
|
||||
inline T* end() {
|
||||
return items + count;
|
||||
}
|
||||
};
|
||||
|
||||
class PlatformInfo {
|
||||
@ -98,7 +140,12 @@ public:
|
||||
first = this;
|
||||
}
|
||||
|
||||
virtual ObjectWriter* makeObjectWriter(OutputStream* out) = 0;
|
||||
enum AccessFlags {
|
||||
Writable = 1 << 0,
|
||||
Executable = 1 << 1
|
||||
};
|
||||
|
||||
virtual bool writeObject(OutputStream* out, Slice<SymbolInfo> symbols, Slice<const uint8_t> data, unsigned accessFlags, unsigned alignment) = 0;
|
||||
|
||||
static Platform* getPlatform(PlatformInfo info);
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user