diff --git a/src/Core/PS4/Linker.cpp b/src/Core/PS4/Linker.cpp index 0cc7e646..0d08e840 100644 --- a/src/Core/PS4/Linker.cpp +++ b/src/Core/PS4/Linker.cpp @@ -47,6 +47,7 @@ Module* Linker::LoadModule(const std::string& elf_name) if (m->elf->isElfFile()) { LoadModuleToMemory(m); + LoadDynamicInfo(m); } else { @@ -157,4 +158,161 @@ void Linker::LoadModuleToMemory(Module* m) offset += instruction.info.length; runtime_address += instruction.info.length; } +} + +void Linker::LoadDynamicInfo(Module* m) +{ + m->dynamic_info = new DynamicModuleInfo; + + for (const auto* dyn = static_cast(m->m_dynamic); dyn->d_tag != DT_NULL; dyn++) + { + switch (dyn->d_tag) + { + case DT_SCE_HASH: //Offset of the hash table. + m->dynamic_info->hash_table = reinterpret_cast(static_cast(m->m_dynamic_data) + dyn->d_un.d_ptr); + break; + case DT_SCE_HASHSZ: //Size of the hash table + m->dynamic_info->hash_table_size = dyn->d_un.d_val; + break; + case DT_SCE_STRTAB://Offset of the string table. + m->dynamic_info->str_table = reinterpret_cast(static_cast(m->m_dynamic_data) + dyn->d_un.d_ptr); + break; + case DT_SCE_STRSZ: //Size of the string table. + m->dynamic_info->str_table_size = dyn->d_un.d_val; + break; + case DT_SCE_SYMTAB://Offset of the symbol table. + m->dynamic_info->symbol_table = reinterpret_cast(static_cast(m->m_dynamic_data) + dyn->d_un.d_ptr); + break; + case DT_SCE_SYMTABSZ://Size of the symbol table. + m->dynamic_info->symbol_table_total_size = dyn->d_un.d_val; + break; + case DT_INIT: + m->dynamic_info->init_virtual_addr = dyn->d_un.d_ptr; + break; + case DT_FINI: + m->dynamic_info->fini_virtual_addr = dyn->d_un.d_ptr; + break; + case DT_SCE_PLTGOT: //Offset of the global offset table. + m->dynamic_info->pltgot_virtual_addr = dyn->d_un.d_ptr; + break; + case DT_SCE_JMPREL: //Offset of the table containing jump slots. + m->dynamic_info->jmp_relocation_table = reinterpret_cast(static_cast(m->m_dynamic_data) + dyn->d_un.d_ptr); + break; + case DT_SCE_PLTRELSZ: //Size of the global offset table. + m->dynamic_info->jmp_relocation_table_size = dyn->d_un.d_val; + break; + case DT_SCE_PLTREL: //The type of relocations in the relocation table. Should be DT_RELA + m->dynamic_info->jmp_relocation_type = dyn->d_un.d_val; + if (m->dynamic_info->jmp_relocation_type != DT_RELA) + { + LOG_WARN_IF(debug_loader, "DT_SCE_PLTREL is NOT DT_RELA should check!"); + } + break; + case DT_SCE_RELA: //Offset of the relocation table. + m->dynamic_info->relocation_table = reinterpret_cast(static_cast(m->m_dynamic_data) + dyn->d_un.d_ptr); + break; + case DT_SCE_RELASZ: //Size of the relocation table. + m->dynamic_info->relocation_table_size = dyn->d_un.d_val; + break; + case DT_SCE_RELAENT : //The size of relocation table entries. + m->dynamic_info->relocation_table_entries_size = dyn->d_un.d_val; + if (m->dynamic_info->relocation_table_entries_size != 0x18) //this value should always be 0x18 + { + LOG_WARN_IF(debug_loader, "DT_SCE_RELAENT is NOT 0x18 should check!"); + } + break; + case DT_INIT_ARRAY:// Address of the array of pointers to initialization functions + m->dynamic_info->init_array_virtual_addr = dyn->d_un.d_ptr; + break; + case DT_FINI_ARRAY: // Address of the array of pointers to termination functions + m->dynamic_info->fini_array_virtual_addr = dyn->d_un.d_ptr; + break; + case DT_INIT_ARRAYSZ://Size in bytes of the array of initialization functions + m->dynamic_info->init_array_size = dyn->d_un.d_val; + break; + case DT_FINI_ARRAYSZ://Size in bytes of the array of terminationfunctions + m->dynamic_info->fini_array_size = dyn->d_un.d_val; + break; + case DT_PREINIT_ARRAY://Address of the array of pointers to pre - initialization functions + m->dynamic_info->preinit_array_virtual_addr = dyn->d_un.d_ptr; + break; + case DT_PREINIT_ARRAYSZ://Size in bytes of the array of pre - initialization functions + m->dynamic_info->preinit_array_size = dyn->d_un.d_val; + break; + case DT_SCE_SYMENT: //The size of symbol table entries + m->dynamic_info->symbol_table_entries_size = dyn->d_un.d_val; + if (m->dynamic_info->symbol_table_entries_size != 0x18) //this value should always be 0x18 + { + LOG_WARN_IF(debug_loader, "DT_SCE_SYMENT is NOT 0x18 should check!"); + } + break; + case DT_DEBUG: + m->dynamic_info->debug = dyn->d_un.d_val; + break; + case DT_TEXTREL: + m->dynamic_info->textrel = dyn->d_un.d_val; + break; + case DT_FLAGS: + m->dynamic_info->flags = dyn->d_un.d_val; + if (m->dynamic_info->flags != 0x04) //this value should always be DF_TEXTREL (0x04) + { + LOG_WARN_IF(debug_loader, "DT_FLAGS is NOT 0x04 should check!"); + } + break; + case DT_NEEDED://Offset of the library string in the string table to be linked in. + if (m->dynamic_info->str_table != nullptr)//in theory this should already be filled from about just make a test case + { + m->dynamic_info->needed.push_back(m->dynamic_info->str_table + dyn->d_un.d_val); + } + else + { + LOG_ERROR_IF(debug_loader, "DT_NEEDED str table is not loaded should check!"); + } + break; + case DT_SCE_NEEDED_MODULE: + { + ModuleInfo info{}; + info.value = dyn->d_un.d_val; + info.name = m->dynamic_info->str_table + info.name_offset; + m->dynamic_info->import_modules.push_back(info); + } + break; + case DT_SCE_IMPORT_LIB: + { + LibraryInfo info{}; + info.value = dyn->d_un.d_val; + info.name = m->dynamic_info->str_table + info.name_offset; + m->dynamic_info->import_libs.push_back(info); + } + break; + case DT_SCE_FINGERPRINT: + //The fingerprint is a 24 byte (0x18) size buffer that contains a unique identifier for the given app. + //How exactly this is generated isn't known, however it is not necessary to have a valid fingerprint. + //While an invalid fingerprint will cause a warning to be printed to the kernel log, the ELF will still load and run. + LOG_INFO_IF(debug_loader, "unsupported DT_SCE_FINGERPRINT value = ..........: {:#018x}\n", dyn->d_un.d_val); + break; + case DT_SCE_IMPORT_LIB_ATTR: + //The upper 32-bits should contain the module index multiplied by 0x10000. The lower 32-bits should be a constant 0x9. + LOG_INFO_IF(debug_loader, "unsupported DT_SCE_IMPORT_LIB_ATTR value = ..........: {:#018x}\n", dyn->d_un.d_val); + break; + case DT_SCE_ORIGINAL_FILENAME: + m->dynamic_info->filename = m->dynamic_info->str_table + dyn->d_un.d_val; + break; + case DT_SCE_MODULE_INFO://probably only useable in shared modules + { + ModuleInfo info{}; + info.value = dyn->d_un.d_val; + info.name = m->dynamic_info->str_table + info.name_offset; + m->dynamic_info->export_modules.push_back(info); + } + break; + case DT_SCE_MODULE_ATTR: + //TODO? + LOG_INFO_IF(debug_loader, "unsupported DT_SCE_MODULE_ATTR value = ..........: {:#018x}\n", dyn->d_un.d_val); + break; + default: + LOG_INFO_IF(debug_loader, "unsupported dynamic tag ..........: {:#018x}\n", dyn->d_tag); + } + + } } \ No newline at end of file diff --git a/src/Core/PS4/Linker.h b/src/Core/PS4/Linker.h index 002dc30f..4b01a0c4 100644 --- a/src/Core/PS4/Linker.h +++ b/src/Core/PS4/Linker.h @@ -2,6 +2,8 @@ #include "../../Loader/Elf.h" #include +struct DynamicModuleInfo; + /*this struct keeps neccesary info about loaded modules.Main executeable is included too as well*/ struct Module { @@ -11,6 +13,81 @@ struct Module void* m_dynamic = nullptr; void* m_dynamic_data = nullptr; + DynamicModuleInfo* dynamic_info = nullptr; +}; + +struct ModuleInfo +{ + std::string name; + union + { + u64 value; + struct + { + u32 name_offset; + u08 version_minor; + u08 version_major; + u16 id; + }; + }; +}; + +struct LibraryInfo +{ + std::string name; + union + { + u64 value; + struct + { + u32 name_offset; + u16 version; + u16 id; + }; + }; +}; + +struct DynamicModuleInfo +{ + void* hash_table = nullptr; + u64 hash_table_size = 0; + + char* str_table = nullptr; + u64 str_table_size = 0; + + elf_symbol* symbol_table = nullptr; + u64 symbol_table_total_size = 0; + u64 symbol_table_entries_size = 0; + + u64 init_virtual_addr = 0; + u64 fini_virtual_addr = 0; + u64 pltgot_virtual_addr = 0; + u64 init_array_virtual_addr = 0; + u64 fini_array_virtual_addr = 0; + u64 preinit_array_virtual_addr = 0; + u64 init_array_size = 0; + u64 fini_array_size = 0; + u64 preinit_array_size = 0; + + elf_relocation* jmp_relocation_table = nullptr; + u64 jmp_relocation_table_size = 0; + s64 jmp_relocation_type = 0; + + elf_relocation* relocation_table = nullptr; + u64 relocation_table_size = 0; + u64 relocation_table_entries_size = 0; + + u64 debug = 0; + u64 textrel = 0; + u64 flags = 0; + + std::vector needed; + std::vector import_modules; + std::vector export_modules; + std::vector import_libs; + + std::string filename;//filename with absolute path + }; class Linker @@ -22,6 +99,7 @@ public: Module* LoadModule(const std::string& elf_name); Module* FindModule(/*u32 id*/); void LoadModuleToMemory(Module* m); + void LoadDynamicInfo(Module* program); private: std::vector m_modules; diff --git a/src/Loader/Elf.h b/src/Loader/Elf.h index dbe7c9c3..4c5686f4 100644 --- a/src/Loader/Elf.h +++ b/src/Loader/Elf.h @@ -323,6 +323,71 @@ struct elf_program_id_header u64 firmver; u08 digest[32]; }; + +constexpr s64 DT_NULL = 0; +constexpr s64 DT_NEEDED = 0x00000001; +constexpr s64 DT_RELA = 0x00000007; +constexpr s64 DT_INIT = 0x0000000c; +constexpr s64 DT_FINI = 0x0000000d; +constexpr s64 DT_DEBUG = 0x00000015; +constexpr s64 DT_TEXTREL = 0x00000016; +constexpr s64 DT_INIT_ARRAY = 0x00000019; +constexpr s64 DT_FINI_ARRAY = 0x0000001a; +constexpr s64 DT_INIT_ARRAYSZ = 0x0000001b; +constexpr s64 DT_FINI_ARRAYSZ = 0x0000001c; +constexpr s64 DT_FLAGS = 0x0000001e; +constexpr s64 DT_PREINIT_ARRAY = 0x00000020; +constexpr s64 DT_PREINIT_ARRAYSZ = 0x00000021; +constexpr s64 DT_SCE_FINGERPRINT = 0x61000007; +constexpr s64 DT_SCE_ORIGINAL_FILENAME = 0x61000009; +constexpr s64 DT_SCE_MODULE_INFO = 0x6100000d; +constexpr s64 DT_SCE_NEEDED_MODULE = 0x6100000f; +constexpr s64 DT_SCE_MODULE_ATTR = 0x61000011; +constexpr s64 DT_SCE_IMPORT_LIB = 0x61000015; +constexpr s64 DT_SCE_IMPORT_LIB_ATTR = 0x61000019; +constexpr s64 DT_SCE_HASH = 0x61000025; +constexpr s64 DT_SCE_PLTGOT = 0x61000027; +constexpr s64 DT_SCE_JMPREL = 0x61000029; +constexpr s64 DT_SCE_PLTREL = 0x6100002b; +constexpr s64 DT_SCE_PLTRELSZ = 0x6100002d; +constexpr s64 DT_SCE_RELA = 0x6100002f; +constexpr s64 DT_SCE_RELASZ = 0x61000031; +constexpr s64 DT_SCE_RELAENT = 0x61000033; +constexpr s64 DT_SCE_SYMENT = 0x6100003b; +constexpr s64 DT_SCE_HASHSZ = 0x6100003d; +constexpr s64 DT_SCE_STRTAB = 0x61000035; +constexpr s64 DT_SCE_STRSZ = 0x61000037; +constexpr s64 DT_SCE_SYMTAB = 0x61000039; +constexpr s64 DT_SCE_SYMTABSZ = 0x6100003f; + + +struct elf_dynamic +{ + s64 d_tag; + union + { + u64 d_val; + u64 d_ptr; + } d_un; +}; + +struct elf_symbol +{ + u32 st_name; + u08 st_info; + u08 st_other; + u16 st_shndx; + u64 st_value; + u64 st_size; +}; + +struct elf_relocation +{ + u64 rel_offset; + u64 rel_info; + s64 rel_addend; +}; + class Elf { public: diff --git a/src/main.cpp b/src/main.cpp index 8fdb32ba..d59efd18 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -26,17 +26,21 @@ #endif #include "Core/PS4/Linker.h" #include "Util/Singleton.h" - +#include +#include +#include // Main code int main(int argc, char* argv[]) { + + logging::init(true);//init logging - const char* const path = argv[1]; //argument 1 is the path of self file to boot + const char* const path = "videoout_basic.elf";// argv[1]; //argument 1 is the path of self file to boot auto* linker = Singleton::Instance(); auto *module =linker->LoadModule(path);//load main executable - +#if 0 // Setup SDL if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_GAMEPAD) != 0) { @@ -215,6 +219,7 @@ int main(int argc, char* argv[]) SDL_GL_DeleteContext(gl_context); SDL_DestroyWindow(window); SDL_Quit(); +#endif return 0; }