[rpcsx-os/loader] Search for needed by object name

This commit is contained in:
DH 2023-06-29 21:23:02 +03:00
parent 56c2e3a447
commit e6f6c37675
4 changed files with 107 additions and 47 deletions

@ -1 +1 @@
Subproject commit 4cddf2723ff1742e2519c699e3a66ca61324f760
Subproject commit ce17db5749169f42a242591c2d7a9fe105fbf760

View file

@ -4,13 +4,13 @@
#include "orbis/module/Module.hpp"
#include "vfs.hpp"
#include "vm.hpp"
#include <crypto/sha1.h>
#include <elf.h>
#include <map>
#include <memory>
#include <orbis/thread/Process.hpp>
#include <sys/mman.h>
#include <unordered_map>
#include <crypto/sha1.h>
using orbis::utils::Ref;
@ -269,13 +269,17 @@ struct Symbol {
std::uint64_t bindMode;
};
static std::map<std::string, std::filesystem::path, std::less<>> g_moduleOverrideTable;
static std::map<std::string, std::filesystem::path, std::less<>>
g_moduleOverrideTable;
void rx::linker::override(std::string originalModuleName, std::filesystem::path replacedModulePath) {
g_moduleOverrideTable[std::move(originalModuleName)] = std::move(replacedModulePath);
void rx::linker::override(std::string originalModuleName,
std::filesystem::path replacedModulePath) {
g_moduleOverrideTable[std::move(originalModuleName)] =
std::move(replacedModulePath);
}
Ref<orbis::Module> rx::linker::loadModule(std::span<std::byte> image, orbis::Process *process) {
Ref<orbis::Module> rx::linker::loadModule(std::span<std::byte> image,
orbis::Process *process) {
Ref<orbis::Module> result{new orbis::Module{}};
Elf64_Ehdr header;
@ -315,8 +319,8 @@ Ref<orbis::Module> rx::linker::loadModule(std::span<std::byte> image, orbis::Pro
case kElfProgramTypeNull:
break;
case kElfProgramTypeLoad:
baseAddress = std::min(
baseAddress, utils::alignDown(phdr.p_vaddr, phdr.p_align));
baseAddress =
std::min(baseAddress, utils::alignDown(phdr.p_vaddr, phdr.p_align));
imageSize = std::max(
imageSize, utils::alignUp(phdr.p_vaddr + phdr.p_memsz, phdr.p_align));
break;
@ -349,8 +353,8 @@ Ref<orbis::Module> rx::linker::loadModule(std::span<std::byte> image, orbis::Pro
break;
case kElfProgramTypeSceRelRo:
sceRelRoPhdrIndex = index;
baseAddress = std::min(
baseAddress, utils::alignDown(phdr.p_vaddr, phdr.p_align));
baseAddress =
std::min(baseAddress, utils::alignDown(phdr.p_vaddr, phdr.p_align));
imageSize = std::max(
imageSize, utils::alignUp(phdr.p_vaddr + phdr.p_memsz, phdr.p_align));
break;
@ -370,30 +374,40 @@ Ref<orbis::Module> rx::linker::loadModule(std::span<std::byte> image, orbis::Pro
}
auto imageBase = reinterpret_cast<std::byte *>(
rx::vm::map(reinterpret_cast<void *>(baseAddress), utils::alignUp(imageSize, rx::vm::kPageSize),
rx::vm::kMapProtCpuRead | rx::vm::kMapProtCpuWrite,
rx::vm::kMapFlagPrivate | rx::vm::kMapFlagAnonymous));
rx::vm::map(reinterpret_cast<void *>(baseAddress),
utils::alignUp(imageSize, rx::vm::kPageSize),
rx::vm::kMapProtCpuRead | rx::vm::kMapProtCpuWrite,
rx::vm::kMapFlagPrivate | rx::vm::kMapFlagAnonymous));
if (imageBase == MAP_FAILED) {
std::abort();
}
result->entryPoint =
header.e_entry ? reinterpret_cast<std::uintptr_t>(imageBase + header.e_entry) : 0;
header.e_entry
? reinterpret_cast<std::uintptr_t>(imageBase + header.e_entry)
: 0;
if (sceProcParamIndex >= 0) {
result->processParam =
phdrs[sceProcParamIndex].p_vaddr ? reinterpret_cast<void *>(imageBase + phdrs[sceProcParamIndex].p_vaddr) : nullptr;
phdrs[sceProcParamIndex].p_vaddr
? reinterpret_cast<void *>(imageBase +
phdrs[sceProcParamIndex].p_vaddr)
: nullptr;
result->processParamSize = phdrs[sceProcParamIndex].p_memsz;
}
if (sceModuleParamIndex >= 0) {
result->moduleParam =
phdrs[sceProcParamIndex].p_vaddr ? reinterpret_cast<void *>(imageBase + phdrs[sceModuleParamIndex].p_vaddr) : nullptr;
phdrs[sceProcParamIndex].p_vaddr
? reinterpret_cast<void *>(imageBase +
phdrs[sceModuleParamIndex].p_vaddr)
: nullptr;
result->moduleParamSize = phdrs[sceModuleParamIndex].p_memsz;
// std::printf("sce_module_param: ");
// for (auto elem : image.subspan(phdrs[sceModuleParamIndex].p_offset, phdrs[sceModuleParamIndex].p_filesz)) {
// for (auto elem : image.subspan(phdrs[sceModuleParamIndex].p_offset,
// phdrs[sceModuleParamIndex].p_filesz)) {
// std::printf(" %02x", (unsigned)elem);
// }
// std::printf("\n");
@ -403,7 +417,9 @@ Ref<orbis::Module> rx::linker::loadModule(std::span<std::byte> image, orbis::Pro
result->tlsAlign = phdrs[tlsPhdrIndex].p_align;
result->tlsSize = phdrs[tlsPhdrIndex].p_memsz;
result->tlsInitSize = phdrs[tlsPhdrIndex].p_filesz;
result->tlsInit = phdrs[tlsPhdrIndex].p_vaddr ? imageBase + phdrs[tlsPhdrIndex].p_vaddr : nullptr;
result->tlsInit = phdrs[tlsPhdrIndex].p_vaddr
? imageBase + phdrs[tlsPhdrIndex].p_vaddr
: nullptr;
}
if (gnuEhFramePhdrIndex >= 0 && phdrs[gnuEhFramePhdrIndex].p_vaddr > 0) {
@ -462,7 +478,9 @@ Ref<orbis::Module> rx::linker::loadModule(std::span<std::byte> image, orbis::Pro
dataBufferIt += size;
}
result->ehFrame = imageBase + phdrs[gnuEhFramePhdrIndex].p_vaddr + (dataBuffer - image.data() - phdrs[gnuEhFramePhdrIndex].p_offset);
result->ehFrame =
imageBase + phdrs[gnuEhFramePhdrIndex].p_vaddr +
(dataBuffer - image.data() - phdrs[gnuEhFramePhdrIndex].p_offset);
result->ehFrameSize = dataBufferIt - dataBuffer;
}
@ -471,7 +489,8 @@ Ref<orbis::Module> rx::linker::loadModule(std::span<std::byte> image, orbis::Pro
phdr.p_type == kElfProgramTypeSceRelRo) {
std::memcpy(imageBase + phdr.p_vaddr, image.data() + phdr.p_offset,
phdr.p_filesz);
std::memset(imageBase + phdr.p_vaddr + phdr.p_filesz, 0, phdr.p_memsz - phdr.p_filesz);
std::memset(imageBase + phdr.p_vaddr + phdr.p_filesz, 0,
phdr.p_memsz - phdr.p_filesz);
if (phdr.p_type == kElfProgramTypeLoad) {
if (result->segmentCount >= std::size(result->segments)) {
@ -542,16 +561,36 @@ Ref<orbis::Module> rx::linker::loadModule(std::span<std::byte> image, orbis::Pro
// dyn.d_tag == kElfDynamicTypeSceModuleInfo) {
// std::printf(" ('%s')",
// sceStrtab
// ? sceStrtab + static_cast<std::uint32_t>(dyn.d_un.d_val)
// : "<no strtab>");
// ? sceStrtab +
// static_cast<std::uint32_t>(dyn.d_un.d_val) : "<no
// strtab>");
// }
// std::printf("\n");
if (dyn.d_tag == kElfDynamicTypeSceModuleInfo) {
std::strncpy(result->name,
std::strncpy(result->moduleName,
sceStrtab + static_cast<std::uint32_t>(dyn.d_un.d_val),
sizeof(result->name));
sizeof(result->moduleName));
}
if (dyn.d_tag == kElfDynamicTypeSoName) {
std::strncpy(result->soName,
sceStrtab + static_cast<std::uint32_t>(dyn.d_un.d_val),
sizeof(result->soName));
}
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")) {
result->needed.push_back(std::string(name));
} else if (name == "STREQUAL") {
// HACK for broken FWs
result->needed.push_back("libSceDolbyVision.prx");
} else {
std::fprintf(stderr, "Ignoring needed '%s'\n", name.data());
}
}
if (dyn.d_tag == kElfDynamicTypeSceModuleInfo) {
@ -566,8 +605,9 @@ Ref<orbis::Module> rx::linker::loadModule(std::span<std::byte> image, orbis::Pro
result->neededModules.emplace_back();
}
result->neededModules[it->second].name =
sceStrtab + static_cast<std::uint32_t>(dyn.d_un.d_val);
auto &mod = result->neededModules[it->second];
mod.name = sceStrtab + static_cast<std::uint32_t>(dyn.d_un.d_val);
mod.isExport = false;
} else if (dyn.d_tag == kElfDynamicTypeSceImportLib ||
dyn.d_tag == kElfDynamicTypeSceExportLib) {
auto [it, inserted] = idToLibraryIndex.try_emplace(
@ -577,14 +617,18 @@ Ref<orbis::Module> rx::linker::loadModule(std::span<std::byte> image, orbis::Pro
result->neededLibraries.emplace_back();
}
result->neededLibraries[it->second].name =
sceStrtab + static_cast<std::uint32_t>(dyn.d_un.d_val);
auto &lib = result->neededLibraries[it->second];
lib.name = sceStrtab + static_cast<std::uint32_t>(dyn.d_un.d_val);
lib.isExport = dyn.d_tag == kElfDynamicTypeSceExportLib;
}
switch (dyn.d_tag) {
case kElfDynamicTypeScePltGot:
result->pltGot = dyn.d_un.d_ptr ?
reinterpret_cast<std::uint64_t *>(imageBase + dyn.d_un.d_ptr) : nullptr;
result->pltGot =
dyn.d_un.d_ptr
? reinterpret_cast<std::uint64_t *>(imageBase + dyn.d_un.d_ptr)
: nullptr;
break;
case kElfDynamicTypeSceJmpRel:
@ -693,9 +737,6 @@ Ref<orbis::Module> rx::linker::loadModule(std::span<std::byte> image, orbis::Pro
result->base = imageBase;
result->size = imageSize;
// std::printf("Module %s (%p - %p)\n", result->name, result->base,
// (char *)result->base + result->size);
// std::printf("Needed modules: [");
// for (bool isFirst = true; auto &module : result->neededModules) {
// if (isFirst) {
@ -725,6 +766,11 @@ Ref<orbis::Module> rx::linker::loadModule(std::span<std::byte> image, orbis::Pro
result->id = process->modulesMap.insert(result);
result->proc = process;
std::printf("Loaded module '%s' from object '%s', id: %u, address: %p - %p\n",
result->moduleName, result->soName, (unsigned)result->id,
result->base, (char *)result->base + result->size);
if (tlsPhdrIndex >= 0 /* result->tlsSize != 0 */) {
result->tlsIndex = process->nextTlsSlot++;
}
@ -736,7 +782,7 @@ Ref<orbis::Module> rx::linker::loadModuleFile(const char *path,
orbis::Process *process) {
orbis::Ref<IoDeviceInstance> instance;
if (vfs::open(path, kOpenFlagReadOnly, 0, &instance).isError()) {
return{};
return {};
}
auto len = instance->lseek(instance.get(), 0, SEEK_END);
@ -760,8 +806,14 @@ Ref<orbis::Module> rx::linker::loadModuleFile(const char *path,
return loadModule(image, process);
}
Ref<orbis::Module> rx::linker::loadModuleByName(std::string_view name, orbis::Process *process) {
if (auto it = g_moduleOverrideTable.find(name); it != g_moduleOverrideTable.end()) {
Ref<orbis::Module> rx::linker::loadModuleByName(std::string_view name,
orbis::Process *process) {
if (name.ends_with(".prx")) {
name.remove_suffix(4);
}
if (auto it = g_moduleOverrideTable.find(name);
it != g_moduleOverrideTable.end()) {
return loadModuleFile(it->second.c_str(), process);
}
@ -775,5 +827,5 @@ Ref<orbis::Module> rx::linker::loadModuleByName(std::string_view name, orbis::Pr
}
}
return{};
return {};
}

View file

@ -102,7 +102,7 @@ static std::size_t printAddressLocation(char *dest, std::size_t destLen,
continue;
}
return std::snprintf(dest, destLen, "%s+%#" PRIx64, module->name,
return std::snprintf(dest, destLen, "%s+%#" PRIx64, module->soName,
address - moduleBase);
}
@ -460,7 +460,7 @@ static int ps4Exec(orbis::Process *mainProcess,
std::vector<std::uint64_t> envpOffsets;
auto libkernel = rx::linker::loadModuleFile(
"/system/common/lib/libkernel_sys.sprx", mainProcess);
"/system/common/lib/libkernel.sprx", mainProcess);
// *reinterpret_cast<std::uint32_t *>(
// reinterpret_cast<std::byte *>(libkernel->base) + 0x6c2e4) = ~0;

View file

@ -449,29 +449,31 @@ orbis::SysResult exit(orbis::Thread *thread, orbis::sint status) {
SysResult processNeeded(Thread *thread) {
while (true) {
std::set<std::string> allNeededModules;
std::set<std::string> allNeededObjects;
auto proc = thread->tproc;
std::map<std::string, Module *> loadedModules;
std::map<std::string, Module *> loadedObjects;
for (auto [id, module] : proc->modulesMap) {
for (auto mod : module->neededModules) {
allNeededModules.insert(mod.name);
for (const auto &object : module->needed) {
allNeededObjects.insert(object);
}
loadedModules[module->name] = module;
loadedModules[module->moduleName] = module;
loadedObjects[module->soName] = module;
}
bool hasLoadedNeeded = false;
for (auto &needed : allNeededModules) {
if (auto it = loadedModules.find(needed); it != loadedModules.end()) {
for (auto &needed : allNeededObjects) {
if (auto it = loadedObjects.find(needed); it != loadedObjects.end()) {
continue;
}
auto neededModule = rx::linker::loadModuleByName(needed, proc);
if (neededModule == nullptr) {
std::printf("Needed '%s' not found\n", needed.c_str());
std::fprintf(stderr, "Needed '%s' not found\n", needed.c_str());
return ErrorCode::NOENT;
}
@ -487,7 +489,13 @@ SysResult processNeeded(Thread *thread) {
module->importedModules.clear();
module->importedModules.reserve(module->neededModules.size());
for (auto mod : module->neededModules) {
module->importedModules.push_back(loadedModules.at(mod.name));
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);
std::abort();
}
});