diff --git a/rpcs3/Crypto/unself.cpp b/rpcs3/Crypto/unself.cpp index 452030629f..af1d5ef613 100644 --- a/rpcs3/Crypto/unself.cpp +++ b/rpcs3/Crypto/unself.cpp @@ -200,6 +200,15 @@ void AppInfo::Load(const fs::file& f) padding = Read64(f); } +void AppInfo::LoadLE(const fs::file& f) +{ + authid = Read64LE(f); + vendor_id = Read32LE(f); + self_type = Read32LE(f); + version = Read64(f); + padding = Read64(f); +} + void AppInfo::Show() { LOG_NOTICE(LOADER, "AuthID: 0x%llx", authid); @@ -218,6 +227,16 @@ void SectionInfo::Load(const fs::file& f) encrypted = Read32(f); } +void SectionInfo::LoadLE(const fs::file& f) +{ + offset = Read64LE(f); + size = Read64LE(f); + compressed = Read32LE(f); + unknown1 = Read32LE(f); + unknown2 = Read32LE(f); + encrypted = Read32LE(f); +} + void SectionInfo::Show() { LOG_NOTICE(LOADER, "Offset: 0x%llx", offset); @@ -236,6 +255,14 @@ void SCEVersionInfo::Load(const fs::file& f) unknown = Read32(f); } +void SCEVersionInfo::LoadLE(const fs::file& f) +{ + subheader_type = Read32LE(f); + present = Read32LE(f); + size = Read32LE(f); + unknown = Read32LE(f); +} + void SCEVersionInfo::Show() { LOG_NOTICE(LOADER, "Sub-header type: 0x%08x", subheader_type); @@ -290,6 +317,66 @@ void ControlInfo::Load(const fs::file& f) } } +void ControlInfo::LoadLE(const fs::file& f) +{ + type = Read32LE(f); + size = Read32LE(f); + next = Read64LE(f); + + if (type == 1) + { + control_flags.ctrl_flag1 = Read32LE(f); + control_flags.unknown1 = Read32LE(f); + control_flags.unknown2 = Read32LE(f); + control_flags.unknown3 = Read32LE(f); + control_flags.unknown4 = Read32LE(f); + control_flags.unknown5 = Read32LE(f); + control_flags.unknown6 = Read32LE(f); + control_flags.unknown7 = Read32LE(f); + } + else if (type == 2) + { + if (size == 0x30) + { + f.read(file_digest_30.digest, 20); + file_digest_30.unknown = Read64LE(f); + } + else if (size == 0x40) + { + f.read(file_digest_40.digest1, 20); + f.read(file_digest_40.digest2, 20); + file_digest_40.unknown = Read64LE(f); + } + } + else if (type == 3) + { + npdrm.magic = Read32LE(f); + npdrm.unknown1 = Read32LE(f); + npdrm.license = Read32LE(f); + npdrm.type = Read32LE(f); + f.read(npdrm.content_id, 48); + f.read(npdrm.digest, 16); + f.read(npdrm.invdigest, 16); + f.read(npdrm.xordigest, 16); + npdrm.unknown2 = Read64LE(f); + npdrm.unknown3 = Read64LE(f); + } + else if (type == 5) + { + f.read(type5.unk, 0x100); + } + else if (type == 6) + { + type6.unknown1 = Read32LE(f); + f.read(type6.unk, 0xFC); + } + else if (type == 7) + { + f.read(type7.unk, 0x40); + } + +} + void ControlInfo::Show() { LOG_NOTICE(LOADER, "Type: 0x%08x", type); @@ -634,6 +721,19 @@ void SceHeader::Load(const fs::file& f) se_esize = Read64(f); } +void SceHeader::LoadLE(const fs::file& f) +{ + se_magic = Read32(f); + se_hver = Read32LE(f); + se_flags = Read16LE(f); + se_type = Read16LE(f); + se_meta = Read32LE(f); + se_hsize = Read64LE(f); + se_esize = Read64LE(f); + Read64LE(f); + Read64LE(f); +} + void SelfHeader::Load(const fs::file& f) { se_htype = Read64(f); @@ -648,6 +748,11 @@ void SelfHeader::Load(const fs::file& f) pad = Read64(f); } +void SelfHeader::LoadLE(const fs::file& f) +{ + f.read(this, sizeof(*this)); +} + SCEDecrypter::SCEDecrypter(const fs::file& s) : sce_f(s) , data_buf_length(0) @@ -889,7 +994,13 @@ bool SELFDecrypter::LoadHeaders(bool isElf32) { // Read SCE header. self_f.seek(0); - sce_hdr.Load(self_f); + sce_hdr.LoadLE(self_f); + const bool isVita = sce_hdr.se_hver == 3; + + if (!isVita) { + self_f.seek(0); + sce_hdr.Load(self_f); + } // Check SCE magic. if (!sce_hdr.CheckMagic()) @@ -899,11 +1010,18 @@ bool SELFDecrypter::LoadHeaders(bool isElf32) } // Read SELF header. - self_hdr.Load(self_f); + if(!isVita) + self_hdr.Load(self_f); + else + self_hdr.LoadLE(self_f); // Read the APP INFO. self_f.seek(self_hdr.se_appinfooff); - app_info.Load(self_f); + + if(!isVita) + app_info.Load(self_f); + else + app_info.LoadLE(self_f); // Read ELF header. self_f.seek(self_hdr.se_elfoff); @@ -926,7 +1044,10 @@ bool SELFDecrypter::LoadHeaders(bool isElf32) for(u32 i = 0; i < elf32_hdr.e_phnum; ++i) { phdr32_arr.emplace_back(); - phdr32_arr.back().Load(self_f); + if(!isVita) + phdr32_arr.back().Load(self_f); + else + phdr32_arr.back().LoadLE(self_f); } } else @@ -956,13 +1077,18 @@ bool SELFDecrypter::LoadHeaders(bool isElf32) for(u32 i = 0; i < ((isElf32) ? elf32_hdr.e_phnum : elf64_hdr.e_phnum); ++i) { secinfo_arr.emplace_back(); - secinfo_arr.back().Load(self_f); + if(!isVita) + secinfo_arr.back().Load(self_f); + else + secinfo_arr.back().LoadLE(self_f); } // Read SCE version info. self_f.seek(self_hdr.se_sceveroff); - scev_info.Load(self_f); - + if(!isVita) + scev_info.Load(self_f); + else + scev_info.LoadLE(self_f); // Read control info. ctrlinfo_arr.clear(); self_f.seek(self_hdr.se_controloff); @@ -972,7 +1098,10 @@ bool SELFDecrypter::LoadHeaders(bool isElf32) { ctrlinfo_arr.emplace_back(); ControlInfo &cinfo = ctrlinfo_arr.back(); - cinfo.Load(self_f); + if(!isVita) + cinfo.Load(self_f); + else + cinfo.LoadLE(self_f); i += cinfo.size; } @@ -992,7 +1121,10 @@ bool SELFDecrypter::LoadHeaders(bool isElf32) for(u32 i = 0; i < elf32_hdr.e_shnum; ++i) { shdr32_arr.emplace_back(); - shdr32_arr.back().Load(self_f); + if (!isVita) + shdr32_arr.back().Load(self_f); + else + shdr32_arr.back().LoadLE(self_f); } } else @@ -1157,6 +1289,8 @@ bool SELFDecrypter::LoadMetadata(u8* klic_key) memcpy(metadata_iv, keyset.riv, 0x10); // Check DEBUG flag. + if (sce_hdr.se_flags == 0x00c0) + return true; if ((sce_hdr.se_flags & 0x8000) != 0x8000) { // Decrypt the NPDRM layer. @@ -1219,6 +1353,13 @@ bool SELFDecrypter::DecryptData() } } + if (meta_hdr.section_count == 0) { + for (unsigned int i = 0; i < secinfo_arr.size(); i++) + { + data_buf_length += secinfo_arr[i].size; + } + } + // Allocate a buffer to store decrypted data. data_buf = std::make_unique(data_buf_length); @@ -1266,6 +1407,15 @@ bool SELFDecrypter::DecryptData() } } + if (meta_hdr.section_count == 0) { + for (unsigned int i = 0; i < secinfo_arr.size(); i++) + { + self_f.seek(secinfo_arr[i].offset); + self_f.read(data_buf.get() + data_buf_offset, secinfo_arr[i].size); + data_buf_offset += secinfo_arr[i].size; + } + } + return true; } @@ -1288,17 +1438,64 @@ fs::file SELFDecrypter::MakeElf(bool isElf32) WritePhdr(e, phdr32_arr[i]); } - for (unsigned int i = 0; i < meta_hdr.section_count; i++) + if (meta_hdr.section_count != 0) { - // PHDR type. - if (meta_shdr[i].type == 2) + for (unsigned int i = 0; i < meta_hdr.section_count; i++) { - // Seek to the program header data offset and write the data. - e.seek(phdr32_arr[meta_shdr[i].program_idx].p_offset); - e.write(data_buf.get() + data_buf_offset, meta_shdr[i].data_size); + // PHDR type. + if (meta_shdr[i].type == 2) + { + // Seek to the program header data offset and write the data. + e.seek(phdr32_arr[meta_shdr[i].program_idx].p_offset); + e.write(data_buf.get() + data_buf_offset, meta_shdr[i].data_size); + + // Advance the data buffer offset by data size. + data_buf_offset += meta_shdr[i].data_size; + } + } + } + else { + for (unsigned int i = 0; i < phdr32_arr.size(); i++) + { + // Decompress if necessary. + if (secinfo_arr[i].compressed == 2) + { + // Store the length in writeable memory space. + std::unique_ptr decomp_buf_length(new uLongf); + memcpy(decomp_buf_length.get(), &phdr32_arr[i].p_filesz, sizeof(uLongf)); + /// Create a pointer to a buffer for decompression. + std::unique_ptr decomp_buf(new u8[phdr32_arr[i].p_filesz]); + + // Create a buffer separate from data_buf to uncompress. + std::unique_ptr zlib_buf(new u8[data_buf_length]); + memcpy(zlib_buf.get(), data_buf.get(), data_buf_length); + + // Use zlib uncompress on the new buffer. + // decomp_buf_length changes inside the call to uncompress, so it must be a pointer to correct type (in writeable mem space). + int rv = uncompress(decomp_buf.get(), decomp_buf_length.get(), zlib_buf.get() + data_buf_offset, data_buf_length); + + // Check for errors (TODO: Probably safe to remove this once these changes have passed testing.) + switch (rv) + { + case Z_MEM_ERROR: LOG_ERROR(LOADER, "MakeELF encountered a Z_MEM_ERROR!"); break; + case Z_BUF_ERROR: LOG_ERROR(LOADER, "MakeELF encountered a Z_BUF_ERROR!"); break; + case Z_DATA_ERROR: LOG_ERROR(LOADER, "MakeELF encountered a Z_DATA_ERROR!"); break; + default: break; + } + + // Seek to the program header data offset and write the data. + e.seek(phdr32_arr[i].p_offset); + e.write(decomp_buf.get(), phdr32_arr[i].p_filesz); + } + else + { + // Seek to the program header data offset and write the data. + e.seek(phdr32_arr[i].p_offset); + e.write(data_buf.get() + data_buf_offset, secinfo_arr[i].size); + } // Advance the data buffer offset by data size. - data_buf_offset += meta_shdr[i].data_size; + data_buf_offset += secinfo_arr[i].size; } } @@ -1424,8 +1621,18 @@ static bool IsSelfElf32(const fs::file& f) SceHeader hdr; SelfHeader sh; - hdr.Load(f); - sh.Load(f); + + hdr.LoadLE(f); + const bool isVita = hdr.se_hver == 3; + + if (!isVita) { + f.seek(0); + hdr.Load(f); + sh.Load(f); + }else{ + sh.LoadLE(f); + } + // Locate the class byte and check it. u8 elf_class[0x8]; @@ -1451,13 +1658,21 @@ static bool CheckDebugSelf(fs::file& s) // Check for DEBUG version. if (key_version == 0x80 || key_version == 0xc0) { - LOG_WARNING(LOADER, "Debug SELF detected! Removing fake header..."); + + s.seek(0x04); + const u16 version = s.read>(); + if (version == 3) + return false; + + LOG_WARNING(LOADER, "Debug SELF detected! Removing fake header..."); + // Get the real elf offset. s.seek(0x10); + const u64 realoffset = key_version == 0x80 ? +s.read>() : +s.read>(); // Start at the real elf offset. - s.seek(key_version == 0x80 ? +s.read>() : +s.read>()); + s.seek(realoffset); // Write the real ELF file back. fs::file e = fs::make_stream>(); diff --git a/rpcs3/Crypto/unself.h b/rpcs3/Crypto/unself.h index 257a21dbef..45890c22b3 100644 --- a/rpcs3/Crypto/unself.h +++ b/rpcs3/Crypto/unself.h @@ -11,6 +11,7 @@ struct AppInfo u64 padding; void Load(const fs::file& f); + void LoadLE(const fs::file& f); void Show(); }; @@ -24,6 +25,7 @@ struct SectionInfo u32 encrypted; void Load(const fs::file& f); + void LoadLE(const fs::file& f); void Show(); }; @@ -35,6 +37,7 @@ struct SCEVersionInfo u32 unknown; void Load(const fs::file& f); + void LoadLE(const fs::file& f); void Show(); }; @@ -92,9 +95,33 @@ struct ControlInfo u64 unknown3; } npdrm; + + // type 5 0x110 bytes + struct + { + u32 pad; + u8 unk[0x100]; + } type5; + + // type 6 0x110 bytes + struct + { + u32 pad; + u32 unknown1; + u8 unk[0xFC]; + } type6; + + // type 7 0x50 bytes + struct + { + u32 pad; + u8 unk[0x40]; + } type7; + }; void Load(const fs::file& f); + void LoadLE(const fs::file& f); void Show(); }; @@ -317,6 +344,7 @@ struct SceHeader u64 se_esize; void Load(const fs::file& f); + void LoadLE(const fs::file& f); void Show(){} bool CheckMagic() const { return se_magic == 0x53434500; } }; @@ -335,6 +363,7 @@ struct SelfHeader u64 pad; void Load(const fs::file& f); + void LoadLE(const fs::file& f); void Show(){} }; diff --git a/rpcs3/Emu/PSP2/ARMv7Module.cpp b/rpcs3/Emu/PSP2/ARMv7Module.cpp index 37de3862e3..568193e0cc 100644 --- a/rpcs3/Emu/PSP2/ARMv7Module.cpp +++ b/rpcs3/Emu/PSP2/ARMv7Module.cpp @@ -201,25 +201,35 @@ struct psv_moduleinfo_t struct psv_libent_t { le_t size; // ??? - le_t unk0; - le_t unk1; + le_t version; + le_t flags; le_t fcount; - le_t vcount; - le_t unk2; - le_t unk3; - le_t data[1]; // ... + le_t vcount; + le_t unk2; + le_t module_nid; + le_t module_name; /* Pointer to name of this module */ + le_t nid_table; /* Pointer to array of 32-bit NIDs to export */ + le_t entry_table; /* Pointer to array of data pointers for each NID */ }; struct psv_libstub_t { le_t size; // 0x2C, 0x34 - le_t unk0; // (usually 1, 5 for sceLibKernel) - le_t unk1; // (usually 0) + le_t version; // (usually 1, 5 for sceLibKernel) + le_t flags; // (usually 0) le_t fcount; le_t vcount; le_t unk2; le_t unk3; - le_t data[1]; // ... + le_t module_nid; /* NID of module to import */ + le_t module_name; /* Pointer to name of imported module, for debugging */ + le_t reserved2; + le_t func_nid_table; /* Pointer to array of function NIDs to import */ + le_t func_entry_table;/* Pointer to array of stub functions to fill */ + le_t var_nid_table; /* Pointer to array of variable NIDs to import */ + le_t var_entry_table; /* Pointer to array of data pointers to write to */ + le_t unk_nid_table; + le_t unk_entry_table; }; struct psv_libcparam_t @@ -257,6 +267,48 @@ struct psv_process_param_t vm::lcptr sce_libcparam; }; +struct psv_reloc +{ + u32 addr; + u32 type; + u64 data; +}; + +/** \name Macros to get SCE reloc values +* @{ +*/ +#define SCE_RELOC_SHORT_OFFSET(x) (((x).r_opt1 >> 20) | ((x).r_opt2 & 0xFFFFF) << 12) +#define SCE_RELOC_SHORT_ADDEND(x) ((x).r_opt2 >> 20) +#define SCE_RELOC_LONG_OFFSET(x) ((x).r_offset) +#define SCE_RELOC_LONG_ADDEND(x) ((x).r_addend) +#define SCE_RELOC_LONG_CODE2(x) (((x).r_type >> 20) & 0xFF) +#define SCE_RELOC_LONG_DIST2(x) (((x).r_type >> 28) & 0xF) +#define SCE_RELOC_IS_SHORT(x) (((x).r_type) & 0xF) +#define SCE_RELOC_CODE(x) (((x).r_type >> 8) & 0xFF) +#define SCE_RELOC_SYMSEG(x) (((x).r_type >> 4) & 0xF) +#define SCE_RELOC_DATSEG(x) (((x).r_type >> 16) & 0xF) +/** @}*/ + +/** \name Vita supported relocations +* @{ +*/ +#define R_ARM_NONE 0 +#define R_ARM_ABS32 2 +#define R_ARM_REL32 3 +#define R_ARM_THM_CALL 10 +#define R_ARM_CALL 28 +#define R_ARM_JUMP24 29 +#define R_ARM_TARGET1 38 +#define R_ARM_V4BX 40 +#define R_ARM_TARGET2 41 +#define R_ARM_PREL31 42 +#define R_ARM_MOVW_ABS_NC 43 +#define R_ARM_MOVT_ABS 44 +#define R_ARM_THM_MOVW_ABS_NC 47 +#define R_ARM_THM_MOVT_ABS 48 +/** @}*/ + + static void arm_patch_refs(u32 refs, u32 addr) { auto ptr = vm::cptr::make(refs); @@ -314,27 +366,243 @@ void arm_load_exec(const arm_exec_object& elf) u32 tls_fsize{}; u32 tls_vsize{}; - for (const auto& prog : elf.progs) + std::unique_ptr p_vaddr = std::make_unique(elf.progs.size()); + + for (int i = 0; i < elf.progs.size(); i++) { + const auto& prog = elf.progs[i]; + const u32 addr = vm::cast(prog.p_vaddr, HERE); + const u32 size = ::narrow(prog.p_memsz, "p_memsz" HERE); + const u32 type = prog.p_type; + const u32 flag = prog.p_flags; + if (prog.p_type == 0x1 /* LOAD */ && prog.p_memsz) { - if (!vm::falloc(prog.p_vaddr & ~0xfff, prog.p_memsz + (prog.p_vaddr & 0xfff), vm::main)) + if (!(p_vaddr[i] = vm::alloc(size, vm::main))) { - fmt::throw_exception("vm::falloc() failed (addr=0x%x, size=0x%x)", prog.p_vaddr, prog.p_memsz); + fmt::throw_exception("vm::alloc() failed (size=0x%x)", size); } - if (prog.p_paddr) + if (elf.header.e_type == elf_type::psv1 && prog.p_paddr) { - module_info.set(prog.p_vaddr + (prog.p_paddr - prog.p_offset)); + module_info.set(start_addr + (prog.p_paddr - prog.p_offset)); LOG_NOTICE(LOADER, "Found program with p_paddr=0x%x", prog.p_paddr); } if (!start_addr) { - start_addr = prog.p_vaddr; + start_addr = p_vaddr[i]; } - std::memcpy(vm::base(prog.p_vaddr), prog.bin.data(), prog.p_filesz); + std::memcpy(vm::base(p_vaddr[i]), prog.bin.data(), prog.p_filesz); + } + else if (prog.p_type == 0x60000000) { + // Relocation code taken from + // https://github.com/yifanlu/UVLoader/blob/master/relocate.c + // Relocation information of the SCE_PPURELA segment + typedef union sce_reloc + { + u32 r_type; + struct + { + u32 r_opt1; + u32 r_opt2; + } r_short; + struct + { + u32 r_type; + u32 r_addend; + u32 r_offset; + } r_long; + } sce_reloc_t; + + for (uint i = 0; i < prog.p_filesz; ) + { + const auto& rel = reinterpret_cast(prog.bin[i]); + u32 r_offset; + u32 r_addend; + u8 r_symseg; + u8 r_datseg; + s32 offset; + u32 symval, addend, loc; + u32 upper, lower, sign, j1, j2; + u32 value; + + if (SCE_RELOC_IS_SHORT(rel)) + { + r_offset = SCE_RELOC_SHORT_OFFSET(rel.r_short); + r_addend = SCE_RELOC_SHORT_ADDEND(rel.r_short); + LOG_NOTICE(LOADER, "SHORT RELOC %X %X %X", r_offset, r_addend, SCE_RELOC_CODE(rel)); + i += 8; + } + else + { + r_offset = SCE_RELOC_LONG_OFFSET(rel.r_long); + r_addend = SCE_RELOC_LONG_ADDEND(rel.r_long); + if (SCE_RELOC_LONG_CODE2(rel.r_long)) + { + LOG_NOTICE(LOADER, "Code2 ignored for relocation at %X.", i); + } + LOG_NOTICE(LOADER, "LONG RELOC %X %X %X", r_offset, r_addend, SCE_RELOC_CODE(rel)); + i += 12; + } + + // get values + r_symseg = SCE_RELOC_SYMSEG(rel); + r_datseg = SCE_RELOC_DATSEG(rel); + symval = r_symseg == 15 ? 0 : p_vaddr[r_symseg]; + loc = p_vaddr[r_datseg] + r_offset; + + // perform relocation + // taken from linux/arch/arm/kernel/module.c of Linux Kernel 4.0 + switch (SCE_RELOC_CODE(rel)) + { + case R_ARM_V4BX: + { + /* Preserve Rm and the condition code. Alter + * other bits to re-code instruction as + * MOV PC,Rm. + */ + value = vm::_ref(loc & 0xf000000f) | 0x01a0f000; + } + break; + case R_ARM_ABS32: + case R_ARM_TARGET1: + { + value = r_addend + symval; + } + break; + case R_ARM_REL32: + case R_ARM_TARGET2: + { + value = r_addend + symval - loc; + } + break; + case R_ARM_THM_CALL: + { + upper = vm::_ref(loc); + lower = vm::_ref(loc + 2); + + /* + * 25 bit signed address range (Thumb-2 BL and B.W + * instructions): + * S:I1:I2:imm10:imm11:0 + * where: + * S = upper[10] = offset[24] + * I1 = ~(J1 ^ S) = offset[23] + * I2 = ~(J2 ^ S) = offset[22] + * imm10 = upper[9:0] = offset[21:12] + * imm11 = lower[10:0] = offset[11:1] + * J1 = lower[13] + * J2 = lower[11] + */ + sign = (upper >> 10) & 1; + j1 = (lower >> 13) & 1; + j2 = (lower >> 11) & 1; + offset = r_addend + symval - loc; + + if (offset <= (s32)0xff000000 || + offset >= (s32)0x01000000) { + LOG_NOTICE(LOADER, "reloc %x out of range: 0x%08X", i, symval); + break; + } + + sign = (offset >> 24) & 1; + j1 = sign ^ (~(offset >> 23) & 1); + j2 = sign ^ (~(offset >> 22) & 1); + upper = (u16)((upper & 0xf800) | (sign << 10) | + ((offset >> 12) & 0x03ff)); + lower = (u16)((lower & 0xd000) | + (j1 << 13) | (j2 << 11) | + ((offset >> 1) & 0x07ff)); + + value = ((u32)lower << 16) | upper; + } + break; + case R_ARM_CALL: + case R_ARM_JUMP24: + { + offset = r_addend + symval - loc; + if (offset <= (s32)0xfe000000 || + offset >= (s32)0x02000000) { + LOG_NOTICE(LOADER, "reloc %x out of range: 0x%08X", i, symval); + break; + } + + offset >>= 2; + offset &= 0x00ffffff; + + value = vm::_ref(loc & 0xff000000) | offset; + } + break; + case R_ARM_PREL31: + { + offset = r_addend + symval - loc; + value = offset & 0x7fffffff; + } + break; + case R_ARM_MOVW_ABS_NC: + case R_ARM_MOVT_ABS: + { + offset = symval + r_addend; + if (SCE_RELOC_CODE(rel) == R_ARM_MOVT_ABS) + offset >>= 16; + + value = vm::_ref(loc); + value &= 0xfff0f000; + value |= ((offset & 0xf000) << 4) | + (offset & 0x0fff); + } + break; + case R_ARM_THM_MOVW_ABS_NC: + case R_ARM_THM_MOVT_ABS: + { + upper = vm::_ref(loc); + lower = vm::_ref(loc + 2); + + /* + * MOVT/MOVW instructions encoding in Thumb-2: + * + * i = upper[10] + * imm4 = upper[3:0] + * imm3 = lower[14:12] + * imm8 = lower[7:0] + * + * imm16 = imm4:i:imm3:imm8 + */ + offset = r_addend + symval; + + if (SCE_RELOC_CODE(rel) == R_ARM_THM_MOVT_ABS) + offset >>= 16; + + upper = (u16)((upper & 0xfbf0) | + ((offset & 0xf000) >> 12) | + ((offset & 0x0800) >> 1)); + lower = (u16)((lower & 0x8f00) | + ((offset & 0x0700) << 4) | + (offset & 0x00ff)); + + value = ((u32)lower << 16) | upper; + } + break; + case R_ARM_NONE: + continue; + + default: + { + LOG_NOTICE(LOADER, "Unknown relocation code %u at %x", SCE_RELOC_CODE(rel), i); + continue; + } + } + + LOG_NOTICE(LOADER, "Writing at %X[%d], %X, %X, %d", p_vaddr[r_datseg], r_datseg, r_offset, value, sizeof(value)); + if ((r_offset + sizeof(value)) > elf.progs[r_datseg].p_filesz) + { + LOG_NOTICE(LOADER, "Relocation overflows segment"); + continue; + } + vm::_ref(p_vaddr[r_datseg]+r_offset) = value; + } } } @@ -352,7 +620,7 @@ void arm_load_exec(const arm_exec_object& elf) tls_fsize = module_info->data[6]; tls_vsize = module_info->data[7]; } - else if (module_info->data[5] == 0xffffffff) + else if (module_info->data[5] == 0xffffffff || module_info->data[5] == 0) { tls_faddr = module_info->data[1]; // Guess tls_fsize = module_info->data[2]; @@ -384,14 +652,16 @@ void arm_load_exec(const arm_exec_object& elf) else { LOG_NOTICE(LOADER, "Loading libent at *0x%x", libent); - LOG_NOTICE(LOADER, "** 0x%x, 0x%x", libent->unk0, libent->unk1); + LOG_NOTICE(LOADER, "** 0x%x, 0x%x", libent->version, libent->flags); LOG_NOTICE(LOADER, "** Functions: %u", libent->fcount); LOG_NOTICE(LOADER, "** Variables: %u", libent->vcount); - LOG_NOTICE(LOADER, "** 0x%x, 0x%08x", libent->unk2, libent->unk3); + LOG_NOTICE(LOADER, "** 0x%x, 0x%08x", libent->unk2, libent->module_nid); - const auto export_nids = vm::cptr::make(libent->data[size == 0x20 ? 2 : 1]); - const auto export_data = vm::cptr::make(libent->data[size == 0x20 ? 3 : 2]); + const auto export_nids = vm::cptr::make(libent->nid_table); + const auto export_data = vm::cptr::make(libent->entry_table); + LOG_NOTICE(LOADER, "** 0x%x, 0x%08x", export_data, export_nids); + for (u32 i = 0, count = export_data - export_nids; i < count; i++) { const u32 nid = export_nids[i]; @@ -442,7 +712,7 @@ void arm_load_exec(const arm_exec_object& elf) } else { - const std::string module_name(vm::_ptr(libstub->data[size == 0x34 ? 1 : 0])); + const std::string module_name(vm::_ptr(libstub->module_name)); LOG_NOTICE(LOADER, "Loading libstub at 0x%x: %s", libstub, module_name); @@ -468,13 +738,13 @@ void arm_load_exec(const arm_exec_object& elf) } } - LOG_NOTICE(LOADER, "** 0x%x, 0x%x", libstub->unk0, libstub->unk1); + LOG_NOTICE(LOADER, "** 0x%x, 0x%x", libstub->version, libstub->flags); LOG_NOTICE(LOADER, "** Functions: %u", libstub->fcount); LOG_NOTICE(LOADER, "** Variables: %u", libstub->vcount); LOG_NOTICE(LOADER, "** 0x%x, 0x%08x", libstub->unk2, libstub->unk3); - const auto fnids = vm::cptr::make(libstub->data[size == 0x34 ? 3 : 1]); - const auto fstubs = vm::cptr::make(libstub->data[size == 0x34 ? 4 : 2]); + const auto fnids = vm::cptr::make(libstub->func_nid_table); + const auto fstubs = vm::cptr::make(libstub->func_entry_table); for (u32 j = 0; j < libstub->fcount; j++) { @@ -517,8 +787,8 @@ void arm_load_exec(const arm_exec_object& elf) fstub[0] = 0xe0700090 | arm_code::hack::index::insert(index); } - const auto vnids = vm::cptr::make(libstub->data[size == 0x34 ? 5 : 3]); - const auto vstub = vm::cptr::make(libstub->data[size == 0x34 ? 6 : 4]); + const auto vnids = vm::cptr::make(libstub->var_nid_table); + const auto vstub = vm::cptr::make(libstub->var_entry_table); for (u32 j = 0; j < libstub->vcount; j++) { @@ -559,6 +829,8 @@ void arm_load_exec(const arm_exec_object& elf) const auto libc_param = proc_param->sce_libcparam; + if (libc_param) { + LOG_NOTICE(LOADER, "__sce_libcparam(*0x%x) analysis...", libc_param); verify(HERE), libc_param->size >= 0x1c; @@ -570,6 +842,8 @@ void arm_load_exec(const arm_exec_object& elf) LOG_NOTICE(LOADER, "*** &sceLibcHeapExtendedAlloc = 0x%x", libc_param->sceLibcHeapExtendedAlloc); LOG_NOTICE(LOADER, "*** &sceLibcHeapDelayedAlloc = 0x%x", libc_param->sceLibcHeapDelayedAlloc); + } + const auto stop_code = vm::ptr::make(vm::alloc(3 * 4, vm::main)); stop_code[0] = 0xf870; // HACK instruction (Thumb) stop_code[1] = 1; // Predefined function index (HLE return) diff --git a/rpcs3/Emu/System.cpp b/rpcs3/Emu/System.cpp index c4cf4a504e..7a48966204 100644 --- a/rpcs3/Emu/System.cpp +++ b/rpcs3/Emu/System.cpp @@ -729,7 +729,7 @@ void Emulator::Load(bool add_only) vm::ps3::init(); spu_load_exec(spu_exec); } - else if (arm_exec.open(elf_file) == elf_error::ok) + else if (arm_exec.open(elf_file, 0, elf_opt::no_sections + elf_opt::no_sections) == elf_error::ok) { // ARMv7 executable g_system = system_type::psv;