2014-01-31 08:23:00 +13:00
|
|
|
|
2019-01-18 17:04:17 +01:00
|
|
|
#pragma warning(disable : 4786)
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2019-01-18 15:55:06 +01:00
|
|
|
#include "bbruntime_dll.hpp"
|
|
|
|
|
#include "../debugger/debugger.hpp"
|
2014-01-31 08:23:00 +13:00
|
|
|
|
|
|
|
|
using namespace std;
|
|
|
|
|
|
|
|
|
|
#include <eh.h>
|
|
|
|
|
#include <float.h>
|
2019-01-18 17:04:17 +01:00
|
|
|
#include <map>
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2019-01-18 15:55:06 +01:00
|
|
|
#include "bbruntime.hpp"
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2019-01-18 17:04:17 +01:00
|
|
|
class DummyDebugger : public Debugger {
|
|
|
|
|
public:
|
|
|
|
|
virtual void debugRun() {}
|
|
|
|
|
virtual void debugStop() {} // bbruntime_panic(0); }
|
|
|
|
|
virtual void debugStmt(int srcpos, const char* file) {}
|
|
|
|
|
virtual void debugEnter(void* frame, void* env, const char* func) {}
|
|
|
|
|
virtual void debugLeave() {}
|
|
|
|
|
virtual void debugLog(const char* msg) {}
|
|
|
|
|
virtual void debugMsg(const char* e, bool serious)
|
|
|
|
|
{
|
|
|
|
|
if (serious)
|
|
|
|
|
MessageBox(0, e, "Error!", MB_OK | MB_TOPMOST | MB_SETFOREGROUND);
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
2019-01-18 17:04:17 +01:00
|
|
|
virtual void debugSys(void* msg) {}
|
2014-01-31 08:23:00 +13:00
|
|
|
};
|
|
|
|
|
|
2019-01-18 17:04:17 +01:00
|
|
|
static HINSTANCE hinst;
|
|
|
|
|
static map<const char*, void*> syms;
|
|
|
|
|
map<const char*, void*>::iterator sym_it;
|
|
|
|
|
static gxRuntime* gx_runtime;
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2019-01-18 17:04:17 +01:00
|
|
|
static void rtSym(const char* sym, void* pc)
|
|
|
|
|
{
|
|
|
|
|
syms[sym] = pc;
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
|
2019-01-18 17:04:17 +01:00
|
|
|
static void _cdecl seTranslator(unsigned int u, EXCEPTION_POINTERS* pExp)
|
|
|
|
|
{
|
|
|
|
|
switch (u) {
|
2014-01-31 08:23:00 +13:00
|
|
|
case EXCEPTION_INT_DIVIDE_BY_ZERO:
|
2019-01-18 17:04:17 +01:00
|
|
|
bbruntime_panic("Integer divide by zero");
|
2014-01-31 08:23:00 +13:00
|
|
|
case EXCEPTION_ACCESS_VIOLATION:
|
2019-01-18 17:04:17 +01:00
|
|
|
bbruntime_panic("Memory access violation");
|
2014-01-31 08:23:00 +13:00
|
|
|
case EXCEPTION_ILLEGAL_INSTRUCTION:
|
2019-01-18 17:04:17 +01:00
|
|
|
bbruntime_panic("Illegal instruction");
|
2014-01-31 08:23:00 +13:00
|
|
|
case EXCEPTION_STACK_OVERFLOW:
|
2019-01-18 17:04:17 +01:00
|
|
|
bbruntime_panic("Stack overflow!");
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
2019-01-18 17:04:17 +01:00
|
|
|
bbruntime_panic("Unknown runtime exception");
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
|
2019-01-18 17:04:17 +01:00
|
|
|
int Runtime::version()
|
|
|
|
|
{
|
2014-01-31 08:23:00 +13:00
|
|
|
return VERSION;
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-18 17:04:17 +01:00
|
|
|
const char* Runtime::nextSym()
|
|
|
|
|
{
|
|
|
|
|
if (!syms.size()) {
|
|
|
|
|
bbruntime_link(rtSym);
|
|
|
|
|
sym_it = syms.begin();
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
2019-01-18 17:04:17 +01:00
|
|
|
if (sym_it == syms.end()) {
|
|
|
|
|
syms.clear();
|
|
|
|
|
return 0;
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
return (sym_it++)->first;
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-18 17:04:17 +01:00
|
|
|
int Runtime::symValue(const char* sym)
|
|
|
|
|
{
|
|
|
|
|
map<const char*, void*>::iterator it = syms.find(sym);
|
|
|
|
|
if (it != syms.end())
|
|
|
|
|
return (int)it->second;
|
2014-01-31 08:23:00 +13:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-18 17:04:17 +01:00
|
|
|
void Runtime::startup(HINSTANCE h)
|
|
|
|
|
{
|
|
|
|
|
hinst = h;
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
|
2019-01-18 17:04:17 +01:00
|
|
|
void Runtime::shutdown()
|
|
|
|
|
{
|
|
|
|
|
trackmem(false);
|
2014-01-31 08:23:00 +13:00
|
|
|
syms.clear();
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-18 17:04:17 +01:00
|
|
|
void Runtime::execute(void (*pc)(), const char* args, Debugger* dbg)
|
|
|
|
|
{
|
|
|
|
|
bool debug = !!dbg;
|
2014-01-31 08:23:00 +13:00
|
|
|
|
|
|
|
|
static DummyDebugger dummydebug;
|
|
|
|
|
|
2019-01-18 17:04:17 +01:00
|
|
|
if (!dbg)
|
|
|
|
|
dbg = &dummydebug;
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2019-01-18 17:04:17 +01:00
|
|
|
trackmem(true);
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2016-07-20 02:01:40 +02:00
|
|
|
_se_translator_function old_trans = _set_se_translator(seTranslator);
|
2019-01-18 17:04:17 +01:00
|
|
|
_control87(_RC_NEAR | _PC_24 | _EM_INVALID | _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW | _EM_INEXACT
|
|
|
|
|
| _EM_DENORMAL,
|
|
|
|
|
0xfffff);
|
2014-01-31 08:23:00 +13:00
|
|
|
|
|
|
|
|
//strip spaces from ends of args...
|
2019-01-18 17:04:17 +01:00
|
|
|
string params = args;
|
|
|
|
|
while (params.size() && params[0] == ' ')
|
|
|
|
|
params = params.substr(1);
|
|
|
|
|
while (params.size() && params[params.size() - 1] == ' ')
|
|
|
|
|
params = params.substr(0, params.size() - 1);
|
|
|
|
|
|
|
|
|
|
if (gx_runtime = gxRuntime::openRuntime(hinst, params, dbg)) {
|
|
|
|
|
bbruntime_run(gx_runtime, pc, debug);
|
|
|
|
|
|
|
|
|
|
gxRuntime* t = gx_runtime;
|
|
|
|
|
gx_runtime = 0;
|
|
|
|
|
gxRuntime::closeRuntime(t);
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
|
2016-07-20 02:01:40 +02:00
|
|
|
_control87(_CW_DEFAULT, 0xfffff);
|
|
|
|
|
_set_se_translator(old_trans);
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
|
2019-01-18 17:04:17 +01:00
|
|
|
void Runtime::asyncStop()
|
|
|
|
|
{
|
|
|
|
|
if (gx_runtime)
|
|
|
|
|
gx_runtime->asyncStop();
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
|
2019-01-18 17:04:17 +01:00
|
|
|
void Runtime::asyncRun()
|
|
|
|
|
{
|
|
|
|
|
if (gx_runtime)
|
|
|
|
|
gx_runtime->asyncRun();
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
|
2019-01-18 17:04:17 +01:00
|
|
|
void Runtime::asyncEnd()
|
|
|
|
|
{
|
|
|
|
|
if (gx_runtime)
|
|
|
|
|
gx_runtime->asyncEnd();
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
|
2019-01-18 17:04:17 +01:00
|
|
|
void Runtime::checkmem(streambuf* buf)
|
|
|
|
|
{
|
|
|
|
|
ostream out(buf);
|
|
|
|
|
::checkmem(out);
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
|
2019-01-18 17:04:17 +01:00
|
|
|
Runtime* _cdecl runtimeGetRuntime()
|
|
|
|
|
{
|
2014-01-31 08:23:00 +13:00
|
|
|
static Runtime runtime;
|
|
|
|
|
return &runtime;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/********************** BUTT UGLY DLL->EXE HOOK! *************************/
|
|
|
|
|
|
2019-01-18 17:04:17 +01:00
|
|
|
static void* module_pc;
|
|
|
|
|
static map<string, int> module_syms;
|
|
|
|
|
static map<string, int> runtime_syms;
|
|
|
|
|
static Runtime* runtime;
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2019-01-18 17:04:17 +01:00
|
|
|
static void fail()
|
|
|
|
|
{
|
|
|
|
|
MessageBox(0, "Unable to run Blitz Basic module", 0, 0);
|
2014-01-31 08:23:00 +13:00
|
|
|
ExitProcess(-1);
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-18 17:04:17 +01:00
|
|
|
struct Sym {
|
2014-01-31 08:23:00 +13:00
|
|
|
string name;
|
2019-01-18 17:04:17 +01:00
|
|
|
int value;
|
2014-01-31 08:23:00 +13:00
|
|
|
};
|
|
|
|
|
|
2019-01-18 17:04:17 +01:00
|
|
|
static Sym getSym(void** p)
|
|
|
|
|
{
|
|
|
|
|
Sym sym;
|
|
|
|
|
char* t = (char*)*p;
|
|
|
|
|
while (char c = *t++)
|
|
|
|
|
sym.name += c;
|
|
|
|
|
sym.value = *(int*)t + (int)module_pc;
|
|
|
|
|
*p = t + 4;
|
|
|
|
|
return sym;
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
|
2019-01-18 17:04:17 +01:00
|
|
|
static int findSym(const string& t)
|
|
|
|
|
{
|
|
|
|
|
map<string, int>::iterator it;
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2019-01-18 17:04:17 +01:00
|
|
|
it = module_syms.find(t);
|
|
|
|
|
if (it != module_syms.end())
|
|
|
|
|
return it->second;
|
|
|
|
|
it = runtime_syms.find(t);
|
|
|
|
|
if (it != runtime_syms.end())
|
|
|
|
|
return it->second;
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2019-01-18 17:04:17 +01:00
|
|
|
string err = "Can't find symbol: " + t;
|
|
|
|
|
MessageBox(0, err.c_str(), 0, 0);
|
2014-01-31 08:23:00 +13:00
|
|
|
ExitProcess(0);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-18 17:04:17 +01:00
|
|
|
static void link()
|
|
|
|
|
{
|
|
|
|
|
while (const char* sc = runtime->nextSym()) {
|
2014-01-31 08:23:00 +13:00
|
|
|
string t(sc);
|
|
|
|
|
|
2019-01-18 17:04:17 +01:00
|
|
|
if (t[0] == '_') {
|
|
|
|
|
runtime_syms["_" + t] = runtime->symValue(sc);
|
2014-01-31 08:23:00 +13:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-18 17:04:17 +01:00
|
|
|
if (t[0] == '!')
|
|
|
|
|
t = t.substr(1);
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2019-01-18 17:04:17 +01:00
|
|
|
if (!isalnum(t[0]))
|
|
|
|
|
t = t.substr(1);
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2019-01-18 17:04:17 +01:00
|
|
|
for (int k = 0; k < t.size(); ++k) {
|
|
|
|
|
if (isalnum(t[k]) || t[k] == '_')
|
|
|
|
|
continue;
|
|
|
|
|
t = t.substr(0, k);
|
|
|
|
|
break;
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
|
2019-01-18 17:04:17 +01:00
|
|
|
runtime_syms["_f" + tolower(t)] = runtime->symValue(sc);
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
|
2019-01-18 17:04:17 +01:00
|
|
|
HRSRC hres = FindResource(0, MAKEINTRESOURCE(1111), RT_RCDATA);
|
|
|
|
|
if (!hres)
|
|
|
|
|
fail();
|
|
|
|
|
HGLOBAL hglo = LoadResource(0, hres);
|
|
|
|
|
if (!hglo)
|
|
|
|
|
fail();
|
|
|
|
|
void* p = LockResource(hglo);
|
|
|
|
|
if (!p)
|
|
|
|
|
fail();
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2019-01-18 17:04:17 +01:00
|
|
|
int sz = *(int*)p;
|
|
|
|
|
p = (int*)p + 1;
|
2014-01-31 08:23:00 +13:00
|
|
|
|
|
|
|
|
//replace malloc for service pack 2 Data Execution Prevention (DEP).
|
2019-01-18 17:04:17 +01:00
|
|
|
module_pc = VirtualAlloc(0, sz, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2019-01-18 17:04:17 +01:00
|
|
|
memcpy(module_pc, p, sz);
|
|
|
|
|
p = (char*)p + sz;
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2019-01-18 17:04:17 +01:00
|
|
|
int k, cnt;
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2019-01-18 17:04:17 +01:00
|
|
|
cnt = *(int*)p;
|
|
|
|
|
p = (int*)p + 1;
|
|
|
|
|
for (k = 0; k < cnt; ++k) {
|
|
|
|
|
Sym sym = getSym(&p);
|
|
|
|
|
if (sym.value < (int)module_pc || sym.value >= (int)module_pc + sz)
|
|
|
|
|
fail();
|
|
|
|
|
module_syms[sym.name] = sym.value;
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
|
2019-01-18 17:04:17 +01:00
|
|
|
cnt = *(int*)p;
|
|
|
|
|
p = (int*)p + 1;
|
|
|
|
|
for (k = 0; k < cnt; ++k) {
|
|
|
|
|
Sym sym = getSym(&p);
|
|
|
|
|
int* pp = (int*)sym.value;
|
|
|
|
|
int dest = findSym(sym.name);
|
|
|
|
|
*pp += dest - (int)pp;
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
|
2019-01-18 17:04:17 +01:00
|
|
|
cnt = *(int*)p;
|
|
|
|
|
p = (int*)p + 1;
|
|
|
|
|
for (k = 0; k < cnt; ++k) {
|
|
|
|
|
Sym sym = getSym(&p);
|
|
|
|
|
int* pp = (int*)sym.value;
|
|
|
|
|
int dest = findSym(sym.name);
|
|
|
|
|
*pp += dest;
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
runtime_syms.clear();
|
|
|
|
|
module_syms.clear();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
extern "C" _declspec(dllexport) int _stdcall bbWinMain();
|
2019-01-18 17:04:17 +01:00
|
|
|
extern "C" BOOL _stdcall _DllMainCRTStartup(HANDLE, DWORD, LPVOID);
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2019-01-18 17:04:17 +01:00
|
|
|
bool WINAPI DllMain(HANDLE module, DWORD reason, void* reserved)
|
|
|
|
|
{
|
2014-01-31 08:23:00 +13:00
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-18 17:04:17 +01:00
|
|
|
int __stdcall bbWinMain()
|
|
|
|
|
{
|
|
|
|
|
HINSTANCE inst = GetModuleHandle(0);
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2019-01-18 17:04:17 +01:00
|
|
|
_DllMainCRTStartup(inst, DLL_PROCESS_ATTACH, 0);
|
2014-01-31 08:23:00 +13:00
|
|
|
|
|
|
|
|
#ifdef BETA
|
2019-01-18 17:04:17 +01:00
|
|
|
int ver = VERSION & 0x7fff;
|
|
|
|
|
string t = "Created with Blitz3D Beta V" + itoa(ver / 100) + "." + itoa(ver % 100);
|
|
|
|
|
MessageBox(GetDesktopWindow(), t.c_str(), "Blitz3D Message", MB_OK);
|
2014-01-31 08:23:00 +13:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifdef SCHOOLS
|
2019-01-18 17:04:17 +01:00
|
|
|
MessageBox(GetDesktopWindow(), "Created with the schools version of Blitz Basic", "Blitz Basic Message", MB_OK);
|
2014-01-31 08:23:00 +13:00
|
|
|
#endif
|
|
|
|
|
|
2019-01-18 17:04:17 +01:00
|
|
|
runtime = runtimeGetRuntime();
|
|
|
|
|
runtime->startup(inst);
|
2014-01-31 08:23:00 +13:00
|
|
|
|
|
|
|
|
link();
|
|
|
|
|
|
|
|
|
|
//get cmd_line and params
|
2019-01-18 17:04:17 +01:00
|
|
|
string cmd = GetCommandLine(), params;
|
|
|
|
|
while (cmd.size() && cmd[0] == ' ')
|
|
|
|
|
cmd = cmd.substr(1);
|
|
|
|
|
if (cmd.find('\"') == 0) {
|
|
|
|
|
int n = cmd.find('\"', 1);
|
|
|
|
|
if (n != string::npos) {
|
|
|
|
|
params = cmd.substr(n + 1);
|
|
|
|
|
cmd = cmd.substr(1, n - 1);
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
2019-01-18 17:04:17 +01:00
|
|
|
} else {
|
|
|
|
|
int n = cmd.find(' ');
|
|
|
|
|
if (n != string::npos) {
|
|
|
|
|
params = cmd.substr(n + 1);
|
|
|
|
|
cmd = cmd.substr(0, n);
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-18 17:04:17 +01:00
|
|
|
runtime->execute((void (*)())module_pc, params.c_str(), 0);
|
2014-01-31 08:23:00 +13:00
|
|
|
runtime->shutdown();
|
|
|
|
|
|
2019-01-18 17:04:17 +01:00
|
|
|
_DllMainCRTStartup(inst, DLL_PROCESS_DETACH, 0);
|
2014-01-31 08:23:00 +13:00
|
|
|
|
|
|
|
|
ExitProcess(0);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|