From bba99d4a22cd0434c9cd2f9e4ac1278ff6b2a378 Mon Sep 17 00:00:00 2001 From: Ben Vanik Date: Sun, 27 Jan 2013 12:48:10 -0800 Subject: [PATCH] Refactoring to allow for raw binary loading. --- include/xenia/cpu/codegen/module_generator.h | 6 +- include/xenia/cpu/exec_module.h | 9 +- include/xenia/cpu/processor.h | 3 + include/xenia/cpu/sdb.h | 53 ++- include/xenia/kernel/runtime.h | 2 + src/cpu/codegen/module_generator.cc | 11 +- src/cpu/exec_module.cc | 37 +- src/cpu/processor.cc | 24 +- src/cpu/sdb.cc | 428 ++++++++++--------- src/kernel/runtime.cc | 27 ++ test/codegen/ori.bin | Bin 4 -> 8 bytes test/codegen/ori.dis | 1 + test/codegen/ori.s | 1 + tools/xenia-test/xenia-test.cc | 7 +- 14 files changed, 378 insertions(+), 231 deletions(-) diff --git a/include/xenia/cpu/codegen/module_generator.h b/include/xenia/cpu/codegen/module_generator.h index 62965cd27..2ed8af158 100644 --- a/include/xenia/cpu/codegen/module_generator.h +++ b/include/xenia/cpu/codegen/module_generator.h @@ -35,7 +35,8 @@ class ModuleGenerator { public: ModuleGenerator( xe_memory_ref memory, kernel::ExportResolver* export_resolver, - kernel::UserModule* module, sdb::SymbolDatabase* sdb, + const char* module_name, const char* module_path, + sdb::SymbolDatabase* sdb, llvm::LLVMContext* context, llvm::Module* gen_module); ~ModuleGenerator(); @@ -61,7 +62,8 @@ private: xe_memory_ref memory_; kernel::ExportResolver* export_resolver_; - kernel::UserModule* module_; + char* module_name_; + char* module_path_; sdb::SymbolDatabase* sdb_; llvm::LLVMContext* context_; diff --git a/include/xenia/cpu/exec_module.h b/include/xenia/cpu/exec_module.h index 780ac5423..955279f80 100644 --- a/include/xenia/cpu/exec_module.h +++ b/include/xenia/cpu/exec_module.h @@ -41,22 +41,25 @@ class ExecModule { public: ExecModule( xe_memory_ref memory, shared_ptr export_resolver, - kernel::UserModule* user_module, + const char* module_name, const char* module_path, shared_ptr& engine); ~ExecModule(); - int Prepare(); + int PrepareUserModule(kernel::UserModule* user_module); + int PrepareRawBinary(uint32_t start_address, uint32_t end_address); void Dump(); private: + int Prepare(); int InjectGlobals(); int Init(); int Uninit(); xe_memory_ref memory_; shared_ptr export_resolver_; - kernel::UserModule* module_; + char* module_name_; + char* module_path_; shared_ptr engine_; shared_ptr sdb_; shared_ptr context_; diff --git a/include/xenia/cpu/processor.h b/include/xenia/cpu/processor.h index fa404b216..312bc7229 100644 --- a/include/xenia/cpu/processor.h +++ b/include/xenia/cpu/processor.h @@ -38,6 +38,9 @@ public: int Setup(); + int PrepareModule(const char* module_name, const char* module_path, + uint32_t start_address, uint32_t end_address, + shared_ptr export_resolver); int PrepareModule(kernel::UserModule* user_module, shared_ptr export_resolver); diff --git a/include/xenia/cpu/sdb.h b/include/xenia/cpu/sdb.h index 078f0f84b..b302a806b 100644 --- a/include/xenia/cpu/sdb.h +++ b/include/xenia/cpu/sdb.h @@ -142,11 +142,10 @@ public: class SymbolDatabase { public: - SymbolDatabase(xe_memory_ref memory, kernel::ExportResolver* export_resolver, - kernel::UserModule* module); - ~SymbolDatabase(); + SymbolDatabase(xe_memory_ref memory, kernel::ExportResolver* export_resolver); + virtual ~SymbolDatabase(); - int Analyze(); + virtual int Analyze(); ExceptionEntrySymbol* GetOrInsertExceptionEntry(uint32_t address); FunctionSymbol* GetOrInsertFunction(uint32_t address); @@ -161,24 +160,21 @@ public: void Dump(); void DumpFunctionBlocks(FunctionSymbol* fn); -private: +protected: typedef std::map SymbolMap; typedef std::list FunctionList; - int FindGplr(); - int AddImports(const xe_xex2_import_library_t *library); - int AddMethodHints(); int AnalyzeFunction(FunctionSymbol* fn); int CompleteFunctionGraph(FunctionSymbol* fn); bool FillHoles(); int FlushQueue(); - bool IsValueInTextRange(uint32_t value); bool IsRestGprLr(uint32_t addr); + virtual uint32_t GetEntryPoint() = 0; + virtual bool IsValueInTextRange(uint32_t value) = 0; xe_memory_ref memory_; kernel::ExportResolver* export_resolver_; - kernel::UserModule* module_; size_t function_count_; size_t variable_count_; SymbolMap symbols_; @@ -186,6 +182,43 @@ private: }; +class RawSymbolDatabase : public SymbolDatabase { +public: + RawSymbolDatabase(xe_memory_ref memory, + kernel::ExportResolver* export_resolver, + uint32_t start_address, uint32_t end_address); + virtual ~RawSymbolDatabase(); + +private: + virtual uint32_t GetEntryPoint(); + virtual bool IsValueInTextRange(uint32_t value); + + uint32_t start_address_; + uint32_t end_address_; +}; + + +class XexSymbolDatabase : public SymbolDatabase { +public: + XexSymbolDatabase(xe_memory_ref memory, + kernel::ExportResolver* export_resolver, + kernel::UserModule* module); + virtual ~XexSymbolDatabase(); + + virtual int Analyze(); + +private: + int FindGplr(); + int AddImports(const xe_xex2_import_library_t *library); + int AddMethodHints(); + + virtual uint32_t GetEntryPoint(); + virtual bool IsValueInTextRange(uint32_t value); + + kernel::UserModule* module_; +}; + + } // namespace sdb } // namespace cpu } // namespace xe diff --git a/include/xenia/kernel/runtime.h b/include/xenia/kernel/runtime.h index bebdd2c27..8db0035e9 100644 --- a/include/xenia/kernel/runtime.h +++ b/include/xenia/kernel/runtime.h @@ -44,6 +44,8 @@ public: shared_ptr export_resolver(); const xechar_t* command_line(); + int LoadBinaryModule(const xechar_t* path, uint32_t start_address); + int LoadModule(const xechar_t* path); void LaunchModule(UserModule* user_module); UserModule* GetModule(const xechar_t* path); diff --git a/src/cpu/codegen/module_generator.cc b/src/cpu/codegen/module_generator.cc index 6d7d30d80..bce0fdaf4 100644 --- a/src/cpu/codegen/module_generator.cc +++ b/src/cpu/codegen/module_generator.cc @@ -39,11 +39,12 @@ using namespace xe::kernel; ModuleGenerator::ModuleGenerator( xe_memory_ref memory, ExportResolver* export_resolver, - UserModule* module, SymbolDatabase* sdb, + const char* module_name, const char* module_path, SymbolDatabase* sdb, LLVMContext* context, Module* gen_module) { memory_ = xe_memory_retain(memory); export_resolver_ = export_resolver; - module_ = module; + module_name_ = xestrdupa(module_name); + module_path_ = xestrdupa(module_path); sdb_ = sdb; context_ = context; gen_module_ = gen_module; @@ -57,6 +58,8 @@ ModuleGenerator::~ModuleGenerator() { } delete di_builder_; + xe_free(module_path_); + xe_free(module_name_); xe_memory_release(memory_); } @@ -67,7 +70,7 @@ int ModuleGenerator::Generate() { // This is used when creating any debug info. We may want to go more // fine grained than this, but for now it's something. xechar_t dir[2048]; - XEIGNORE(xestrcpy(dir, XECOUNT(dir), module_->path())); + XEIGNORE(xestrcpy(dir, XECOUNT(dir), module_path_)); xechar_t* slash = xestrrchr(dir, '/'); if (slash) { *(slash + 1) = 0; @@ -75,7 +78,7 @@ int ModuleGenerator::Generate() { di_builder_ = new DIBuilder(*gen_module_); di_builder_->createCompileUnit( 0, - StringRef(module_->name()), + StringRef(module_name_), StringRef(dir), StringRef("xenia"), true, diff --git a/src/cpu/exec_module.cc b/src/cpu/exec_module.cc index cdc936352..74bacc35b 100644 --- a/src/cpu/exec_module.cc +++ b/src/cpu/exec_module.cc @@ -46,13 +46,13 @@ using namespace xe::kernel; ExecModule::ExecModule( xe_memory_ref memory, shared_ptr export_resolver, - UserModule* user_module, shared_ptr& engine) { + const char* module_name, const char* module_path, + shared_ptr& engine) { memory_ = xe_memory_retain(memory); export_resolver_ = export_resolver; - module_ = user_module; + module_name_ = xestrdupa(module_name); + module_path_ = xestrdupa(module_path); engine_ = engine; - sdb_ = shared_ptr( - new sdb::SymbolDatabase(memory_, export_resolver_.get(), module_)); context_ = shared_ptr(new LLVMContext()); } @@ -63,9 +63,26 @@ ExecModule::~ExecModule() { engine_->removeModule(gen_module_.get()); } + xe_free(module_path_); + xe_free(module_name_); xe_memory_release(memory_); } +int ExecModule::PrepareUserModule(kernel::UserModule* user_module) { + sdb_ = shared_ptr( + new sdb::XexSymbolDatabase(memory_, export_resolver_.get(), user_module)); + + return Prepare(); +} + +int ExecModule::PrepareRawBinary(uint32_t start_address, uint32_t end_address) { + sdb_ = shared_ptr( + new sdb::RawSymbolDatabase(memory_, export_resolver_.get(), + start_address, end_address)); + + return Prepare(); +} + int ExecModule::Prepare() { int result_code = 1; std::string error_message; @@ -112,13 +129,13 @@ int ExecModule::Prepare() { // Dump the symbol database. if (FLAGS_dump_module_map) { xesnprintf(file_name, XECOUNT(file_name), - "%s%s.map", FLAGS_dump_path.c_str(), module_->name()); + "%s%s.map", FLAGS_dump_path.c_str(), module_name_); sdb_->Write(file_name); } // Initialize the module. gen_module_ = shared_ptr( - new Module(module_->name(), *context_.get())); + new Module(module_name_, *context_.get())); // TODO(benavnik): addModuleFlag? // Inject globals. @@ -134,8 +151,8 @@ int ExecModule::Prepare() { // Build the module from the source code. codegen_ = auto_ptr(new ModuleGenerator( - memory_, export_resolver_.get(), module_, sdb_.get(), - context_.get(), gen_module_.get())); + memory_, export_resolver_.get(), module_name_, module_path_, + sdb_.get(), context_.get(), gen_module_.get())); XEEXPECTZERO(codegen_->Generate()); // Write to cache. @@ -144,7 +161,7 @@ int ExecModule::Prepare() { // Dump pre-optimized module to disk. if (FLAGS_dump_module_bitcode) { xesnprintf(file_name, XECOUNT(file_name), - "%s%s-preopt.bc", FLAGS_dump_path.c_str(), module_->name()); + "%s%s-preopt.bc", FLAGS_dump_path.c_str(), module_name_); outs = auto_ptr(new raw_fd_ostream( file_name, error_message, raw_fd_ostream::F_Binary)); XEEXPECTTRUE(error_message.empty()); @@ -176,7 +193,7 @@ int ExecModule::Prepare() { // Dump post-optimized module to disk. if (FLAGS_optimize_ir_modules && FLAGS_dump_module_bitcode) { xesnprintf(file_name, XECOUNT(file_name), - "%s%s.bc", FLAGS_dump_path.c_str(), module_->name()); + "%s%s.bc", FLAGS_dump_path.c_str(), module_name_); outs = auto_ptr(new raw_fd_ostream( file_name, error_message, raw_fd_ostream::F_Binary)); XEEXPECTTRUE(error_message.empty()); diff --git a/src/cpu/processor.cc b/src/cpu/processor.cc index c6144bda1..e7a44c554 100644 --- a/src/cpu/processor.cc +++ b/src/cpu/processor.cc @@ -85,12 +85,32 @@ int Processor::Setup() { return 0; } +int Processor::PrepareModule( + const char* module_name, const char* module_path, + uint32_t start_address, uint32_t end_address, + shared_ptr export_resolver) { + ExecModule* exec_module = new ExecModule( + memory_, export_resolver, module_name, module_path, engine_); + + if (exec_module->PrepareRawBinary(start_address, end_address)) { + delete exec_module; + return 1; + } + + modules_.push_back(exec_module); + + exec_module->Dump(); + + return 0; +} + int Processor::PrepareModule(UserModule* user_module, shared_ptr export_resolver) { ExecModule* exec_module = new ExecModule( - memory_, export_resolver, user_module, engine_); + memory_, export_resolver, user_module->name(), user_module->path(), + engine_); - if (exec_module->Prepare()) { + if (exec_module->PrepareUserModule(user_module)) { delete exec_module; return 1; } diff --git a/src/cpu/sdb.cc b/src/cpu/sdb.cc index 57eef2ab9..3726a546a 100644 --- a/src/cpu/sdb.cc +++ b/src/cpu/sdb.cc @@ -95,11 +95,10 @@ ExceptionEntrySymbol::ExceptionEntrySymbol() : address(0), function(0) { } -SymbolDatabase::SymbolDatabase( - xe_memory_ref memory, ExportResolver* export_resolver, UserModule* module) { +SymbolDatabase::SymbolDatabase(xe_memory_ref memory, + ExportResolver* export_resolver) { memory_ = xe_memory_retain(memory); export_resolver_ = export_resolver; - module_ = module; } SymbolDatabase::~SymbolDatabase() { @@ -115,27 +114,8 @@ int SymbolDatabase::Analyze() { // This uses a queue to do a breadth-first search of all accessible // functions. Callbacks and such likely won't be hit. - const xe_xex2_header_t *header = module_->xex_header(); - - // Find __savegprlr_* and __restgprlr_*. - FindGplr(); - - // Add each import thunk. - for (size_t n = 0; n < header->import_library_count; n++) { - AddImports(&header->import_libraries[n]); - } - - // Add each export root. - // TODO(benvanik): exports. - // - insert fn or variable - // - queue fn - - // Add method hints, if available. - // Not all XEXs have these. - AddMethodHints(); - // Queue entry point of the application. - FunctionSymbol* fn = GetOrInsertFunction(header->exe_entry_point); + FunctionSymbol* fn = GetOrInsertFunction(GetEntryPoint()); fn->name = xestrdupa("start"); // Keep pumping the queue until there's nothing left to do. @@ -316,173 +296,6 @@ void SymbolDatabase::DumpFunctionBlocks(FunctionSymbol* fn) { } } -int SymbolDatabase::FindGplr() { - // Special stack save/restore functions. - // __savegprlr_14 to __savegprlr_31 - // __restgprlr_14 to __restgprlr_31 - // http://research.microsoft.com/en-us/um/redmond/projects/invisible/src/crt/md/ppc/xxx.s.htm - // It'd be nice to stash these away and mark them as such to allow for - // special codegen. - static const uint32_t code_values[] = { - 0x68FFC1F9, // __savegprlr_14 - 0x70FFE1F9, // __savegprlr_15 - 0x78FF01FA, // __savegprlr_16 - 0x80FF21FA, // __savegprlr_17 - 0x88FF41FA, // __savegprlr_18 - 0x90FF61FA, // __savegprlr_19 - 0x98FF81FA, // __savegprlr_20 - 0xA0FFA1FA, // __savegprlr_21 - 0xA8FFC1FA, // __savegprlr_22 - 0xB0FFE1FA, // __savegprlr_23 - 0xB8FF01FB, // __savegprlr_24 - 0xC0FF21FB, // __savegprlr_25 - 0xC8FF41FB, // __savegprlr_26 - 0xD0FF61FB, // __savegprlr_27 - 0xD8FF81FB, // __savegprlr_28 - 0xE0FFA1FB, // __savegprlr_29 - 0xE8FFC1FB, // __savegprlr_30 - 0xF0FFE1FB, // __savegprlr_31 - 0xF8FF8191, - 0x2000804E, - 0x68FFC1E9, // __restgprlr_14 - 0x70FFE1E9, // __restgprlr_15 - 0x78FF01EA, // __restgprlr_16 - 0x80FF21EA, // __restgprlr_17 - 0x88FF41EA, // __restgprlr_18 - 0x90FF61EA, // __restgprlr_19 - 0x98FF81EA, // __restgprlr_20 - 0xA0FFA1EA, // __restgprlr_21 - 0xA8FFC1EA, // __restgprlr_22 - 0xB0FFE1EA, // __restgprlr_23 - 0xB8FF01EB, // __restgprlr_24 - 0xC0FF21EB, // __restgprlr_25 - 0xC8FF41EB, // __restgprlr_26 - 0xD0FF61EB, // __restgprlr_27 - 0xD8FF81EB, // __restgprlr_28 - 0xE0FFA1EB, // __restgprlr_29 - 0xE8FFC1EB, // __restgprlr_30 - 0xF0FFE1EB, // __restgprlr_31 - 0xF8FF8181, - 0xA603887D, - 0x2000804E, - }; - - uint32_t gplr_start = 0; - const xe_xex2_header_t* header = module_->xex_header(); - for (size_t n = 0, i = 0; n < header->section_count; n++) { - const xe_xex2_section_t* section = &header->sections[n]; - const size_t start_address = - header->exe_address + (i * xe_xex2_section_length); - const size_t end_address = - start_address + (section->info.page_count * xe_xex2_section_length); - if (section->info.type == XEX_SECTION_CODE) { - gplr_start = xe_memory_search_aligned( - memory_, start_address, end_address, - code_values, XECOUNT(code_values)); - if (gplr_start) { - break; - } - } - i += section->info.page_count; - } - if (!gplr_start) { - return 0; - } - - // Add function stubs. - char name[32]; - uint32_t address = gplr_start; - for (int n = 14; n <= 31; n++) { - xesnprintf(name, XECOUNT(name), "__savegprlr_%d", n); - FunctionSymbol* fn = GetOrInsertFunction(address); - fn->end_address = fn->start_address + (31 - n) * 4 + 2 * 4; - fn->name = xestrdupa(name); - fn->type = FunctionSymbol::User; - fn->flags |= FunctionSymbol::kFlagSaveGprLr; - address += 4; - } - address = gplr_start + 20 * 4; - for (int n = 14; n <= 31; n++) { - xesnprintf(name, XECOUNT(name), "__restgprlr_%d", n); - FunctionSymbol* fn = GetOrInsertFunction(address); - fn->end_address = fn->start_address + (31 - n) * 4 + 3 * 4; - fn->name = xestrdupa(name); - fn->type = FunctionSymbol::User; - fn->flags |= FunctionSymbol::kFlagRestGprLr; - address += 4; - } - - return 0; -} - -int SymbolDatabase::AddImports(const xe_xex2_import_library_t* library) { - xe_xex2_ref xex = module_->xex(); - xe_xex2_import_info_t* import_infos; - size_t import_info_count; - if (xe_xex2_get_import_infos(xex, library, &import_infos, - &import_info_count)) { - xe_xex2_release(xex); - return 1; - } - - char name[128]; - for (size_t n = 0; n < import_info_count; n++) { - const xe_xex2_import_info_t* info = &import_infos[n]; - - KernelExport* kernel_export = export_resolver_->GetExportByOrdinal( - library->name, info->ordinal); - - VariableSymbol* var = GetOrInsertVariable(info->value_address); - if (kernel_export) { - if (info->thunk_address) { - xesnprintfa(name, XECOUNT(name), "__imp__%s", kernel_export->name); - } else { - xesnprintfa(name, XECOUNT(name), "%s", kernel_export->name); - } - } else { - xesnprintfa(name, XECOUNT(name), "__imp__%s_%.3X", library->name, - info->ordinal); - } - var->name = xestrdupa(name); - if (info->thunk_address) { - FunctionSymbol* fn = GetOrInsertFunction(info->thunk_address); - fn->end_address = fn->start_address + 16 - 4; - fn->type = FunctionSymbol::Kernel; - fn->kernel_export = kernel_export; - if (kernel_export) { - xesnprintfa(name, XECOUNT(name), "%s", kernel_export->name); - } else { - xesnprintfa(name, XECOUNT(name), "__kernel_%s_%.3X", library->name, - info->ordinal); - } - fn->name = xestrdupa(name); - } - } - - xe_free(import_infos); - xe_xex2_release(xex); - return 0; -} - -int SymbolDatabase::AddMethodHints() { - PEMethodInfo* method_infos; - size_t method_info_count; - if (module_->GetMethodHints(&method_infos, &method_info_count)) { - return 1; - } - - for (size_t n = 0; n < method_info_count; n++) { - PEMethodInfo* method_info = &method_infos[n]; - FunctionSymbol* fn = GetOrInsertFunction(method_info->address); - fn->end_address = method_info->address + method_info->total_length - 4; - fn->type = FunctionSymbol::User; - // TODO(benvanik): something with prolog_length? - } - - xe_free(method_infos); - return 0; -} - int SymbolDatabase::AnalyzeFunction(FunctionSymbol* fn) { // Ignore functions already analyzed. if (fn->blocks.size()) { @@ -849,7 +662,235 @@ int SymbolDatabase::FlushQueue() { return 0; } -bool SymbolDatabase::IsValueInTextRange(uint32_t value) { +bool SymbolDatabase::IsRestGprLr(uint32_t addr) { + FunctionSymbol* fn = GetFunction(addr); + return fn && (fn->flags & FunctionSymbol::kFlagRestGprLr); +} + +RawSymbolDatabase::RawSymbolDatabase( + xe_memory_ref memory, ExportResolver* export_resolver, + uint32_t start_address, uint32_t end_address) : + SymbolDatabase(memory, export_resolver) { + start_address_ = start_address; + end_address_ = end_address; +} + +RawSymbolDatabase::~RawSymbolDatabase() { +} + +uint32_t RawSymbolDatabase::GetEntryPoint() { + return start_address_; +} + +bool RawSymbolDatabase::IsValueInTextRange(uint32_t value) { + return value >= start_address_ && value < end_address_; +} + +XexSymbolDatabase::XexSymbolDatabase( + xe_memory_ref memory, ExportResolver* export_resolver, UserModule* module) : + SymbolDatabase(memory, export_resolver) { + module_ = module; +} + +XexSymbolDatabase::~XexSymbolDatabase() { +} + +int XexSymbolDatabase::Analyze() { + const xe_xex2_header_t *header = module_->xex_header(); + + // Find __savegprlr_* and __restgprlr_*. + FindGplr(); + + // Add each import thunk. + for (size_t n = 0; n < header->import_library_count; n++) { + AddImports(&header->import_libraries[n]); + } + + // Add each export root. + // TODO(benvanik): exports. + // - insert fn or variable + // - queue fn + + // Add method hints, if available. + // Not all XEXs have these. + AddMethodHints(); + + return SymbolDatabase::Analyze(); +} + +int XexSymbolDatabase::FindGplr() { + // Special stack save/restore functions. + // __savegprlr_14 to __savegprlr_31 + // __restgprlr_14 to __restgprlr_31 + // http://research.microsoft.com/en-us/um/redmond/projects/invisible/src/crt/md/ppc/xxx.s.htm + // It'd be nice to stash these away and mark them as such to allow for + // special codegen. + static const uint32_t code_values[] = { + 0x68FFC1F9, // __savegprlr_14 + 0x70FFE1F9, // __savegprlr_15 + 0x78FF01FA, // __savegprlr_16 + 0x80FF21FA, // __savegprlr_17 + 0x88FF41FA, // __savegprlr_18 + 0x90FF61FA, // __savegprlr_19 + 0x98FF81FA, // __savegprlr_20 + 0xA0FFA1FA, // __savegprlr_21 + 0xA8FFC1FA, // __savegprlr_22 + 0xB0FFE1FA, // __savegprlr_23 + 0xB8FF01FB, // __savegprlr_24 + 0xC0FF21FB, // __savegprlr_25 + 0xC8FF41FB, // __savegprlr_26 + 0xD0FF61FB, // __savegprlr_27 + 0xD8FF81FB, // __savegprlr_28 + 0xE0FFA1FB, // __savegprlr_29 + 0xE8FFC1FB, // __savegprlr_30 + 0xF0FFE1FB, // __savegprlr_31 + 0xF8FF8191, + 0x2000804E, + 0x68FFC1E9, // __restgprlr_14 + 0x70FFE1E9, // __restgprlr_15 + 0x78FF01EA, // __restgprlr_16 + 0x80FF21EA, // __restgprlr_17 + 0x88FF41EA, // __restgprlr_18 + 0x90FF61EA, // __restgprlr_19 + 0x98FF81EA, // __restgprlr_20 + 0xA0FFA1EA, // __restgprlr_21 + 0xA8FFC1EA, // __restgprlr_22 + 0xB0FFE1EA, // __restgprlr_23 + 0xB8FF01EB, // __restgprlr_24 + 0xC0FF21EB, // __restgprlr_25 + 0xC8FF41EB, // __restgprlr_26 + 0xD0FF61EB, // __restgprlr_27 + 0xD8FF81EB, // __restgprlr_28 + 0xE0FFA1EB, // __restgprlr_29 + 0xE8FFC1EB, // __restgprlr_30 + 0xF0FFE1EB, // __restgprlr_31 + 0xF8FF8181, + 0xA603887D, + 0x2000804E, + }; + + uint32_t gplr_start = 0; + const xe_xex2_header_t* header = module_->xex_header(); + for (size_t n = 0, i = 0; n < header->section_count; n++) { + const xe_xex2_section_t* section = &header->sections[n]; + const size_t start_address = + header->exe_address + (i * xe_xex2_section_length); + const size_t end_address = + start_address + (section->info.page_count * xe_xex2_section_length); + if (section->info.type == XEX_SECTION_CODE) { + gplr_start = xe_memory_search_aligned( + memory_, start_address, end_address, + code_values, XECOUNT(code_values)); + if (gplr_start) { + break; + } + } + i += section->info.page_count; + } + if (!gplr_start) { + return 0; + } + + // Add function stubs. + char name[32]; + uint32_t address = gplr_start; + for (int n = 14; n <= 31; n++) { + xesnprintf(name, XECOUNT(name), "__savegprlr_%d", n); + FunctionSymbol* fn = GetOrInsertFunction(address); + fn->end_address = fn->start_address + (31 - n) * 4 + 2 * 4; + fn->name = xestrdupa(name); + fn->type = FunctionSymbol::User; + fn->flags |= FunctionSymbol::kFlagSaveGprLr; + address += 4; + } + address = gplr_start + 20 * 4; + for (int n = 14; n <= 31; n++) { + xesnprintf(name, XECOUNT(name), "__restgprlr_%d", n); + FunctionSymbol* fn = GetOrInsertFunction(address); + fn->end_address = fn->start_address + (31 - n) * 4 + 3 * 4; + fn->name = xestrdupa(name); + fn->type = FunctionSymbol::User; + fn->flags |= FunctionSymbol::kFlagRestGprLr; + address += 4; + } + + return 0; +} + +int XexSymbolDatabase::AddImports(const xe_xex2_import_library_t* library) { + xe_xex2_ref xex = module_->xex(); + xe_xex2_import_info_t* import_infos; + size_t import_info_count; + if (xe_xex2_get_import_infos(xex, library, &import_infos, + &import_info_count)) { + xe_xex2_release(xex); + return 1; + } + + char name[128]; + for (size_t n = 0; n < import_info_count; n++) { + const xe_xex2_import_info_t* info = &import_infos[n]; + + KernelExport* kernel_export = export_resolver_->GetExportByOrdinal( + library->name, info->ordinal); + + VariableSymbol* var = GetOrInsertVariable(info->value_address); + if (kernel_export) { + if (info->thunk_address) { + xesnprintfa(name, XECOUNT(name), "__imp__%s", kernel_export->name); + } else { + xesnprintfa(name, XECOUNT(name), "%s", kernel_export->name); + } + } else { + xesnprintfa(name, XECOUNT(name), "__imp__%s_%.3X", library->name, + info->ordinal); + } + var->name = xestrdupa(name); + if (info->thunk_address) { + FunctionSymbol* fn = GetOrInsertFunction(info->thunk_address); + fn->end_address = fn->start_address + 16 - 4; + fn->type = FunctionSymbol::Kernel; + fn->kernel_export = kernel_export; + if (kernel_export) { + xesnprintfa(name, XECOUNT(name), "%s", kernel_export->name); + } else { + xesnprintfa(name, XECOUNT(name), "__kernel_%s_%.3X", library->name, + info->ordinal); + } + fn->name = xestrdupa(name); + } + } + + xe_free(import_infos); + xe_xex2_release(xex); + return 0; +} + +int XexSymbolDatabase::AddMethodHints() { + PEMethodInfo* method_infos; + size_t method_info_count; + if (module_->GetMethodHints(&method_infos, &method_info_count)) { + return 1; + } + + for (size_t n = 0; n < method_info_count; n++) { + PEMethodInfo* method_info = &method_infos[n]; + FunctionSymbol* fn = GetOrInsertFunction(method_info->address); + fn->end_address = method_info->address + method_info->total_length - 4; + fn->type = FunctionSymbol::User; + // TODO(benvanik): something with prolog_length? + } + + xe_free(method_infos); + return 0; +} + +uint32_t XexSymbolDatabase::GetEntryPoint() { + const xe_xex2_header_t* header = module_->xex_header(); + return header->exe_entry_point; +}; + +bool XexSymbolDatabase::IsValueInTextRange(uint32_t value) { const xe_xex2_header_t* header = module_->xex_header(); for (size_t n = 0, i = 0; n < header->section_count; n++) { const xe_xex2_section_t* section = &header->sections[n]; @@ -864,8 +905,3 @@ bool SymbolDatabase::IsValueInTextRange(uint32_t value) { } return false; } - -bool SymbolDatabase::IsRestGprLr(uint32_t addr) { - FunctionSymbol* fn = GetFunction(addr); - return fn && (fn->flags & FunctionSymbol::kFlagRestGprLr); -} diff --git a/src/kernel/runtime.cc b/src/kernel/runtime.cc index d073d4da2..82f3cc1da 100644 --- a/src/kernel/runtime.cc +++ b/src/kernel/runtime.cc @@ -66,6 +66,33 @@ const xechar_t* Runtime::command_line() { return command_line_; } +int Runtime::LoadBinaryModule(const xechar_t* path, uint32_t start_address) { + const xechar_t* name = xestrrchr(path, '/') + 1; + + // TODO(benvanik): map file from filesystem + xe_mmap_ref mmap = xe_mmap_open(pal_, kXEFileModeRead, path, 0, 0); + if (!mmap) { + return NULL; + } + void* addr = xe_mmap_get_addr(mmap); + size_t length = xe_mmap_get_length(mmap); + + int result_code = 1; + + XEEXPECTZERO(xe_copy_memory(xe_memory_addr(memory_, start_address), + xe_memory_get_length(memory_), + addr, length)); + + // Prepare the module. + XEEXPECTZERO(processor_->PrepareModule( + name, path, start_address, start_address + length, export_resolver_)); + + result_code = 0; +XECLEANUP: + xe_mmap_release(mmap); + return result_code; +} + int Runtime::LoadModule(const xechar_t* path) { if (GetModule(path)) { return 0; diff --git a/test/codegen/ori.bin b/test/codegen/ori.bin index fd7833805662ba095dd6b7ab60b98e93f74e0071..dffec1c24eb45145eefb3919f508abdb9ee11a36 100755 GIT binary patch literal 8 PcmYdj{{P>vfk6QP6lw#| literal 4 LcmYdj{{J5U1_}b= diff --git a/test/codegen/ori.dis b/test/codegen/ori.dis index db3cdd1fd..40cb4d543 100644 --- a/test/codegen/ori.dis +++ b/test/codegen/ori.dis @@ -6,3 +6,4 @@ Disassembly of section .text: 0000000082010000 <.text>: 82010000: 60 83 ff ff ori r3,r4,65535 + 82010004: 4e 80 00 20 blr diff --git a/test/codegen/ori.s b/test/codegen/ori.s index c5e6810c4..7375a1e08 100644 --- a/test/codegen/ori.s +++ b/test/codegen/ori.s @@ -2,4 +2,5 @@ ori r3, r4, 0xFFFF +blr # REGISTER_OUT r3 0xBABE diff --git a/tools/xenia-test/xenia-test.cc b/tools/xenia-test/xenia-test.cc index 1f0e6c7cd..7753b14b1 100644 --- a/tools/xenia-test/xenia-test.cc +++ b/tools/xenia-test/xenia-test.cc @@ -102,15 +102,14 @@ int run_test(xe_pal_ref pal, string& src_file_path) { runtime = shared_ptr(new Runtime(pal, processor, XT(""))); - // TODO(benvanik): load test binary file into memory - // bin_file_path - // XEEXPECTZERO(runtime->LoadModule(path)); + // Load the binary module. + XEEXPECTZERO(runtime->LoadBinaryModule(bin_file_path.c_str(), 0x82010000)); // Setup test state from annotations. XEEXPECTZERO(setup_test_state(memory, processor.get(), annotations)); // Execute test. - // TODO(benvanik): execute test + XEEXPECTZERO(processor->Execute(0x82010000)); // Assert test state expectations. XEEXPECTZERO(check_test_results(memory, processor.get(), annotations));