#include "linker.hpp" #include "image_util.hpp" #include "std.hpp" using namespace std; class BBModule : public Module { public: BBModule(); BBModule(istream& in); ~BBModule(); void* link(Module* libs); bool createExe(const char* exe_file, const char* dll_file); int getPC(); void emit(int byte); void emitw(int word); void emitd(int dword); void emitx(void* mem, int sz); bool addSymbol(const char* sym, int pc); bool addReloc(const char* dest_sym, int pc, bool pcrel); bool findSymbol(const char* sym, int* pc); private: char* data; int data_sz, pc; bool linked; map symbols; map rel_relocs, abs_relocs; bool findSym(const string& t, Module* libs, int* n) { if (findSymbol(t.c_str(), n)) return true; if (libs->findSymbol(t.c_str(), n)) return true; string err = "Symbol '" + t + "' not found"; MessageBox(GetDesktopWindow(), err.c_str(), "Blitz Linker Error", MB_TOPMOST | MB_SETFOREGROUND); return false; } void ensure(int n) { if (pc + n <= data_sz) return; data_sz = data_sz / 2 + data_sz; if (data_sz < pc + n) data_sz = pc + n; char* old_data = data; data = new char[data_sz]; memcpy(data, old_data, pc); delete old_data; } }; BBModule::BBModule() : data(0), data_sz(0), pc(0), linked(false) {} BBModule::~BBModule() { if (linked) VirtualFree(data, 0, MEM_RELEASE); else delete[] data; } void* BBModule::link(Module* libs) { if (linked) return data; int dest; map::iterator it; char* p = (char*)VirtualAlloc(0, pc, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); memcpy(p, data, pc); delete[] data; data = p; linked = true; for (it = rel_relocs.begin(); it != rel_relocs.end(); ++it) { if (!findSym(it->second, libs, &dest)) return 0; int* p = (int*)(data + it->first); *p += (dest - (int)p); } for (it = abs_relocs.begin(); it != abs_relocs.end(); ++it) { if (!findSym(it->second, libs, &dest)) return 0; int* p = (int*)(data + it->first); *p += dest; } return data; } int BBModule::getPC() { return pc; } void BBModule::emit(int byte) { ensure(1); data[pc++] = byte; } void BBModule::emitw(int word) { ensure(2); *(short*)(data + pc) = word; pc += 2; } void BBModule::emitd(int dword) { ensure(4); *(int*)(data + pc) = dword; pc += 4; } void BBModule::emitx(void* mem, int sz) { ensure(sz); memcpy(data + pc, mem, sz); pc += sz; } bool BBModule::addSymbol(const char* sym, int pc) { string t(sym); if (symbols.find(t) != symbols.end()) return false; symbols[t] = pc; return true; } bool BBModule::addReloc(const char* dest_sym, int pc, bool pcrel) { map& rel = pcrel ? rel_relocs : abs_relocs; if (rel.find(pc) != rel.end()) return false; rel[pc] = string(dest_sym); return true; } bool BBModule::findSymbol(const char* sym, int* pc) { string t = string(sym); map::iterator it = symbols.find(t); if (it == symbols.end()) return false; *pc = it->second + (int)data; return true; } int Linker::version() { return VERSION; } bool Linker::canCreateExe() { #ifdef DEMO return false; #else return true; #endif } Module* Linker::createModule() { return new BBModule(); } void Linker::deleteModule(Module* mod) { delete mod; } Linker* _cdecl linkerGetLinker() { static Linker linker; return &linker; } bool BBModule::createExe(const char* exe_file, const char* dll_file) { #ifdef DEMO return false; #else //find proc address of bbWinMain HMODULE hmod = LoadLibrary(dll_file); if (!hmod) return false; int proc = (int)GetProcAddress(hmod, "_bbWinMain@0"); int entry = proc - (int)hmod; FreeLibrary(hmod); if (!proc) return false; if (!CopyFile(dll_file, exe_file, false)) return false; if (!openImage(exe_file)) return false; makeExe(entry); //create module //code size: code... //num_syms: name,val... //num_rels: name,val... //num_abss: name,val... // qstreambuf buf; iostream out(&buf); map::iterator it; map::iterator rit; //write the code int sz = pc; out.write((char*)&sz, 4); out.write(data, pc); //write symbols sz = symbols.size(); out.write((char*)&sz, 4); for (it = symbols.begin(); it != symbols.end(); ++it) { string t = it->first + '\0'; out.write(t.data(), t.size()); sz = it->second; out.write((char*)&sz, 4); } //write relative relocs sz = rel_relocs.size(); out.write((char*)&sz, 4); for (rit = rel_relocs.begin(); rit != rel_relocs.end(); ++rit) { string t = rit->second + '\0'; out.write(t.data(), t.size()); sz = rit->first; out.write((char*)&sz, 4); } //write absolute relocs sz = abs_relocs.size(); out.write((char*)&sz, 4); for (rit = abs_relocs.begin(); rit != abs_relocs.end(); ++rit) { string t = rit->second + '\0'; out.write(t.data(), t.size()); sz = rit->first; out.write((char*)&sz, 4); } replaceRsrc(10, 1111, 1033, buf.data(), buf.size()); closeImage(); return true; #endif }