Refactoring to allow for raw binary loading.
This commit is contained in:
parent
26d5df0d38
commit
bba99d4a22
|
@ -35,7 +35,8 @@ class ModuleGenerator {
|
||||||
public:
|
public:
|
||||||
ModuleGenerator(
|
ModuleGenerator(
|
||||||
xe_memory_ref memory, kernel::ExportResolver* export_resolver,
|
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);
|
llvm::LLVMContext* context, llvm::Module* gen_module);
|
||||||
~ModuleGenerator();
|
~ModuleGenerator();
|
||||||
|
|
||||||
|
@ -61,7 +62,8 @@ private:
|
||||||
|
|
||||||
xe_memory_ref memory_;
|
xe_memory_ref memory_;
|
||||||
kernel::ExportResolver* export_resolver_;
|
kernel::ExportResolver* export_resolver_;
|
||||||
kernel::UserModule* module_;
|
char* module_name_;
|
||||||
|
char* module_path_;
|
||||||
sdb::SymbolDatabase* sdb_;
|
sdb::SymbolDatabase* sdb_;
|
||||||
|
|
||||||
llvm::LLVMContext* context_;
|
llvm::LLVMContext* context_;
|
||||||
|
|
|
@ -41,22 +41,25 @@ class ExecModule {
|
||||||
public:
|
public:
|
||||||
ExecModule(
|
ExecModule(
|
||||||
xe_memory_ref memory, shared_ptr<kernel::ExportResolver> export_resolver,
|
xe_memory_ref memory, shared_ptr<kernel::ExportResolver> export_resolver,
|
||||||
kernel::UserModule* user_module,
|
const char* module_name, const char* module_path,
|
||||||
shared_ptr<llvm::ExecutionEngine>& engine);
|
shared_ptr<llvm::ExecutionEngine>& engine);
|
||||||
~ExecModule();
|
~ExecModule();
|
||||||
|
|
||||||
int Prepare();
|
int PrepareUserModule(kernel::UserModule* user_module);
|
||||||
|
int PrepareRawBinary(uint32_t start_address, uint32_t end_address);
|
||||||
|
|
||||||
void Dump();
|
void Dump();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
int Prepare();
|
||||||
int InjectGlobals();
|
int InjectGlobals();
|
||||||
int Init();
|
int Init();
|
||||||
int Uninit();
|
int Uninit();
|
||||||
|
|
||||||
xe_memory_ref memory_;
|
xe_memory_ref memory_;
|
||||||
shared_ptr<kernel::ExportResolver> export_resolver_;
|
shared_ptr<kernel::ExportResolver> export_resolver_;
|
||||||
kernel::UserModule* module_;
|
char* module_name_;
|
||||||
|
char* module_path_;
|
||||||
shared_ptr<llvm::ExecutionEngine> engine_;
|
shared_ptr<llvm::ExecutionEngine> engine_;
|
||||||
shared_ptr<sdb::SymbolDatabase> sdb_;
|
shared_ptr<sdb::SymbolDatabase> sdb_;
|
||||||
shared_ptr<llvm::LLVMContext> context_;
|
shared_ptr<llvm::LLVMContext> context_;
|
||||||
|
|
|
@ -38,6 +38,9 @@ public:
|
||||||
|
|
||||||
int Setup();
|
int Setup();
|
||||||
|
|
||||||
|
int PrepareModule(const char* module_name, const char* module_path,
|
||||||
|
uint32_t start_address, uint32_t end_address,
|
||||||
|
shared_ptr<kernel::ExportResolver> export_resolver);
|
||||||
int PrepareModule(kernel::UserModule* user_module,
|
int PrepareModule(kernel::UserModule* user_module,
|
||||||
shared_ptr<kernel::ExportResolver> export_resolver);
|
shared_ptr<kernel::ExportResolver> export_resolver);
|
||||||
|
|
||||||
|
|
|
@ -142,11 +142,10 @@ public:
|
||||||
|
|
||||||
class SymbolDatabase {
|
class SymbolDatabase {
|
||||||
public:
|
public:
|
||||||
SymbolDatabase(xe_memory_ref memory, kernel::ExportResolver* export_resolver,
|
SymbolDatabase(xe_memory_ref memory, kernel::ExportResolver* export_resolver);
|
||||||
kernel::UserModule* module);
|
virtual ~SymbolDatabase();
|
||||||
~SymbolDatabase();
|
|
||||||
|
|
||||||
int Analyze();
|
virtual int Analyze();
|
||||||
|
|
||||||
ExceptionEntrySymbol* GetOrInsertExceptionEntry(uint32_t address);
|
ExceptionEntrySymbol* GetOrInsertExceptionEntry(uint32_t address);
|
||||||
FunctionSymbol* GetOrInsertFunction(uint32_t address);
|
FunctionSymbol* GetOrInsertFunction(uint32_t address);
|
||||||
|
@ -161,24 +160,21 @@ public:
|
||||||
void Dump();
|
void Dump();
|
||||||
void DumpFunctionBlocks(FunctionSymbol* fn);
|
void DumpFunctionBlocks(FunctionSymbol* fn);
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
typedef std::map<uint32_t, Symbol*> SymbolMap;
|
typedef std::map<uint32_t, Symbol*> SymbolMap;
|
||||||
typedef std::list<FunctionSymbol*> FunctionList;
|
typedef std::list<FunctionSymbol*> FunctionList;
|
||||||
|
|
||||||
int FindGplr();
|
|
||||||
int AddImports(const xe_xex2_import_library_t *library);
|
|
||||||
int AddMethodHints();
|
|
||||||
int AnalyzeFunction(FunctionSymbol* fn);
|
int AnalyzeFunction(FunctionSymbol* fn);
|
||||||
int CompleteFunctionGraph(FunctionSymbol* fn);
|
int CompleteFunctionGraph(FunctionSymbol* fn);
|
||||||
bool FillHoles();
|
bool FillHoles();
|
||||||
int FlushQueue();
|
int FlushQueue();
|
||||||
|
|
||||||
bool IsValueInTextRange(uint32_t value);
|
|
||||||
bool IsRestGprLr(uint32_t addr);
|
bool IsRestGprLr(uint32_t addr);
|
||||||
|
virtual uint32_t GetEntryPoint() = 0;
|
||||||
|
virtual bool IsValueInTextRange(uint32_t value) = 0;
|
||||||
|
|
||||||
xe_memory_ref memory_;
|
xe_memory_ref memory_;
|
||||||
kernel::ExportResolver* export_resolver_;
|
kernel::ExportResolver* export_resolver_;
|
||||||
kernel::UserModule* module_;
|
|
||||||
size_t function_count_;
|
size_t function_count_;
|
||||||
size_t variable_count_;
|
size_t variable_count_;
|
||||||
SymbolMap symbols_;
|
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 sdb
|
||||||
} // namespace cpu
|
} // namespace cpu
|
||||||
} // namespace xe
|
} // namespace xe
|
||||||
|
|
|
@ -44,6 +44,8 @@ public:
|
||||||
shared_ptr<ExportResolver> export_resolver();
|
shared_ptr<ExportResolver> export_resolver();
|
||||||
const xechar_t* command_line();
|
const xechar_t* command_line();
|
||||||
|
|
||||||
|
int LoadBinaryModule(const xechar_t* path, uint32_t start_address);
|
||||||
|
|
||||||
int LoadModule(const xechar_t* path);
|
int LoadModule(const xechar_t* path);
|
||||||
void LaunchModule(UserModule* user_module);
|
void LaunchModule(UserModule* user_module);
|
||||||
UserModule* GetModule(const xechar_t* path);
|
UserModule* GetModule(const xechar_t* path);
|
||||||
|
|
|
@ -39,11 +39,12 @@ using namespace xe::kernel;
|
||||||
|
|
||||||
ModuleGenerator::ModuleGenerator(
|
ModuleGenerator::ModuleGenerator(
|
||||||
xe_memory_ref memory, ExportResolver* export_resolver,
|
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) {
|
LLVMContext* context, Module* gen_module) {
|
||||||
memory_ = xe_memory_retain(memory);
|
memory_ = xe_memory_retain(memory);
|
||||||
export_resolver_ = export_resolver;
|
export_resolver_ = export_resolver;
|
||||||
module_ = module;
|
module_name_ = xestrdupa(module_name);
|
||||||
|
module_path_ = xestrdupa(module_path);
|
||||||
sdb_ = sdb;
|
sdb_ = sdb;
|
||||||
context_ = context;
|
context_ = context;
|
||||||
gen_module_ = gen_module;
|
gen_module_ = gen_module;
|
||||||
|
@ -57,6 +58,8 @@ ModuleGenerator::~ModuleGenerator() {
|
||||||
}
|
}
|
||||||
|
|
||||||
delete di_builder_;
|
delete di_builder_;
|
||||||
|
xe_free(module_path_);
|
||||||
|
xe_free(module_name_);
|
||||||
xe_memory_release(memory_);
|
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
|
// This is used when creating any debug info. We may want to go more
|
||||||
// fine grained than this, but for now it's something.
|
// fine grained than this, but for now it's something.
|
||||||
xechar_t dir[2048];
|
xechar_t dir[2048];
|
||||||
XEIGNORE(xestrcpy(dir, XECOUNT(dir), module_->path()));
|
XEIGNORE(xestrcpy(dir, XECOUNT(dir), module_path_));
|
||||||
xechar_t* slash = xestrrchr(dir, '/');
|
xechar_t* slash = xestrrchr(dir, '/');
|
||||||
if (slash) {
|
if (slash) {
|
||||||
*(slash + 1) = 0;
|
*(slash + 1) = 0;
|
||||||
|
@ -75,7 +78,7 @@ int ModuleGenerator::Generate() {
|
||||||
di_builder_ = new DIBuilder(*gen_module_);
|
di_builder_ = new DIBuilder(*gen_module_);
|
||||||
di_builder_->createCompileUnit(
|
di_builder_->createCompileUnit(
|
||||||
0,
|
0,
|
||||||
StringRef(module_->name()),
|
StringRef(module_name_),
|
||||||
StringRef(dir),
|
StringRef(dir),
|
||||||
StringRef("xenia"),
|
StringRef("xenia"),
|
||||||
true,
|
true,
|
||||||
|
|
|
@ -46,13 +46,13 @@ using namespace xe::kernel;
|
||||||
|
|
||||||
ExecModule::ExecModule(
|
ExecModule::ExecModule(
|
||||||
xe_memory_ref memory, shared_ptr<ExportResolver> export_resolver,
|
xe_memory_ref memory, shared_ptr<ExportResolver> export_resolver,
|
||||||
UserModule* user_module, shared_ptr<llvm::ExecutionEngine>& engine) {
|
const char* module_name, const char* module_path,
|
||||||
|
shared_ptr<llvm::ExecutionEngine>& engine) {
|
||||||
memory_ = xe_memory_retain(memory);
|
memory_ = xe_memory_retain(memory);
|
||||||
export_resolver_ = export_resolver;
|
export_resolver_ = export_resolver;
|
||||||
module_ = user_module;
|
module_name_ = xestrdupa(module_name);
|
||||||
|
module_path_ = xestrdupa(module_path);
|
||||||
engine_ = engine;
|
engine_ = engine;
|
||||||
sdb_ = shared_ptr<sdb::SymbolDatabase>(
|
|
||||||
new sdb::SymbolDatabase(memory_, export_resolver_.get(), module_));
|
|
||||||
|
|
||||||
context_ = shared_ptr<LLVMContext>(new LLVMContext());
|
context_ = shared_ptr<LLVMContext>(new LLVMContext());
|
||||||
}
|
}
|
||||||
|
@ -63,9 +63,26 @@ ExecModule::~ExecModule() {
|
||||||
engine_->removeModule(gen_module_.get());
|
engine_->removeModule(gen_module_.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
xe_free(module_path_);
|
||||||
|
xe_free(module_name_);
|
||||||
xe_memory_release(memory_);
|
xe_memory_release(memory_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ExecModule::PrepareUserModule(kernel::UserModule* user_module) {
|
||||||
|
sdb_ = shared_ptr<sdb::SymbolDatabase>(
|
||||||
|
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<sdb::SymbolDatabase>(
|
||||||
|
new sdb::RawSymbolDatabase(memory_, export_resolver_.get(),
|
||||||
|
start_address, end_address));
|
||||||
|
|
||||||
|
return Prepare();
|
||||||
|
}
|
||||||
|
|
||||||
int ExecModule::Prepare() {
|
int ExecModule::Prepare() {
|
||||||
int result_code = 1;
|
int result_code = 1;
|
||||||
std::string error_message;
|
std::string error_message;
|
||||||
|
@ -112,13 +129,13 @@ int ExecModule::Prepare() {
|
||||||
// Dump the symbol database.
|
// Dump the symbol database.
|
||||||
if (FLAGS_dump_module_map) {
|
if (FLAGS_dump_module_map) {
|
||||||
xesnprintf(file_name, XECOUNT(file_name),
|
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);
|
sdb_->Write(file_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize the module.
|
// Initialize the module.
|
||||||
gen_module_ = shared_ptr<Module>(
|
gen_module_ = shared_ptr<Module>(
|
||||||
new Module(module_->name(), *context_.get()));
|
new Module(module_name_, *context_.get()));
|
||||||
// TODO(benavnik): addModuleFlag?
|
// TODO(benavnik): addModuleFlag?
|
||||||
|
|
||||||
// Inject globals.
|
// Inject globals.
|
||||||
|
@ -134,8 +151,8 @@ int ExecModule::Prepare() {
|
||||||
|
|
||||||
// Build the module from the source code.
|
// Build the module from the source code.
|
||||||
codegen_ = auto_ptr<ModuleGenerator>(new ModuleGenerator(
|
codegen_ = auto_ptr<ModuleGenerator>(new ModuleGenerator(
|
||||||
memory_, export_resolver_.get(), module_, sdb_.get(),
|
memory_, export_resolver_.get(), module_name_, module_path_,
|
||||||
context_.get(), gen_module_.get()));
|
sdb_.get(), context_.get(), gen_module_.get()));
|
||||||
XEEXPECTZERO(codegen_->Generate());
|
XEEXPECTZERO(codegen_->Generate());
|
||||||
|
|
||||||
// Write to cache.
|
// Write to cache.
|
||||||
|
@ -144,7 +161,7 @@ int ExecModule::Prepare() {
|
||||||
// Dump pre-optimized module to disk.
|
// Dump pre-optimized module to disk.
|
||||||
if (FLAGS_dump_module_bitcode) {
|
if (FLAGS_dump_module_bitcode) {
|
||||||
xesnprintf(file_name, XECOUNT(file_name),
|
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<raw_ostream>(new raw_fd_ostream(
|
outs = auto_ptr<raw_ostream>(new raw_fd_ostream(
|
||||||
file_name, error_message, raw_fd_ostream::F_Binary));
|
file_name, error_message, raw_fd_ostream::F_Binary));
|
||||||
XEEXPECTTRUE(error_message.empty());
|
XEEXPECTTRUE(error_message.empty());
|
||||||
|
@ -176,7 +193,7 @@ int ExecModule::Prepare() {
|
||||||
// Dump post-optimized module to disk.
|
// Dump post-optimized module to disk.
|
||||||
if (FLAGS_optimize_ir_modules && FLAGS_dump_module_bitcode) {
|
if (FLAGS_optimize_ir_modules && FLAGS_dump_module_bitcode) {
|
||||||
xesnprintf(file_name, XECOUNT(file_name),
|
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<raw_ostream>(new raw_fd_ostream(
|
outs = auto_ptr<raw_ostream>(new raw_fd_ostream(
|
||||||
file_name, error_message, raw_fd_ostream::F_Binary));
|
file_name, error_message, raw_fd_ostream::F_Binary));
|
||||||
XEEXPECTTRUE(error_message.empty());
|
XEEXPECTTRUE(error_message.empty());
|
||||||
|
|
|
@ -85,12 +85,32 @@ int Processor::Setup() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Processor::PrepareModule(
|
||||||
|
const char* module_name, const char* module_path,
|
||||||
|
uint32_t start_address, uint32_t end_address,
|
||||||
|
shared_ptr<ExportResolver> 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,
|
int Processor::PrepareModule(UserModule* user_module,
|
||||||
shared_ptr<ExportResolver> export_resolver) {
|
shared_ptr<ExportResolver> export_resolver) {
|
||||||
ExecModule* exec_module = new ExecModule(
|
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;
|
delete exec_module;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
428
src/cpu/sdb.cc
428
src/cpu/sdb.cc
|
@ -95,11 +95,10 @@ ExceptionEntrySymbol::ExceptionEntrySymbol() :
|
||||||
address(0), function(0) {
|
address(0), function(0) {
|
||||||
}
|
}
|
||||||
|
|
||||||
SymbolDatabase::SymbolDatabase(
|
SymbolDatabase::SymbolDatabase(xe_memory_ref memory,
|
||||||
xe_memory_ref memory, ExportResolver* export_resolver, UserModule* module) {
|
ExportResolver* export_resolver) {
|
||||||
memory_ = xe_memory_retain(memory);
|
memory_ = xe_memory_retain(memory);
|
||||||
export_resolver_ = export_resolver;
|
export_resolver_ = export_resolver;
|
||||||
module_ = module;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SymbolDatabase::~SymbolDatabase() {
|
SymbolDatabase::~SymbolDatabase() {
|
||||||
|
@ -115,27 +114,8 @@ int SymbolDatabase::Analyze() {
|
||||||
// This uses a queue to do a breadth-first search of all accessible
|
// This uses a queue to do a breadth-first search of all accessible
|
||||||
// functions. Callbacks and such likely won't be hit.
|
// 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.
|
// Queue entry point of the application.
|
||||||
FunctionSymbol* fn = GetOrInsertFunction(header->exe_entry_point);
|
FunctionSymbol* fn = GetOrInsertFunction(GetEntryPoint());
|
||||||
fn->name = xestrdupa("start");
|
fn->name = xestrdupa("start");
|
||||||
|
|
||||||
// Keep pumping the queue until there's nothing left to do.
|
// 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) {
|
int SymbolDatabase::AnalyzeFunction(FunctionSymbol* fn) {
|
||||||
// Ignore functions already analyzed.
|
// Ignore functions already analyzed.
|
||||||
if (fn->blocks.size()) {
|
if (fn->blocks.size()) {
|
||||||
|
@ -849,7 +662,235 @@ int SymbolDatabase::FlushQueue() {
|
||||||
return 0;
|
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();
|
const xe_xex2_header_t* header = module_->xex_header();
|
||||||
for (size_t n = 0, i = 0; n < header->section_count; n++) {
|
for (size_t n = 0, i = 0; n < header->section_count; n++) {
|
||||||
const xe_xex2_section_t* section = &header->sections[n];
|
const xe_xex2_section_t* section = &header->sections[n];
|
||||||
|
@ -864,8 +905,3 @@ bool SymbolDatabase::IsValueInTextRange(uint32_t value) {
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SymbolDatabase::IsRestGprLr(uint32_t addr) {
|
|
||||||
FunctionSymbol* fn = GetFunction(addr);
|
|
||||||
return fn && (fn->flags & FunctionSymbol::kFlagRestGprLr);
|
|
||||||
}
|
|
||||||
|
|
|
@ -66,6 +66,33 @@ const xechar_t* Runtime::command_line() {
|
||||||
return 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) {
|
int Runtime::LoadModule(const xechar_t* path) {
|
||||||
if (GetModule(path)) {
|
if (GetModule(path)) {
|
||||||
return 0;
|
return 0;
|
||||||
|
|
Binary file not shown.
|
@ -6,3 +6,4 @@ Disassembly of section .text:
|
||||||
|
|
||||||
0000000082010000 <.text>:
|
0000000082010000 <.text>:
|
||||||
82010000: 60 83 ff ff ori r3,r4,65535
|
82010000: 60 83 ff ff ori r3,r4,65535
|
||||||
|
82010004: 4e 80 00 20 blr
|
||||||
|
|
|
@ -2,4 +2,5 @@
|
||||||
|
|
||||||
ori r3, r4, 0xFFFF
|
ori r3, r4, 0xFFFF
|
||||||
|
|
||||||
|
blr
|
||||||
# REGISTER_OUT r3 0xBABE
|
# REGISTER_OUT r3 0xBABE
|
||||||
|
|
|
@ -102,15 +102,14 @@ int run_test(xe_pal_ref pal, string& src_file_path) {
|
||||||
|
|
||||||
runtime = shared_ptr<Runtime>(new Runtime(pal, processor, XT("")));
|
runtime = shared_ptr<Runtime>(new Runtime(pal, processor, XT("")));
|
||||||
|
|
||||||
// TODO(benvanik): load test binary file into memory
|
// Load the binary module.
|
||||||
// bin_file_path
|
XEEXPECTZERO(runtime->LoadBinaryModule(bin_file_path.c_str(), 0x82010000));
|
||||||
// XEEXPECTZERO(runtime->LoadModule(path));
|
|
||||||
|
|
||||||
// Setup test state from annotations.
|
// Setup test state from annotations.
|
||||||
XEEXPECTZERO(setup_test_state(memory, processor.get(), annotations));
|
XEEXPECTZERO(setup_test_state(memory, processor.get(), annotations));
|
||||||
|
|
||||||
// Execute test.
|
// Execute test.
|
||||||
// TODO(benvanik): execute test
|
XEEXPECTZERO(processor->Execute(0x82010000));
|
||||||
|
|
||||||
// Assert test state expectations.
|
// Assert test state expectations.
|
||||||
XEEXPECTZERO(check_test_results(memory, processor.get(), annotations));
|
XEEXPECTZERO(check_test_results(memory, processor.get(), annotations));
|
||||||
|
|
Loading…
Reference in New Issue