mirror of
https://github.com/RPCSX/rpcsx.git
synced 2026-04-04 14:08:37 +00:00
[rpcsx-os] [orbis-kernel] implement lazy symbol binding
Use libSceSysmodule to resolve dependencies Stub /dev/camera
This commit is contained in:
parent
08a097e46e
commit
3232e57445
10 changed files with 345 additions and 79 deletions
|
|
@ -69,6 +69,121 @@ static void allocateTlsOffset(orbis::Process *process, orbis::Module *module) {
|
|||
module->isTlsDone = true;
|
||||
}
|
||||
|
||||
static orbis::SysResult doPltRelocation(orbis::Process *process,
|
||||
orbis::Module *module,
|
||||
orbis::Relocation rel) {
|
||||
auto symbol = module->symbols.at(rel.symbolIndex);
|
||||
|
||||
auto A = rel.addend;
|
||||
auto B = reinterpret_cast<std::uint64_t>(module->base);
|
||||
auto where = reinterpret_cast<std::uint64_t *>(B + rel.offset);
|
||||
auto where32 = reinterpret_cast<std::uint32_t *>(B + rel.offset);
|
||||
auto P = reinterpret_cast<std::uintptr_t>(where);
|
||||
|
||||
auto findDefModule = [module,
|
||||
symbol] -> std::pair<orbis::Module *, std::uint64_t> {
|
||||
if (symbol.moduleIndex == -1 || symbol.bind == orbis::SymbolBind::Local) {
|
||||
return std::pair(module, symbol.address);
|
||||
}
|
||||
|
||||
auto &defModule = module->importedModules.at(symbol.moduleIndex);
|
||||
if (!defModule) {
|
||||
// std::printf(
|
||||
// "Delaying plt relocation '%s' ('%s'), symbol '%llx' in %s
|
||||
// module\n", module->moduleName, module->soName, (unsigned long
|
||||
// long)symbol.id,
|
||||
// module->neededModules[symbol.moduleIndex].name.c_str());
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
auto library = module->neededLibraries.at(symbol.libraryIndex);
|
||||
|
||||
std::vector<std::string> foundInLibs;
|
||||
for (auto defSym : defModule->symbols) {
|
||||
if (defSym.id != symbol.id || defSym.bind == orbis::SymbolBind::Local) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (defSym.visibility == orbis::SymbolVisibility::Hidden) {
|
||||
std::printf("Ignoring hidden symbol\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
auto defLib = defModule->neededLibraries.at(defSym.libraryIndex);
|
||||
|
||||
if (defLib.name == library.name) {
|
||||
return std::pair(defModule.get(), defSym.address);
|
||||
}
|
||||
|
||||
foundInLibs.emplace_back(std::string_view(defLib.name));
|
||||
}
|
||||
|
||||
for (auto nsDefModule : defModule->namespaceModules) {
|
||||
for (auto defSym : nsDefModule->symbols) {
|
||||
if (defSym.id != symbol.id || defSym.bind == orbis::SymbolBind::Local) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (defSym.visibility == orbis::SymbolVisibility::Hidden) {
|
||||
std::printf("Ignoring hidden symbol\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
auto defLib = nsDefModule->neededLibraries.at(defSym.libraryIndex);
|
||||
|
||||
if (defLib.name == library.name) {
|
||||
return std::pair(nsDefModule.get(), defSym.address);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::printf(
|
||||
"'%s' ('%s') uses undefined symbol '%llx' in '%s' ('%s') module\n",
|
||||
module->moduleName, module->soName, (unsigned long long)symbol.id,
|
||||
defModule->moduleName, defModule->soName);
|
||||
if (foundInLibs.size() > 0) {
|
||||
std::printf("Requested library is '%s', exists in libraries: [",
|
||||
library.name.c_str());
|
||||
|
||||
for (bool isFirst = true; auto &lib : foundInLibs) {
|
||||
if (isFirst) {
|
||||
isFirst = false;
|
||||
} else {
|
||||
std::printf(", ");
|
||||
}
|
||||
|
||||
std::printf("'%s'", lib.c_str());
|
||||
}
|
||||
std::printf("]\n");
|
||||
}
|
||||
return std::pair(module, symbol.address);
|
||||
};
|
||||
|
||||
switch (rel.relType) {
|
||||
case kRelJumpSlot: {
|
||||
bool isLazyBind = false; // TODO
|
||||
if (isLazyBind) {
|
||||
*where += B;
|
||||
} else {
|
||||
auto [defObj, S] = findDefModule();
|
||||
|
||||
if (defObj == nullptr) {
|
||||
return orbis::ErrorCode::INVAL;
|
||||
}
|
||||
|
||||
*where = reinterpret_cast<std::uintptr_t>(defObj->base) + S;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
std::fprintf(stderr, "unimplemented relocation type %u\n",
|
||||
(unsigned)rel.relType);
|
||||
std::abort();
|
||||
return {};
|
||||
}
|
||||
|
||||
static orbis::SysResult doRelocation(orbis::Process *process,
|
||||
orbis::Module *module,
|
||||
orbis::Relocation rel) {
|
||||
|
|
@ -80,18 +195,22 @@ static orbis::SysResult doRelocation(orbis::Process *process,
|
|||
auto where32 = reinterpret_cast<std::uint32_t *>(B + rel.offset);
|
||||
auto P = reinterpret_cast<std::uintptr_t>(where);
|
||||
|
||||
auto findDefModule = [module, symbol] {
|
||||
auto findDefModule = [module, symbol,
|
||||
rel] -> std::pair<orbis::Module *, std::uint64_t> {
|
||||
if (symbol.moduleIndex == -1 || symbol.bind == orbis::SymbolBind::Local) {
|
||||
return std::pair(module, symbol.address);
|
||||
}
|
||||
|
||||
auto &defModule = module->importedModules.at(symbol.moduleIndex);
|
||||
if (!defModule) {
|
||||
std::printf(
|
||||
"'%s' ('%s') uses undefined symbol '%llx' in unloaded module\n",
|
||||
module->moduleName, module->soName, (unsigned long long)symbol.id);
|
||||
std::printf("'%s' ('%s') uses undefined symbol '%llx' in unloaded module "
|
||||
"'%s', rel %u\n",
|
||||
module->moduleName, module->soName,
|
||||
(unsigned long long)symbol.id,
|
||||
module->neededModules.at(symbol.moduleIndex).name.c_str(),
|
||||
rel.relType);
|
||||
|
||||
return std::pair(module, symbol.address);
|
||||
return {};
|
||||
}
|
||||
|
||||
auto library = module->neededLibraries.at(symbol.libraryIndex);
|
||||
|
|
@ -162,12 +281,20 @@ static orbis::SysResult doRelocation(orbis::Process *process,
|
|||
return {};
|
||||
case kRel64: {
|
||||
auto [defObj, S] = findDefModule();
|
||||
|
||||
if (defObj == nullptr) {
|
||||
return orbis::ErrorCode::INVAL;
|
||||
}
|
||||
*where = reinterpret_cast<std::uintptr_t>(defObj->base) + S + A;
|
||||
return {};
|
||||
}
|
||||
return {};
|
||||
case kRelPc32: {
|
||||
auto [defObj, S] = findDefModule();
|
||||
|
||||
if (defObj == nullptr) {
|
||||
return orbis::ErrorCode::INVAL;
|
||||
}
|
||||
*where32 = reinterpret_cast<std::uintptr_t>(defObj->base) + S + A - P;
|
||||
return {};
|
||||
}
|
||||
|
|
@ -175,37 +302,39 @@ static orbis::SysResult doRelocation(orbis::Process *process,
|
|||
// return{};
|
||||
case kRelGlobDat: {
|
||||
auto [defObj, S] = findDefModule();
|
||||
|
||||
if (defObj == nullptr) {
|
||||
return orbis::ErrorCode::INVAL;
|
||||
}
|
||||
*where = reinterpret_cast<std::uintptr_t>(defObj->base) + S;
|
||||
return {};
|
||||
}
|
||||
case kRelJumpSlot: {
|
||||
bool isLazyBind = false; // TODO
|
||||
if (isLazyBind) {
|
||||
*where += B;
|
||||
} else {
|
||||
auto [defObj, S] = findDefModule();
|
||||
*where = reinterpret_cast<std::uintptr_t>(defObj->base) + S;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
case kRelRelative:
|
||||
*where = B + A;
|
||||
return {};
|
||||
case kRelDtpMod64: {
|
||||
auto [defObj, S] = findDefModule();
|
||||
if (defObj == nullptr) {
|
||||
return orbis::ErrorCode::INVAL;
|
||||
}
|
||||
*where += defObj->tlsIndex;
|
||||
return {};
|
||||
}
|
||||
case kRelDtpOff64: {
|
||||
auto [defObj, S] = findDefModule();
|
||||
if (defObj == nullptr) {
|
||||
return orbis::ErrorCode::INVAL;
|
||||
}
|
||||
*where += S + A;
|
||||
return {};
|
||||
}
|
||||
case kRelTpOff64: {
|
||||
auto [defObj, S] = findDefModule();
|
||||
if (defObj == nullptr) {
|
||||
return orbis::ErrorCode::INVAL;
|
||||
}
|
||||
if (!defObj->isTlsDone) {
|
||||
allocateTlsOffset(process, module);
|
||||
allocateTlsOffset(process, defObj);
|
||||
}
|
||||
*where = S - defObj->tlsOffset + A;
|
||||
return {};
|
||||
|
|
@ -217,8 +346,11 @@ static orbis::SysResult doRelocation(orbis::Process *process,
|
|||
}
|
||||
case kRelTpOff32: {
|
||||
auto [defObj, S] = findDefModule();
|
||||
if (defObj == nullptr) {
|
||||
return orbis::ErrorCode::INVAL;
|
||||
}
|
||||
if (!defObj->isTlsDone) {
|
||||
allocateTlsOffset(process, module);
|
||||
allocateTlsOffset(process, defObj);
|
||||
}
|
||||
*where32 = S - defObj->tlsOffset + A;
|
||||
return {};
|
||||
|
|
@ -232,25 +364,45 @@ static orbis::SysResult doRelocation(orbis::Process *process,
|
|||
}
|
||||
|
||||
orbis::SysResult orbis::Module::relocate(Process *process) {
|
||||
for (auto rel : pltRelocations) {
|
||||
auto result = doRelocation(process, this, rel);
|
||||
if (!pltRelocations.empty()) {
|
||||
kvector<Relocation> delayedRelocations;
|
||||
std::size_t resolved = 0;
|
||||
std::size_t delayed = 0;
|
||||
for (auto rel : pltRelocations) {
|
||||
auto result = doPltRelocation(process, this, rel);
|
||||
|
||||
if (result.isError()) {
|
||||
return result;
|
||||
if (result.isError()) {
|
||||
delayedRelocations.push_back(rel);
|
||||
++delayed;
|
||||
} else {
|
||||
++resolved;
|
||||
}
|
||||
}
|
||||
|
||||
std::printf("plt relocation of %s: delayed/resolved: %zu/%zu\n", moduleName,
|
||||
delayed, resolved);
|
||||
pltRelocations = std::move(delayedRelocations);
|
||||
}
|
||||
|
||||
pltRelocations = {};
|
||||
if (!nonPltRelocations.empty()) {
|
||||
kvector<Relocation> delayedRelocations;
|
||||
std::size_t resolved = 0;
|
||||
std::size_t delayed = 0;
|
||||
for (auto rel : nonPltRelocations) {
|
||||
auto result = doRelocation(process, this, rel);
|
||||
|
||||
for (auto rel : nonPltRelocations) {
|
||||
auto result = doRelocation(process, this, rel);
|
||||
|
||||
if (result.isError()) {
|
||||
return result;
|
||||
if (result.isError()) {
|
||||
delayedRelocations.push_back(rel);
|
||||
++delayed;
|
||||
} else {
|
||||
++resolved;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nonPltRelocations = {};
|
||||
std::printf("non-plt relocation of %s: delayed/resolved: %zu/%zu\n",
|
||||
moduleName, delayed, resolved);
|
||||
nonPltRelocations = std::move(delayedRelocations);
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -93,7 +93,10 @@ orbis::SysResult orbis::sys_regmgr_call(Thread *thread, uint32_t op,
|
|||
if (int_value->encoded_id == 0x12356328ECF5617B ||
|
||||
int_value->encoded_id == 0x22666251FE7BECFF) {
|
||||
int_value->value = 1;
|
||||
return {};
|
||||
}
|
||||
|
||||
int_value->value = 0;
|
||||
}
|
||||
|
||||
return {};
|
||||
|
|
@ -623,14 +626,30 @@ orbis::SysResult orbis::sys_dmem_container(Thread *thread, uint id) {
|
|||
orbis::SysResult orbis::sys_get_authinfo(Thread *thread, pid_t pid,
|
||||
ptr<void> info) {
|
||||
struct authinfo {
|
||||
uint64_t a;
|
||||
uint64_t b;
|
||||
uint64_t unk0;
|
||||
uint64_t caps[4];
|
||||
uint64_t attrs[4];
|
||||
uint64_t unk[8];
|
||||
};
|
||||
static_assert(sizeof(authinfo) == 136);
|
||||
|
||||
authinfo result {
|
||||
.unk0 = 0x3100000000000001,
|
||||
.caps = {
|
||||
0x2000038000000000,
|
||||
0x000000000000FF00,
|
||||
0x0000000000000000,
|
||||
0x0000000000000000,
|
||||
},
|
||||
.attrs = {
|
||||
0x4000400040000000,
|
||||
0x4000000000000000,
|
||||
0x0080000000000002,
|
||||
0xF0000000FFFF4000,
|
||||
},
|
||||
};
|
||||
|
||||
std::memset(info, 0, 136);
|
||||
((authinfo *)info)->b = ~0;
|
||||
|
||||
return {};
|
||||
return uwrite((ptr<authinfo>)info, result);
|
||||
}
|
||||
orbis::SysResult orbis::sys_mname(Thread *thread, uint64_t addr, uint64_t len,
|
||||
ptr<const char[32]> name) {
|
||||
|
|
@ -688,11 +707,9 @@ orbis::SysResult orbis::sys_dynlib_get_list(Thread *thread,
|
|||
if (actualNum >= numArray) {
|
||||
break;
|
||||
}
|
||||
|
||||
pArray[actualNum++] = id;
|
||||
}
|
||||
uwrite(pActualNum, actualNum);
|
||||
return {};
|
||||
return uwrite(pActualNum, actualNum);
|
||||
}
|
||||
orbis::SysResult orbis::sys_dynlib_get_info(Thread *thread,
|
||||
SceKernelModule handle,
|
||||
|
|
@ -847,7 +864,8 @@ orbis::SysResult orbis::sys_dl_get_metadata(Thread *thread /* TODO */) {
|
|||
return ErrorCode::NOSYS;
|
||||
}
|
||||
orbis::SysResult orbis::sys_workaround8849(Thread *thread /* TODO */) {
|
||||
return ErrorCode::NOSYS;
|
||||
thread->retval[0] = 1;
|
||||
return {};
|
||||
}
|
||||
orbis::SysResult orbis::sys_is_development_mode(Thread *thread /* TODO */) {
|
||||
return ErrorCode::NOSYS;
|
||||
|
|
@ -887,12 +905,12 @@ orbis::sys_dynlib_get_info_ex(Thread *thread, SceKernelModule handle,
|
|||
std::memcpy(result.segments, module->segments,
|
||||
sizeof(ModuleSegment) * module->segmentCount);
|
||||
result.segmentCount = module->segmentCount;
|
||||
result.refCount = module->references.load(std::memory_order::relaxed);
|
||||
result.refCount = 1;
|
||||
ORBIS_LOG_WARNING(__FUNCTION__, result.id, result.name, result.tlsIndex,
|
||||
result.tlsInit, result.tlsInitSize, result.tlsSize,
|
||||
result.tlsOffset, result.tlsAlign, result.initProc,
|
||||
result.finiProc, result.ehFrameHdr, result.ehFrame,
|
||||
result.ehFrameHdrSize, result.ehFrameSize);
|
||||
result.ehFrameHdrSize, result.ehFrameSize, result.segmentCount, result.refCount);
|
||||
return uwrite(destModuleInfoEx, result);
|
||||
}
|
||||
orbis::SysResult orbis::sys_budget_getid(Thread *thread) {
|
||||
|
|
|
|||
|
|
@ -64,6 +64,23 @@ orbis::SysResult orbis::sys___sysctl(Thread *thread, ptr<sint> name,
|
|||
memset(old, 0, sizeof(app_info));
|
||||
return {};
|
||||
}
|
||||
|
||||
if (name[0] == 1 && name[1] == 14 && name[2] == 44) {
|
||||
// GetLibkernelTextLocation
|
||||
if (*oldlenp != 16) {
|
||||
return ErrorCode::INVAL;
|
||||
}
|
||||
|
||||
auto *dest = (uint64_t *)old;
|
||||
|
||||
for (auto [id, mod] : thread->tproc->modulesMap) {
|
||||
if (std::string_view("libkernel") == mod->moduleName) {
|
||||
dest[0] = (uint64_t)mod->segments[0].addr;
|
||||
dest[1] = mod->segments[0].size;
|
||||
return{};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (namelen == 2) {
|
||||
|
|
@ -169,7 +186,7 @@ orbis::SysResult orbis::sys___sysctl(Thread *thread, ptr<sint> name,
|
|||
}
|
||||
|
||||
*(uint32_t *)old = 1;
|
||||
break;
|
||||
return{};
|
||||
|
||||
case sysctl_kern::sdk_version: {
|
||||
if (*oldlenp != 4 || new_ != nullptr || newlen != 0) {
|
||||
|
|
@ -187,7 +204,7 @@ orbis::SysResult orbis::sys___sysctl(Thread *thread, ptr<sint> name,
|
|||
std::printf("Reporting SDK version %x\n",
|
||||
*reinterpret_cast<uint32_t *>(sdkVersion));
|
||||
*(uint32_t *)old = *reinterpret_cast<uint32_t *>(sdkVersion);
|
||||
break;
|
||||
return{};
|
||||
}
|
||||
|
||||
case sysctl_kern::sched_cpusetsize:
|
||||
|
|
@ -196,7 +213,7 @@ orbis::SysResult orbis::sys___sysctl(Thread *thread, ptr<sint> name,
|
|||
}
|
||||
|
||||
*(std::uint32_t *)old = 4;
|
||||
break;
|
||||
return{};
|
||||
|
||||
case sysctl_kern::rng_pseudo:
|
||||
if (*oldlenp != 0x40 || new_ != nullptr || newlen != 0) {
|
||||
|
|
@ -205,7 +222,7 @@ orbis::SysResult orbis::sys___sysctl(Thread *thread, ptr<sint> name,
|
|||
|
||||
|
||||
std::memset(old, 0, 0x40);
|
||||
break;
|
||||
return{};
|
||||
|
||||
case sysctl_kern::kern_37: {
|
||||
struct kern37_value {
|
||||
|
|
@ -220,7 +237,7 @@ orbis::SysResult orbis::sys___sysctl(Thread *thread, ptr<sint> name,
|
|||
|
||||
auto value = (kern37_value *)old;
|
||||
value->size = sizeof(kern37_value);
|
||||
break;
|
||||
return{};
|
||||
}
|
||||
|
||||
case sysctl_kern::proc_ptc: {
|
||||
|
|
@ -229,7 +246,7 @@ orbis::SysResult orbis::sys___sysctl(Thread *thread, ptr<sint> name,
|
|||
}
|
||||
|
||||
*(std::uint64_t *)old = 1357;
|
||||
break;
|
||||
return{};
|
||||
}
|
||||
|
||||
case sysctl_kern::cpu_mode: {
|
||||
|
|
@ -241,7 +258,7 @@ orbis::SysResult orbis::sys___sysctl(Thread *thread, ptr<sint> name,
|
|||
// 1 - 7 cpu, low power
|
||||
// 5 - 7 cpu, normal
|
||||
*(std::uint32_t *)old = 5;
|
||||
break;
|
||||
return{};
|
||||
}
|
||||
|
||||
default:
|
||||
|
|
@ -263,7 +280,7 @@ orbis::SysResult orbis::sys___sysctl(Thread *thread, ptr<sint> name,
|
|||
}
|
||||
|
||||
*(uint32_t *)old = 0x4000;
|
||||
break;
|
||||
return{};
|
||||
|
||||
default:
|
||||
break;
|
||||
|
|
@ -289,5 +306,15 @@ orbis::SysResult orbis::sys___sysctl(Thread *thread, ptr<sint> name,
|
|||
}
|
||||
}
|
||||
|
||||
std::string concatName;
|
||||
for (unsigned int i = 0; i < namelen; ++i) {
|
||||
if (i != 0) {
|
||||
concatName += '.';
|
||||
}
|
||||
|
||||
concatName += std::to_string(name[i]);
|
||||
}
|
||||
|
||||
ORBIS_LOG_TODO(__FUNCTION__, concatName);
|
||||
return {};
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue