[rpcsx-os/linker] Implement SceFreeTypeFull building

This commit is contained in:
DH 2023-06-30 17:14:05 +03:00
parent e3444b4fc2
commit cfd1374afa
4 changed files with 101 additions and 27 deletions

@ -1 +1 @@
Subproject commit 287b6e4470c6f6ac5501a3eab17e81e943c4d245
Subproject commit 0a6f130e955a1ed7c4bcfdef0f9975e953435c12

View file

@ -562,7 +562,9 @@ Ref<orbis::Module> rx::linker::loadModule(std::span<std::byte> image,
if (dyn.d_tag == kElfDynamicTypeNeeded) {
auto name = std::string_view(
sceStrtab + static_cast<std::uint32_t>(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<orbis::Module> rx::linker::loadModuleFile(const char *path,
return loadModule(image, process);
}
static Ref<orbis::Module> createSceFreeTypeFull(orbis::Process *process) {
auto result = orbis::create<orbis::Module>();
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<void *>(+[] {});
result->finiProc = reinterpret_cast<void *>(+[] {});
result->id = process->modulesMap.insert(result);
result->proc = process;
return result;
}
Ref<orbis::Module> 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;

View file

@ -4,24 +4,25 @@
#include "orbis/utils/Rc.hpp"
#include <cstddef>
#include <filesystem>
#include <optional>
#include <span>
namespace rx::linker {
inline constexpr char nidLookup[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-";
constexpr std::uint64_t decodeNid(std::string_view nid) {
constexpr std::optional<std::uint64_t> 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<uint32_t>(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 {

View file

@ -40,7 +40,7 @@ orbis::SysResult mmap(orbis::Thread *thread, orbis::caddr_t addr,
}
thread->retval[0] = reinterpret_cast<std::uint64_t>(result);
return{};
return {};
}
orbis::SysResult munmap(orbis::Thread *thread, orbis::ptr<void> 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 {};