#include #include #include #include #include #include #include #include #include #include #include #include #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; #define AOUTHDR external_aouthdr #include "rs6000.h" bool verboseFlag = false; inline int getI16(const void *xx) { const unsigned char *x = (const unsigned char*)xx; return (x[0] << 8) | x[1]; } inline int getI32(const void *xx) { const unsigned char *x = (const unsigned char*)xx; return (x[0] << 24) | (x[1] << 16) | (x[2] << 8) | x[3]; } inline int getI8(const void *xx) { return *(const unsigned char*)xx; } template inline int get(const ch (&x) [n]) { switch(n) { case 1: return getI8(x); case 2: return getI16(x); case 4: return getI32(x); default: abort(); } } class StringTable { size_t sz = 0; std::vector strings; public: size_t insert(const std::string& str) { size_t off = sz; strings.push_back(str); sz += str.size() + 1; return off; } size_t size() const { return sz; } void write(std::ostream& out) { if(verboseFlag) std::cerr << "strings..." << std::flush; for(const auto& str : strings) out.write(str.c_str(),str.size()+1); if(verboseFlag) std::cerr << "done.\n"; } }; class ImportLib { public: std::string path, base, mem; std::vector imports; std::vector xcoffImportIndices; std::string pefName; int nameOffset; bool weak; std::vector symNameOffsets; ImportLib(StringTable& stringTable, std::string path, std::string base, std::string mem) : path(path), base(base), mem(mem), weak(false) { std::string name = mem.empty() ? base : mem; if(name.empty()) // skip initial empty entry return; if(verboseFlag) std::cerr << "XCOFF name \"" << name << '"' << std::endl; int dotIndex = name.rfind('.'); if(dotIndex) { name = name.substr(0,dotIndex); if(name.substr(0,3) == "lib") name = name.substr(3); } if(name.length() > 6) { if(name.substr(name.length()-6,6) == "__weak") { name = name.substr(0,name.length()-6); weak = true; } } if(name.length() > 5) { // the shared library name has been encoded as hex by MakeImport // in order to avoid potential file name issues // classic MacOS shared library names are in MacRoman and // may contain wierd characters; the shared library name is used // as the file name for the archive member, so there can be problems. if(name.substr(0,5) == "imp__") { std::string realName; int i; int n = name.size(); for(i = 5; i < n && name[i] != '_'; i++) ; ++i; for(; i + 1 < n && name[i] != '_'; i+=2) { char c1 = tolower(name[i]); char c2 = tolower(name[i+1]); assert(isdigit(c1) || (c1 >= 'a' && c1 <= 'f')); assert(isdigit(c2) || (c2 >= 'a' && c2 <= 'f')); int c = (c1 >= 'a' ? c1 - 'a' + 10 : c1 - '0') * 16 + (c2 >= 'a' ? c2 - 'a' + 10 : c2 - '0'); realName += (char)c; } name = realName; } } pefName = name; nameOffset = stringTable.insert(pefName); if(verboseFlag) { std::cerr << "PEF name \"" << pefName << '"'; if(weak) std::cerr << " (weak)"; std::cerr << " at " << std::hex << nameOffset << std::dec << std::endl; } } void addSym(StringTable& stringTable, const std::string& name, int xcoffIndex) { imports.push_back(name); symNameOffsets.push_back(stringTable.insert(name)); xcoffImportIndices.push_back(xcoffIndex); } }; class ExportTable { std::vector table; size_t power_; struct Sym { uint32_t key; PEFExportedSymbol sym; }; std::vector symbols; uint32_t hash(const std::string& str) { int32_t hash = 0; for(char c : str) hash = ((hash << 1) - (hash >> 16)) ^ c; return uint32_t( (str.size() << 16) | ((hash ^ (hash >> 16)) & 0xFFFF) ); } void build() { int sz; power_ = 0; for(sz = 1; sz < 65536; sz *= 2, power_++) if(symbols.size() / sz < 10) break; table.clear(); table.resize(sz); std::sort(symbols.begin(), symbols.end(), [sz](const auto& a, const auto& b) { return a.key % sz < b.key % sz; }); for(const auto& sym : symbols) table[sym.key % sz] += 1 << 18; int off = 0; for(auto& slot : table) { slot |= off; off += slot >> 18; } } public: void addExport(StringTable& stringTable, const std::string& name, uint32_t value, int16_t section, uint8_t clas) { uint32_t classAndName = ((uint32_t)clas << 24) | stringTable.insert(name); symbols.push_back({hash(name), {classAndName, value, section}}); } size_t power() { if(table.empty()) build(); return power_; } size_t count() { if(table.empty()) build(); return symbols.size(); } size_t size() { if(table.empty()) build(); return 4 * table.size() + 14 * symbols.size(); } void write(std::ostream& out) { if(verboseFlag) std::cerr << "exports..." << std::flush; for(auto& key : table) eswap(&key); for(auto& sym : symbols) { eswap(&sym.key); eswap(&sym.sym); } out.write((char*)table.data(), 4 * table.size()); for(auto& sym : symbols) out.write((char*)&sym.key, 4); for(auto& sym : symbols) out.write((char*)&sym.sym, 10); if(verboseFlag) std::cerr << "done.\n"; } }; void mkpef(const std::string& inFn, const std::string& outFn) { std::ifstream in(inFn); external_filehdr xcoffHeader; external_aouthdr aoutHeader; in.read((char*) &xcoffHeader, sizeof(xcoffHeader)); assert((size_t)get(xcoffHeader.f_opthdr) >= sizeof(aoutHeader)); in.read((char*)&aoutHeader, sizeof(aoutHeader)); in.seekg(get(xcoffHeader.f_opthdr) - sizeof(aoutHeader),std::ios_base::cur); if(verboseFlag) { std::cerr << "flags: " << std::hex << get(xcoffHeader.f_flags) << std::dec << std::endl; std::cerr << "symptr: " << get(xcoffHeader.f_symptr) << std::endl; std::cerr << "nsyms: " << get(xcoffHeader.f_nsyms) << std::endl; } std::map xcoffSections; std::map xcoffSectionNumbers; int nSections = get(xcoffHeader.f_nscns); for(int i=0;i importLibs; std::vector importedSymbolIndices; int totalImportedSyms = 0; std::vector relocInstructions; { external_scnhdr xcoffLoaderSection = xcoffSections[".loader"]; external_ldhdr xcoffLoaderHeader; char * loaderSectionPtr = (char*)alloca(get(xcoffLoaderSection.s_size)); in.seekg(get(xcoffLoaderSection.s_scnptr)); in.read(loaderSectionPtr, get(xcoffLoaderSection.s_size)); xcoffLoaderHeader = *(external_ldhdr*)loaderSectionPtr; char *p = loaderSectionPtr + get(xcoffLoaderHeader.l_impoff); for(int i=0; i= 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; } mkpef(inputFn, outputFn); return 0; }