Skip to content

Commit

Permalink
linker: initial ps5 Dyn/DynExec support
Browse files Browse the repository at this point in the history
  • Loading branch information
DHrpcs3 committed Nov 17, 2024
1 parent b983ca6 commit 0218bcd
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 37 deletions.
12 changes: 12 additions & 0 deletions rpcsx/iodev/dce.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,18 @@ static orbis::ErrorCode dce_ioctl(orbis::File *file, std::uint64_t request,
return {};
}

if (request == 0x80308217) {
ORBIS_LOG_ERROR(__FUNCTION__, request);
thread->where();
return{};
}

if (request == 0x80208218) {
ORBIS_LOG_ERROR(__FUNCTION__, request);
thread->where();
return{};
}

if (request == 0x80088209) { // deallocate?
auto arg = *reinterpret_cast<std::uint64_t *>(argp);
ORBIS_LOG_ERROR("dce: 0x80088209", arg);
Expand Down
99 changes: 64 additions & 35 deletions rpcsx/linker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ enum OrbisElfDynamicType {
kElfDynamicTypeSymbolic = 16,
kElfDynamicTypeRel = 17,
kElfDynamicTypeRelSize = 18,
kElfDynamicTypeRelEent = 19,
kElfDynamicTypeRelEnt = 19,
kElfDynamicTypePltRel = 20,
kElfDynamicTypeDebug = 21,
kElfDynamicTypeTextRel = 22,
Expand Down Expand Up @@ -191,6 +191,7 @@ enum OrbisElfDynamicType {
kElfDynamicTypeSceOriginalFilename1 = 0x61000041,
kElfDynamicTypeSceModuleInfo1 = 0x61000043,
kElfDynamicTypeSceNeededModule1 = 0x61000045,
kElfDynamicTypeSceExportLib1 = 0x61000047,
kElfDynamicTypeSceImportLib1 = 0x61000049,
kElfDynamicTypeSceSymTabSize = 0x6100003f,
kElfDynamicTypeRelaCount = 0x6ffffff9
Expand Down Expand Up @@ -236,8 +237,8 @@ inline const char *toString(OrbisElfDynamicType dynType) {
return "Rel";
case kElfDynamicTypeRelSize:
return "RelSize";
case kElfDynamicTypeRelEent:
return "RelEent";
case kElfDynamicTypeRelEnt:
return "RelEnt";
case kElfDynamicTypePltRel:
return "PltRel";
case kElfDynamicTypeDebug:
Expand Down Expand Up @@ -320,6 +321,8 @@ inline const char *toString(OrbisElfDynamicType dynType) {
return "SceSymTabSize";
case kElfDynamicTypeRelaCount:
return "RelaCount";
case kElfDynamicTypeSceExportLib1:
return "SceExportLib1";
}

return "<unknown>";
Expand Down Expand Up @@ -457,9 +460,9 @@ Ref<orbis::Module> rx::linker::loadModule(std::span<std::byte> image,

auto imageBase = reinterpret_cast<std::byte *>(
vm::map(reinterpret_cast<void *>(baseAddress),
rx::alignUp(imageSize, vm::kPageSize), 0,
vm::kMapFlagPrivate | vm::kMapFlagAnonymous |
(baseAddress ? vm::kMapFlagFixed : 0)));
rx::alignUp(imageSize, vm::kPageSize), 0,
vm::kMapFlagPrivate | vm::kMapFlagAnonymous |
(baseAddress ? vm::kMapFlagFixed : 0)));

if (imageBase == MAP_FAILED) {
std::abort();
Expand Down Expand Up @@ -566,6 +569,11 @@ Ref<orbis::Module> rx::linker::loadModule(std::span<std::byte> image,
result->ehFrameSize = dataBufferIt - dataBuffer;
}

orbis::Relocation *pltRelocations = nullptr;
std::size_t pltRelocationCount = 0;
orbis::Relocation *nonPltRelocations = nullptr;
std::size_t nonPltRelocationCount = 0;

if (dynamicPhdrIndex >= 0 && phdrs[dynamicPhdrIndex].p_filesz > 0) {
auto &dynPhdr = phdrs[dynamicPhdrIndex];
std::vector<Elf64_Dyn> dyns(dynPhdr.p_filesz / sizeof(Elf64_Dyn));
Expand Down Expand Up @@ -655,15 +663,11 @@ Ref<orbis::Module> rx::linker::loadModule(std::span<std::byte> image,
std::unordered_map<std::uint64_t, std::size_t> idToModuleIndex;
std::unordered_map<std::uint64_t, std::size_t> idToLibraryIndex;

orbis::Relocation *pltRelocations = nullptr;
std::size_t pltRelocationCount = 0;
orbis::Relocation *nonPltRelocations = nullptr;
std::size_t nonPltRelocationCount = 0;

for (auto dyn : dyns) {
if (dyn.d_tag == kElfDynamicTypeSceModuleInfo) {
if (dyn.d_tag == kElfDynamicTypeSceModuleInfo ||
dyn.d_tag == kElfDynamicTypeSceModuleInfo1) {
std::strncpy(result->moduleName,
sceStrtab + static_cast<std::uint32_t>(dyn.d_un.d_val),
strtab + static_cast<std::uint32_t>(dyn.d_un.d_val),
sizeof(result->moduleName));
} else if (dyn.d_tag == kElfDynamicTypeSceModuleAttr) {
result->attributes = dyn.d_un.d_val;
Expand All @@ -675,11 +679,13 @@ Ref<orbis::Module> rx::linker::loadModule(std::span<std::byte> image,
sizeof(result->soName));
}

if (dyn.d_tag == kElfDynamicTypeSceModuleInfo) {
if (dyn.d_tag == kElfDynamicTypeSceModuleInfo ||
dyn.d_tag == kElfDynamicTypeSceModuleInfo1) {
idToModuleIndex[dyn.d_un.d_val >> 48] = -1;
}

if (dyn.d_tag == kElfDynamicTypeSceNeededModule) {
if (dyn.d_tag == kElfDynamicTypeSceNeededModule ||
dyn.d_tag == kElfDynamicTypeSceNeededModule1) {
auto [it, inserted] = idToModuleIndex.try_emplace(
dyn.d_un.d_val >> 48, result->neededModules.size());

Expand All @@ -692,7 +698,9 @@ Ref<orbis::Module> rx::linker::loadModule(std::span<std::byte> image,
mod.attr = static_cast<std::uint16_t>(dyn.d_un.d_val >> 32);
mod.isExport = false;
} else if (dyn.d_tag == kElfDynamicTypeSceImportLib ||
dyn.d_tag == kElfDynamicTypeSceExportLib) {
dyn.d_tag == kElfDynamicTypeSceImportLib1 ||
dyn.d_tag == kElfDynamicTypeSceExportLib ||
dyn.d_tag == kElfDynamicTypeSceExportLib1) {
auto [it, inserted] = idToLibraryIndex.try_emplace(
dyn.d_un.d_val >> 48, result->neededLibraries.size());

Expand All @@ -703,7 +711,8 @@ Ref<orbis::Module> rx::linker::loadModule(std::span<std::byte> image,
auto &lib = result->neededLibraries[it->second];

lib.name = strtab + static_cast<std::uint32_t>(dyn.d_un.d_val);
lib.isExport = dyn.d_tag == kElfDynamicTypeSceExportLib;
lib.isExport = dyn.d_tag == kElfDynamicTypeSceExportLib ||
dyn.d_tag == kElfDynamicTypeSceExportLib1;
} else if (dyn.d_tag == kElfDynamicTypeSceExportLibAttr ||
dyn.d_tag == kElfDynamicTypeSceImportLibAttr) {
auto [it, inserted] = idToLibraryIndex.try_emplace(
Expand All @@ -719,13 +728,19 @@ Ref<orbis::Module> rx::linker::loadModule(std::span<std::byte> image,
}

switch (dyn.d_tag) {
case kElfDynamicTypePltGot:
case kElfDynamicTypeScePltGot:
result->pltGot = dyn.d_un.d_ptr
? reinterpret_cast<std::uint64_t *>(
imageBase - baseAddress + dyn.d_un.d_ptr)
: nullptr;
break;

case kElfDynamicTypeJmpRel:
pltRelocations = reinterpret_cast<orbis::Relocation *>(
imageBase - baseAddress + dyn.d_un.d_ptr);
break;

case kElfDynamicTypeSceJmpRel:
if (sceDynlibData != nullptr) {
pltRelocations = reinterpret_cast<orbis::Relocation *>(
Expand All @@ -737,9 +752,16 @@ Ref<orbis::Module> rx::linker::loadModule(std::span<std::byte> image,
break;
case kElfDynamicTypeScePltRel:
break;
case kElfDynamicTypePltRelSize:
case kElfDynamicTypeScePltRelSize:
pltRelocationCount = dyn.d_un.d_val / sizeof(orbis::Relocation);
break;

case kElfDynamicTypeRela:
nonPltRelocations = reinterpret_cast<orbis::Relocation *>(
imageBase - baseAddress + dyn.d_un.d_ptr);
break;

case kElfDynamicTypeSceRela:
if (sceDynlibData != nullptr) {
nonPltRelocations = reinterpret_cast<orbis::Relocation *>(
Expand All @@ -749,6 +771,7 @@ Ref<orbis::Module> rx::linker::loadModule(std::span<std::byte> image,
image.data() + dyn.d_un.d_ptr);
}
break;
case kElfDynamicTypeRelaSize:
case kElfDynamicTypeSceRelaSize:
nonPltRelocationCount = dyn.d_un.d_val / sizeof(orbis::Relocation);
break;
Expand Down Expand Up @@ -831,25 +854,12 @@ Ref<orbis::Module> rx::linker::loadModule(std::span<std::byte> image,
result->symbols.push_back(symbol);
}
}

if (pltRelocations != nullptr && pltRelocationCount > 0) {
result->pltRelocations.reserve(pltRelocationCount);
for (auto rel : std::span(pltRelocations, pltRelocationCount)) {
result->pltRelocations.push_back(rel);
}
}

if (nonPltRelocations != nullptr && nonPltRelocationCount > 0) {
result->nonPltRelocations.reserve(nonPltRelocationCount);
for (auto rel : std::span(nonPltRelocations, nonPltRelocationCount)) {
result->nonPltRelocations.push_back(rel);
}
}
}

for (auto phdr : phdrs) {
if (phdr.p_type == kElfProgramTypeLoad ||
phdr.p_type == kElfProgramTypeSceRelRo) {
phdr.p_type == kElfProgramTypeSceRelRo ||
phdr.p_type == kElfProgramTypeGnuRelRo) {
auto segmentEnd = rx::alignUp(phdr.p_vaddr + phdr.p_memsz, vm::kPageSize);
auto segmentBegin =
rx::alignDown(phdr.p_vaddr - baseAddress, phdr.p_align);
Expand All @@ -858,7 +868,8 @@ Ref<orbis::Module> rx::linker::loadModule(std::span<std::byte> image,
std::memcpy(imageBase + phdr.p_vaddr - baseAddress,
image.data() + phdr.p_offset, phdr.p_filesz);

if (phdr.p_type == kElfProgramTypeSceRelRo) {
if (phdr.p_type == kElfProgramTypeSceRelRo ||
phdr.p_type == kElfProgramTypeGnuRelRo) {
phdr.p_flags |= vm::kMapProtCpuWrite; // TODO: reprotect on relocations
}

Expand All @@ -874,6 +885,10 @@ Ref<orbis::Module> rx::linker::loadModule(std::span<std::byte> image,
mapFlags |= vm::kMapProtCpuRead;
}

if (mapFlags == 0) {
mapFlags = vm::kMapProtCpuWrite;
}

vm::protect(imageBase + segmentBegin, segmentSize, mapFlags);

if (phdr.p_type == kElfProgramTypeLoad) {
Expand All @@ -889,6 +904,20 @@ Ref<orbis::Module> rx::linker::loadModule(std::span<std::byte> image,
}
}

if (pltRelocations != nullptr && pltRelocationCount > 0) {
result->pltRelocations.reserve(pltRelocationCount);
for (auto rel : std::span(pltRelocations, pltRelocationCount)) {
result->pltRelocations.push_back(rel);
}
}

if (nonPltRelocations != nullptr && nonPltRelocationCount > 0) {
result->nonPltRelocations.reserve(nonPltRelocationCount);
for (auto rel : std::span(nonPltRelocations, nonPltRelocationCount)) {
result->nonPltRelocations.push_back(rel);
}
}

result->base = imageBase - baseAddress;
result->size = imageSize + baseAddress;
result->phdrAddress = phdrPhdrIndex >= 0 ? phdrs[phdrPhdrIndex].p_vaddr
Expand All @@ -899,12 +928,12 @@ Ref<orbis::Module> rx::linker::loadModule(std::span<std::byte> image,
std::printf("Loaded module '%s' (%lx) from object '%s', address: %p - %p\n",
result->moduleName, (unsigned long)result->attributes,
result->soName, imageBase, (char *)imageBase + result->size);
for (auto mod : result->neededModules) {
for (const auto &mod : result->neededModules) {
std::printf(" needed module '%s' (%lx)\n", mod.name.c_str(),
(unsigned long)mod.attr);
}

for (auto lib : result->neededLibraries) {
for (const auto &lib : result->neededLibraries) {
std::printf(" needed library '%s' (%lx), kind %s\n", lib.name.c_str(),
(unsigned long)lib.attr, lib.isExport ? "export" : "import");
}
Expand Down
6 changes: 4 additions & 2 deletions rpcsx/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -604,11 +604,13 @@ ExecEnv ps4CreateExecEnv(orbis::Thread *mainThread,
mainThread->tproc->sdkVersion = orbis::g_context.sdkVersion;
}

if (executableModule->interp.empty()) {
if (executableModule->type == rx::linker::kElfTypeExec ||
executableModule->type == rx::linker::kElfTypeSceExec) {
return {.entryPoint = entryPoint, .interpBase = interpBase};
}

if (vfs::exists(executableModule->interp, mainThread)) {
if (!executableModule->interp.empty() &&
vfs::exists(executableModule->interp, mainThread)) {
auto loader =
rx::linker::loadModuleFile(executableModule->interp, mainThread);
loader->id = mainThread->tproc->modulesMap.insert(loader);
Expand Down

0 comments on commit 0218bcd

Please sign in to comment.