Merge pull request #864 from jeffrey12cali/fix/dlsym-default-scope
fix(module): resolve the default dlsym scope against the main program
This commit is contained in:
commit
b82c1c2f70
|
|
@ -104,6 +104,9 @@ if(BUILD_TESTING)
|
|||
target_link_libraries(guest_dynamic_loader_tests PRIVATE libkernel libc)
|
||||
configure_windows_unwind(guest_dynamic_loader_tests)
|
||||
add_dependencies(guest_dynamic_loader_tests guest_module_fixture)
|
||||
if(NOT WIN32)
|
||||
set_target_properties(guest_dynamic_loader_tests PROPERTIES ENABLE_EXPORTS ON)
|
||||
endif()
|
||||
add_test(NAME guest_dynamic_loader COMMAND guest_dynamic_loader_tests $<TARGET_FILE_NAME:guest_module_fixture>)
|
||||
set_tests_properties(guest_dynamic_loader PROPERTIES
|
||||
WORKING_DIRECTORY "$<TARGET_FILE_DIR:guest_module_fixture>")
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
#include <windows.h>
|
||||
#else
|
||||
#include <dlfcn.h>
|
||||
#include <link.h>
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
|
|
@ -49,6 +50,39 @@ void* Symbol(Module& module, const char* name) {
|
|||
return ::dlsym(module.native, name);
|
||||
#endif
|
||||
}
|
||||
#ifndef _WIN32
|
||||
std::uintptr_t MainProgramBase() {
|
||||
static const std::uintptr_t base = [] {
|
||||
struct Scan {
|
||||
std::uintptr_t value = 0;
|
||||
};
|
||||
Scan scan;
|
||||
::dl_iterate_phdr(
|
||||
[](dl_phdr_info* info, size_t, void* data) {
|
||||
auto* found = static_cast<Scan*>(data);
|
||||
if (found->value == 0 && info->dlpi_name != nullptr && info->dlpi_name[0] == '\0') found->value = info->dlpi_addr;
|
||||
return found->value == 0 ? 0 : 1;
|
||||
},
|
||||
&scan);
|
||||
return scan.value;
|
||||
}();
|
||||
return base;
|
||||
}
|
||||
|
||||
bool FromGuestModule(void* address) {
|
||||
Dl_info info{};
|
||||
if (address == nullptr || !::dladdr(address, &info) || info.dli_fname == nullptr) return false;
|
||||
if (reinterpret_cast<std::uintptr_t>(info.dli_fbase) == MainProgramBase()) return true;
|
||||
const std::string path(info.dli_fname);
|
||||
return path.ends_with(".prx");
|
||||
}
|
||||
|
||||
void* DefaultScopeSymbol(const char* symbolName) {
|
||||
auto* result = ::dlsym(RTLD_DEFAULT, symbolName);
|
||||
return FromGuestModule(result) ? result : nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
void* FindSymbol(Module& module, const char* name) {
|
||||
if (auto* symbol = Symbol(module, name)) return symbol;
|
||||
const auto nid = Nid::ComputeNid(name, "");
|
||||
|
|
@ -116,7 +150,7 @@ void* APS5_VABI dlsym_nid_postfix(void* handle, const char* name) {
|
|||
std::vector<std::shared_ptr<Module>> search;
|
||||
{
|
||||
std::lock_guard lock(modulesMutex);
|
||||
if (handle == reinterpret_cast<void*>(static_cast<std::intptr_t>(-2))) {
|
||||
if (handle == nullptr || handle == reinterpret_cast<void*>(static_cast<std::intptr_t>(-2))) {
|
||||
for (const auto& [key, module] : modules) if (module->global) search.push_back(module);
|
||||
} else {
|
||||
auto found = modules.find(reinterpret_cast<std::uintptr_t>(handle));
|
||||
|
|
@ -125,6 +159,13 @@ void* APS5_VABI dlsym_nid_postfix(void* handle, const char* name) {
|
|||
}
|
||||
}
|
||||
for (const auto& module : search) if (auto* result = FindSymbol(*module, name)) return result;
|
||||
#ifndef _WIN32
|
||||
if (handle == nullptr || handle == reinterpret_cast<void*>(static_cast<std::intptr_t>(-2))) {
|
||||
if (auto* result = DefaultScopeSymbol(name)) return result;
|
||||
const auto nid = Nid::ComputeNid(name, "");
|
||||
if (auto* result = DefaultScopeSymbol(nid.c_str())) return result;
|
||||
}
|
||||
#endif
|
||||
Error("dlsym: symbol not found in supported module scope");
|
||||
return nullptr;
|
||||
} catch (const std::exception& error) { Error(error.what()); return nullptr; }
|
||||
|
|
|
|||
|
|
@ -2,6 +2,9 @@
|
|||
#include <cstdlib>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#ifndef _WIN32
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
#include <stdexcept>
|
||||
#include <thread>
|
||||
extern "C" {
|
||||
|
|
@ -13,6 +16,9 @@ int APS5_VABI _sceKernelRtldThreadAtexitIncrement_nid_postfix(const void*);
|
|||
int APS5_VABI _sceKernelRtldThreadAtexitDecrement_nid_postfix(const void*);
|
||||
}
|
||||
static void Require(bool value) { if (!value) std::abort(); }
|
||||
#ifndef _WIN32
|
||||
extern "C" int APS5_VABI GuestDefaultScopeOnly(int a, int b) { return a * b; }
|
||||
#endif
|
||||
template<typename TFunction>
|
||||
static bool ThrowsRuntimeError(TFunction function) {
|
||||
try {
|
||||
|
|
@ -38,6 +44,7 @@ int main(int argc, char** argv) {
|
|||
auto add = reinterpret_cast<Add>(dlsym_nid_postfix(module, "GuestModuleAdd"));
|
||||
Require(add && add(17, 25) == 42);
|
||||
Require(dlsym_nid_postfix(reinterpret_cast<void*>(-2), "GuestModuleAdd") == reinterpret_cast<void*>(add));
|
||||
Require(dlsym_nid_postfix(nullptr, "GuestModuleAdd") == reinterpret_cast<void*>(add));
|
||||
#ifndef _WIN32
|
||||
auto mul = reinterpret_cast<Add>(dlsym_nid_postfix(module, "GuestModuleMul"));
|
||||
Require(mul && mul(6, 7) == 42);
|
||||
|
|
@ -88,4 +95,20 @@ int main(int argc, char** argv) {
|
|||
Require(ThrowsRuntimeError([] { _sceKernelRtldThreadAtexitDecrement_nid_postfix(reinterpret_cast<const void*>(&Require)); }));
|
||||
int local = 0;
|
||||
Require(ThrowsRuntimeError([&] { _sceKernelRtldThreadAtexitIncrement_nid_postfix(&local); }));
|
||||
#ifndef _WIN32
|
||||
Require(dlsym_nid_postfix(nullptr, "malloc") == nullptr);
|
||||
Require(dlsym_nid_postfix(nullptr, "dlopen") == nullptr);
|
||||
Require(dlsym_nid_postfix(nullptr, "pthread_create") == nullptr);
|
||||
Require(dlsym_nid_postfix(nullptr, "GuestDefaultScopeOnly") == reinterpret_cast<void*>(&GuestDefaultScopeOnly));
|
||||
Require(dlsym_nid_postfix(reinterpret_cast<void*>(-2), "GuestDefaultScopeOnly") == reinterpret_cast<void*>(&GuestDefaultScopeOnly));
|
||||
const auto hostLoaded = std::filesystem::absolute("anyps5-host-loaded-module-for-test.prx");
|
||||
std::filesystem::copy_file(argv[1], hostLoaded, std::filesystem::copy_options::overwrite_existing);
|
||||
void* host = ::dlopen(hostLoaded.c_str(), RTLD_NOW | RTLD_GLOBAL);
|
||||
Require(host != nullptr);
|
||||
void* hostAdd = ::dlsym(host, "3qcG+yBRS+s");
|
||||
Require(hostAdd != nullptr);
|
||||
Require(dlsym_nid_postfix(nullptr, "GuestModuleAdd") == hostAdd);
|
||||
Require(dlsym_nid_postfix(nullptr, "malloc") == nullptr);
|
||||
Require(::dlclose(host) == 0);
|
||||
#endif
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue