#include #include #include #include #include #include #include #include #include #include #include "powerpc.h" #include "PEF.h" typedef unsigned bfd_size_type; typedef unsigned bfd_vma; #define SYMNMLEN 8 #define PARAMS(x) x struct bfd_link_hash_entry {}; struct bfd_link_hash_table {}; typedef int bfd; typedef int asection; typedef int bfd_boolean; typedef char bfd_byte; #include "xcoff.h" /* n_sclass storage classes: */ #define C_EFCN 0xFFU /* physical end of function */ #define C_NULL 0U /* */ #define C_AUTO 1U /* automatic variable */ #define C_EXT 2U /* external symbol */ #define C_STAT 3U /* static symbol */ #define C_REG 4U /* register variable */ #define C_EXTDEF 5U /* external definition */ #define C_LABEL 6U /* label */ #define C_ULABEL 7U /* undefined label */ #define C_MOS 8U /* structure member */ #define C_ARG 9U /* function argument */ #define C_STRTAG 10U /* structure tag */ #define C_MOU 11U /* union member */ #define C_UNTAG 12U /* union tag */ #define C_TPDEF 13U /* type definition */ #define C_USTATIC 14U /* uninitialized static */ #define C_ENTAG 15U /* enumeration tag */ #define C_MOE 16U /* enumeration member */ #define C_REGPARM 17U /* register argument */ #define C_FIELD 18U /* bit field */ #define C_BLOCK 100U /* ".bb" or ".eb" */ #define C_FCN 101U /* ".bf" or ".ef" */ #define C_EOS 102U /* end of structure */ #define C_FILE 103U /* file name */ #define C_LINE 104U /* utility program use (?) */ #define C_ALIAS 105U /* duplicate tag */ #define C_HIDDEN 106U /* unnamed static symbol */ #define C_HIDEXT 107U /* unnamed external symbol */ #define C_BINCL 108U /* beginning of include file */ #define C_EINCL 109U /* end of include file */ //#define C_INFO 110U /* special information */ bool verboseFlag = false; inline int getI16(char *x) { return (((unsigned short)x[0]) << 8) | (unsigned short)x[1]; } inline int getI32(char *x) { return (((unsigned char)x[0]) << 24) | (((unsigned char)x[1]) << 16) | (((unsigned char)x[2]) << 8) | ((unsigned char)x[3]); } template void eswap(T *data, const char * format) { int endianTest = 1; if(*(char*)&endianTest == 0) return; char *p = reinterpret_cast(data); const char *q = format; while(char c = *q++) { if(c == 'L') { std::swap(p[0], p[3]); std::swap(p[1], p[2]); p += 4; } else if(c == 's') { std::swap(p[0], p[1]); p += 2; } else { assert(c == '.'); ++p; } } //assert(p == reinterpret_cast(data+1)); assert(p == reinterpret_cast(data) + sizeof(T)); } const char *SwapPEFContainerHeader = "LLLLLLLLssL"; const char *SwapPEFSectionHeader = "LLLLLL...."; const char *SwapPEFLoaderInfoHeader = "LLLLLLLLLLLLLL"; const char *SwapPEFImportedLibrary = "LLLLL..s"; const char *SwapPEFImportedSymbol = "L"; const char *SwapPEFLoaderRelocationHeader = "ssLL"; class ImportLib { public: std::string path, base, mem; std::vector imports; int nameOffset; bool weak; std::vector symNameOffsets; ImportLib(std::string path, std::string base, std::string mem) : path(path), base(base), mem(mem), weak(false) { } }; void mkpef(std::istream& in, std::ostream& out, std::string mainSymbol = "__start" ) { external_filehdr xcoffHeader; in.read((char*) &xcoffHeader, sizeof(xcoffHeader)); in.seekg(getI16(xcoffHeader.f_opthdr),std::ios_base::cur); if(verboseFlag) std::cerr << "flags: " << std::hex << getI16(xcoffHeader.f_flags) << std::dec << std::endl; if(verboseFlag) { std::cerr << "symptr: " << getI32(xcoffHeader.f_symptr) << std::endl; std::cerr << "nsyms: " << getI32(xcoffHeader.f_nsyms) << std::endl; } int nSections = getI16(xcoffHeader.f_nscns); PEFContainerHeader pefHeader; memset(&pefHeader,0,sizeof(pefHeader)); pefHeader.tag1 = kPEFTag1; pefHeader.tag2 = kPEFTag2; pefHeader.architecture = 'pwpc'; pefHeader.formatVersion = kPEFVersion; pefHeader.sectionCount = 3; // .text, .data, .loader pefHeader.instSectionCount = 2; // .text, .data std::map xcoffSections; std::map xcoffSectionNumbers; std::map xcoffSectionNames; std::map pefSectionNumbers; pefSectionNumbers[".text"] = 0; pefSectionNumbers[".data"] = 1; for(int i=0;i importLibs; std::vector relocInstructions; std::map importSources; std::map importedSymbolIndices; std::set importedSymbolSet; int totalImportedSyms = 0; { external_scnhdr xcoffLoaderSection = xcoffSections[".loader"]; internal_ldhdr xcoffLoaderHeader; char * loaderSectionPtr = (char*)alloca(getI32(xcoffLoaderSection.s_size)); in.seekg(getI32(xcoffLoaderSection.s_scnptr)); in.read(loaderSectionPtr, getI32(xcoffLoaderSection.s_size)); xcoffLoaderHeader = *(internal_ldhdr*)loaderSectionPtr; eswap(&xcoffLoaderHeader, "LLLLLLLLLL"); char *p = loaderSectionPtr + xcoffLoaderHeader.l_impoff; for(unsigned i=0; i 4) in.read(stringTable+4, stringTableLen-5); stringTable[stringTableLen-1] = 0; } if(verboseFlag) { std::cerr << "tell: " << in.tellg() << std::endl; std::cerr << "seeking to symptr: " << getI32(xcoffHeader.f_symptr) << std::endl; } in.seekg(getI32(xcoffHeader.f_symptr),std::ios::beg); if(verboseFlag) std::cerr << "tell: " << in.tellg() << std::endl; int nSymEntries = getI32(xcoffHeader.f_nsyms); std::vector syms(nSymEntries); in.read((char*) &syms[0], sizeof(external_syment)*nSymEntries); std::vector symNames; for(int i=0; i < nSymEntries; i++) { external_syment ent = syms[i]; std::string name; if(getI32(ent.e.e.e_zeroes) == 0) { if(getI16(ent.e_scnum) == -2) name = "#debug#"; else name = stringTable + getI32(ent.e.e.e_offset); } else name = ent.e.e_name; if(verboseFlag) { std::cerr << "[" << i << "] Symbol: " << name << std::hex << " e_value: " << getI32(ent.e_value) << " e_scnum: " << getI16(ent.e_scnum) << " e_type: " << getI16(ent.e_type) << " e_sclass: " << (int)ent.e_sclass[0] << std::dec << std::endl; } symNames.push_back(name); for(int j=0; j loaderStringTable; int loaderStringTableSize = 0; for(unsigned i=1;i 6) { if(name.substr(name.length()-6,6) == "__weak") { name = name.substr(0,name.length()-6); imp.weak = true; } } if(verboseFlag) { std::cerr << "PEF name \"" << name << '"'; if(imp.weak) std::cerr << " (weak)"; std::cerr << " at " << std::hex << loaderStringTableSize << std::dec << std::endl; } importLibs[i].nameOffset = loaderStringTableSize; loaderStringTable.push_back(name); loaderStringTableSize += name.length() + 1; for(unsigned j=0;j= argc) { std::cerr << "makepef: -o requires an argument.\n"; return 1; } if(hadOutput) { std::cerr << "makepef: -o can only be used once.\n"; return 1; } outputFn = argv[i]; hadOutput = true; } else { if(hadInput) { std::cerr << "makepef: can only handle one input file.\n"; return 1; } inputFn = argv[i]; hadInput = true; } } if(!hadInput) { std::cerr << "makepef: no input file specified.\n"; return 1; } if(!hadOutput) { std::cerr << "makepef: no output file specified.\n"; return 1; } std::ifstream in(inputFn.c_str()); std::ofstream out(outputFn.c_str()); mkpef(in, out); return 0; }