diff --git a/src/alloy/backend/ivm/ivm_function.cc b/src/alloy/backend/ivm/ivm_function.cc index c4c0d97f9..8cd6835d6 100644 --- a/src/alloy/backend/ivm/ivm_function.cc +++ b/src/alloy/backend/ivm/ivm_function.cc @@ -23,7 +23,7 @@ using namespace alloy::runtime; IVMFunction::IVMFunction(FunctionInfo* symbol_info) : register_count_(0), intcode_count_(0), intcodes_(0), source_map_count_(0), source_map_(0), - GuestFunction(symbol_info) { + Function(symbol_info) { } IVMFunction::~IVMFunction() { diff --git a/src/alloy/backend/ivm/ivm_function.h b/src/alloy/backend/ivm/ivm_function.h index 7fee49db0..c7da76f89 100644 --- a/src/alloy/backend/ivm/ivm_function.h +++ b/src/alloy/backend/ivm/ivm_function.h @@ -21,7 +21,7 @@ namespace backend { namespace ivm { -class IVMFunction : public runtime::GuestFunction { +class IVMFunction : public runtime::Function { public: IVMFunction(runtime::FunctionInfo* symbol_info); virtual ~IVMFunction(); diff --git a/src/alloy/backend/ivm/ivm_intcode.cc b/src/alloy/backend/ivm/ivm_intcode.cc index f7e0cdbde..20544028c 100644 --- a/src/alloy/backend/ivm/ivm_intcode.cc +++ b/src/alloy/backend/ivm/ivm_intcode.cc @@ -712,6 +712,13 @@ int Translate_CALL_INDIRECT_TRUE(TranslationContext& ctx, Instr* i) { return DispatchToC(ctx, i, fns[i->src1.value->type]); } +uint32_t IntCode_CALL_EXTERN(IntCodeState& ics, const IntCode* i) { + return IntCode_CALL_XX(ics, i, i->src1_reg); +} +int Translate_CALL_EXTERN(TranslationContext& ctx, Instr* i) { + return DispatchToC(ctx, i, IntCode_CALL_EXTERN); +} + uint32_t IntCode_RETURN(IntCodeState& ics, const IntCode* i) { return IA_RETURN; } @@ -4009,6 +4016,7 @@ static const TranslateFn dispatch_table[] = { Translate_CALL_TRUE, Translate_CALL_INDIRECT, Translate_CALL_INDIRECT_TRUE, + Translate_CALL_EXTERN, Translate_RETURN, Translate_RETURN_TRUE, diff --git a/src/alloy/backend/x64/lowering/lowering_sequences.cc b/src/alloy/backend/x64/lowering/lowering_sequences.cc index ec5be7d6f..f161424a8 100644 --- a/src/alloy/backend/x64/lowering/lowering_sequences.cc +++ b/src/alloy/backend/x64/lowering/lowering_sequences.cc @@ -96,12 +96,6 @@ void Dummy() { // } -void UnimplementedExtern(void* raw_context, ExternFunction* extern_fn) { - // TODO(benvanik): generate this thunk at runtime? or a shim? - auto thread_state = *((ThreadState**)raw_context); - extern_fn->Call(thread_state); -} - uint64_t DynamicRegisterLoad(void* raw_context, uint32_t address) { auto thread_state = *((ThreadState**)raw_context); auto cbs = thread_state->runtime()->access_callbacks(); @@ -149,44 +143,30 @@ void* ResolveFunctionSymbol(void* raw_context, FunctionInfo* symbol_info) { Function* fn = NULL; thread_state->runtime()->ResolveFunction(symbol_info->address(), &fn); XEASSERTNOTNULL(fn); - XEASSERT(fn->type() == Function::USER_FUNCTION); auto x64_fn = (X64Function*)fn; return x64_fn->machine_code(); } -void* ResolveFunctionAddress(void* raw_context, uint64_t target_address) { +void* ResolveFunctionAddress(void* raw_context, uint32_t target_address) { // TODO(benvanik): generate this thunk at runtime? or a shim? auto thread_state = *((ThreadState**)raw_context); Function* fn = NULL; thread_state->runtime()->ResolveFunction(target_address, &fn); XEASSERTNOTNULL(fn); - XEASSERT(fn->type() == Function::USER_FUNCTION); auto x64_fn = (X64Function*)fn; return x64_fn->machine_code(); } void IssueCall(X64Emitter& e, FunctionInfo* symbol_info, uint32_t flags) { - // If we are an extern function, we can directly insert a call. auto fn = symbol_info->function(); - if (fn && fn->type() == Function::EXTERN_FUNCTION) { - auto extern_fn = (ExternFunction*)fn; - if (extern_fn->handler()) { - e.mov(e.rdx, (uint64_t)extern_fn->arg0()); - e.mov(e.r8, (uint64_t)extern_fn->arg1()); - e.mov(e.rax, (uint64_t)extern_fn->handler()); - } else { - // Unimplemented - call dummy. - e.mov(e.rdx, (uint64_t)extern_fn); - e.mov(e.rax, (uint64_t)UnimplementedExtern); - } - } else { - // Generic call, resolve address. - // TODO(benvanik): caching/etc. For now this makes debugging easier. - e.mov(e.rdx, (uint64_t)symbol_info); - e.mov(e.rax, (uint64_t)ResolveFunctionSymbol); - e.call(e.rax); - e.mov(e.rcx, e.qword[e.rsp + 0]); - e.mov(e.rdx, e.qword[e.rcx + 8]); // membase - } + // Resolve address to the function to call and store in rax. + // TODO(benvanik): caching/etc. For now this makes debugging easier. + e.mov(e.rdx, (uint64_t)symbol_info); + e.mov(e.rax, (uint64_t)ResolveFunctionSymbol); + e.call(e.rax); + e.mov(e.rcx, e.qword[e.rsp + 0]); + e.mov(e.rdx, e.qword[e.rcx + 8]); // membase + + // Actually jump/call to rax. if (flags & CALL_TAIL) { // TODO(benvanik): adjust stack? e.add(e.rsp, 72); @@ -198,6 +178,8 @@ void IssueCall(X64Emitter& e, FunctionInfo* symbol_info, uint32_t flags) { } } void IssueCallIndirect(X64Emitter& e, Value* target, uint32_t flags) { + // Resolve address to the function to call and store in rax. + // TODO(benvanik): caching/etc. For now this makes debugging easier. Reg64 r; e.BeginOp(target, r, 0); if (r != e.rdx) { @@ -208,6 +190,8 @@ void IssueCallIndirect(X64Emitter& e, Value* target, uint32_t flags) { e.call(e.rax); e.mov(e.rcx, e.qword[e.rsp + 0]); e.mov(e.rdx, e.qword[e.rcx + 8]); // membase + + // Actually jump/call to rax. if (flags & CALL_TAIL) { // TODO(benvanik): adjust stack? e.add(e.rsp, 72); @@ -349,6 +333,17 @@ table->AddSequence(OPCODE_CALL_INDIRECT_TRUE, [](X64Emitter& e, Instr*& i) { return true; }); +table->AddSequence(OPCODE_CALL_EXTERN, [](X64Emitter& e, Instr*& i) { + auto symbol_info = i->src1.symbol_info; + XEASSERT(symbol_info->behavior() == FunctionInfo::BEHAVIOR_EXTERN); + XEASSERTNOTNULL(symbol_info->extern_handler()); + e.mov(e.rdx, (uint64_t)symbol_info->extern_arg0()); + e.mov(e.r8, (uint64_t)symbol_info->extern_arg1()); + CallNative(e, symbol_info->extern_handler()); + i = e.Advance(i); + return true; +}); + table->AddSequence(OPCODE_RETURN, [](X64Emitter& e, Instr*& i) { // If this is the last instruction in the last block, just let us // fall through. diff --git a/src/alloy/backend/x64/x64_function.cc b/src/alloy/backend/x64/x64_function.cc index c668c14f1..b8172247e 100644 --- a/src/alloy/backend/x64/x64_function.cc +++ b/src/alloy/backend/x64/x64_function.cc @@ -21,7 +21,7 @@ using namespace alloy::runtime; X64Function::X64Function(FunctionInfo* symbol_info) : machine_code_(NULL), code_size_(0), - GuestFunction(symbol_info) { + Function(symbol_info) { } X64Function::~X64Function() { diff --git a/src/alloy/backend/x64/x64_function.h b/src/alloy/backend/x64/x64_function.h index e879a72c7..5166fd879 100644 --- a/src/alloy/backend/x64/x64_function.h +++ b/src/alloy/backend/x64/x64_function.h @@ -20,7 +20,7 @@ namespace backend { namespace x64 { -class X64Function : public runtime::GuestFunction { +class X64Function : public runtime::Function { public: X64Function(runtime::FunctionInfo* symbol_info); virtual ~X64Function(); diff --git a/src/alloy/frontend/ppc/ppc_emit_control.cc b/src/alloy/frontend/ppc/ppc_emit_control.cc index 83a50a2c4..9815c4649 100644 --- a/src/alloy/frontend/ppc/ppc_emit_control.cc +++ b/src/alloy/frontend/ppc/ppc_emit_control.cc @@ -380,8 +380,8 @@ XEEMITTER(mcrf, 0x4C000000, XL )(PPCHIRBuilder& f, InstrData& i) { // System linkage (A-24) XEEMITTER(sc, 0x44000002, SC )(PPCHIRBuilder& f, InstrData& i) { - XEINSTRNOTIMPLEMENTED(); - return 1; + f.CallExtern(f.symbol_info()); + return 0; } diff --git a/src/alloy/hir/hir_builder.cc b/src/alloy/hir/hir_builder.cc index 99d5649d1..69cabc286 100644 --- a/src/alloy/hir/hir_builder.cc +++ b/src/alloy/hir/hir_builder.cc @@ -557,6 +557,13 @@ void HIRBuilder::CallIndirectTrue( EndBlock(); } +void HIRBuilder::CallExtern(FunctionInfo* symbol_info) { + Instr* i = AppendInstr(OPCODE_CALL_EXTERN_info, 0); + i->src1.symbol_info = symbol_info; + i->src2.value = i->src3.value = NULL; + EndBlock(); +} + void HIRBuilder::Return() { Instr* i = AppendInstr(OPCODE_RETURN_info, 0); i->src1.value = i->src2.value = i->src3.value = NULL; diff --git a/src/alloy/hir/hir_builder.h b/src/alloy/hir/hir_builder.h index 05fa632de..e5a0aef07 100644 --- a/src/alloy/hir/hir_builder.h +++ b/src/alloy/hir/hir_builder.h @@ -74,6 +74,7 @@ public: uint32_t call_flags = 0); void CallIndirect(Value* value, uint32_t call_flags = 0); void CallIndirectTrue(Value* cond, Value* value, uint32_t call_flags = 0); + void CallExtern(runtime::FunctionInfo* symbol_info); void Return(); void ReturnTrue(Value* cond); diff --git a/src/alloy/hir/opcodes.h b/src/alloy/hir/opcodes.h index 9fdcd311e..2b8649afe 100644 --- a/src/alloy/hir/opcodes.h +++ b/src/alloy/hir/opcodes.h @@ -94,6 +94,7 @@ enum Opcode { OPCODE_CALL_TRUE, OPCODE_CALL_INDIRECT, OPCODE_CALL_INDIRECT_TRUE, + OPCODE_CALL_EXTERN, OPCODE_RETURN, OPCODE_RETURN_TRUE, diff --git a/src/alloy/hir/opcodes.inl b/src/alloy/hir/opcodes.inl index abdea12db..485fa529b 100644 --- a/src/alloy/hir/opcodes.inl +++ b/src/alloy/hir/opcodes.inl @@ -74,6 +74,12 @@ DEFINE_OPCODE( OPCODE_SIG_X_V_V, OPCODE_FLAG_BRANCH); +DEFINE_OPCODE( + OPCODE_CALL_EXTERN, + "call_extern", + OPCODE_SIG_X_S, + OPCODE_FLAG_BRANCH); + DEFINE_OPCODE( OPCODE_RETURN, "return", diff --git a/src/alloy/runtime/function.cc b/src/alloy/runtime/function.cc index c09d3b929..f8b74f48f 100644 --- a/src/alloy/runtime/function.cc +++ b/src/alloy/runtime/function.cc @@ -17,8 +17,9 @@ using namespace alloy; using namespace alloy::runtime; -Function::Function(Type type, uint64_t address) : - type_(type), address_(address), debug_info_(0) { +Function::Function(FunctionInfo* symbol_info) : + address_(symbol_info->address()), + symbol_info_(symbol_info), debug_info_(0) { // TODO(benvanik): create on demand? lock_ = AllocMutex(); } @@ -77,43 +78,27 @@ int Function::Call(ThreadState* thread_state) { if (original_thread_state != thread_state) { ThreadState::Bind(thread_state); } - int result = CallImpl(thread_state); + + int result = 0; + + if (symbol_info_->behavior() == FunctionInfo::BEHAVIOR_EXTERN) { + auto handler = symbol_info_->extern_handler(); + if (handler) { + handler(thread_state->raw_context(), + symbol_info_->extern_arg0(), + symbol_info_->extern_arg1()); + } else { + XELOGW("undefined extern call to %.8X %s", + symbol_info_->address(), + symbol_info_->name()); + result = 1; + } + } else { + CallImpl(thread_state); + } + if (original_thread_state != thread_state) { ThreadState::Bind(original_thread_state); } return result; } - -ExternFunction::ExternFunction( - uint64_t address, Handler handler, void* arg0, void* arg1) : - name_(0), - handler_(handler), arg0_(arg0), arg1_(arg1), - Function(Function::EXTERN_FUNCTION, address) { -} - -ExternFunction::~ExternFunction() { - if (name_) { - xe_free(name_); - } -} - -void ExternFunction::set_name(const char* name) { - name_ = xestrdupa(name); -} - -int ExternFunction::CallImpl(ThreadState* thread_state) { - if (!handler_) { - XELOGW("undefined extern call to %.8X %s", address(), name()); - return 0; - } - handler_(thread_state->raw_context(), arg0_, arg1_); - return 0; -} - -GuestFunction::GuestFunction(FunctionInfo* symbol_info) : - symbol_info_(symbol_info), - Function(Function::USER_FUNCTION, symbol_info->address()) { -} - -GuestFunction::~GuestFunction() { -} diff --git a/src/alloy/runtime/function.h b/src/alloy/runtime/function.h index d150f91a6..629276c0b 100644 --- a/src/alloy/runtime/function.h +++ b/src/alloy/runtime/function.h @@ -24,17 +24,11 @@ class ThreadState; class Function { public: - enum Type { - UNKNOWN_FUNCTION = 0, - EXTERN_FUNCTION, - USER_FUNCTION, - }; -public: - Function(Type type, uint64_t address); + Function(FunctionInfo* symbol_info); virtual ~Function(); - Type type() const { return type_; } uint64_t address() const { return address_; } + FunctionInfo* symbol_info() const { return symbol_info_; } DebugInfo* debug_info() const { return debug_info_; } void set_debug_info(DebugInfo* debug_info) { debug_info_ = debug_info; } @@ -51,8 +45,8 @@ protected: virtual int CallImpl(ThreadState* thread_state) = 0; protected: - Type type_; uint64_t address_; + FunctionInfo* symbol_info_; DebugInfo* debug_info_; // TODO(benvanik): move elsewhere? DebugData? @@ -61,43 +55,6 @@ protected: }; -class ExternFunction : public Function { -public: - typedef void(*Handler)(void* context, void* arg0, void* arg1); -public: - ExternFunction(uint64_t address, Handler handler, void* arg0, void* arg1); - virtual ~ExternFunction(); - - const char* name() const { return name_; } - void set_name(const char* name); - - Handler handler() const { return handler_; } - void* arg0() const { return arg0_; } - void* arg1() const { return arg1_; } - -protected: - virtual int CallImpl(ThreadState* thread_state); - -protected: - char* name_; - Handler handler_; - void* arg0_; - void* arg1_; -}; - - -class GuestFunction : public Function { -public: - GuestFunction(FunctionInfo* symbol_info); - virtual ~GuestFunction(); - - FunctionInfo* symbol_info() const { return symbol_info_; } - -protected: - FunctionInfo* symbol_info_; -}; - - } // namespace runtime } // namespace alloy diff --git a/src/alloy/runtime/symbol_info.cc b/src/alloy/runtime/symbol_info.cc index 3a486840d..e87727b3a 100644 --- a/src/alloy/runtime/symbol_info.cc +++ b/src/alloy/runtime/symbol_info.cc @@ -34,11 +34,19 @@ void SymbolInfo::set_name(const char* name) { FunctionInfo::FunctionInfo(Module* module, uint64_t address) : end_address_(0), behavior_(BEHAVIOR_DEFAULT), function_(0), SymbolInfo(SymbolInfo::TYPE_FUNCTION, module, address) { + xe_zero_struct(&extern_info_, sizeof(extern_info_)); } FunctionInfo::~FunctionInfo() { } +void FunctionInfo::SetupExtern(ExternHandler handler, void* arg0, void* arg1) { + behavior_ = BEHAVIOR_EXTERN; + extern_info_.handler = handler; + extern_info_.arg0 = arg0; + extern_info_.arg1 = arg1; +} + VariableInfo::VariableInfo(Module* module, uint64_t address) : SymbolInfo(SymbolInfo::TYPE_VARIABLE, module, address) { } diff --git a/src/alloy/runtime/symbol_info.h b/src/alloy/runtime/symbol_info.h index c91fda40a..8d2a964e7 100644 --- a/src/alloy/runtime/symbol_info.h +++ b/src/alloy/runtime/symbol_info.h @@ -63,6 +63,7 @@ public: BEHAVIOR_PROLOG, BEHAVIOR_EPILOG, BEHAVIOR_EPILOG_RETURN, + BEHAVIOR_EXTERN, }; public: @@ -79,10 +80,21 @@ public: Function* function() const { return function_; } void set_function(Function* value) { function_ = value; } + typedef void(*ExternHandler)(void* context, void* arg0, void* arg1); + void SetupExtern(ExternHandler handler, void* arg0, void* arg1); + ExternHandler extern_handler() const { return extern_info_.handler; } + void* extern_arg0() const { return extern_info_.arg0; } + void* extern_arg1() const { return extern_info_.arg1; } + private: uint64_t end_address_; Behavior behavior_; Function* function_; + struct { + ExternHandler handler; + void* arg0; + void* arg1; + } extern_info_; }; class VariableInfo : public SymbolInfo { diff --git a/src/xenia/cpu/processor.cc b/src/xenia/cpu/processor.cc index e03890a92..6fd7347dd 100644 --- a/src/xenia/cpu/processor.cc +++ b/src/xenia/cpu/processor.cc @@ -648,7 +648,6 @@ json_t* Processor::DumpModule(XexModule* module, bool& succeeded) { json_object_set_new(import_library_json, "imports", imports_json); json_array_append_new(library_imports_json, import_library_json); - xe_free(import_infos); } json_object_set_new(module_json, "libraryImports", library_imports_json); diff --git a/src/xenia/cpu/xex_module.cc b/src/xenia/cpu/xex_module.cc index 9291724d2..2ff90c16a 100644 --- a/src/xenia/cpu/xex_module.cc +++ b/src/xenia/cpu/xex_module.cc @@ -135,14 +135,12 @@ int XexModule::SetupLibraryImports(const xe_xex2_import_library_t* library) { if (kernel_export->type == KernelExport::Function) { // Not exactly sure what this should be... if (info->thunk_address) { - // slot = XESWAP32BE(info->thunk_address); - // Setting this breaks other emu code that relies on it not being - // modified. Not sure what to do. + *slot = XESWAP32BE(info->thunk_address); } else { // TODO(benvanik): find out what import variables are. XELOGW("kernel import variable not defined %.8X %s", info->value_address, kernel_export->name); - //*slot = XESWAP32BE(0xF00DF00D); + *slot = XESWAP32BE(0xF00DF00D); } } else { if (kernel_export->is_implemented) { @@ -165,39 +163,45 @@ int XexModule::SetupLibraryImports(const xe_xex2_import_library_t* library) { info->ordinal); } - FunctionInfo* fn_info; - DeclareFunction(info->thunk_address, &fn_info); - fn_info->set_end_address(info->thunk_address + 16 - 4); - //fn->type = FunctionSymbol::Kernel; - //fn->kernel_export = kernel_export; - fn_info->set_name(name); - fn_info->set_status(SymbolInfo::STATUS_DECLARED); + // On load we have something like this in memory: + // li r3, 0 + // li r4, 0x1F5 + // mtspr CTR, r11 + // bctr + // Real consoles rewrite this with some code that sets r11. + // If we did that we'd still have to put a thunk somewhere and do the + // dynamic lookup. Instead, we rewrite it to use syscalls, as they + // aren't used on the 360. Alloy backends can either take the syscall + // or do something smarter. + // sc + // blr + // nop + // nop + uint8_t* p = memory()->Translate(info->thunk_address); + XESETUINT32BE(p + 0x0, 0x44000002); + XESETUINT32BE(p + 0x4, 0x4E800020); + XESETUINT32BE(p + 0x8, 0x60000000); + XESETUINT32BE(p + 0xC, 0x60000000); - ExternFunction::Handler handler = 0; + FunctionInfo::ExternHandler handler = 0; void* handler_data = 0; if (kernel_export) { - handler = (ExternFunction::Handler)kernel_export->function_data.shim; + handler = (FunctionInfo::ExternHandler)kernel_export->function_data.shim; handler_data = kernel_export->function_data.shim_data; } else { - handler = (ExternFunction::Handler)UndefinedImport; + handler = (FunctionInfo::ExternHandler)UndefinedImport; handler_data = this; } - DefineFunction(fn_info); - auto fn = new ExternFunction( - info->thunk_address, - handler, - handler_data, - NULL); - if (kernel_export) { - fn->set_name(kernel_export->name); - } - fn_info->set_function(fn); - fn_info->set_status(SymbolInfo::STATUS_DEFINED); + FunctionInfo* fn_info; + DeclareFunction(info->thunk_address, &fn_info); + fn_info->set_end_address(info->thunk_address + 16 - 4); + fn_info->set_name(name); + fn_info->SetupExtern(handler, handler_data, NULL); + fn_info->set_status(SymbolInfo::STATUS_DECLARED); } } - xe_free(import_infos); return 0; } diff --git a/src/xenia/export_resolver.cc b/src/xenia/export_resolver.cc index f630a3c48..9d09b63ec 100644 --- a/src/xenia/export_resolver.cc +++ b/src/xenia/export_resolver.cc @@ -36,6 +36,28 @@ void ExportResolver::RegisterTable( } } +uint16_t ExportResolver::GetLibraryOrdinal(const char* library_name) { + uint16_t n = 0; + for (auto it = tables_.begin(); it != tables_.end(); ++it, n++) { + if (!xestrcmpa(library_name, it->name)) { + return n; + } + } + return -1; +} + +KernelExport* ExportResolver::GetExportByOrdinal( + const uint16_t library_ordinal, const uint32_t ordinal) { + auto& table = tables_[library_ordinal]; + // TODO(benvanik): binary search? + for (size_t n = 0; n < table.count; n++) { + if (table.exports[n].ordinal == ordinal) { + return &table.exports[n]; + } + } + return NULL; +} + KernelExport* ExportResolver::GetExportByOrdinal(const char* library_name, const uint32_t ordinal) { for (std::vector::iterator it = tables_.begin(); diff --git a/src/xenia/export_resolver.h b/src/xenia/export_resolver.h index fcc9a6d87..487e8bd9c 100644 --- a/src/xenia/export_resolver.h +++ b/src/xenia/export_resolver.h @@ -68,6 +68,10 @@ public: void RegisterTable(const char* library_name, KernelExport* exports, const size_t count); + uint16_t GetLibraryOrdinal(const char* library_name); + + KernelExport* GetExportByOrdinal(const uint16_t library_ordinal, + const uint32_t ordinal); KernelExport* GetExportByOrdinal(const char* library_name, const uint32_t ordinal); KernelExport* GetExportByName(const char* library_name, const char* name); diff --git a/src/xenia/kernel/objects/xuser_module.cc b/src/xenia/kernel/objects/xuser_module.cc index 86d25847e..3a07b209a 100644 --- a/src/xenia/kernel/objects/xuser_module.cc +++ b/src/xenia/kernel/objects/xuser_module.cc @@ -345,8 +345,6 @@ void XUserModule::Dump() { } } - - xe_free(import_infos); } printf("\n"); diff --git a/src/xenia/kernel/util/xex2.cc b/src/xenia/kernel/util/xex2.cc index 5532200d8..af71eb182 100644 --- a/src/xenia/kernel/util/xex2.cc +++ b/src/xenia/kernel/util/xex2.cc @@ -24,11 +24,16 @@ using namespace alloy; typedef struct xe_xex2 { xe_ref_t ref; - Memory* memory; + Memory* memory; - xe_xex2_header_t header; + xe_xex2_header_t header; std::vector* sections; + + struct { + size_t count; + xe_xex2_import_info_t* infos; + } library_imports[16]; } xe_xex2_t; @@ -39,6 +44,8 @@ int xe_xex2_read_image(xe_xex2_ref xex, const uint8_t *xex_addr, const size_t xex_length, Memory* memory); int xe_xex2_load_pe(xe_xex2_ref xex); +int xe_xex2_find_import_infos(xe_xex2_ref xex, + const xe_xex2_import_library_t* library); xe_xex2_ref xe_xex2_load(Memory* memory, @@ -58,6 +65,11 @@ xe_xex2_ref xe_xex2_load(Memory* memory, XEEXPECTZERO(xe_xex2_load_pe(xex)); + for (size_t n = 0; n < xex->header.import_library_count; n++) { + auto library = &xex->header.import_libraries[n]; + XEEXPECTZERO(xe_xex2_find_import_infos(xex, library)); + } + return xex; XECLEANUP: @@ -894,12 +906,10 @@ const PESection* xe_xex2_get_pe_section(xe_xex2_ref xex, const char* name) { return NULL; } -int xe_xex2_get_import_infos(xe_xex2_ref xex, - const xe_xex2_import_library_t *library, - xe_xex2_import_info_t **out_import_infos, - size_t *out_import_info_count) { - uint8_t *mem = xex->memory->membase(); - const xe_xex2_header_t *header = xe_xex2_get_header(xex); +int xe_xex2_find_import_infos(xe_xex2_ref xex, + const xe_xex2_import_library_t *library) { + uint8_t* mem = xex->memory->membase(); + auto header = xe_xex2_get_header(xex); // Find library index for verification. size_t library_index = -1; @@ -970,13 +980,34 @@ int xe_xex2_get_import_infos(xe_xex2_ref xex, } } - *out_import_info_count = info_count; - *out_import_infos = infos; + xex->library_imports[library_index].count = info_count; + xex->library_imports[library_index].infos = infos; return 0; XECLEANUP: xe_free(infos); - *out_import_info_count = 0; - *out_import_infos = NULL; return 1; } + +int xe_xex2_get_import_infos(xe_xex2_ref xex, + const xe_xex2_import_library_t *library, + xe_xex2_import_info_t **out_import_infos, + size_t *out_import_info_count) { + auto header = xe_xex2_get_header(xex); + + // Find library index for verification. + size_t library_index = -1; + for (size_t n = 0; n < header->import_library_count; n++) { + if (&header->import_libraries[n] == library) { + library_index = n; + break; + } + } + if (library_index == (size_t)-1) { + return 1; + } + + *out_import_info_count = xex->library_imports[library_index].count; + *out_import_infos = xex->library_imports[library_index].infos; + return 0; +}