Skip to content

Commit

Permalink
[rpcsx-os] [orbis-kernel] implement lazy symbol binding
Browse files Browse the repository at this point in the history
Use libSceSysmodule to resolve dependencies
Stub /dev/camera
  • Loading branch information
DHrpcs3 committed Oct 28, 2023
1 parent 08a097e commit 8b7eee1
Show file tree
Hide file tree
Showing 10 changed files with 352 additions and 82 deletions.
218 changes: 185 additions & 33 deletions orbis-kernel/src/module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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);

return std::pair(module, symbol.address);
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 {};
}

auto library = module->neededLibraries.at(symbol.libraryIndex);
Expand Down Expand Up @@ -162,50 +281,60 @@ 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 {};
}
// case kRelCopy:
// return{};
case kRelGlobDat: {
auto [defObj, S] = findDefModule();
*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;

if (defObj == nullptr) {
return orbis::ErrorCode::INVAL;
}
*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 {};
Expand All @@ -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 {};
Expand All @@ -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 (result.isError()) {
return result;
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()) {
delayedRelocations.push_back(rel);
++delayed;
} else {
++resolved;
}
}
}

pltRelocations = {};

for (auto rel : nonPltRelocations) {
auto result = doRelocation(process, this, rel);
std::printf("plt relocation of %s: delayed/resolved: %zu/%zu\n", moduleName,
delayed, resolved);
pltRelocations = std::move(delayedRelocations);
}

if (result.isError()) {
return result;
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);

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 {};
}
Expand Down
46 changes: 34 additions & 12 deletions orbis-kernel/src/sys/sys_sce.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 {};
Expand Down Expand Up @@ -622,15 +625,35 @@ orbis::SysResult orbis::sys_dmem_container(Thread *thread, uint id) {
}
orbis::SysResult orbis::sys_get_authinfo(Thread *thread, pid_t pid,
ptr<void> info) {
if (pid != thread->tproc->pid) {
return ErrorCode::SRCH;
}

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) {
Expand Down Expand Up @@ -688,11 +711,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,
Expand Down Expand Up @@ -847,7 +868,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;
Expand Down Expand Up @@ -887,12 +909,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) {
Expand Down
Loading

0 comments on commit 8b7eee1

Please sign in to comment.