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 {}; 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? if (request == 0x80088209) { // deallocate?
auto arg = *reinterpret_cast<std::uint64_t *>(argp); auto arg = *reinterpret_cast<std::uint64_t *>(argp);
ORBIS_LOG_ERROR("dce: 0x80088209", arg); ORBIS_LOG_ERROR("dce: 0x80088209", arg);

View file

@ -152,7 +152,7 @@ enum OrbisElfDynamicType {
kElfDynamicTypeSymbolic = 16, kElfDynamicTypeSymbolic = 16,
kElfDynamicTypeRel = 17, kElfDynamicTypeRel = 17,
kElfDynamicTypeRelSize = 18, kElfDynamicTypeRelSize = 18,
kElfDynamicTypeRelEent = 19, kElfDynamicTypeRelEnt = 19,
kElfDynamicTypePltRel = 20, kElfDynamicTypePltRel = 20,
kElfDynamicTypeDebug = 21, kElfDynamicTypeDebug = 21,
kElfDynamicTypeTextRel = 22, kElfDynamicTypeTextRel = 22,
@ -191,6 +191,7 @@ enum OrbisElfDynamicType {
kElfDynamicTypeSceOriginalFilename1 = 0x61000041, kElfDynamicTypeSceOriginalFilename1 = 0x61000041,
kElfDynamicTypeSceModuleInfo1 = 0x61000043, kElfDynamicTypeSceModuleInfo1 = 0x61000043,
kElfDynamicTypeSceNeededModule1 = 0x61000045, kElfDynamicTypeSceNeededModule1 = 0x61000045,
kElfDynamicTypeSceExportLib1 = 0x61000047,
kElfDynamicTypeSceImportLib1 = 0x61000049, kElfDynamicTypeSceImportLib1 = 0x61000049,
kElfDynamicTypeSceSymTabSize = 0x6100003f, kElfDynamicTypeSceSymTabSize = 0x6100003f,
kElfDynamicTypeRelaCount = 0x6ffffff9 kElfDynamicTypeRelaCount = 0x6ffffff9
@ -236,8 +237,8 @@ inline const char *toString(OrbisElfDynamicType dynType) {
return "Rel"; return "Rel";
case kElfDynamicTypeRelSize: case kElfDynamicTypeRelSize:
return "RelSize"; return "RelSize";
case kElfDynamicTypeRelEent: case kElfDynamicTypeRelEnt:
return "RelEent"; return "RelEnt";
case kElfDynamicTypePltRel: case kElfDynamicTypePltRel:
return "PltRel"; return "PltRel";
case kElfDynamicTypeDebug: case kElfDynamicTypeDebug:
@ -320,6 +321,8 @@ inline const char *toString(OrbisElfDynamicType dynType) {
return "SceSymTabSize"; return "SceSymTabSize";
case kElfDynamicTypeRelaCount: case kElfDynamicTypeRelaCount:
return "RelaCount"; return "RelaCount";
case kElfDynamicTypeSceExportLib1:
return "SceExportLib1";
} }
return "<unknown>"; return "<unknown>";
@ -457,9 +460,9 @@ Ref<orbis::Module> rx::linker::loadModule(std::span<std::byte> image,
auto imageBase = reinterpret_cast<std::byte *>( auto imageBase = reinterpret_cast<std::byte *>(
vm::map(reinterpret_cast<void *>(baseAddress), vm::map(reinterpret_cast<void *>(baseAddress),
rx::alignUp(imageSize, vm::kPageSize), 0, rx::alignUp(imageSize, vm::kPageSize), 0,
vm::kMapFlagPrivate | vm::kMapFlagAnonymous | vm::kMapFlagPrivate | vm::kMapFlagAnonymous |
(baseAddress ? vm::kMapFlagFixed : 0))); (baseAddress ? vm::kMapFlagFixed : 0)));
if (imageBase == MAP_FAILED) { if (imageBase == MAP_FAILED) {
std::abort(); std::abort();
@ -566,6 +569,11 @@ Ref<orbis::Module> rx::linker::loadModule(std::span<std::byte> image,
result->ehFrameSize = dataBufferIt - dataBuffer; 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) { if (dynamicPhdrIndex >= 0 && phdrs[dynamicPhdrIndex].p_filesz > 0) {
auto &dynPhdr = phdrs[dynamicPhdrIndex]; auto &dynPhdr = phdrs[dynamicPhdrIndex];
std::vector<Elf64_Dyn> dyns(dynPhdr.p_filesz / sizeof(Elf64_Dyn)); 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> idToModuleIndex;
std::unordered_map<std::uint64_t, std::size_t> idToLibraryIndex; 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) { for (auto dyn : dyns) {
if (dyn.d_tag == kElfDynamicTypeSceModuleInfo) { if (dyn.d_tag == kElfDynamicTypeSceModuleInfo ||
dyn.d_tag == kElfDynamicTypeSceModuleInfo1) {
std::strncpy(result->moduleName, 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)); sizeof(result->moduleName));
} else if (dyn.d_tag == kElfDynamicTypeSceModuleAttr) { } else if (dyn.d_tag == kElfDynamicTypeSceModuleAttr) {
result->attributes = dyn.d_un.d_val; 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)); 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; 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( auto [it, inserted] = idToModuleIndex.try_emplace(
dyn.d_un.d_val >> 48, result->neededModules.size()); 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.attr = static_cast<std::uint16_t>(dyn.d_un.d_val >> 32);
mod.isExport = false; mod.isExport = false;
} else if (dyn.d_tag == kElfDynamicTypeSceImportLib || } 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( auto [it, inserted] = idToLibraryIndex.try_emplace(
dyn.d_un.d_val >> 48, result->neededLibraries.size()); 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]; auto &lib = result->neededLibraries[it->second];
lib.name = strtab + static_cast<std::uint32_t>(dyn.d_un.d_val); 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 || } else if (dyn.d_tag == kElfDynamicTypeSceExportLibAttr ||
dyn.d_tag == kElfDynamicTypeSceImportLibAttr) { dyn.d_tag == kElfDynamicTypeSceImportLibAttr) {
auto [it, inserted] = idToLibraryIndex.try_emplace( 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) { switch (dyn.d_tag) {
case kElfDynamicTypePltGot:
case kElfDynamicTypeScePltGot: case kElfDynamicTypeScePltGot:
result->pltGot = dyn.d_un.d_ptr result->pltGot = dyn.d_un.d_ptr
? reinterpret_cast<std::uint64_t *>( ? reinterpret_cast<std::uint64_t *>(
@ -726,6 +736,11 @@ Ref<orbis::Module> rx::linker::loadModule(std::span<std::byte> image,
: nullptr; : nullptr;
break; break;
case kElfDynamicTypeJmpRel:
pltRelocations = reinterpret_cast<orbis::Relocation *>(
imageBase - baseAddress + dyn.d_un.d_ptr);
break;
case kElfDynamicTypeSceJmpRel: case kElfDynamicTypeSceJmpRel:
if (sceDynlibData != nullptr) { if (sceDynlibData != nullptr) {
pltRelocations = reinterpret_cast<orbis::Relocation *>( pltRelocations = reinterpret_cast<orbis::Relocation *>(
@ -737,9 +752,16 @@ Ref<orbis::Module> rx::linker::loadModule(std::span<std::byte> image,
break; break;
case kElfDynamicTypeScePltRel: case kElfDynamicTypeScePltRel:
break; break;
case kElfDynamicTypePltRelSize:
case kElfDynamicTypeScePltRelSize: case kElfDynamicTypeScePltRelSize:
pltRelocationCount = dyn.d_un.d_val / sizeof(orbis::Relocation); pltRelocationCount = dyn.d_un.d_val / sizeof(orbis::Relocation);
break; break;
case kElfDynamicTypeRela:
nonPltRelocations = reinterpret_cast<orbis::Relocation *>(
imageBase - baseAddress + dyn.d_un.d_ptr);
break;
case kElfDynamicTypeSceRela: case kElfDynamicTypeSceRela:
if (sceDynlibData != nullptr) { if (sceDynlibData != nullptr) {
nonPltRelocations = reinterpret_cast<orbis::Relocation *>( 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); image.data() + dyn.d_un.d_ptr);
} }
break; break;
case kElfDynamicTypeRelaSize:
case kElfDynamicTypeSceRelaSize: case kElfDynamicTypeSceRelaSize:
nonPltRelocationCount = dyn.d_un.d_val / sizeof(orbis::Relocation); nonPltRelocationCount = dyn.d_un.d_val / sizeof(orbis::Relocation);
break; break;
@ -831,25 +854,12 @@ Ref<orbis::Module> rx::linker::loadModule(std::span<std::byte> image,
result->symbols.push_back(symbol); 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) { for (auto phdr : phdrs) {
if (phdr.p_type == kElfProgramTypeLoad || 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 segmentEnd = rx::alignUp(phdr.p_vaddr + phdr.p_memsz, vm::kPageSize);
auto segmentBegin = auto segmentBegin =
rx::alignDown(phdr.p_vaddr - baseAddress, phdr.p_align); 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, std::memcpy(imageBase + phdr.p_vaddr - baseAddress,
image.data() + phdr.p_offset, phdr.p_filesz); 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 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; mapFlags |= vm::kMapProtCpuRead;
} }
if (mapFlags == 0) {
mapFlags = vm::kMapProtCpuWrite;
}
vm::protect(imageBase + segmentBegin, segmentSize, mapFlags); vm::protect(imageBase + segmentBegin, segmentSize, mapFlags);
if (phdr.p_type == kElfProgramTypeLoad) { 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->base = imageBase - baseAddress;
result->size = imageSize + baseAddress; result->size = imageSize + baseAddress;
result->phdrAddress = phdrPhdrIndex >= 0 ? phdrs[phdrPhdrIndex].p_vaddr 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", std::printf("Loaded module '%s' (%lx) from object '%s', address: %p - %p\n",
result->moduleName, (unsigned long)result->attributes, result->moduleName, (unsigned long)result->attributes,
result->soName, imageBase, (char *)imageBase + result->size); 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(), std::printf(" needed module '%s' (%lx)\n", mod.name.c_str(),
(unsigned long)mod.attr); (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(), std::printf(" needed library '%s' (%lx), kind %s\n", lib.name.c_str(),
(unsigned long)lib.attr, lib.isExport ? "export" : "import"); (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; 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}; return {.entryPoint = entryPoint, .interpBase = interpBase};
} }
if (vfs::exists(executableModule->interp, mainThread)) { if (!executableModule->interp.empty() &&
vfs::exists(executableModule->interp, mainThread)) {
auto loader = auto loader =
rx::linker::loadModuleFile(executableModule->interp, mainThread); rx::linker::loadModuleFile(executableModule->interp, mainThread);
loader->id = mainThread->tproc->modulesMap.insert(loader); loader->id = mainThread->tproc->modulesMap.insert(loader);