diff --git a/src/xenia/cpu/xex_module.cc b/src/xenia/cpu/xex_module.cc index 1e4b56f26..2ecd3581b 100644 --- a/src/xenia/cpu/xex_module.cc +++ b/src/xenia/cpu/xex_module.cc @@ -24,6 +24,7 @@ #include "xenia/cpu/processor.h" #include "xenia/emulator.h" #include "xenia/kernel/kernel_state.h" +#include "xenia/kernel/user_module.h" #include "xenia/kernel/xmodule.h" #include "third_party/crypto/TinySHA1.hpp" @@ -1062,6 +1063,15 @@ bool XexModule::LoadContinue() { opt_import_libraries->string_table.count); assert_not_null(string_table[library_name_index]); auto library_name = std::string(string_table[library_name_index]); + + if (!kernel_state_->IsModuleLoaded(library_name)) { + if (auto module = kernel_state_->LoadUserModule(library_name)) { + if (kernel_state_->FinishLoadingUserModule(module, false)) { + library_name = module->path(); + } + } + } + SetupLibraryImports(library_name, library); library_offset += library->size; } diff --git a/src/xenia/kernel/kernel_state.cc b/src/xenia/kernel/kernel_state.cc index f0d0c439e..861c7cc33 100644 --- a/src/xenia/kernel/kernel_state.cc +++ b/src/xenia/kernel/kernel_state.cc @@ -217,6 +217,28 @@ bool KernelState::IsKernelModule(const std::string_view name) { return false; } +bool KernelState::IsModuleLoaded(const std::string_view name) { + if (name.empty()) { + return true; + } + + for (auto kernel_module : kernel_modules_) { + if (kernel_module->Matches(name)) { + return true; + } + } + + auto global_lock = global_critical_region_.Acquire(); + + for (auto user_module : user_modules_) { + if (user_module->Matches(name)) { + return true; + } + } + + return false; +} + object_ref KernelState::GetKernelModule( const std::string_view name) { assert_true(IsKernelModule(name)); @@ -431,9 +453,14 @@ object_ref KernelState::LoadUserModule( auto name = xe::utf8::find_name_from_guest_path(raw_name); std::string path(raw_name); if (name == raw_name) { - assert_not_null(executable_module_); - path = xe::utf8::join_guest_paths( - xe::utf8::find_base_guest_path(executable_module_->path()), name); + if (!executable_module_) { + path = xe::utf8::join_guest_paths( + xe::utf8::find_base_guest_path((*user_modules_.cbegin())->path()), + name); + } else { + path = xe::utf8::join_guest_paths( + xe::utf8::find_base_guest_path(executable_module_->path()), name); + } } object_ref module; @@ -521,6 +548,9 @@ X_RESULT KernelState::FinishLoadingUserModule( 1, // DLL_PROCESS_ATTACH 0, // 0 because always dynamic }; + + module->is_attached_ = true; + auto thread_state = XThread::GetCurrentThread()->thread_state(); processor()->Execute(thread_state, module->entry_point(), args, xe::countof(args)); @@ -808,9 +838,16 @@ void KernelState::OnThreadExecute(XThread* thread) { if (user_module->is_dll_module() && user_module->entry_point()) { uint64_t args[] = { user_module->handle(), - 2, // DLL_THREAD_ATTACH - 0, // 0 because always dynamic + user_module->is_attached_ + ? static_cast(2) // DLL_THREAD_ATTACH - Used to call + // DLL for each thread created. + : static_cast(1), // DLL_PROCESS_ATTACH - Used only + // once for initialization. + 0, // 0 because always dynamic }; + + user_module->is_attached_ = true; + processor()->Execute(thread_state, user_module->entry_point(), args, xe::countof(args)); } diff --git a/src/xenia/kernel/kernel_state.h b/src/xenia/kernel/kernel_state.h index 26ccad48e..60d5ac07c 100644 --- a/src/xenia/kernel/kernel_state.h +++ b/src/xenia/kernel/kernel_state.h @@ -226,6 +226,7 @@ class KernelState { bool RegisterUserModule(object_ref module); void UnregisterUserModule(UserModule* module); bool IsKernelModule(const std::string_view name); + bool IsModuleLoaded(const std::string_view name); object_ref GetModule(const std::string_view name, bool user_only = false); diff --git a/src/xenia/kernel/user_module.h b/src/xenia/kernel/user_module.h index 02dbc3e7d..49c812233 100644 --- a/src/xenia/kernel/user_module.h +++ b/src/xenia/kernel/user_module.h @@ -108,6 +108,11 @@ class UserModule : public XModule { ByteStream* stream, const std::string_view path); + // TODO(Gliniak): This shouldn't be required. It is used for initial DLL + // initialization. Which should happen on main thread before main execution + // which isn't really possible right now. + bool is_attached_ = false; + private: void CalculateHash();