linker: initial ps5 Dyn/DynExec support

This commit is contained in:
DH 2024-11-18 00:59:01 +03:00
parent b983ca6aa5
commit 0218bcd06a
3 changed files with 80 additions and 37 deletions

View File

@ -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);

View File

@ -152,7 +152,7 @@ enum OrbisElfDynamicType {
kElfDynamicTypeSymbolic = 16,
kElfDynamicTypeRel = 17,
kElfDynamicTypeRelSize = 18,
kElfDynamicTypeRelEent = 19,
kElfDynamicTypeRelEnt = 19,
kElfDynamicTypePltRel = 20,
kElfDynamicTypeDebug = 21,
kElfDynamicTypeTextRel = 22,
@ -191,6 +191,7 @@ enum OrbisElfDynamicType {
kElfDynamicTypeSceOriginalFilename1 = 0x61000041,
kElfDynamicTypeSceModuleInfo1 = 0x61000043,
kElfDynamicTypeSceNeededModule1 = 0x61000045,
kElfDynamicTypeSceExportLib1 = 0x61000047,
kElfDynamicTypeSceImportLib1 = 0x61000049,
kElfDynamicTypeSceSymTabSize = 0x6100003f,
kElfDynamicTypeRelaCount = 0x6ffffff9
@ -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:
@ -320,6 +321,8 @@ inline const char *toString(OrbisElfDynamicType dynType) {
return "SceSymTabSize";
case kElfDynamicTypeRelaCount:
return "RelaCount";
case kElfDynamicTypeSceExportLib1:
return "SceExportLib1";
}
return "<unknown>";
@ -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();
@ -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));
@ -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;
@ -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());
@ -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());
@ -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(
@ -719,6 +728,7 @@ 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 *>(
@ -726,6 +736,11 @@ Ref<orbis::Module> rx::linker::loadModule(std::span<std::byte> image,
: 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 *>(
@ -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 *>(
@ -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;
@ -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);
@ -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
}
@ -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) {
@ -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
@ -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");
}

View File

@ -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);