PSP2: Fix vitasdk homebrew loading

This commit is contained in:
ggf906 2017-12-26 13:03:55 +01:00
parent 19d181fa4c
commit b12a2f7ea5
4 changed files with 566 additions and 48 deletions

View file

@ -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<u8[]>(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<uLongf> 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<u8[]> decomp_buf(new u8[phdr32_arr[i].p_filesz]);
// Create a buffer separate from data_buf to uncompress.
std::unique_ptr<u8[]> 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<le_t<u16>>();
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<be_t<u64>>() : +s.read<le_t<u64>>();
// Start at the real elf offset.
s.seek(key_version == 0x80 ? +s.read<be_t<u64>>() : +s.read<le_t<u64>>());
s.seek(realoffset);
// Write the real ELF file back.
fs::file e = fs::make_stream<std::vector<u8>>();

View file

@ -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(){}
};

View file

@ -201,25 +201,35 @@ struct psv_moduleinfo_t
struct psv_libent_t
{
le_t<u16> size; // ???
le_t<u16> unk0;
le_t<u16> unk1;
le_t<u16> version;
le_t<u16> flags;
le_t<u16> fcount;
le_t<u16> vcount;
le_t<u16> unk2;
le_t<u32> unk3;
le_t<u32> data[1]; // ...
le_t<u32> vcount;
le_t<u32> unk2;
le_t<u32> module_nid;
le_t<u32> module_name; /* Pointer to name of this module */
le_t<u32> nid_table; /* Pointer to array of 32-bit NIDs to export */
le_t<u32> entry_table; /* Pointer to array of data pointers for each NID */
};
struct psv_libstub_t
{
le_t<u16> size; // 0x2C, 0x34
le_t<u16> unk0; // (usually 1, 5 for sceLibKernel)
le_t<u16> unk1; // (usually 0)
le_t<u16> version; // (usually 1, 5 for sceLibKernel)
le_t<u16> flags; // (usually 0)
le_t<u16> fcount;
le_t<u16> vcount;
le_t<u16> unk2;
le_t<u32> unk3;
le_t<u32> data[1]; // ...
le_t<u32> module_nid; /* NID of module to import */
le_t<u32> module_name; /* Pointer to name of imported module, for debugging */
le_t<u32> reserved2;
le_t<u32> func_nid_table; /* Pointer to array of function NIDs to import */
le_t<u32> func_entry_table;/* Pointer to array of stub functions to fill */
le_t<u32> var_nid_table; /* Pointer to array of variable NIDs to import */
le_t<u32> var_entry_table; /* Pointer to array of data pointers to write to */
le_t<u32> unk_nid_table;
le_t<u32> unk_entry_table;
};
struct psv_libcparam_t
@ -257,6 +267,48 @@ struct psv_process_param_t
vm::lcptr<psv_libcparam_t> 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<u32>::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<u32[]> p_vaddr = std::make_unique<u32[]>(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<u32>(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<const sce_reloc_t&>(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<u32>(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<u16>(loc);
lower = vm::_ref<u16>(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<u32>(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<u32>(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<u16>(loc);
lower = vm::_ref<u16>(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<u32>(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<u32>::make(libent->data[size == 0x20 ? 2 : 1]);
const auto export_data = vm::cptr<u32>::make(libent->data[size == 0x20 ? 3 : 2]);
const auto export_nids = vm::cptr<u32>::make(libent->nid_table);
const auto export_data = vm::cptr<u32>::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<char>(libstub->data[size == 0x34 ? 1 : 0]));
const std::string module_name(vm::_ptr<char>(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<u32>::make(libstub->data[size == 0x34 ? 3 : 1]);
const auto fstubs = vm::cptr<u32>::make(libstub->data[size == 0x34 ? 4 : 2]);
const auto fnids = vm::cptr<u32>::make(libstub->func_nid_table);
const auto fstubs = vm::cptr<u32>::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<arm_encoding::A1>::index::insert(index);
}
const auto vnids = vm::cptr<u32>::make(libstub->data[size == 0x34 ? 5 : 3]);
const auto vstub = vm::cptr<u32>::make(libstub->data[size == 0x34 ? 6 : 4]);
const auto vnids = vm::cptr<u32>::make(libstub->var_nid_table);
const auto vstub = vm::cptr<u32>::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<u32>::make(vm::alloc(3 * 4, vm::main));
stop_code[0] = 0xf870; // HACK instruction (Thumb)
stop_code[1] = 1; // Predefined function index (HLE return)

View file

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