Files
BlitzNext/Linker/lib/linker.cpp
T

271 lines
4.9 KiB
C++
Raw Normal View History

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
}