diff --git a/makefile b/makefile index b4fc22d13a..2912cfde5b 100755 --- a/makefile +++ b/makefile @@ -241,7 +241,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 @@ -341,9 +340,6 @@ ifeq ($(platform),darwin) x := $(error "couldn't find SDK for iOS version") endif - ifeq ($(build-arch),powerpc) - converter-cflags += -DOPPOSITE_ENDIAN - endif flags = -arch armv7 -isysroot \ $(sdk-dir)/iPhoneOS$(ios-version).sdk/ openjdk-extra-cflags += $(flags) @@ -353,9 +349,6 @@ ifeq ($(platform),darwin) endif ifeq ($(arch),powerpc) - ifneq (,$(filter i386 x86_64 arm,$(build-arch))) - converter-cflags += -DOPPOSITE_ENDIAN - endif openjdk-extra-cflags += -arch ppc -mmacosx-version-min=${OSX_SDK_VERSION} cflags += -arch ppc -mmacosx-version-min=${OSX_SDK_VERSION} asmflags += -arch ppc -mmacosx-version-min=${OSX_SDK_VERSION} @@ -363,9 +356,6 @@ ifeq ($(platform),darwin) endif ifeq ($(arch),i386) - ifeq ($(build-arch),powerpc) - converter-cflags += -DOPPOSITE_ENDIAN - endif openjdk-extra-cflags += -arch i386 -mmacosx-version-min=${OSX_SDK_VERSION} cflags += -arch i386 -mmacosx-version-min=${OSX_SDK_VERSION} asmflags += -arch i386 -mmacosx-version-min=${OSX_SDK_VERSION} @@ -373,9 +363,6 @@ ifeq ($(platform),darwin) endif ifeq ($(arch),x86_64) - ifeq ($(build-arch),powerpc) - converter-cflags += -DOPPOSITE_ENDIAN - endif openjdk-extra-cflags += -arch x86_64 cflags += -arch x86_64 asmflags += -arch x86_64 @@ -444,6 +431,7 @@ endif ifeq ($(mode),debug) optimization-cflags = -O0 -g3 + converter-cflags += -O0 -g3 strip = : endif ifeq ($(mode),debug-fast) @@ -636,14 +624,20 @@ generator-objects = \ $(call generator-cpp-objects,$(generator-sources),$(src),$(build)) generator = $(build)/generator -converter-objects = \ - $(build)/binaryToObject-main.o \ - $(build)/binaryToObject-elf64.o \ - $(build)/binaryToObject-elf32.o \ - $(build)/binaryToObject-mach-o64.o \ - $(build)/binaryToObject-mach-o32.o \ - $(build)/binaryToObject-pe.o -converter = $(build)/binaryToObject +converter-depends = \ + $(src)/binaryToObject/tools.h \ + $(src)/binaryToObject/endianness.h + + +converter-sources = \ + $(src)/binaryToObject/main.cpp \ + $(src)/binaryToObject/tools.cpp \ + $(src)/binaryToObject/elf.cpp \ + $(src)/binaryToObject/mach-o.cpp \ + $(src)/binaryToObject/pe.cpp + +converter-objects = $(call cpp-objects,$(converter-sources),$(src),$(build)) +converter = $(build)/binaryToObject/binaryToObject static-library = $(build)/lib$(name).a executable = $(build)/$(name)${exe-suffix} @@ -848,26 +842,12 @@ $(boot-object): $(boot-source) $(boot-javahome-object): $(src)/boot-javahome.cpp $(compile-object) -$(build)/binaryToObject-main.o: $(src)/binaryToObject/main.cpp - $(build-cxx) $(converter-cflags) -c $(^) -o $(@) - -$(build)/binaryToObject-elf64.o: $(src)/binaryToObject/elf.cpp - $(build-cxx) $(converter-cflags) -DBITS_PER_WORD=64 -c $(^) -o $(@) - -$(build)/binaryToObject-elf32.o: $(src)/binaryToObject/elf.cpp - $(build-cxx) $(converter-cflags) -DBITS_PER_WORD=32 -c $(^) -o $(@) - -$(build)/binaryToObject-mach-o64.o: $(src)/binaryToObject/mach-o.cpp - $(build-cxx) $(converter-cflags) -DBITS_PER_WORD=64 -c $(^) -o $(@) - -$(build)/binaryToObject-mach-o32.o: $(src)/binaryToObject/mach-o.cpp - $(build-cxx) $(converter-cflags) -DBITS_PER_WORD=32 -c $(^) -o $(@) - -$(build)/binaryToObject-pe.o: $(src)/binaryToObject/pe.cpp - $(build-cxx) $(converter-cflags) -c $(^) -o $(@) +$(converter-objects): $(build)/binaryToObject/%.o: $(src)/binaryToObject/%.cpp $(converter-depends) + @mkdir -p $(dir $(@)) + $(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 $(@)" diff --git a/src/binaryToObject/elf.cpp b/src/binaryToObject/elf.cpp index bdfdce51c3..3548ac8431 100644 --- a/src/binaryToObject/elf.cpp +++ b/src/binaryToObject/elf.cpp @@ -8,12 +8,15 @@ There is NO WARRANTY for this software. See license.txt for details. */ -#include "stdint.h" -#include "stdio.h" -#include "string.h" +#include +#include +#include +#include #include "endianness.h" +#include "tools.h" + #define EI_NIDENT 16 #define EI_MAG0 0 @@ -62,344 +65,316 @@ #define STV_DEFAULT 0 -#define ELF64_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) -#define ELF32_ST_INFO(bind, type) ELF64_ST_INFO((bind), (type)) - -#if (BITS_PER_WORD == 64) -# define FileHeader Elf64_Ehdr -# define SectionHeader Elf64_Shdr -# define Symbol Elf64_Sym -# define Class ELFCLASS64 -# define SYMBOL_INFO ELF64_ST_INFO -#elif (BITS_PER_WORD == 32) -# define FileHeader Elf32_Ehdr -# define SectionHeader Elf32_Shdr -# define Symbol Elf32_Sym -# define Class ELFCLASS32 -# define SYMBOL_INFO ELF32_ST_INFO -#else -# error -#endif +#define SYMBOL_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) #define OSABI ELFOSABI_SYSV namespace { -typedef uint16_t Elf64_Half; -typedef uint32_t Elf64_Word; -typedef uint64_t Elf64_Addr; -typedef uint64_t Elf64_Xword; -typedef uint16_t Elf64_Section; -typedef uint64_t Elf64_Off; +using namespace avian::tools; -struct Elf64_Ehdr { - unsigned char e_ident[EI_NIDENT]; - Elf64_Half e_type; - Elf64_Half e_machine; - Elf64_Word e_version; - Elf64_Addr e_entry; - Elf64_Off e_phoff; - Elf64_Off e_shoff; - Elf64_Word e_flags; - Elf64_Half e_ehsize; - Elf64_Half e_phentsize; - Elf64_Half e_phnum; - Elf64_Half e_shentsize; - Elf64_Half e_shnum; - Elf64_Half e_shstrndx; +template +struct ElfTypes { + typedef uint16_t Half; + typedef uint32_t Word; + typedef AddrTy Addr; + typedef uint64_t Xword; + typedef uint16_t Section; + typedef AddrTy Off; + typedef AddrTy XFlags; + static const unsigned BytesPerWord = sizeof(AddrTy); }; -struct Elf64_Shdr { - Elf64_Word sh_name; - Elf64_Word sh_type; - Elf64_Xword sh_flags; - Elf64_Addr sh_addr; - Elf64_Off sh_offset; - Elf64_Xword sh_size; - Elf64_Word sh_link; - Elf64_Word sh_info; - Elf64_Xword sh_addralign; - Elf64_Xword sh_entsize; -}; +template +struct Symbol_Ty; -struct Elf64_Sym { - Elf64_Word st_name; +template<> +struct Symbol_Ty { + typedef ElfTypes Elf; + + Elf::Word st_name; unsigned char st_info; unsigned char st_other; - Elf64_Section st_shndx; - Elf64_Addr st_value; - Elf64_Xword st_size; + Elf::Section st_shndx; + Elf::Addr st_value; + Elf::Xword st_size; }; -typedef uint16_t Elf32_Half; -typedef uint32_t Elf32_Word; -typedef uint32_t Elf32_Addr; -typedef uint64_t Elf32_Xword; -typedef uint16_t Elf32_Section; -typedef uint32_t Elf32_Off; +template<> +struct Symbol_Ty { + typedef ElfTypes Elf; -struct Elf32_Ehdr { - unsigned char e_ident[EI_NIDENT]; - Elf32_Half e_type; - Elf32_Half e_machine; - Elf32_Word e_version; - Elf32_Addr e_entry; - Elf32_Off e_phoff; - Elf32_Off e_shoff; - Elf32_Word e_flags; - Elf32_Half e_ehsize; - Elf32_Half e_phentsize; - Elf32_Half e_phnum; - Elf32_Half e_shentsize; - Elf32_Half e_shnum; - Elf32_Half e_shstrndx; -}; - -struct Elf32_Shdr { - Elf32_Word sh_name; - Elf32_Word sh_type; - Elf32_Word sh_flags; - Elf32_Addr sh_addr; - Elf32_Off sh_offset; - Elf32_Word sh_size; - Elf32_Word sh_link; - Elf32_Word sh_info; - Elf32_Word sh_addralign; - Elf32_Word sh_entsize; -}; - -struct Elf32_Sym { - Elf32_Word st_name; - Elf32_Addr st_value; - Elf32_Word st_size; + Elf::Word st_name; + Elf::Addr st_value; + Elf::Word st_size; unsigned char st_info; unsigned char st_other; - Elf32_Section st_shndx; + Elf::Section st_shndx; }; -void -writeObject(const uint8_t* data, unsigned size, FILE* out, - const char* startName, const char* endName, - const char* sectionName, unsigned sectionFlags, - unsigned alignment, int machine, int encoding) -{ - const unsigned sectionCount = 5; - const unsigned symbolCount = 2; +using avian::endian::Endianness; - const unsigned sectionNameLength = strlen(sectionName) + 1; - const unsigned startNameLength = strlen(startName) + 1; - const unsigned endNameLength = strlen(endName) + 1; +#define V1 Endianness::v1 +#define V2 Endianness::v2 +#define V3 Endianness::v3 +#define V4 Endianness::v4 +#define VANY Endianness::vAny - 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 = VW(0); - fileHeader.e_phoff = VW(0); - fileHeader.e_shoff = VW(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 = VW(sectionFlags); - bodySection.sh_addr = VW(0); - unsigned bodySectionOffset - = sizeof(FileHeader) + (sizeof(SectionHeader) * sectionCount); - bodySection.sh_offset = VW(bodySectionOffset); - unsigned bodySectionSize = size; - bodySection.sh_size = VW(bodySectionSize); - bodySection.sh_link = V4(0); - bodySection.sh_info = V4(0); - bodySection.sh_addralign = VW(alignment); - bodySection.sh_entsize = VW(0); - - SectionHeader sectionStringTableSection; - sectionStringTableSection.sh_name = V4(sectionStringTableNameOffset); - sectionStringTableSection.sh_type = V4(SHT_STRTAB); - sectionStringTableSection.sh_flags = VW(0); - sectionStringTableSection.sh_addr = VW(0); - unsigned sectionStringTableSectionOffset - = bodySectionOffset + bodySectionSize; - sectionStringTableSection.sh_offset = VW(sectionStringTableSectionOffset); - unsigned sectionStringTableSectionSize = sectionStringTableLength; - sectionStringTableSection.sh_size = VW(sectionStringTableSectionSize); - sectionStringTableSection.sh_link = V4(0); - sectionStringTableSection.sh_info = V4(0); - sectionStringTableSection.sh_addralign = VW(1); - sectionStringTableSection.sh_entsize = VW(0); - - SectionHeader stringTableSection; - stringTableSection.sh_name = V4(stringTableNameOffset); - stringTableSection.sh_type = V4(SHT_STRTAB); - stringTableSection.sh_flags = VW(0); - stringTableSection.sh_addr = VW(0); - unsigned stringTableSectionOffset - = sectionStringTableSectionOffset + sectionStringTableSectionSize; - stringTableSection.sh_offset = VW(stringTableSectionOffset); - unsigned stringTableSectionSize = stringTableLength; - stringTableSection.sh_size = VW(stringTableSectionSize); - stringTableSection.sh_link = V4(0); - stringTableSection.sh_info = V4(0); - stringTableSection.sh_addralign = VW(1); - stringTableSection.sh_entsize = VW(0); - - SectionHeader symbolTableSection; - symbolTableSection.sh_name = V4(symbolTableNameOffset); - symbolTableSection.sh_type = V4(SHT_SYMTAB); - symbolTableSection.sh_flags = VW(0); - symbolTableSection.sh_addr = VW(0); - unsigned symbolTableSectionOffset - = stringTableSectionOffset + stringTableSectionSize; - symbolTableSection.sh_offset = VW(symbolTableSectionOffset); - unsigned symbolTableSectionSize = sizeof(Symbol) * symbolCount; - symbolTableSection.sh_size = VW(symbolTableSectionSize); - symbolTableSection.sh_link = V4(stringTableSectionNumber); - symbolTableSection.sh_info = V4(0); - symbolTableSection.sh_addralign = VW(BITS_PER_WORD / 8); - symbolTableSection.sh_entsize = VW(sizeof(Symbol)); - - Symbol startSymbol; - startSymbol.st_name = V4(startNameOffset); - startSymbol.st_value = VW(0); - startSymbol.st_size = VW(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 = VW(size); - endSymbol.st_size = VW(0); - endSymbol.st_info = V1(SYMBOL_INFO(STB_GLOBAL, STT_NOTYPE)); - endSymbol.st_other = V1(STV_DEFAULT); - endSymbol.st_shndx = V2(bodySectionNumber); - - fwrite(&fileHeader, 1, sizeof(fileHeader), out); - fwrite(&nullSection, 1, sizeof(nullSection), out); - fwrite(&bodySection, 1, sizeof(bodySection), out); - fwrite(§ionStringTableSection, 1, sizeof(sectionStringTableSection), - out); - fwrite(&stringTableSection, 1, sizeof(stringTableSection), out); - fwrite(&symbolTableSection, 1, sizeof(symbolTableSection), out); - - fwrite(data, 1, size, out); - - fputc(0, out); - fwrite(sectionStringTableName, 1, sectionStringTableNameLength, out); - fwrite(stringTableName, 1, stringTableNameLength, out); - fwrite(symbolTableName, 1, symbolTableNameLength, out); - fwrite(sectionName, 1, sectionNameLength, out); - - fputc(0, out); - fwrite(startName, 1, startNameLength, out); - fwrite(endName, 1, endNameLength, out); - - fwrite(&startSymbol, 1, sizeof(startSymbol), out); - fwrite(&endSymbol, 1, sizeof(endSymbol), out); +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 ElfPlatform : public Platform { +public: + + typedef ElfTypes Elf; + static const unsigned Class = Elf::BytesPerWord / 4; + + struct FileHeader { + unsigned char e_ident[EI_NIDENT]; + typename Elf::Half e_type; + typename Elf::Half e_machine; + typename Elf::Word e_version; + typename Elf::Addr e_entry; + typename Elf::Off e_phoff; + typename Elf::Off e_shoff; + typename Elf::Word e_flags; + typename Elf::Half e_ehsize; + typename Elf::Half e_phentsize; + typename Elf::Half e_phnum; + typename Elf::Half e_shentsize; + typename Elf::Half e_shnum; + typename Elf::Half e_shstrndx; + }; + + struct SectionHeader { + typename Elf::Word sh_name; + typename Elf::Word sh_type; + typename Elf::XFlags sh_flags; + typename Elf::Addr sh_addr; + typename Elf::Off sh_offset; + typename Elf::Off sh_size; + typename Elf::Word sh_link; + typename Elf::Word sh_info; + typename Elf::Addr sh_addralign; + typename Elf::Off sh_entsize; + }; + + typedef Symbol_Ty Symbol; + + 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; + + AddrTy dataOffset; + + FileHeader header; + StringTable strings; + + FileWriter(unsigned machine): + sectionCount(0), + dataOffset(sizeof(FileHeader)) + { + 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(0)); + header.e_phoff = VANY(static_cast(0)); + header.e_shoff = VANY(static_cast(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)); + } + + void writeHeader(OutputStream* out) { + header.e_shnum = V2(sectionCount); + header.e_shstrndx = V2(sectionStringTableSectionNumber); + out->writeChunk(&header, sizeof(FileHeader)); + } + }; + + class SectionWriter { + public: + FileWriter& file; + String name; + SectionHeader header; + const size_t* dataSize; + const uint8_t* const* data; + + 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(bodySectionOffset)); + // header.sh_size = VANY(static_cast(*dataSize)); + header.sh_link = V4(link); + header.sh_info = V4(0); + header.sh_addralign = VANY(static_cast(alignment)); + header.sh_entsize = VANY(static_cast(entsize)); + } + + void writeHeader(OutputStream* out) { + if(dataSize) { + header.sh_offset = VANY(file.dataOffset); + header.sh_size = VANY(static_cast(*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 symbols, Slice 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(sym->addr)); + symbolStruct.st_size = VANY(static_cast(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; + } +}; + +ElfPlatform elfx86Platform(PlatformInfo::x86); +ElfPlatform elfArmPlatform(PlatformInfo::Arm); +ElfPlatform elfPowerPCPlatform(PlatformInfo::PowerPC); +ElfPlatform elfx86_64Platform(PlatformInfo::x86_64); + + } // namespace - -#define MACRO_MAKE_NAME(a, b, c) a##b##c -#define MAKE_NAME(a, b, c) MACRO_MAKE_NAME(a, b, c) - -namespace binaryToObject { - -bool -MAKE_NAME(writeElf, BITS_PER_WORD, Object) - (uint8_t* data, unsigned size, FILE* out, const char* startName, - const char* endName, const char* architecture, unsigned alignment, - bool writable, bool executable) -{ - int machine; - int encoding; - if (strcmp(architecture, "x86_64") == 0) { - machine = EM_X86_64; - encoding = ELFDATA2LSB; - } else if (strcmp(architecture, "i386") == 0) { - machine = EM_386; - encoding = ELFDATA2LSB; - } else if (strcmp(architecture, "arm") == 0) { - machine = EM_ARM; - encoding = ELFDATA2LSB; - } else if (strcmp(architecture, "powerpc") == 0) { - machine = EM_PPC; - encoding = ELFDATA2MSB; - } else { - fprintf(stderr, "unsupported architecture: %s\n", architecture); - return false; - } - - const char* sectionName; - unsigned sectionFlags = SHF_ALLOC; - if (writable) { - if (executable) { - sectionName = ".rwx"; - sectionFlags |= SHF_WRITE | SHF_EXECINSTR; - } else { - sectionName = ".data"; - sectionFlags |= SHF_WRITE; - } - } else if (executable) { - sectionName = ".text"; - sectionFlags |= SHF_EXECINSTR; - } else { - sectionName = ".rodata"; - } - - writeObject(data, size, out, startName, endName, sectionName, sectionFlags, - alignment, machine, encoding); - - return true; -} - -} // namespace binaryToObject diff --git a/src/binaryToObject/endianness.h b/src/binaryToObject/endianness.h index 46cfcd8b46..0537fb8bfe 100644 --- a/src/binaryToObject/endianness.h +++ b/src/binaryToObject/endianness.h @@ -1,38 +1,81 @@ -#ifndef ENDIANNESS_H -#define ENDIANNESS_H +/* Copyright (c) 2008-2011, Avian Contributors -#define V1(v) (v) + Permission to use, copy, modify, and/or distribute this software + for any purpose with or without fee is hereby granted, provided + that the above copyright notice and this permission notice appear + in all copies. -#ifdef OPPOSITE_ENDIAN -# define V2(v) \ - ((((v) >> 8) & 0xFF) | \ - (((v) << 8))) -# define V4(v) \ - ((((v) >> 24) & 0x000000FF) | \ - (((v) >> 8) & 0x0000FF00) | \ - (((v) << 8) & 0x00FF0000) | \ - (((v) << 24))) -# define V8(v) \ - (((static_cast(v) >> 56) & UINT64_C(0x00000000000000FF)) | \ - ((static_cast(v) >> 40) & UINT64_C(0x000000000000FF00)) | \ - ((static_cast(v) >> 24) & UINT64_C(0x0000000000FF0000)) | \ - ((static_cast(v) >> 8) & UINT64_C(0x00000000FF000000)) | \ - ((static_cast(v) << 8) & UINT64_C(0x000000FF00000000)) | \ - ((static_cast(v) << 24) & UINT64_C(0x0000FF0000000000)) | \ - ((static_cast(v) << 40) & UINT64_C(0x00FF000000000000)) | \ - ((static_cast(v) << 56))) -#else -# define V2(v) (v) -# define V4(v) (v) -# define V8(v) (v) -#endif + There is NO WARRANTY for this software. See license.txt for + details. */ -#if (BITS_PER_WORD == 64) -# define VW(v) V8(v) -#elif (BITS_PER_WORD == 32) -# define VW(v) V4(v) -#else -# error -#endif +#ifndef AVIAN_ENDIANNESS_H +#define AVIAN_ENDIANNESS_H -#endif//ENDIANNESS_H +namespace avian { + +namespace endian { + +static union { + uint32_t i; + char c[4]; +} _DetectEndianness = {1}; + +const bool LittleEndian = _DetectEndianness.c[0] == 1; + +template +class Endianness { +public: + static inline uint8_t v1(uint8_t v) { + return v; + } + + static inline uint16_t v2(uint16_t v) { + if(LittleEndian == TargetLittleEndian) { + return v; + } else { + return ((v >> 8) & 0xFF) | (v << 8); + } + } + + static inline uint32_t v4(uint32_t v) { + if(LittleEndian == TargetLittleEndian) { + return v; + } else { + return + ((v >> 24) & 0x000000FF) | + ((v >> 8) & 0x0000FF00) | + ((v << 8) & 0x00FF0000) | + ((v << 24)); + } + } + + static inline uint32_t vAny(uint32_t v) { + return v4(v); + } + + static inline uint64_t v8(uint64_t v) { + if(LittleEndian == TargetLittleEndian) { + return v; + } else { + return + ((static_cast(v) >> 56) & (static_cast(0xff) << 0)) | + ((static_cast(v) >> 40) & (static_cast(0xff) << 8)) | + ((static_cast(v) >> 24) & (static_cast(0xff) << 16)) | + ((static_cast(v) >> 8) & (static_cast(0xff) << 24)) | + ((static_cast(v) << 8) & (static_cast(0xff) << 32)) | + ((static_cast(v) << 24) & (static_cast(0xff) << 40)) | + ((static_cast(v) << 40) & (static_cast(0xff) << 48)) | + ((static_cast(v) << 56)); + } + } + + static inline uint64_t vAny(uint64_t v) { + return v8(v); + } +}; + +} // namespace endian + +} // namespace avian + +#endif // AVIAN_ENDIANNESS_H diff --git a/src/binaryToObject/mach-o.cpp b/src/binaryToObject/mach-o.cpp index 8b37e85aaf..ef9cbe5f30 100644 --- a/src/binaryToObject/mach-o.cpp +++ b/src/binaryToObject/mach-o.cpp @@ -8,19 +8,19 @@ There is NO WARRANTY for this software. See license.txt for details. */ -#include "stdint.h" -#include "stdio.h" -#include "string.h" +#include +#include +#include #include "endianness.h" +#include "tools.h" + #define MH_MAGIC_64 0xfeedfacf #define MH_MAGIC 0xfeedface #define MH_OBJECT 1 -#define LC_SEGMENT_64 0x19 -#define LC_SEGMENT 1 #define LC_SYMTAB 2 #define S_REGULAR 0 @@ -40,142 +40,21 @@ #define CPU_SUBTYPE_POWERPC_ALL 0 #define CPU_SUBTYPE_ARM_V7 9 -#if (BITS_PER_WORD == 64) -# define Magic MH_MAGIC_64 -# define Segment LC_SEGMENT_64 -# define FileHeader mach_header_64 -# define SegmentCommand segment_command_64 -# define Section section_64 -# define NList struct nlist_64 -#elif (BITS_PER_WORD == 32) -# define Magic MH_MAGIC -# define Segment LC_SEGMENT -# define FileHeader mach_header -# define SegmentCommand segment_command -# define Section section -# define NList struct nlist -#else -# error -#endif - namespace { +using namespace avian::tools; + typedef int cpu_type_t; typedef int cpu_subtype_t; typedef int vm_prot_t; -struct mach_header_64 { - uint32_t magic; - cpu_type_t cputype; - cpu_subtype_t cpusubtype; - uint32_t filetype; - uint32_t ncmds; - uint32_t sizeofcmds; - uint32_t flags; - uint32_t reserved; -}; +using avian::endian::Endianness; -struct segment_command_64 { - uint32_t cmd; - uint32_t cmdsize; - char segname[16]; - uint64_t vmaddr; - uint64_t vmsize; - uint64_t fileoff; - uint64_t filesize; - vm_prot_t maxprot; - vm_prot_t initprot; - uint32_t nsects; - uint32_t flags; -}; - -struct section_64 { - char sectname[16]; - char segname[16]; - uint64_t addr; - uint64_t size; - uint32_t offset; - uint32_t align; - uint32_t reloff; - uint32_t nreloc; - uint32_t flags; - uint32_t reserved1; - uint32_t reserved2; - uint32_t reserved3; -}; - -struct nlist_64 { - union { - uint32_t n_strx; - } n_un; - uint8_t n_type; - uint8_t n_sect; - uint16_t n_desc; - uint64_t n_value; -}; - -struct mach_header { - uint32_t magic; - cpu_type_t cputype; - cpu_subtype_t cpusubtype; - uint32_t filetype; - uint32_t ncmds; - uint32_t sizeofcmds; - uint32_t flags; -}; - -struct segment_command { - uint32_t cmd; - uint32_t cmdsize; - char segname[16]; - uint32_t vmaddr; - uint32_t vmsize; - uint32_t fileoff; - uint32_t filesize; - vm_prot_t maxprot; - vm_prot_t initprot; - uint32_t nsects; - uint32_t flags; -}; - -struct section { - char sectname[16]; - char segname[16]; - uint32_t addr; - uint32_t size; - uint32_t offset; - uint32_t align; - uint32_t reloff; - uint32_t nreloc; - uint32_t flags; - uint32_t reserved1; - uint32_t reserved2; -}; - -struct symtab_command { - uint32_t cmd; - uint32_t cmdsize; - uint32_t symoff; - uint32_t nsyms; - uint32_t stroff; - uint32_t strsize; -}; - -struct nlist { - union { - int32_t n_strx; - } n_un; - uint8_t n_type; - uint8_t n_sect; - int16_t n_desc; - uint32_t n_value; -}; - -inline unsigned -pad(unsigned n) -{ - return (n + ((BITS_PER_WORD / 8) - 1)) & ~((BITS_PER_WORD / 8) - 1); -} +#define V1 Endianness::v1 +#define V2 Endianness::v2 +#define V3 Endianness::v3 +#define V4 Endianness::v4 +#define VANY Endianness::vAny inline unsigned log(unsigned n) @@ -185,177 +64,233 @@ log(unsigned n) return r; } -void -writeObject(const uint8_t* data, unsigned size, FILE* out, - 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; +template +class MachOPlatform : public Platform { +public: - FileHeader header = { - V4(Magic), // magic - V4(cpuType), - V4(cpuSubType), - V4(MH_OBJECT), // filetype, - V4(2), // ncmds - V4(sizeof(SegmentCommand) - + sizeof(Section) - + sizeof(symtab_command)), // sizeofcmds - V4(0) // flags + struct FileHeader { + uint32_t magic; + cpu_type_t cputype; + cpu_subtype_t cpusubtype; + uint32_t filetype; + uint32_t ncmds; + uint32_t sizeofcmds; + + union { + uint32_t flags; + AddrTy flagsAndMaybeReserved; + }; }; - SegmentCommand segment = { - V4(Segment), // cmd - V4(sizeof(SegmentCommand) + sizeof(Section)), // cmdsize - "", // segname - VW(0), // vmaddr - VW(pad(size)), // vmsize - VW(sizeof(FileHeader) - + sizeof(SegmentCommand) - + sizeof(Section) - + sizeof(symtab_command)), // fileoff - VW(pad(size)), // filesize - V4(7), // maxprot - V4(7), // initprot - V4(1), // nsects - V4(0) // flags + + struct SegmentCommand { + uint32_t cmd; + uint32_t cmdsize; + char segname[16]; + AddrTy vmaddr; + AddrTy vmsize; + AddrTy fileoff; + AddrTy filesize; + vm_prot_t maxprot; + vm_prot_t initprot; + uint32_t nsects; + uint32_t flags; }; - strncpy(segment.segname, segmentName, sizeof(segment.segname)); - - Section sect = { - "", // sectname - "", // segname - VW(0), // addr - VW(pad(size)), // size - V4(sizeof(FileHeader) - + sizeof(SegmentCommand) - + sizeof(Section) - + sizeof(symtab_command)), // offset - V4(log(alignment)), // align - V4(0), // reloff - V4(0), // nreloc - V4(S_REGULAR), // flags - V4(0), // reserved1 - V4(0), // reserved2 + struct Section { + char sectname[16]; + char segname[16]; + AddrTy addr; + AddrTy size; + uint32_t offset; + uint32_t align; + uint32_t reloff; + uint32_t nreloc; + uint32_t flags; + uint32_t reserved1; + AddrTy reserved2AndMaybe3; }; - strncpy(sect.segname, segmentName, sizeof(sect.segname)); - strncpy(sect.sectname, sectionName, sizeof(sect.sectname)); - - symtab_command symbolTable = { - V4(LC_SYMTAB), // cmd - V4(sizeof(symtab_command)), // cmdsize - V4(sizeof(FileHeader) - + sizeof(SegmentCommand) - + sizeof(Section) - + sizeof(symtab_command) - + pad(size)), // symoff - V4(2), // nsyms - V4(sizeof(FileHeader) - + sizeof(SegmentCommand) - + sizeof(Section) - + sizeof(symtab_command) - + pad(size) - + (sizeof(NList) * 2)), // stroff - V4(1 + startNameLength + endNameLength), // strsize + struct NList { + union { + uint32_t n_strx; + } n_un; + uint8_t n_type; + uint8_t n_sect; + uint16_t n_desc; + AddrTy n_value; }; - NList symbolList[] = { - { - V4(1), // n_un - V1(N_SECT | N_EXT), // n_type - V1(1), // n_sect - V2(0), // n_desc - VW(0) // n_value - }, - { - V4(1 + startNameLength), // n_un - V1(N_SECT | N_EXT), // n_type - V1(1), // n_sect - V2(0), // n_desc - VW(size) // n_value + struct SymtabCommand { + uint32_t cmd; + uint32_t cmdsize; + uint32_t symoff; + uint32_t nsyms; + uint32_t stroff; + uint32_t strsize; + }; + + static const unsigned BytesPerWord = sizeof(AddrTy); + static const unsigned Segment = BytesPerWord == 8 ? 0x19 : 1; + static const unsigned Magic = BytesPerWord == 8 ? 0xfeedfacf : 0xfeedface; + + static inline unsigned + pad(unsigned n) + { + return (n + (BytesPerWord - 1)) & ~(BytesPerWord - 1); + } + + virtual bool writeObject(OutputStream* out, Slice symbols, Slice 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; + break; + default: + // should never happen (see MachOPlatform declarations at bottom) + fprintf(stderr, "unsupported architecture: %d\n", info.arch); + return false; } - }; - fwrite(&header, 1, sizeof(header), out); - fwrite(&segment, 1, sizeof(segment), out); - fwrite(§, 1, sizeof(sect), out); - fwrite(&symbolTable, 1, sizeof(symbolTable), out); + 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"; + } - fwrite(data, 1, size, out); - for (unsigned i = 0; i < pad(size) - size; ++i) fputc(0, out); + 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 + }; - fwrite(&symbolList, 1, sizeof(symbolList), out); + AddrTy finalSize = pad(data.count); - fputc(0, out); - fwrite(startName, 1, startNameLength, out); - fwrite(endName, 1, endNameLength, out); -} + SegmentCommand segment = { + V4(Segment), // cmd + V4(sizeof(SegmentCommand) + sizeof(Section)), // cmdsize + "", // segname + VANY(static_cast(0)), // vmaddr + VANY(static_cast(finalSize)), // vmsize + VANY(static_cast(sizeof(FileHeader) + + sizeof(SegmentCommand) + + sizeof(Section) + + sizeof(SymtabCommand))), // fileoff + VANY(static_cast(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(0)), // addr + VANY(static_cast(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(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); + } + + MachOPlatform(PlatformInfo::Architecture arch): + Platform(PlatformInfo(PlatformInfo::Darwin, arch)) {} + +}; + +MachOPlatform darwinx86Platform(PlatformInfo::x86); +MachOPlatform darwinArmPlatform(PlatformInfo::Arm); +MachOPlatform darwinPowerPCPlatform(PlatformInfo::PowerPC); +MachOPlatform darwinx86_64Platform(PlatformInfo::x86_64); } // namespace - -#define MACRO_MAKE_NAME(a, b, c) a##b##c -#define MAKE_NAME(a, b, c) MACRO_MAKE_NAME(a, b, c) - -namespace binaryToObject { - -bool -MAKE_NAME(writeMachO, BITS_PER_WORD, Object) - (uint8_t* data, unsigned size, FILE* out, const char* startName, - const char* endName, const char* architecture, unsigned alignment, - bool writable, bool executable) -{ - cpu_type_t cpuType; - cpu_subtype_t cpuSubType; - if (strcmp(architecture, "x86_64") == 0) { - cpuType = CPU_TYPE_X86_64; - cpuSubType = CPU_SUBTYPE_X86_64_ALL; - } else if (strcmp(architecture, "i386") == 0) { - cpuType = CPU_TYPE_I386; - cpuSubType = CPU_SUBTYPE_I386_ALL; - } else if (strcmp(architecture, "powerpc") == 0) { - cpuType = CPU_TYPE_POWERPC; - cpuSubType = CPU_SUBTYPE_POWERPC_ALL; - } else if (strcmp(architecture, "arm") == 0) { - cpuType = CPU_TYPE_ARM; - cpuSubType = CPU_SUBTYPE_ARM_V7; - } else { - fprintf(stderr, "unsupported architecture: %s\n", architecture); - return false; - } - - const char* segmentName; - const char* sectionName; - if (writable) { - if (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, out, myStartName, myEndName, segmentName, - sectionName, alignment, cpuType, cpuSubType); - - return true; -} - -} // namespace binaryToObject diff --git a/src/binaryToObject/main.cpp b/src/binaryToObject/main.cpp index ffc6f1e017..e9bc749abc 100644 --- a/src/binaryToObject/main.cpp +++ b/src/binaryToObject/main.cpp @@ -8,111 +8,60 @@ There is NO WARRANTY for this software. See license.txt for details. */ -#include "stdint.h" -#include "stdio.h" -#include "stdlib.h" -#include "string.h" +#include +#include +#include +#include -#include "sys/stat.h" +#include #ifdef WIN32 #include #else -#include "sys/mman.h" +#include #endif -#include "fcntl.h" -#include "unistd.h" +#include +#include -namespace binaryToObject { +#include "tools.h" -bool -writeElf64Object(uint8_t* data, unsigned size, FILE* out, - const char* startName, const char* endName, - const char* architecture, unsigned alignment, bool writable, - bool executable); +extern "C" +void __cxa_pure_virtual() { + abort(); +} -bool -writeElf32Object(uint8_t* data, unsigned size, FILE* out, - const char* startName, const char* endName, - const char* architecture, unsigned alignment, bool writable, - bool executable); +void* operator new(size_t size) { + return malloc(size); +} -bool -writeMachO64Object(uint8_t* data, unsigned size, FILE* out, - const char* startName, const char* endName, - const char* architecture, unsigned alignment, bool writable, - bool executable); - -bool -writeMachO32Object(uint8_t* data, unsigned size, FILE* out, - const char* startName, const char* endName, - const char* architecture, unsigned alignment, bool writable, - bool executable); - -bool -writePEObject(uint8_t* data, unsigned size, FILE* out, const char* startName, - const char* endName, const char* architecture, - unsigned alignment, bool writable, bool executable); - -} // namespace binaryToObject +void operator delete(void* mem) { abort(); } namespace { +using namespace avian::tools; + bool -writeObject(uint8_t* data, unsigned size, FILE* out, const char* startName, - const char* endName, const char* platform, +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) { - using namespace binaryToObject; + Platform* platform = Platform::getPlatform(PlatformInfo(os, architecture)); - bool found = false; - bool success = false; - if (strcmp("linux", platform) == 0) { - if (strcmp("x86_64", architecture) == 0) { - found = true; - success = writeElf64Object - (data, size, out, startName, endName, architecture, alignment, - writable, executable); - } else if (strcmp("i386", architecture) == 0 - or strcmp("arm", architecture) == 0 - or strcmp("powerpc", architecture) == 0) - { - found = true; - success = writeElf32Object - (data, size, out, startName, endName, architecture, alignment, - writable, executable); - } - } else if (strcmp("darwin", platform) == 0) { - if (strcmp("x86_64", architecture) == 0) { - found = true; - success = writeMachO64Object - (data, size, out, startName, endName, architecture, alignment, - writable, executable); - } else if (strcmp("i386", architecture) == 0 - or strcmp("powerpc", architecture) == 0 - or strcmp("arm", architecture) == 0) - { - found = true; - success = writeMachO32Object - (data, size, out, startName, endName, architecture, alignment, - writable, executable); - } - } else if (strcmp("windows", platform) == 0 - and ((strcmp("x86_64", architecture) == 0 - or strcmp("i386", architecture) == 0))) - { - found = true; - success = writePEObject - (data, size, out, startName, endName, architecture, alignment, writable, - executable); - } - - if (not found) { - fprintf(stderr, "unsupported platform: %s/%s\n", platform, architecture); + if(!platform) { + fprintf(stderr, "unsupported platform: %s/%s\n", os, architecture); return false; } - return success; + SymbolInfo symbols[2]; + symbols[0].name = startName; + symbols[0].addr = 0; + symbols[1].name = endName; + symbols[1].addr = size; + + unsigned accessFlags = (writable ? Platform::Writable : 0) | (executable ? Platform::Executable : 0); + + return platform->writeObject(out, Slice(symbols, 2), Slice(data, size), accessFlags, alignment); + } void @@ -191,13 +140,11 @@ main(int argc, const char** argv) bool success = false; if (data) { - FILE* out = fopen(argv[2], "wb"); - if (out) { + FileOutputStream out(argv[2]); + if (out.isValid()) { success = writeObject - (data, size, out, argv[3], argv[4], argv[5], argv[6], alignment, + (data, size, &out, argv[3], argv[4], argv[5], argv[6], alignment, writable, executable); - - fclose(out); } else { fprintf(stderr, "unable to open %s\n", argv[2]); } diff --git a/src/binaryToObject/pe.cpp b/src/binaryToObject/pe.cpp index 45cc9556a9..aab60feb90 100644 --- a/src/binaryToObject/pe.cpp +++ b/src/binaryToObject/pe.cpp @@ -8,16 +8,21 @@ There is NO WARRANTY for this software. See license.txt for details. */ -#include "stdint.h" -#include "stdio.h" -#include "string.h" +#include +#include +#include +#include + +#include "tools.h" + +namespace { #define IMAGE_SIZEOF_SHORT_NAME 8 #define IMAGE_FILE_RELOCS_STRIPPED 1 #define IMAGE_FILE_LINE_NUMS_STRIPPED 4 #define IMAGE_FILE_MACHINE_AMD64 0x8664 -#define IMAGE_FILE_MACHINE_I386 0x014c +#define IMAGE_FILE_MACHINE_I386 0x014c #define IMAGE_FILE_32BIT_MACHINE 256 #define IMAGE_SCN_ALIGN_1BYTES 0x100000 @@ -29,8 +34,6 @@ #define IMAGE_SCN_MEM_WRITE 0x80000000 #define IMAGE_SCN_CNT_CODE 32 -namespace { - struct IMAGE_FILE_HEADER { uint16_t Machine; uint16_t NumberOfSections; @@ -77,155 +80,202 @@ pad(unsigned n) return (n + (4 - 1)) & ~(4 - 1); } -void -writeObject(const uint8_t* data, unsigned size, FILE* out, - const char* startName, const char* endName, - const char* sectionName, int machine, int machineMask, - int sectionMask) -{ - const unsigned sectionCount = 1; - const unsigned symbolCount = 2; +using namespace avian::tools; - const unsigned sectionNumber = 1; +template +class WindowsPlatform : public Platform { +public: - const unsigned startNameLength = strlen(startName) + 1; - const unsigned endNameLength = strlen(endName) + 1; - const unsigned startNameOffset = 4; - const unsigned endNameOffset = startNameOffset + startNameLength; + class FileWriter { + public: + unsigned sectionCount; + unsigned symbolCount; + unsigned dataStart; + unsigned dataOffset; - 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_FILE_HEADER header; + + StringTable strings; + Buffer symbols; + + FileWriter(unsigned machine, unsigned machineMask, unsigned symbolCount): + sectionCount(0), + symbolCount(symbolCount), + dataStart(sizeof(IMAGE_FILE_HEADER)), + dataOffset(0) + { + 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; + } + + 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); + } }; - 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 + 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(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); + } + + }; - strncpy(reinterpret_cast(sectionHeader.Name), sectionName, - sizeof(sectionHeader.Name)); + virtual bool writeObject(OutputStream* out, Slice symbols, Slice data, unsigned accessFlags, unsigned alignment) { - IMAGE_SYMBOL startSymbol = { - { 0 }, // Name - 0, // Value - sectionNumber, // SectionNumber - 0, // Type - 2, // StorageClass - 0, // NumberOfAuxSymbols - }; - startSymbol.N.Name.Long = startNameOffset; + int machine; + int machineMask; - IMAGE_SYMBOL endSymbol = { - { 0 }, // Name - size, // Value - sectionNumber, // SectionNumber - 0, // Type - 2, // StorageClass - 0, // NumberOfAuxSymbols - }; - endSymbol.N.Name.Long = endNameOffset; + if (BytesPerWord == 8) { + machine = IMAGE_FILE_MACHINE_AMD64; + machineMask = 0; + } else { // if (BytesPerWord == 8) + machine = IMAGE_FILE_MACHINE_I386; + machineMask = IMAGE_FILE_32BIT_MACHINE; + } - fwrite(&fileHeader, 1, sizeof(fileHeader), out); - fwrite(§ionHeader, 1, sizeof(sectionHeader), out); + 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; + } - fwrite(data, 1, size, out); - for (unsigned i = 0; i < pad(size) - size; ++i) fputc(0, out); + sectionMask |= IMAGE_SCN_MEM_READ; - fwrite(&startSymbol, 1, sizeof(startSymbol), out); - fwrite(&endSymbol, 1, sizeof(endSymbol), out); + 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; + } - uint32_t symbolTableSize = endNameOffset + endNameLength; - fwrite(&symbolTableSize, 1, 4, out); + FileWriter file(machine, machineMask, symbols.count); - fwrite(startName, 1, startNameLength, out); - fwrite(endName, 1, endNameLength, out); -} + 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(): + Platform(PlatformInfo(PlatformInfo::Windows, BytesPerWord == 4 ? PlatformInfo::x86 : PlatformInfo::x86_64)) {} +}; + +WindowsPlatform<4> windows32Platform; +WindowsPlatform<8> windows64Platform; } // namespace - -namespace binaryToObject { - -bool -writePEObject -(uint8_t* data, unsigned size, FILE* out, const char* startName, - const char* endName, const char* architecture, unsigned alignment, - bool writable, bool executable) -{ - int machine; - int machineMask; - if (strcmp(architecture, "x86_64") == 0) { - machine = IMAGE_FILE_MACHINE_AMD64; - machineMask = 0; - } else if (strcmp(architecture, "i386") == 0) { - machine = IMAGE_FILE_MACHINE_I386; - machineMask = IMAGE_FILE_32BIT_MACHINE; - } else { - fprintf(stderr, "unsupported architecture: %s\n", architecture); - return false; - } - - 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 (writable) { - if (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; -} - -} // namespace binaryToObject diff --git a/src/binaryToObject/tools.cpp b/src/binaryToObject/tools.cpp new file mode 100644 index 0000000000..4f8b8170d0 --- /dev/null +++ b/src/binaryToObject/tools.cpp @@ -0,0 +1,125 @@ +/* Copyright (c) 2009, Avian Contributors + + Permission to use, copy, modify, and/or distribute this software + for any purpose with or without fee is hereby granted, provided + that the above copyright notice and this permission notice appear + in all copies. + + There is NO WARRANTY for this software. See license.txt for + details. */ + +#include +#include +#include +#include + +#include "tools.h" + +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); +} + +void OutputStream::writeRepeat(uint8_t byte, size_t size) { + for(size_t i = 0; i < size; i++) { + write(byte); + } +} + +FileOutputStream::FileOutputStream(const char* name): + file(fopen(name, "wb")) {} + +FileOutputStream::~FileOutputStream() { + if(file) { + fclose(file); + } +} + +bool FileOutputStream::isValid() { + return file; +} + +void FileOutputStream::writeChunk(const void* data, size_t size) { + fwrite(data, size, 1, file); +} + +void FileOutputStream::write(uint8_t byte) { + fputc(byte, file); +} + + +Platform* Platform::first = 0; + +PlatformInfo::OperatingSystem PlatformInfo::osFromString(const char* os) { + if(strcmp(os, "linux") == 0) { + return Linux; + } else if(strcmp(os, "windows") == 0) { + return Windows; + } else if(strcmp(os, "darwin") == 0) { + return Darwin; + } else { + return UnknownOS; + } +} + +PlatformInfo::Architecture PlatformInfo::archFromString(const char* arch) { + if(strcmp(arch, "i386") == 0) { + return x86; + } else if(strcmp(arch, "x86_64") == 0) { + return x86_64; + } else if(strcmp(arch, "powerpc") == 0) { + return PowerPC; + } else if(strcmp(arch, "arm") == 0) { + return Arm; + } else { + return UnknownArch; + } +} + +Platform* Platform::getPlatform(PlatformInfo info) { + for(Platform* p = first; p; p = p->next) { + if(p->info == info) { + return p; + } + } + return 0; +} + +} // namespace tools + +} // namespace avian \ No newline at end of file diff --git a/src/binaryToObject/tools.h b/src/binaryToObject/tools.h new file mode 100644 index 0000000000..bc3d1f4f19 --- /dev/null +++ b/src/binaryToObject/tools.h @@ -0,0 +1,157 @@ +/* Copyright (c) 2009, Avian Contributors + + Permission to use, copy, modify, and/or distribute this software + for any purpose with or without fee is hereby granted, provided + that the above copyright notice and this permission notice appear + in all copies. + + There is NO WARRANTY for this software. See license.txt for + details. */ + +#ifndef AVIAN_TOOLS_H_ +#define AVIAN_TOOLS_H_ + +namespace avian { + +namespace tools { + +class OutputStream { +public: + virtual void writeChunk(const void* data, size_t size) = 0; + virtual void write(uint8_t byte); + virtual void writeRepeat(uint8_t byte, size_t size); +}; + +class FileOutputStream : public OutputStream { +private: + FILE* file; +public: + FileOutputStream(const char* name); + ~FileOutputStream(); + + bool isValid(); + + virtual void writeChunk(const void* data, size_t size); + virtual void write(uint8_t byte); +}; + +class String { +public: + const char* text; + size_t length; + + String(const char* text); +}; + +class SymbolInfo { +public: + unsigned addr; + String name; + + 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 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 { +public: + enum OperatingSystem { + Linux, Windows, Darwin, UnknownOS + }; + + enum Architecture { + x86, x86_64, PowerPC, Arm, UnknownArch + }; + + const OperatingSystem os; + const Architecture arch; + + static OperatingSystem osFromString(const char* os); + static Architecture archFromString(const char* arch); + + inline PlatformInfo(OperatingSystem os, Architecture arch): + os(os), + arch(arch) {} + + inline PlatformInfo(const char* os, const char* arch): + os(osFromString(os)), + arch(archFromString(arch)) {} + + inline bool operator == (const PlatformInfo& other) { + return os == other.os && arch == other.arch; + } + + inline bool isLittleEndian() { + return arch != PowerPC; + } +}; + +class Platform { +private: + Platform* next; + static Platform* first; +public: + PlatformInfo info; + + inline Platform(PlatformInfo info): + next(first), + info(info) + { + first = this; + } + + enum AccessFlags { + Writable = 1 << 0, + Executable = 1 << 1 + }; + + virtual bool writeObject(OutputStream* out, Slice symbols, Slice data, unsigned accessFlags, unsigned alignment) = 0; + + static Platform* getPlatform(PlatformInfo info); +}; + +} // namespace tools + +} // namespace avian + +#endif \ No newline at end of file