diff --git a/src/xenia/cpu/xex_module.cc b/src/xenia/cpu/xex_module.cc index af6f6e588..f3f36951b 100644 --- a/src/xenia/cpu/xex_module.cc +++ b/src/xenia/cpu/xex_module.cc @@ -41,11 +41,19 @@ XexModule::XexModule(Processor* processor, KernelState* kernel_state) processor_(processor), kernel_state_(kernel_state), xex_(nullptr), + xex_header_(nullptr), base_address_(0), low_address_(0), high_address_(0) {} -XexModule::~XexModule() { xe_xex2_dealloc(xex_); } +XexModule::~XexModule() { + xe_xex2_dealloc(xex_); + + if (xex_header_) { + delete[] xex_header_; + xex_header_ = nullptr; + } +} bool XexModule::GetOptHeader(const xex2_header* header, xe_xex2_header_keys key, void** out_ptr) { @@ -287,6 +295,21 @@ bool XexModule::Load(const std::string& name, const std::string& path, return true; } +bool XexModule::Unload() { + // Just deallocate the memory occupied by the exe + uint32_t exe_address = 0; + GetOptHeader(XEX_HEADER_IMAGE_BASE_ADDRESS, &exe_address); + assert_not_zero(exe_address); + + memory()->LookupHeap(exe_address)->Release(exe_address); + + assert_not_null(xex_header_); // Unloading a module that wasn't loaded? + delete[] xex_header_; + xex_header_ = nullptr; + + return true; +} + bool XexModule::SetupLibraryImports(const char* name, const xex2_import_library* library) { ExportResolver* kernel_resolver = nullptr; diff --git a/src/xenia/cpu/xex_module.h b/src/xenia/cpu/xex_module.h index f4723a6cb..692e0e4fe 100644 --- a/src/xenia/cpu/xex_module.h +++ b/src/xenia/cpu/xex_module.h @@ -68,6 +68,7 @@ class XexModule : public xe::cpu::Module { bool Load(const std::string& name, const std::string& path, const void* xex_addr, size_t xex_length); bool Load(const std::string& name, const std::string& path, xe_xex2_ref xex); + bool Unload(); const std::string& name() const override { return name_; } diff --git a/src/xenia/kernel/objects/xuser_module.cc b/src/xenia/kernel/objects/xuser_module.cc index f4fbdee69..ab2094b6d 100644 --- a/src/xenia/kernel/objects/xuser_module.cc +++ b/src/xenia/kernel/objects/xuser_module.cc @@ -24,7 +24,7 @@ using namespace xe::cpu; XUserModule::XUserModule(KernelState* kernel_state, const char* path) : XModule(kernel_state, ModuleType::kUserModule, path) {} -XUserModule::~XUserModule() {} +XUserModule::~XUserModule() { Unload(); } X_STATUS XUserModule::LoadFromFile(std::string path) { X_STATUS result = X_STATUS_UNSUCCESSFUL; @@ -111,6 +111,15 @@ X_STATUS XUserModule::LoadFromMemory(const void* addr, const size_t length) { return X_STATUS_SUCCESS; } +X_STATUS XUserModule::Unload() { + if (!xex_module()->Unload()) { + return X_STATUS_UNSUCCESSFUL; + } + + OnUnload(); + return X_STATUS_SUCCESS; +} + uint32_t XUserModule::GetProcAddressByOrdinal(uint16_t ordinal) { return xex_module()->GetProcAddress(ordinal); } diff --git a/src/xenia/kernel/objects/xuser_module.h b/src/xenia/kernel/objects/xuser_module.h index 3f3da1ac3..dc9a168dd 100644 --- a/src/xenia/kernel/objects/xuser_module.h +++ b/src/xenia/kernel/objects/xuser_module.h @@ -29,6 +29,9 @@ class XUserModule : public XModule { const xe::cpu::XexModule* xex_module() const { return reinterpret_cast(processor_module_); } + xe::cpu::XexModule* xex_module() { + return reinterpret_cast(processor_module_); + } const xex2_header* xex_header() const { return xex_module()->xex_header(); } uint32_t guest_xex_header() const { return guest_xex_header_; } @@ -39,6 +42,7 @@ class XUserModule : public XModule { X_STATUS LoadFromFile(std::string path); X_STATUS LoadFromMemory(const void* addr, const size_t length); + X_STATUS Unload(); uint32_t GetProcAddressByOrdinal(uint16_t ordinal) override; uint32_t GetProcAddressByName(const char* name) override;