2014-01-31 08:23:00 +13:00
|
|
|
|
2019-01-18 15:54:29 +01:00
|
|
|
#include "linker.hpp"
|
|
|
|
|
#include "image_util.hpp"
|
2019-01-18 17:03:57 +01:00
|
|
|
#include "std.hpp"
|
2019-01-18 15:54:29 +01:00
|
|
|
|
|
|
|
|
using namespace std;
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2019-01-18 17:03:57 +01:00
|
|
|
class BBModule : public Module {
|
|
|
|
|
public:
|
2014-01-31 08:23:00 +13:00
|
|
|
BBModule();
|
2019-01-18 17:03:57 +01:00
|
|
|
BBModule(istream& in);
|
2014-01-31 08:23:00 +13:00
|
|
|
~BBModule();
|
|
|
|
|
|
2019-01-18 17:03:57 +01:00
|
|
|
void* link(Module* libs);
|
|
|
|
|
bool createExe(const char* exe_file, const char* dll_file);
|
2014-01-31 08:23:00 +13:00
|
|
|
|
|
|
|
|
int getPC();
|
|
|
|
|
|
2019-01-18 17:03:57 +01:00
|
|
|
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<string, int> symbols;
|
|
|
|
|
map<int, string> 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);
|
2014-01-31 08:23:00 +13:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-18 17:03:57 +01:00
|
|
|
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);
|
2014-01-31 08:23:00 +13:00
|
|
|
delete old_data;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2019-01-18 17:03:57 +01:00
|
|
|
BBModule::BBModule() : data(0), data_sz(0), pc(0), linked(false) {}
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2019-01-18 17:03:57 +01:00
|
|
|
BBModule::~BBModule()
|
|
|
|
|
{
|
|
|
|
|
if (linked)
|
|
|
|
|
VirtualFree(data, 0, MEM_RELEASE);
|
|
|
|
|
else
|
|
|
|
|
delete[] data;
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
|
2019-01-18 17:03:57 +01:00
|
|
|
void* BBModule::link(Module* libs)
|
|
|
|
|
{
|
|
|
|
|
if (linked)
|
|
|
|
|
return data;
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2019-01-18 17:03:57 +01:00
|
|
|
int dest;
|
|
|
|
|
map<int, string>::iterator it;
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2019-01-18 17:03:57 +01:00
|
|
|
char* p = (char*)VirtualAlloc(0, pc, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
|
|
|
|
|
memcpy(p, data, pc);
|
2014-01-31 08:23:00 +13:00
|
|
|
delete[] data;
|
2019-01-18 17:03:57 +01:00
|
|
|
data = p;
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2019-01-18 17:03:57 +01:00
|
|
|
linked = true;
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2019-01-18 17:03:57 +01:00
|
|
|
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);
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
|
2019-01-18 17:03:57 +01:00
|
|
|
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;
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-18 17:03:57 +01:00
|
|
|
int BBModule::getPC()
|
|
|
|
|
{
|
2014-01-31 08:23:00 +13:00
|
|
|
return pc;
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-18 17:03:57 +01:00
|
|
|
void BBModule::emit(int byte)
|
|
|
|
|
{
|
|
|
|
|
ensure(1);
|
|
|
|
|
data[pc++] = byte;
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
|
2019-01-18 17:03:57 +01:00
|
|
|
void BBModule::emitw(int word)
|
|
|
|
|
{
|
|
|
|
|
ensure(2);
|
|
|
|
|
*(short*)(data + pc) = word;
|
|
|
|
|
pc += 2;
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
|
2019-01-18 17:03:57 +01:00
|
|
|
void BBModule::emitd(int dword)
|
|
|
|
|
{
|
|
|
|
|
ensure(4);
|
|
|
|
|
*(int*)(data + pc) = dword;
|
|
|
|
|
pc += 4;
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
|
2019-01-18 17:03:57 +01:00
|
|
|
void BBModule::emitx(void* mem, int sz)
|
|
|
|
|
{
|
|
|
|
|
ensure(sz);
|
|
|
|
|
memcpy(data + pc, mem, sz);
|
|
|
|
|
pc += sz;
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
|
2019-01-18 17:03:57 +01:00
|
|
|
bool BBModule::addSymbol(const char* sym, int pc)
|
|
|
|
|
{
|
2014-01-31 08:23:00 +13:00
|
|
|
string t(sym);
|
2019-01-18 17:03:57 +01:00
|
|
|
if (symbols.find(t) != symbols.end())
|
|
|
|
|
return false;
|
|
|
|
|
symbols[t] = pc;
|
|
|
|
|
return true;
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
|
2019-01-18 17:03:57 +01:00
|
|
|
bool BBModule::addReloc(const char* dest_sym, int pc, bool pcrel)
|
|
|
|
|
{
|
|
|
|
|
map<int, string>& rel = pcrel ? rel_relocs : abs_relocs;
|
|
|
|
|
if (rel.find(pc) != rel.end())
|
|
|
|
|
return false;
|
|
|
|
|
rel[pc] = string(dest_sym);
|
|
|
|
|
return true;
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
|
2019-01-18 17:03:57 +01:00
|
|
|
bool BBModule::findSymbol(const char* sym, int* pc)
|
|
|
|
|
{
|
|
|
|
|
string t = string(sym);
|
|
|
|
|
map<string, int>::iterator it = symbols.find(t);
|
|
|
|
|
if (it == symbols.end())
|
|
|
|
|
return false;
|
|
|
|
|
*pc = it->second + (int)data;
|
2014-01-31 08:23:00 +13:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-18 17:03:57 +01:00
|
|
|
int Linker::version()
|
|
|
|
|
{
|
2014-01-31 08:23:00 +13:00
|
|
|
return VERSION;
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-18 17:03:57 +01:00
|
|
|
bool Linker::canCreateExe()
|
|
|
|
|
{
|
2014-01-31 08:23:00 +13:00
|
|
|
#ifdef DEMO
|
|
|
|
|
return false;
|
|
|
|
|
#else
|
|
|
|
|
return true;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-18 17:03:57 +01:00
|
|
|
Module* Linker::createModule()
|
|
|
|
|
{
|
2016-10-03 17:11:15 +02:00
|
|
|
return new BBModule();
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
|
2019-01-18 17:03:57 +01:00
|
|
|
void Linker::deleteModule(Module* mod)
|
|
|
|
|
{
|
2014-01-31 08:23:00 +13:00
|
|
|
delete mod;
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-18 17:03:57 +01:00
|
|
|
Linker* _cdecl linkerGetLinker()
|
|
|
|
|
{
|
|
|
|
|
static Linker linker;
|
|
|
|
|
return &linker;
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
|
2019-01-18 17:03:57 +01:00
|
|
|
bool BBModule::createExe(const char* exe_file, const char* dll_file)
|
|
|
|
|
{
|
2014-01-31 08:23:00 +13:00
|
|
|
#ifdef DEMO
|
|
|
|
|
return false;
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
|
|
//find proc address of bbWinMain
|
2019-01-18 17:03:57 +01:00
|
|
|
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;
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2019-01-18 17:03:57 +01:00
|
|
|
if (!CopyFile(dll_file, exe_file, false))
|
|
|
|
|
return false;
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2019-01-18 17:03:57 +01:00
|
|
|
if (!openImage(exe_file))
|
|
|
|
|
return false;
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2019-01-18 17:03:57 +01:00
|
|
|
makeExe(entry);
|
2014-01-31 08:23:00 +13:00
|
|
|
|
|
|
|
|
//create module
|
|
|
|
|
//code size: code...
|
|
|
|
|
//num_syms: name,val...
|
|
|
|
|
//num_rels: name,val...
|
|
|
|
|
//num_abss: name,val...
|
|
|
|
|
//
|
|
|
|
|
qstreambuf buf;
|
2019-01-18 17:03:57 +01:00
|
|
|
iostream out(&buf);
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2019-01-18 17:03:57 +01:00
|
|
|
map<string, int>::iterator it;
|
|
|
|
|
map<int, string>::iterator rit;
|
2014-01-31 08:23:00 +13:00
|
|
|
|
|
|
|
|
//write the code
|
2019-01-18 17:03:57 +01:00
|
|
|
int sz = pc;
|
|
|
|
|
out.write((char*)&sz, 4);
|
|
|
|
|
out.write(data, pc);
|
2014-01-31 08:23:00 +13:00
|
|
|
|
|
|
|
|
//write symbols
|
2019-01-18 17:03:57 +01:00
|
|
|
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);
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//write relative relocs
|
2019-01-18 17:03:57 +01:00
|
|
|
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);
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//write absolute relocs
|
2019-01-18 17:03:57 +01:00
|
|
|
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);
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
|
2019-01-18 17:03:57 +01:00
|
|
|
replaceRsrc(10, 1111, 1033, buf.data(), buf.size());
|
2014-01-31 08:23:00 +13:00
|
|
|
|
|
|
|
|
closeImage();
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
#endif
|
|
|
|
|
}
|