From b20681c1bf555c337b15796b3910d0d48488b102 Mon Sep 17 00:00:00 2001 From: Daniel Karbach Date: Tue, 19 Mar 2013 18:53:42 +0100 Subject: [PATCH] relocate scripts it totally works, yay \o/ well, except for referencing unavailable symbols in scripts --- src/common/Script.cpp | 39 ++++++++++++++++++++++ src/common/Script.h | 2 ++ src/loader/Compiler.cpp | 66 ++++++++++++++++++++++++++++++++++++++ src/loader/Compiler.h | 5 +++ src/loader/Interpreter.cpp | 4 ++- src/loader/Loader.cpp | 35 ++++++++++++++++++++ src/loader/Loader.h | 1 + src/loader/ObjectFile.cpp | 24 +++++++++++++- src/loader/ObjectFile.h | 16 +++++++++ 9 files changed, 190 insertions(+), 2 deletions(-) diff --git a/src/common/Script.cpp b/src/common/Script.cpp index 05dd819..c5caf57 100644 --- a/src/common/Script.cpp +++ b/src/common/Script.cpp @@ -1,5 +1,7 @@ #include "Script.h" +#include "../math/Vector.h" + namespace common { Script::Script() @@ -12,4 +14,41 @@ Script::~Script() { } + +unsigned int Script::Code::Size() const { + unsigned int size = sizeof(Code); + if (numParams == 0) { + return size; + } + unsigned int argSize = 0; + switch (type) { + default: + argSize = 0; + break; + case TYPE_ADDRESS: + argSize = sizeof(void *); + break; + case TYPE_INTEGER: + argSize = sizeof(int); + break; + case TYPE_VECTOR: + argSize = sizeof(math::Vector); + break; + } + switch (numParams) { + case 3: + case 2: + if (reg2 == 7) { + size += argSize; + } + case 1: + if (reg1 == 7) { + size += argSize; + } + default: + break; + } + return size; +} + } diff --git a/src/common/Script.h b/src/common/Script.h index c3f4838..be15a5e 100644 --- a/src/common/Script.h +++ b/src/common/Script.h @@ -41,6 +41,8 @@ public: Type type : 2; unsigned int reg1 : 3; unsigned int reg2 : 3; + + unsigned int Size() const; }; public: diff --git a/src/loader/Compiler.cpp b/src/loader/Compiler.cpp index b2d23be..13f3dfc 100644 --- a/src/loader/Compiler.cpp +++ b/src/loader/Compiler.cpp @@ -2,6 +2,7 @@ #include "Interpreter.h" #include "TypeDescription.h" +#include "../common/Script.h" #include #include @@ -18,6 +19,7 @@ using std::iostream; using std::make_pair; using std::map; using std::ostream; +using std::pair; using std::runtime_error; using std::set; using std::string; @@ -51,6 +53,9 @@ void Compiler::Write(iostream &out) { fileHeader.arraysBegin = out.tellp(); WriteArrays(out); fileHeader.arraysEnd = out.tellp(); + fileHeader.scriptsBegin = out.tellp(); + WriteScripts(out); + fileHeader.scriptsEnd = out.tellp(); out.seekp(0); WriteHeader(out); WriteExports(out); @@ -148,6 +153,11 @@ void Compiler::WriteObjects(ostream &out) { Write(out, &object, sizeof(Object)); addressMap.insert(make_pair(*j, out.tellp())); Write(out, *j, object.size); + + if (td.TypeId() == Interpreter::SCRIPT_ID) { + common::Script *script = reinterpret_cast(*j); + scripts.push_back(make_pair(const_cast(script->text), script->textlen)); + } } } } @@ -180,6 +190,18 @@ void Compiler::WriteImages(ostream &out) { } } +void Compiler::WriteScripts(ostream &out) { + for (vector >::const_iterator + i(scripts.begin()), end(scripts.end()); + i != end; ++i) { + Script s; + s.size = i->second; + Write(out, &s, sizeof(Script)); + addressMap.insert(make_pair(i->first, out.tellp())); + Write(out, i->first, s.size); + } +} + void Compiler::PrepareExport(Export &exp, const string &str) { const Interpreter::ParsedDefinition &dfn @@ -253,6 +275,18 @@ void Compiler::Relocate(iostream &out) { out.seekg(out.tellp()); delete[] buffer; } + Script script; + for (; out && out.tellg() < fileHeader.scriptsEnd;) { + out.read(reinterpret_cast(&script), sizeof(Script)); + buffer = new char[script.size]; + unsigned int pos = out.tellg(); + out.read(buffer, script.size); + RelocateScript(buffer, script.size); + out.seekp(pos); + out.write(buffer, script.size); + out.seekg(out.tellp()); + delete[] buffer; + } } void Compiler::RelocateArray(char *array, int size) { @@ -306,6 +340,38 @@ void Compiler::Relocate( } } +void Compiler::RelocateScript(char *text, unsigned int textlen) { + for (char *i = text, *end = text + textlen; i < end;) { + common::Script::Code *code = + reinterpret_cast(i); + if (code->type == common::Script::TYPE_ADDRESS && code->numParams > 0) { + if (code->reg1 == 7) { + char *addr = i + sizeof(common::Script::Code); + std::map::const_iterator + found(addressMap.find(*reinterpret_cast(addr))); + if (found == addressMap.end()) { + throw std::runtime_error("unable to relocate script code"); + } + *reinterpret_cast(addr) = found->second; + } + + if (code->numParams > 1 && code->reg2 == 7) { + char *addr = i + sizeof(common::Script::Code); + if (code->reg1 == 7) { + addr += sizeof(void *); + } + std::map::const_iterator + found(addressMap.find(*reinterpret_cast(addr))); + if (found == addressMap.end()) { + throw std::runtime_error("unable to relocate script code"); + } + *reinterpret_cast(addr) = found->second; + } + } + i += code->Size(); + } +} + void Compiler::Write(ostream &out, const void *data, int amount) { out.write(reinterpret_cast(data), amount); diff --git a/src/loader/Compiler.h b/src/loader/Compiler.h index 2f89752..d406bbf 100644 --- a/src/loader/Compiler.h +++ b/src/loader/Compiler.h @@ -8,6 +8,8 @@ #include #include #include +#include +#include #include namespace loader { @@ -33,10 +35,12 @@ private: void WriteExports(std::ostream &); void WriteExternals(std::ostream &); void WriteImages(std::ostream &); + void WriteScripts(std::ostream &); void Relocate(std::iostream &); void RelocateArray(char *, int size); void Relocate(unsigned int pos, char *dest, const TypeDescription &); + void RelocateScript(char *, unsigned int); void PrepareExport(Export &, const std::string &); void PrepareExternal(External &, const Interpreter::PostponedDefinition &); @@ -54,6 +58,7 @@ private: std::map addressMap; std::map images; + std::vector > scripts; }; diff --git a/src/loader/Interpreter.cpp b/src/loader/Interpreter.cpp index 3cb0d45..d13c3c6 100644 --- a/src/loader/Interpreter.cpp +++ b/src/loader/Interpreter.cpp @@ -959,16 +959,18 @@ void Interpreter::CreateTypeDescriptions() { td.SetDescription("A signed integer."); td.SetSize(sizeof(int)); } - {; + { TypeDescription &td(TypeDescription::Create(PATH_ID, "Path")); td.SetDescription("A path in the filesystem which is interpreted relative to the source file's location."); td.SetSize(1); td.AddSupertype(STRING_ID, 0); } { + Script s; TypeDescription &td(TypeDescription::Create(SCRIPT_ID, "Script")); td.SetDescription("Collection of commands that define a behaviour."); td.SetSize(sizeof(Script)); + td.AddField("text", FieldDescription(((char *)&s.text) - ((char *)&s), STRING_ID).SetAggregate()); } { TypeDescription &td(TypeDescription::Create(STRING_ID, "String")); diff --git a/src/loader/Loader.cpp b/src/loader/Loader.cpp index ba5dcc0..3c7f2bd 100644 --- a/src/loader/Loader.cpp +++ b/src/loader/Loader.cpp @@ -1,5 +1,7 @@ #include "Loader.h" +#include "../common/Script.h" + #include #include #include @@ -64,6 +66,9 @@ void Loader::Load(const std::string &filePath) { LoadImages(header->ident, header->ImagesBegin(), header->ImagesEnd()); + LoadScripts(header->ident, + header->ScriptsBegin(), + header->ScriptsEnd()); InitObjects( header->ObjectsBegin(), @@ -203,6 +208,36 @@ void Loader::LoadArrays(char *src, Array *begin, Array *end) { } } +void Loader::LoadScripts(char *src, Script *begin, Script *end) { + for (Script *s = begin; s < end; s = s->Next()) { + for (char *i = s->Text(), *end = s->Text() + s->size; i < end;) { + common::Script::Code *code = + reinterpret_cast(i); + if (code->type == common::Script::TYPE_ADDRESS && code->numParams > 0) { + if (code->reg1 == 7) { + char *addr = i + sizeof(common::Script::Code); + unsigned int offset = *reinterpret_cast(addr); + if (offset) { + *reinterpret_cast(addr) = src + offset; + } + } + + if (code->numParams > 1 && code->reg2 == 7) { + char *addr = i + sizeof(common::Script::Code); + if (code->reg1 == 7) { + addr += sizeof(void *); + } + unsigned int offset = *reinterpret_cast(addr); + if (offset) { + *reinterpret_cast(addr) = src + offset; + } + } + } + i += code->Size(); + } + } +} + void Loader::InitObjects(Object *begin, Object *end) { for (Object *i = begin; i < end; i = i->Next()) { diff --git a/src/loader/Loader.h b/src/loader/Loader.h index c962f20..17f637a 100644 --- a/src/loader/Loader.h +++ b/src/loader/Loader.h @@ -32,6 +32,7 @@ private: void LoadObjects(char *src, Object *begin, Object *end); void LoadObject(char *src, char *dest, const TypeDescription &); void LoadArrays(char *src, Array *begin, Array *end); + void LoadScripts(char *src, Script *begin, Script *end); void InitObjects(Object *begin, Object *end); void InitObject(char *object, const TypeDescription &); diff --git a/src/loader/ObjectFile.cpp b/src/loader/ObjectFile.cpp index b6ab2b7..76cc982 100644 --- a/src/loader/ObjectFile.cpp +++ b/src/loader/ObjectFile.cpp @@ -13,10 +13,14 @@ ObjectFileHeader::ObjectFileHeader() , exportsEnd(0) , externalsBegin(0) , externalsEnd(0) +, imagesBegin(0) +, imagesEnd(0) , objectsBegin(0) , objectsEnd(0) , arraysBegin(0) -, arraysEnd(0) { +, arraysEnd(0) +, scriptsBegin(0) +, scriptsEnd(0) { ident[0] = 'L'; ident[1] = '2'; ident[2] = 'E'; @@ -119,6 +123,16 @@ Array *ObjectFileHeader::ArraysEnd() { return reinterpret_cast(data + arraysEnd); } +Script *ObjectFileHeader::ScriptsBegin() { + char *data = reinterpret_cast(this); + return reinterpret_cast