diff --git a/bin/xenia-run b/bin/xenia-run index 33aace055..225d605ce 100755 --- a/bin/xenia-run +++ b/bin/xenia-run @@ -14,3 +14,8 @@ if [ ! -f "$EXEC" ]; then fi $EXEC "$@" + + +# TODO(benvanik): add --valgrind and --leaks +# xbb --debug && rm valgrind.txt && valgrind --log-file=valgrind.txt --dsymutil=yes build/xenia/debug/xenia-run "$@" +# --track-origins=yes --leak-check=full diff --git a/include/xenia/cpu/exec_module.h b/include/xenia/cpu/exec_module.h index 1c21417b6..780ac5423 100644 --- a/include/xenia/cpu/exec_module.h +++ b/include/xenia/cpu/exec_module.h @@ -50,6 +50,7 @@ public: void Dump(); private: + int InjectGlobals(); int Init(); int Uninit(); diff --git a/include/xenia/cpu/ppc/state.h b/include/xenia/cpu/ppc/state.h index 3aaf7fae2..6ed27339c 100644 --- a/include/xenia/cpu/ppc/state.h +++ b/include/xenia/cpu/ppc/state.h @@ -10,45 +10,54 @@ #ifndef XENIA_CPU_PPC_STATE_H_ #define XENIA_CPU_PPC_STATE_H_ -#include + +/** + * NOTE: this file is included by xethunk and as such should have a *MINIMAL* + * set of dependencies! + */ + +#include -namespace xe { -namespace cpu { -namespace ppc { +// namespace FPRF { +// enum FPRF_e { +// QUIET_NAN = 0x00088000, +// NEG_INFINITY = 0x00090000, +// NEG_NORMALIZED = 0x00010000, +// NEG_DENORMALIZED = 0x00018000, +// NEG_ZERO = 0x00048000, +// POS_ZERO = 0x00040000, +// POS_DENORMALIZED = 0x00028000, +// POS_NORMALIZED = 0x00020000, +// POS_INFINITY = 0x000A0000, +// }; +// } // FPRF -namespace SPR { - enum SPR_e { - XER = 1, - LR = 8, - CTR = 9, +typedef struct XECACHEALIGN { + union { + struct { + float x; + float y; + float z; + float w; + }; + float f4[4]; + struct { + uint64_t low; + uint64_t high; + }; }; -} // SPR - - -namespace FPRF { - enum FPRF_e { - QUIET_NAN = 0x00088000, - NEG_INFINITY = 0x00090000, - NEG_NORMALIZED = 0x00010000, - NEG_DENORMALIZED = 0x00018000, - NEG_ZERO = 0x00048000, - POS_ZERO = 0x00040000, - POS_DENORMALIZED = 0x00028000, - POS_NORMALIZED = 0x00020000, - POS_INFINITY = 0x000A0000, - }; -} // FPRF +} xe_float4_t; typedef struct XECACHEALIGN64 { uint64_t r[32]; // General purpose registers - xefloat4_t v[128]; // VMX128 vector registers + xe_float4_t v[128]; // VMX128 vector registers double f[32]; // Floating-point registers - uint32_t pc; // Current PC (CIA) - uint32_t npc; // Next PC (NIA) + uint32_t cia; // Current PC (CIA) + uint32_t nia; // Next PC (NIA) uint64_t xer; // XER register uint64_t lr; // Link register uint64_t ctr; // Count register @@ -109,23 +118,13 @@ typedef struct XECACHEALIGN64 { } bits; } fpscr; // Floating-point status and control register - uint32_t get_fprf() { - return fpscr.value & 0x000F8000; - } - void set_fprf(const uint32_t v) { - fpscr.value = (fpscr.value & ~0x000F8000) | v; - } -} PpcRegisters; - - -typedef struct { - PpcRegisters registers; -} PpcState; - - -} // namespace ppc -} // namespace cpu -} // namespace xe + // uint32_t get_fprf() { + // return fpscr.value & 0x000F8000; + // } + // void set_fprf(const uint32_t v) { + // fpscr.value = (fpscr.value & ~0x000F8000) | v; + // } +} xe_ppc_state_t; #endif // XENIA_CPU_PPC_STATE_H_ diff --git a/include/xenia/cpu/processor.h b/include/xenia/cpu/processor.h index d75b2e368..fa404b216 100644 --- a/include/xenia/cpu/processor.h +++ b/include/xenia/cpu/processor.h @@ -49,6 +49,8 @@ private: xe_memory_ref memory_; shared_ptr engine_; + auto_ptr dummy_context_; + std::vector modules_; }; diff --git a/include/xenia/cpu/sdb.h b/include/xenia/cpu/sdb.h index 6a76829b2..a82ae1c25 100644 --- a/include/xenia/cpu/sdb.h +++ b/include/xenia/cpu/sdb.h @@ -71,6 +71,8 @@ public: kTargetNone = 4, }; + FunctionBlock(); + uint32_t start_address; uint32_t end_address; @@ -96,7 +98,7 @@ public: kFlagRestGprLr = 1 << 2, }; - FunctionSymbol() : Symbol(Function) {} + FunctionSymbol(); virtual ~FunctionSymbol(); FunctionBlock* GetBlock(uint32_t address); @@ -120,7 +122,7 @@ public: class VariableSymbol : public Symbol { public: - VariableSymbol() : Symbol(Variable) {} + VariableSymbol(); virtual ~VariableSymbol(); uint32_t address; @@ -129,7 +131,7 @@ public: class ExceptionEntrySymbol : public Symbol { public: - ExceptionEntrySymbol() : Symbol(ExceptionEntry) {} + ExceptionEntrySymbol(); virtual ~ExceptionEntrySymbol() {} uint32_t address; diff --git a/include/xenia/types.h b/include/xenia/types.h index b3a7629ff..b6f7b463c 100644 --- a/include/xenia/types.h +++ b/include/xenia/types.h @@ -117,21 +117,4 @@ typedef XECACHEALIGN volatile void xe_aligned_void_t; #define XEIGNORE(expr) do { (void)(expr); } while(0) -typedef struct XECACHEALIGN { - union { - struct { - float x; - float y; - float z; - float w; - }; - float f4[4]; - struct { - uint64_t low; - uint64_t high; - }; - }; -} xefloat4_t; - - #endif // XENIA_TYPES_H_ diff --git a/src/cpu/codegen/module_generator.cc b/src/cpu/codegen/module_generator.cc index 3b4730164..fc4aef42c 100644 --- a/src/cpu/codegen/module_generator.cc +++ b/src/cpu/codegen/module_generator.cc @@ -45,9 +45,16 @@ ModuleGenerator::ModuleGenerator( sdb_ = sdb; context_ = context; gen_module_ = gen_module; + di_builder_ = NULL; } ModuleGenerator::~ModuleGenerator() { + for (std::map::iterator it = + functions_.begin(); it != functions_.end(); ++it) { + delete it->second; + } + + delete di_builder_; xe_memory_release(memory_); } @@ -59,7 +66,7 @@ int ModuleGenerator::Generate() { // fine grained than this, but for now it's something. xechar_t dir[2048]; XEIGNORE(xestrcpy(dir, XECOUNT(dir), module_->path())); - xechar_t *slash = xestrrchr(dir, '/'); + xechar_t* slash = xestrrchr(dir, '/'); if (slash) { *(slash + 1) = 0; } diff --git a/src/cpu/exec_module.cc b/src/cpu/exec_module.cc index 373eeecc2..71dac38e6 100644 --- a/src/cpu/exec_module.cc +++ b/src/cpu/exec_module.cc @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -108,6 +109,11 @@ int ExecModule::Prepare() { new Module(module_->name(), *context_.get())); // TODO(benavnik): addModuleFlag? + // Inject globals. + // This should be done ASAP to ensure that JITed functions can use the + // constant addresses. + XEEXPECTZERO(InjectGlobals()); + // Link shared module into generated module. // This gives us a single module that we can optimize and prevents the need // for foreward declarations. @@ -165,19 +171,41 @@ XECLEANUP: return result_code; } +int ExecModule::InjectGlobals() { + LLVMContext& context = *context_.get(); + const DataLayout* dl = engine_->getDataLayout(); + Type* voidPtrTy = PointerType::getUnqual(Type::getVoidTy(context)); + Type* intPtrTy = dl->getIntPtrType(context); + GlobalVariable* gv; + + // xe_memory_base + // This is the base void* pointer to the memory space. + gv = new GlobalVariable( + *gen_module_, + voidPtrTy, + true, + GlobalValue::ExternalLinkage, + 0, + "xe_memory_base"); + // Align to 64b - this makes SSE faster. + gv->setAlignment(64); + gv->setInitializer(ConstantExpr::getIntToPtr( + ConstantInt::get(intPtrTy, (uintptr_t)xe_memory_addr(memory_, 0)), + voidPtrTy)); + + // xe_ppc_state + // ... + + return 0; +} + int ExecModule::Init() { // Run static initializers. I'm not sure we'll have any, but who knows. engine_->runStaticConstructorsDestructors(gen_module_.get(), false); - // Prepare init options. - xe_module_init_options_t init_options; - xe_zero_struct(&init_options, sizeof(init_options)); - init_options.memory_base = xe_memory_addr(memory_, 0); - // Grab the init function and call it. Function* xe_module_init = gen_module_->getFunction("xe_module_init"); std::vector args; - args.push_back(GenericValue(&init_options)); GenericValue ret = engine_->runFunction(xe_module_init, args); return ret.IntVal.getSExtValue(); diff --git a/src/cpu/processor.cc b/src/cpu/processor.cc index e7064ed5c..9d66c07a4 100644 --- a/src/cpu/processor.cc +++ b/src/cpu/processor.cc @@ -71,8 +71,8 @@ int Processor::Setup() { return 1; } - LLVMContext* dummy_context = new LLVMContext(); - Module* dummy_module = new Module("dummy", *dummy_context); + dummy_context_ = auto_ptr(new LLVMContext()); + Module* dummy_module = new Module("dummy", *dummy_context_.get()); std::string error_message; engine_ = shared_ptr( diff --git a/src/cpu/sdb.cc b/src/cpu/sdb.cc index 161ca99b4..8d0e9bd49 100644 --- a/src/cpu/sdb.cc +++ b/src/cpu/sdb.cc @@ -22,6 +22,19 @@ using namespace xe::cpu::sdb; using namespace xe::kernel; +FunctionBlock::FunctionBlock() : + start_address(0), end_address(0), + outgoing_type(kTargetUnknown), outgoing_address(0), + outgoing_function(0) { +} + +FunctionSymbol::FunctionSymbol() : + Symbol(Function), + start_address(0), end_address(0), name(0), + type(Unknown), flags(0), + kernel_export(0), ee(0) { +} + FunctionSymbol::~FunctionSymbol() { delete name; for (std::map::iterator it = blocks.begin(); @@ -68,10 +81,20 @@ FunctionBlock* FunctionSymbol::SplitBlock(uint32_t address) { return NULL; } +VariableSymbol::VariableSymbol() : + Symbol(Variable), + address(0), name(0) { +} + VariableSymbol::~VariableSymbol() { delete name; } +ExceptionEntrySymbol::ExceptionEntrySymbol() : + Symbol(ExceptionEntry), + address(0), function(0) { +} + SymbolDatabase::SymbolDatabase( xe_memory_ref memory, ExportResolver* export_resolver, UserModule* module) { memory_ = xe_memory_retain(memory); @@ -419,6 +442,7 @@ int SymbolDatabase::AddImports(const xe_xex2_import_library_t* library) { } } + xe_free(import_infos); xe_xex2_release(xex); return 0; } @@ -438,6 +462,7 @@ int SymbolDatabase::AddMethodHints() { // TODO(benvanik): something with prolog_length? } + xe_free(method_infos); return 0; } diff --git a/src/cpu/xethunk/xethunk.bc b/src/cpu/xethunk/xethunk.bc index c456885d1..0beeb02cc 100644 Binary files a/src/cpu/xethunk/xethunk.bc and b/src/cpu/xethunk/xethunk.bc differ diff --git a/src/cpu/xethunk/xethunk.c b/src/cpu/xethunk/xethunk.c index 2ac6d662a..773c2f4d2 100644 --- a/src/cpu/xethunk/xethunk.c +++ b/src/cpu/xethunk/xethunk.c @@ -21,15 +21,16 @@ // NOTE: only headers in this directory should be included. #include "xethunk.h" +#include -// The base pointer that all guest addresses should be relative to. -static void* xe_memory_base; +// Global CPU state. +// Instructions that dereference the state use this. +// TODO(benvanik): noalias/invariant/etc?s +static xe_ppc_state_t* xe_ppc_state; -int xe_module_init(xe_module_init_options_t *options) { - xe_memory_base = options->memory_base; - +int xe_module_init() { // TODO(benvanik): setup call table, etc? return 0; diff --git a/src/cpu/xethunk/xethunk.h b/src/cpu/xethunk/xethunk.h index ad71a7270..1548876d8 100644 --- a/src/cpu/xethunk/xethunk.h +++ b/src/cpu/xethunk/xethunk.h @@ -17,11 +17,4 @@ #define XENIA_CPU_XELIB_H_ -typedef struct { - void* memory_base; - - // TODO(benvanik): execute call thunk -} xe_module_init_options_t; - - #endif // XENIA_CPU_XELIB_H_ diff --git a/src/cpu/xethunk/xethunk.ll b/src/cpu/xethunk/xethunk.ll index aacede493..0e1762784 100644 --- a/src/cpu/xethunk/xethunk.ll +++ b/src/cpu/xethunk/xethunk.ll @@ -2,17 +2,7 @@ target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.8.0" -%struct.xe_module_init_options_t = type { i8* } - -@xe_memory_base = internal global i8* null, align 8 - -define i32 @xe_module_init(%struct.xe_module_init_options_t* %options) nounwind uwtable ssp { - %1 = alloca %struct.xe_module_init_options_t*, align 8 - store %struct.xe_module_init_options_t* %options, %struct.xe_module_init_options_t** %1, align 8 - %2 = load %struct.xe_module_init_options_t** %1, align 8 - %3 = getelementptr inbounds %struct.xe_module_init_options_t* %2, i32 0, i32 0 - %4 = load i8** %3, align 8 - store i8* %4, i8** @xe_memory_base, align 8 +define i32 @xe_module_init() nounwind uwtable ssp { ret i32 0 } diff --git a/xenia-build.py b/xenia-build.py index 98c5a497f..9d56ab645 100755 --- a/xenia-build.py +++ b/xenia-build.py @@ -394,7 +394,7 @@ class XethunkCommand(Command): print '' path = 'src/cpu/xethunk/xethunk' - result = shell_call('clang -emit-llvm -O0 -c %s.c -o %s.bc' % (path, path), + result = shell_call('clang -emit-llvm -O0 -Iinclude/ -c %s.c -o %s.bc' % (path, path), throw_on_error=False) if result != 0: return result