From cfd1374afa2845b9f309f7ec347fab40d007365a Mon Sep 17 00:00:00 2001 From: DH Date: Fri, 30 Jun 2023 17:14:05 +0300 Subject: [PATCH] [rpcsx-os/linker] Implement SceFreeTypeFull building --- orbis-kernel | 2 +- rpcsx-os/linker.cpp | 51 ++++++++++++++++++++++++++++++++++++++++- rpcsx-os/linker.hpp | 20 ++++++++++++++--- rpcsx-os/ops.cpp | 55 +++++++++++++++++++++++++++------------------ 4 files changed, 101 insertions(+), 27 deletions(-) diff --git a/orbis-kernel b/orbis-kernel index 287b6e447..0a6f130e9 160000 --- a/orbis-kernel +++ b/orbis-kernel @@ -1 +1 @@ -Subproject commit 287b6e4470c6f6ac5501a3eab17e81e943c4d245 +Subproject commit 0a6f130e955a1ed7c4bcfdef0f9975e953435c12 diff --git a/rpcsx-os/linker.cpp b/rpcsx-os/linker.cpp index 97e867d48..3fb984b5b 100644 --- a/rpcsx-os/linker.cpp +++ b/rpcsx-os/linker.cpp @@ -562,7 +562,9 @@ Ref rx::linker::loadModule(std::span image, if (dyn.d_tag == kElfDynamicTypeNeeded) { auto name = std::string_view( sceStrtab + static_cast(dyn.d_un.d_val)); - if (name.ends_with(".prx")) { + if (name == "libSceFreeTypeOptBm-PRX.prx") { + // TODO + } else if (name.ends_with(".prx")) { result->needed.push_back(std::string(name)); } else if (name == "STREQUAL") { // HACK for broken FWs @@ -820,17 +822,64 @@ Ref rx::linker::loadModuleFile(const char *path, return loadModule(image, process); } +static Ref createSceFreeTypeFull(orbis::Process *process) { + auto result = orbis::create(); + + std::strncpy(result->soName, "libSceFreeTypeFull-PRX.prx", sizeof(result->soName) - 1); + std::strncpy(result->moduleName, "libSceFreeType", sizeof(result->moduleName) - 1); + + result->neededLibraries.push_back({ + .name = "libSceFreeType", + .isExport = true + }); + + for (auto dep : { "libSceFreeTypeSubFunc", "libSceFreeTypeOl", "libSceFreeTypeOt", "libSceFreeTypeOptOl", "libSceFreeTypeHinter" }) { + result->needed.push_back(dep); + result->needed.back() += "-PRX.prx"; + } + + for (auto needed : result->needed) { + auto neededMod = rx::linker::loadModuleByName(needed, process); + + if (neededMod == nullptr) { + std::fprintf(stderr, "Failed to load needed '%s' for FreeType\n", needed.c_str()); + std::abort(); + } + + result->namespaceModules.push_back(neededMod); + } + + // TODO: load native library with module_start and module_stop + result->initProc = reinterpret_cast(+[] {}); + result->finiProc = reinterpret_cast(+[] {}); + + result->id = process->modulesMap.insert(result); + result->proc = process; + + return result; +} + Ref rx::linker::loadModuleByName(std::string_view name, orbis::Process *process) { if (name.ends_with(".prx")) { name.remove_suffix(4); } + if (name.ends_with("-PRX")) { + name.remove_suffix(4); // TODO: implement lib scan + } + if (name.ends_with("-module")) { + name.remove_suffix(7); // TODO: implement lib scan + } if (auto it = g_moduleOverrideTable.find(name); it != g_moduleOverrideTable.end()) { return loadModuleFile(it->second.c_str(), process); } + if (name == "libSceFreeTypeFull") { + return createSceFreeTypeFull(process); + } + for (auto path : {"/system/common/lib/", "/system/priv/lib/"}) { auto filePath = std::string(path); filePath += name; diff --git a/rpcsx-os/linker.hpp b/rpcsx-os/linker.hpp index 3791e2d4c..6f76d877d 100644 --- a/rpcsx-os/linker.hpp +++ b/rpcsx-os/linker.hpp @@ -4,24 +4,25 @@ #include "orbis/utils/Rc.hpp" #include #include +#include #include namespace rx::linker { inline constexpr char nidLookup[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-"; -constexpr std::uint64_t decodeNid(std::string_view nid) { +constexpr std::optional decodeNid(std::string_view nid) { std::uint64_t result = 0; if (nid.size() > 11) { - std::abort(); + return{}; } for (std::size_t i = 0; i < nid.size(); ++i) { auto it = std::strchr(nidLookup, nid[i]); if (it == nullptr) { - std::abort(); + return{}; } auto value = static_cast(it - nidLookup); @@ -39,6 +40,19 @@ constexpr std::uint64_t decodeNid(std::string_view nid) { return result; } +struct nid { + char string[12]; +}; + +constexpr nid encodeNid(std::uint64_t hash) { + return {{nidLookup[(hash >> 58) & 0x3f], nidLookup[(hash >> 52) & 0x3f], + nidLookup[(hash >> 46) & 0x3f], nidLookup[(hash >> 40) & 0x3f], + nidLookup[(hash >> 34) & 0x3f], nidLookup[(hash >> 28) & 0x3f], + nidLookup[(hash >> 22) & 0x3f], nidLookup[(hash >> 16) & 0x3f], + nidLookup[(hash >> 10) & 0x3f], nidLookup[(hash >> 4) & 0x3f], + nidLookup[(hash & 0xf) * 4], 0}}; +} + std::uint64_t encodeFid(std::string_view fid); struct Symbol { diff --git a/rpcsx-os/ops.cpp b/rpcsx-os/ops.cpp index 9221e6fbc..5ca73fce6 100644 --- a/rpcsx-os/ops.cpp +++ b/rpcsx-os/ops.cpp @@ -40,7 +40,7 @@ orbis::SysResult mmap(orbis::Thread *thread, orbis::caddr_t addr, } thread->retval[0] = reinterpret_cast(result); - return{}; + return {}; } orbis::SysResult munmap(orbis::Thread *thread, orbis::ptr addr, @@ -371,15 +371,19 @@ orbis::SysResult dynlib_dlsym(orbis::Thread *thread, orbis::ModuleHandle handle, return ErrorCode::INVAL; } + std::printf("sys_dynlib_dlsym(%s (%s), '%s')\n", module->soName, module->moduleName, symbol); + std::string_view symView(symbol); - if (symView.size() == 11) { - if (auto addr = findSymbolById(module, rx::linker::decodeNid(symView))) { + if (auto nid = rx::linker::decodeNid(symView)) { + if (auto addr = findSymbolById(module, *nid)) { *addrp = addr; return {}; } } + std::printf("sys_dynlib_dlsym(%s (%s), '%s')\n", module->soName, module->moduleName, rx::linker::encodeNid(rx::linker::encodeFid(symView)).string); + if (auto addr = findSymbolById(module, rx::linker::encodeFid(symView))) { *addrp = addr; return {}; @@ -479,11 +483,14 @@ SysResult processNeeded(Thread *thread) { 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::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)); + 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(); @@ -494,23 +501,25 @@ SysResult processNeeded(Thread *thread) { } if (!hasLoadedNeeded) { - thread->tproc->modulesMap.walk( - [&loadedModules](ModuleHandle modId, Module *module) { - // std::printf("Module '%s' has id %u\n", module->name, - // (unsigned)modId); + 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(mod.name); it != loadedModules.end()) { - module->importedModules.push_back(loadedModules.at(mod.name)); - continue; - } + module->importedModules.clear(); + module->importedModules.reserve(module->neededModules.size()); + for (auto mod : module->neededModules) { + if (auto it = loadedModules.find(mod.name); + it != loadedModules.end()) { + module->importedModules.push_back(loadedModules.at(mod.name)); + continue; + } - std::fprintf(stderr, "Not found needed module '%s' for object '%s'\n", mod.name.c_str(), module->soName); - module->importedModules.push_back({}); - } - }); + std::fprintf(stderr, "Not found needed module '%s' for object '%s'\n", + mod.name.c_str(), module->soName); + module->importedModules.push_back({}); + } + }); break; } @@ -521,7 +530,9 @@ SysResult processNeeded(Thread *thread) { SysResult registerEhFrames(Thread *thread) { for (auto [id, module] : thread->tproc->modulesMap) { - __register_frame(module->ehFrame); + if (module->ehFrame != nullptr) { + __register_frame(module->ehFrame); + } } return {};