[rpcsx-os] linker: fix module load order

This commit is contained in:
DH 2023-07-19 01:42:23 +03:00
parent b12cc68bf3
commit 1d55e83965
4 changed files with 144 additions and 71 deletions

View file

@ -798,7 +798,6 @@ Ref<orbis::Module> rx::linker::loadModule(std::span<std::byte> image,
rx::vm::protect(seg.addr, seg.size, rx::vm::kMapProtCpuAll);
}
result->id = process->modulesMap.insert(result);
result->proc = process;
std::printf("Loaded module '%s' from object '%s', id: %u, address: %p - %p\n",
@ -812,8 +811,12 @@ Ref<orbis::Module> rx::linker::loadModule(std::span<std::byte> image,
return result;
}
Ref<orbis::Module> rx::linker::loadModuleFile(const char *path,
Ref<orbis::Module> rx::linker::loadModuleFile(std::string_view path,
orbis::Process *process) {
if (!path.contains('/')) {
return loadModuleByName(path, process);
}
orbis::Ref<IoDeviceInstance> instance;
if (vfs::open(path, kOpenFlagReadOnly, 0, &instance).isError()) {
return {};

View file

@ -77,7 +77,7 @@ void override(std::string originalModuleName,
std::filesystem::path replacedModulePath);
orbis::Ref<orbis::Module> loadModule(std::span<std::byte> image,
orbis::Process *process);
orbis::Ref<orbis::Module> loadModuleFile(const char *path,
orbis::Ref<orbis::Module> loadModuleFile(std::string_view path,
orbis::Process *process);
orbis::Ref<orbis::Module> loadModuleByName(std::string_view name,
orbis::Process *process);

View file

@ -278,6 +278,13 @@ static int ps4Exec(orbis::Process *mainProcess,
auto libkernel = rx::linker::loadModuleFile(
"/system/common/lib/libkernel_sys.sprx", mainProcess);
if (libkernel == nullptr) {
std::fprintf(stderr, "libkernel not found\n");
return 1;
}
libkernel->id = mainProcess->modulesMap.insert(libkernel);
// *reinterpret_cast<std::uint32_t *>(
// reinterpret_cast<std::byte *>(libkernel->base) + 0x6c2e4) = ~0;
@ -502,6 +509,7 @@ int main(int argc, const char *argv[]) {
std::abort();
}
executableModule->id = initProcess->modulesMap.insert(executableModule);
initProcess->processParam = executableModule->processParam;
initProcess->processParamSize = executableModule->processParamSize;
@ -517,8 +525,6 @@ int main(int argc, const char *argv[]) {
status = 1;
}
// entryPoint();
// rx::vm::printHostStats();
rx::vm::deinitialize();
rx::thread::deinitialize();

View file

@ -26,6 +26,94 @@ using namespace orbis;
extern "C" void __register_frame(const void *);
namespace {
static std::pair<SysResult, Ref<Module>>
loadPrx(orbis::Thread *thread, std::string_view name, bool relocate,
std::map<std::string, Module *, std::less<>> &loadedObjects,
std::map<std::string, Module *, std::less<>> &loadedModules,
std::string_view expectedName) {
if (auto it = loadedObjects.find(name); it != loadedObjects.end()) {
return {{}, it->second};
}
auto module = rx::linker::loadModuleFile(name, thread->tproc);
if (module == nullptr) {
if (!expectedName.empty()) {
loadedObjects[std::string(expectedName)] = nullptr;
}
return {ErrorCode::NOENT, {}};
}
if (!expectedName.empty() && expectedName != module->soName) {
if (module->soName[0] != '\0') {
std::fprintf(stderr,
"Module name mismatch, expected '%s', loaded '%s' (%s)\n",
std::string(expectedName).c_str(), module->soName,
module->moduleName);
// std::abort();
}
std::strncpy(module->soName, std::string(expectedName).c_str(),
sizeof(module->soName));
if (module->soName[sizeof(module->soName) - 1] != '\0') {
std::fprintf(stderr, "Too big needed name\n");
std::abort();
}
}
std::printf("Loaded '%s'\n", module->soName);
loadedObjects[module->soName] = module.get();
loadedModules[module->moduleName] = module.get();
for (auto &needed : module->needed) {
auto [result, neededModule] =
loadPrx(thread, needed, relocate, loadedObjects, loadedModules, needed);
if (result.isError() || neededModule == nullptr) {
std::fprintf(stderr, "Needed '%s' not found\n", needed.c_str());
}
}
module->importedModules.reserve(module->neededModules.size());
for (auto mod : module->neededModules) {
if (auto it = loadedModules.find(std::string_view(mod.name));
it != loadedModules.end()) {
module->importedModules.emplace_back(it->second);
continue;
}
std::fprintf(stderr, "Not found needed module '%s' for object '%s'\n",
mod.name.c_str(), module->soName);
module->importedModules.push_back({});
}
if (relocate) {
auto result = module->relocate(thread->tproc);
if (result.isError()) {
return {result, module};
}
}
module->id = thread->tproc->modulesMap.insert(module);
return {{}, module};
}
static std::pair<SysResult, Ref<Module>>
loadPrx(orbis::Thread *thread, std::string_view name, bool relocate) {
std::map<std::string, Module *, std::less<>> loadedObjects;
std::map<std::string, Module *, std::less<>> loadedModules;
for (auto [id, module] : thread->tproc->modulesMap) {
loadedObjects[module->soName] = module;
loadedModules[module->moduleName] = module;
}
return loadPrx(thread, name, relocate, loadedObjects, loadedModules, {});
};
orbis::SysResult mmap(orbis::Thread *thread, orbis::caddr_t addr,
orbis::size_t len, orbis::sint prot, orbis::sint flags,
orbis::sint fd, orbis::off_t pos) {
@ -378,6 +466,7 @@ orbis::SysResult dynlib_get_obj_member(orbis::Thread *thread,
orbis::ModuleHandle handle,
orbis::uint64_t index,
orbis::ptr<orbis::ptr<void>> addrp) {
std::lock_guard lock(thread->tproc->mtx);
auto module = thread->tproc->modulesMap.get(handle);
if (module == nullptr) {
@ -411,6 +500,7 @@ orbis::SysResult dynlib_dlsym(orbis::Thread *thread, orbis::ModuleHandle handle,
orbis::ptr<const char> symbol,
orbis::ptr<orbis::ptr<void>> addrp) {
std::printf("sys_dynlib_dlsym(%u, '%s')\n", (unsigned)handle, symbol);
std::lock_guard lock(thread->tproc->mtx);
auto module = thread->tproc->modulesMap.get(handle);
if (module == nullptr) {
@ -444,17 +534,24 @@ orbis::SysResult dynlib_do_copy_relocations(orbis::Thread *thread) {
// TODO
return {};
}
orbis::SysResult dynlib_load_prx(orbis::Thread *thread,
orbis::ptr<const char> name,
orbis::uint64_t arg1,
orbis::ptr<ModuleHandle> pHandle,
orbis::uint64_t arg3) {
std::printf("sys_dynlib_load_prx: %s\n", name);
auto module = rx::linker::loadModuleFile(name, thread->tproc);
thread->tproc->ops->processNeeded(thread);
auto result = module->relocate(thread->tproc);
std::lock_guard lock(thread->tproc->mtx);
char _name[256];
auto errorCode = ureadString(_name, sizeof(_name), name);
if (errorCode != ErrorCode{}) {
return errorCode;
}
auto [result, module] = loadPrx(thread, _name, true);
if (result.isError()) {
thread->tproc->modulesMap.close(module->id);
return result;
}
@ -583,77 +680,44 @@ orbis::SysResult exit(orbis::Thread *thread, orbis::sint status) {
}
SysResult processNeeded(Thread *thread) {
while (true) {
std::set<std::string, std::less<>> allNeededObjects;
auto proc = thread->tproc;
std::map<std::string, Module *, std::less<>> loadedModules;
std::map<std::string, Module *, std::less<>> loadedObjects;
std::map<std::string, Module *, std::less<>> loadedObjects;
std::map<std::string, Module *, std::less<>> loadedModules;
std::set<std::string> allNeeded;
for (auto [id, module] : proc->modulesMap) {
for (const auto &object : module->needed) {
allNeededObjects.emplace(object.begin(), object.end());
}
loadedModules[module->moduleName] = module;
loadedObjects[module->soName] = module;
for (auto [id, module] : thread->tproc->modulesMap) {
loadedObjects[module->soName] = module;
loadedModules[module->moduleName] = module;
for (auto &needed : module->needed) {
allNeeded.insert(std::string(needed));
}
}
bool hasLoadedNeeded = false;
for (auto needed : allNeeded) {
auto [result, neededModule] =
loadPrx(thread, needed, false, loadedObjects, loadedModules, needed);
for (auto &needed : allNeededObjects) {
if (auto it = loadedObjects.find(needed); it != loadedObjects.end()) {
if (result.isError() || neededModule == nullptr) {
std::fprintf(stderr, "Needed '%s' not found\n", needed.c_str());
continue;
}
}
for (auto [id, module] : thread->tproc->modulesMap) {
module->importedModules.reserve(module->neededModules.size());
for (auto mod : module->neededModules) {
if (auto it = loadedModules.find(std::string_view(mod.name));
it != loadedModules.end()) {
module->importedModules.emplace_back(it->second);
continue;
}
auto neededModule = rx::linker::loadModuleByName(needed, proc);
if (neededModule == nullptr) {
std::fprintf(stderr, "Needed '%s' not found\n", needed.c_str());
continue;
}
if (neededModule->soName != needed) {
if (neededModule->soName[0] != '\0') {
std::fprintf(
stderr, "Module name mismatch, expected '%s', loaded '%s' (%s)\n",
needed.c_str(), neededModule->soName, neededModule->moduleName);
// std::abort();
}
std::strncpy(neededModule->soName, needed.c_str(),
sizeof(neededModule->soName));
if (neededModule->soName[sizeof(neededModule->soName) - 1] != '\0') {
std::fprintf(stderr, "Too big needed name\n");
std::abort();
}
}
hasLoadedNeeded = true;
std::fprintf(stderr, "Not found needed module '%s' for object '%s'\n",
mod.name.c_str(), module->soName);
module->importedModules.push_back({});
}
if (!hasLoadedNeeded) {
thread->tproc->modulesMap.walk([&loadedModules](ModuleHandle modId,
Module *module) {
// std::printf("Module '%s' has id %u\n", module->name,
// (unsigned)modId);
module->importedModules.clear();
module->importedModules.reserve(module->neededModules.size());
for (auto mod : module->neededModules) {
if (auto it = loadedModules.find(std::string_view(mod.name));
it != loadedModules.end()) {
module->importedModules.emplace_back(it->second);
continue;
}
std::fprintf(stderr, "Not found needed module '%s' for object '%s'\n",
mod.name.c_str(), module->soName);
module->importedModules.push_back({});
}
});
break;
}
module->relocate(thread->tproc);
}
return {};