Minor fixes

elf_object
Loader fix
Analyser fix
This commit is contained in:
Nekotekina 2016-07-09 01:36:42 +03:00
parent b89961f01d
commit 06c6c8212d
14 changed files with 498 additions and 123 deletions

View File

@ -231,7 +231,6 @@ jit_compiler::jit_compiler(std::unique_ptr<llvm::Module>&& _module, std::unorder
.setErrorStr(&result) .setErrorStr(&result)
.setMCJITMemoryManager(std::make_unique<MemoryManager>(std::move(table))) .setMCJITMemoryManager(std::make_unique<MemoryManager>(std::move(table)))
.setOptLevel(llvm::CodeGenOpt::Aggressive) .setOptLevel(llvm::CodeGenOpt::Aggressive)
.setRelocationModel(llvm::Reloc::PIC_)
.setCodeModel((u64)s_memory <= 0x60000000 ? llvm::CodeModel::Medium : llvm::CodeModel::Large) // TODO .setCodeModel((u64)s_memory <= 0x60000000 ? llvm::CodeModel::Medium : llvm::CodeModel::Large) // TODO
.setMCPU(llvm::sys::getHostCPUName()) .setMCPU(llvm::sys::getHostCPUName())
.create()); .create());

View File

@ -2022,15 +2022,15 @@ s32 spursTasksetLoadElf(SPUThread& spu, u32* entryPoint, u32* lowestLoadAddr, u6
return CELL_SPURS_TASK_ERROR_INVAL; return CELL_SPURS_TASK_ERROR_INVAL;
} }
const spu_exec_loader loader(fs::file(vm::base(vm::cast(elfAddr, HERE)), u32(0 - elfAddr))); const spu_exec_object obj(fs::file(vm::base(vm::cast(elfAddr, HERE)), u32(0 - elfAddr)));
if (loader != elf_error::ok) if (obj != elf_error::ok)
{ {
return CELL_SPURS_TASK_ERROR_NOEXEC; return CELL_SPURS_TASK_ERROR_NOEXEC;
} }
u32 _lowestLoadAddr = CELL_SPURS_TASK_BOTTOM; u32 _lowestLoadAddr = CELL_SPURS_TASK_BOTTOM;
for (const auto& prog : loader.progs) for (const auto& prog : obj.progs)
{ {
if (prog.p_paddr >= CELL_SPURS_TASK_BOTTOM) if (prog.p_paddr >= CELL_SPURS_TASK_BOTTOM)
{ {
@ -2051,7 +2051,7 @@ s32 spursTasksetLoadElf(SPUThread& spu, u32* entryPoint, u32* lowestLoadAddr, u6
} }
} }
for (const auto& prog : loader.progs) for (const auto& prog : obj.progs)
{ {
if (prog.p_paddr >= CELL_SPURS_TASK_BOTTOM) // ??? if (prog.p_paddr >= CELL_SPURS_TASK_BOTTOM) // ???
{ {
@ -2067,7 +2067,7 @@ s32 spursTasksetLoadElf(SPUThread& spu, u32* entryPoint, u32* lowestLoadAddr, u6
} }
} }
*entryPoint = loader.header.e_entry; *entryPoint = obj.header.e_entry;
if (lowestLoadAddr) *lowestLoadAddr = _lowestLoadAddr; if (lowestLoadAddr) *lowestLoadAddr = _lowestLoadAddr;
return CELL_OK; return CELL_OK;

View File

@ -80,12 +80,231 @@ void ppu_validate(const std::string& fname, const std::vector<ppu_function>& fun
} }
} }
static u32 ppu_test(const vm::cptr<u32> ptr, vm::cptr<void> fend, std::initializer_list<ppu_pattern> pat)
{
vm::cptr<u32> cur = ptr;
for (auto& p : pat)
{
if (cur >= fend)
{
return 0;
}
if (*cur == ppu_instructions::NOP())
{
cur++;
if (cur >= fend)
{
return 0;
}
}
if ((*cur & p.mask) != p.opcode)
{
return 0;
}
cur++;
}
return cur.addr() - ptr.addr();
}
static u32 ppu_test(vm::cptr<u32> ptr, vm::cptr<void> fend, std::initializer_list<std::initializer_list<ppu_pattern>> pats)
{
for (auto pat : pats)
{
if (const u32 len = ppu_test(ptr, fend, pat))
{
return len;
}
}
return 0;
}
namespace ppu_patterns
{
using namespace ppu_instructions;
const std::initializer_list<ppu_pattern> abort1
{
{ STDU(r1, r1, -0xc0) },
{ MFLR(r0) },
{ STD(r26, r1, 0x90) },
{ STD(r27, r1, 0x98) },
{ STD(r28, r1, 0xa0) },
{ STD(r29, r1, 0xa8) },
{ STD(r30, r1, 0xb0) },
{ STD(r31, r1, 0xb8) },
{ STD(r0, r1, 0xd0) },
{ LI(r3, 4) },
{ LI(r4, 0) },
{ LI(r11, 0x3dc) },
{ SC(0) },
{ MR(r29, r1) },
{ CLRLDI(r29, r29, 32) },
{ LWZ(r4, r2, 0), 0xffff },
{ ADDI(r31, r1, 0x70) },
{ LI(r3, 1) },
{ LI(r5, 0x19) },
{ MR(r6, r31) },
{ LWZ(r28, r29, 4) },
{ LI(r11, 0x193) },
{ SC(0) },
{ ADDI(r26, r1, 0x78) },
{ LD(r3, r28, 0x10) },
{ MR(r4, r26) },
{ B(0, false, true), 0x3fffffc }, // .hex2str
{ LI(r5, 0x10) },
{ CLRLDI(r4, r3, 32) },
{ MR(r6, r31) },
{ LI(r3, 1) },
{ LI(r11, 0x193) },
{ SC(0) },
{ LWZ(r27, r2, 0), 0xffff },
{ LI(r3, 1) },
{ LI(r5, 1) },
{ MR(r4, r27) },
{ MR(r6, r31) },
{ LI(r11, 0x193) },
{ SC(0) },
{ LD(r28, r28, 0) },
{ CMPDI(cr7, r28, 0) },
{ BEQ(cr7, +0x6c) },
{ LWZ(r30, r2, 0), 0xffff },
{ LI(r3, 1) },
{ MR(r4, r30) },
{ LI(r5, 0x19) },
{ MR(r6, r31) },
{ LI(r11, 0x193) },
{ SC(0) },
{ CLRLDI(r29, r28, 32) },
{ CLRLDI(r4, r26, 32) },
{ LD(r3, r29, 0x10) },
{ 0, 0xffffffff }, // .hex2str
{ LI(r5, 0x10) },
{ CLRLDI(r4, r3, 32) },
{ MR(r6, r31) },
{ LI(r3, 1) },
{ LI(r11, 0x193) },
{ SC(0) },
{ LI(r3, 1) },
{ MR(r4, r27) },
{ LI(r5, 1) },
{ MR(r6, r31) },
{ LI(r11, 0x193) },
{ SC(0) },
{ LD(r28, r29, 0) },
{ CMPDI(cr7, r28, 0) },
{ BNE(cr7, -0x60) },
{ LWZ(r4, r2, 0), 0xffff },
{ MR(r6, r31) },
{ LI(r3, 1) },
{ LI(r5, 0x27) },
{ LI(r11, 0x193) },
{ SC(0) },
{ LI(r3, 1) },
{ B(0, false, true), 0x3fffffc }, // .sys_process_exit
{ LD(r2, r1, 0x28) },
{ LI(r3, 1) },
{ B(0, false, true), 0x3fffffc }, // .exit
};
const std::initializer_list<ppu_pattern> abort2
{
{ STDU(r1, r1, -0xc0) },
{ MFLR(r0) },
{ STD(r27, r1, 0x98) },
{ STD(r28, r1, 0xa0) },
{ STD(r29, r1, 0xa8) },
{ STD(r30, r1, 0xb0) },
{ STD(r31, r1, 0xb8) },
{ STD(r0, r1, 0xd0) },
{ MR(r9, r1) },
{ CLRLDI(r9, r9, 32) },
{ LWZ(r4, r2, 0), 0xffff },
{ ADDI(r31, r1, 0x70) },
{ LI(r3, 1) },
{ LI(r5, 0x19) },
{ MR(r6, r31) },
{ LWZ(r29, r9, 4) },
{ LI(r11, 0x193) },
{ SC(0) },
{ ADDI(r27, r1, 0x78) },
{ LD(r3, r29, 0x10) },
{ MR(r4, r27) },
{ B(0, false, true), 0x3fffffc }, // .hex2str
{ LI(r5, 0x10) },
{ CLRLDI(r4, r3, 32) },
{ MR(r6, r31) },
{ LI(r3, 1) },
{ LI(r11, 0x193) },
{ SC(0) },
{ LWZ(r28, r2, 0), 0xffff },
{ LI(r3, 1) },
{ LI(r5, 1) },
{ MR(r4, r28) },
{ MR(r6, r31) },
{ LI(r11, 0x193) },
{ SC(0) },
{ LD(r29, r29, 0) },
{ CMPDI(cr7, r29, 0) },
{ BEQ(cr7, +0x6c) },
{ LWZ(r30, r2, 0), 0xffff },
{ LI(r3, 1) },
{ MR(r4, r30) },
{ LI(r5, 0x19) },
{ MR(r6, r31) },
{ LI(r11, 0x193) },
{ SC(0) },
{ CLRLDI(r29, r29, 32) },
{ CLRLDI(r4, r27, 32) },
{ LD(r3, r29, 0x10) },
{ 0, 0xffffffff }, // .hex2str
{ LI(r5, 0x10) },
{ CLRLDI(r4, r3, 32) },
{ MR(r6, r31) },
{ LI(r3, 1) },
{ LI(r11, 0x193) },
{ SC(0) },
{ LI(r3, 1) },
{ MR(r4, r28) },
{ LI(r5, 1) },
{ MR(r6, r31) },
{ LI(r11, 0x193) },
{ SC(0) },
{ LD(r29, r29, 0) },
{ CMPDI(cr7, r29, 0) },
{ BNE(cr7, -0x60) },
{ LWZ(r4, r2, 0), 0xffff },
{ MR(r6, r31) },
{ LI(r3, 1) },
{ LI(r5, 0x27) },
{ LI(r11, 0x193) },
{ SC(0) },
{ LI(r3, 1) },
{ B(0, false, true), 0x3fffffc }, // .sys_process_exit
{ LD(r2, r1, 0x28) },
{ LI(r3, 1) },
{ B(0, false, true), 0x3fffffc }, // .exit
};
const std::initializer_list<std::initializer_list<ppu_pattern>> abort
{
abort1,
abort2,
};
}
std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& segs, const std::vector<std::pair<u32, u32>>& secs, u32 entry, u32 lib_toc) std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& segs, const std::vector<std::pair<u32, u32>>& secs, u32 entry, u32 lib_toc)
{ {
// Assume first segment is executable // Assume first segment is executable
const u32 start = segs[0].first; const u32 start = segs[0].first;
const u32 end = segs[0].first + segs[0].second; const u32 end = segs[0].first + segs[0].second;
const u32 start_toc = entry ? +vm::read32(entry + 4) : lib_toc; const u32 start_toc = entry && !lib_toc ? +vm::read32(entry + 4) : lib_toc;
// Known TOCs (usually only 1) // Known TOCs (usually only 1)
std::unordered_set<u32> TOCs; std::unordered_set<u32> TOCs;
@ -186,26 +405,98 @@ std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& se
// Otherwise, register initial set of functions (likely including the entry point) // Otherwise, register initial set of functions (likely including the entry point)
add_toc(start_toc); add_toc(start_toc);
// Find eh_frame section // Find .eh_frame section
for (const auto& sec : secs) for (const auto& sec : secs)
{ {
const u32 sec_end = sec.first + sec.second; u32 sec_end = sec.first + sec.second;
if (sec.first + 32 >= sec_end || vm::read64(sec.first) != 0x0000001c00000000 || vm::read16(sec.first + 8) != 0x017a) // Probe
for (vm::cptr<u32> ptr = vm::cast(sec.first); ptr.addr() < sec_end;)
{ {
continue; if (ptr % 4 || ptr.addr() < sec.first || ptr.addr() >= sec_end)
{
sec_end = 0;
break;
}
const u32 size = ptr[0] + 4;
if (size == 4 && ptr.addr() == sec_end - 4)
{
// Null terminator
break;
}
if (size % 4 || size < 0x10 || size > sec_end - ptr.addr())
{
sec_end = 0;
break;
}
if (ptr[1])
{
const u32 cie_off = ptr.addr() - ptr[1] + 4;
if (cie_off % 4 || cie_off < sec.first || cie_off >= sec_end)
{
sec_end = 0;
break;
}
}
ptr = vm::cast(ptr.addr() + size);
} }
for (vm::cptr<u32> ptr = vm::cast(sec.first); ptr.addr() < sec_end - 4; ptr = vm::cast(ptr.addr() + ptr[0] + 4)) // Mine
for (vm::cptr<u32> ptr = vm::cast(sec.first); ptr.addr() < sec_end; ptr = vm::cast(ptr.addr() + ptr[0] + 4))
{ {
if (const u32 off = ptr[1]) if (ptr[0] == 0)
{ {
const u32 addr = ptr[3] + (ptr + 2).addr(); // Function offset (64 bit) // Null terminator
const u32 size = ptr[5]; // Function size (64 bit) break;
}
LOG_NOTICE(PPU, ".eh_frame: [0x%x] 0x%x, 0x%x (size=0x%x)", ptr, ptr[0], ptr[1], size); if (ptr[1] == 0)
{
// CIE
LOG_NOTICE(PPU, ".eh_frame: [0x%x] CIE 0x%x", ptr, ptr[0]);
}
else
{
// Get associated CIE (currently unused)
const vm::cptr<u32> cie = vm::cast(ptr.addr() - ptr[1] + 4);
if (!ptr[3]) continue; // TODO (some entries have zero offset) u32 addr = 0;
u32 size = 0;
if ((ptr[2] == -1 || ptr[2] == 0) && ptr[4] == 0)
{
addr = ptr[3] + ptr.addr() + 8;
size = ptr[5];
}
else if (ptr[2] == 0 && ptr[3] == 0)
{
}
else if (ptr[2] != -1 && ptr[4])
{
addr = ptr[2];
size = ptr[3];
}
else
{
LOG_ERROR(PPU, ".eh_frame: [0x%x] 0x%x, 0x%x, 0x%x, 0x%x, 0x%x", ptr, ptr[0], ptr[1], ptr[2], ptr[3], ptr[4]);
continue;
}
LOG_NOTICE(PPU, ".eh_frame: [0x%x] FDE 0x%x (cie=*0x%x, addr=0x%x, size=0x%x)", ptr, ptr[0], cie, addr, size);
if (!addr) continue; // TODO (some entries have zero offset)
if (addr % 4 || addr < start || addr >= end)
{
LOG_ERROR(PPU, ".eh_frame: Invalid function 0x%x", addr);
continue;
}
auto& func = add_func(addr, 0, ptr.addr()); auto& func = add_func(addr, 0, ptr.addr());
func.attr += ppu_attr::known_size; func.attr += ppu_attr::known_size;
@ -230,11 +521,15 @@ std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& se
if (ptr + 1 <= fend && (ptr[0] & 0xfc000001) == B({}, {})) if (ptr + 1 <= fend && (ptr[0] & 0xfc000001) == B({}, {}))
{ {
// Simple gate // Simple gate
func.size = 0x4;
func.blocks.emplace(func.addr, func.size);
const u32 target = ppu_branch_target(ptr[0] & 0x2 ? 0 : ptr.addr(), s32(ptr[0]) << 6 >> 6); const u32 target = ppu_branch_target(ptr[0] & 0x2 ? 0 : ptr.addr(), s32(ptr[0]) << 6 >> 6);
add_func(target, func.toc, func.addr);
continue; if (target >= start && target < end)
{
func.size = 0x4;
func.blocks.emplace(func.addr, func.size);
add_func(target, func.toc, func.addr);
continue;
}
} }
if (ptr + 4 <= fend && if (ptr + 4 <= fend &&
@ -244,13 +539,17 @@ std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& se
(ptr[3] & 0xfc000001) == B({}, {})) (ptr[3] & 0xfc000001) == B({}, {}))
{ {
// TOC change gate // TOC change gate
func.size = 0x10;
func.blocks.emplace(func.addr, func.size);
const u32 new_toc = func.toc && func.toc != -1 ? func.toc + (ptr[1] << 16) + s16(ptr[2]) : 0; const u32 new_toc = func.toc && func.toc != -1 ? func.toc + (ptr[1] << 16) + s16(ptr[2]) : 0;
const u32 target = ppu_branch_target(ptr[3] & 0x2 ? 0 : (ptr + 3).addr(), s32(ptr[3]) << 6 >> 6); const u32 target = ppu_branch_target(ptr[3] & 0x2 ? 0 : (ptr + 3).addr(), s32(ptr[3]) << 6 >> 6);
add_func(target, new_toc, func.addr);
add_toc(new_toc); if (target >= start && target < end)
continue; {
func.size = 0x10;
func.blocks.emplace(func.addr, func.size);
add_func(target, new_toc, func.addr);
add_toc(new_toc);
continue;
}
} }
if (ptr + 8 <= fend && if (ptr + 8 <= fend &&
@ -269,6 +568,15 @@ std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& se
continue; continue;
} }
if (const u32 len = ppu_test(ptr, fend, ppu_patterns::abort))
{
// Function .abort
LOG_NOTICE(PPU, "Function [0x%x]: 'abort'", func.addr);
func.attr += ppu_attr::no_return;
func.attr += ppu_attr::known_size;
func.size = len;
}
if (ptr + 3 <= fend && if (ptr + 3 <= fend &&
(ptr[0] & 0xffff0000) == LI(r0, 0) && (ptr[0] & 0xffff0000) == LI(r0, 0) &&
(ptr[1] & 0xffff0000) == ORIS(r0, r0, 0) && (ptr[1] & 0xffff0000) == ORIS(r0, r0, 0) &&
@ -350,6 +658,13 @@ std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& se
else if (type == ppu_itype::B || type == ppu_itype::BC) else if (type == ppu_itype::B || type == ppu_itype::BC)
{ {
const u32 target = ppu_branch_target(op.aa ? 0 : iaddr, type == ppu_itype::B ? +op.ll : +op.simm16); const u32 target = ppu_branch_target(op.aa ? 0 : iaddr, type == ppu_itype::B ? +op.ll : +op.simm16);
if (target < start || target >= end)
{
LOG_WARNING(PPU, "[0x%x] Invalid branch at 0x%x -> 0x%x", func.addr, iaddr, target);
continue;
}
const bool is_call = op.lk && target != iaddr; const bool is_call = op.lk && target != iaddr;
const auto pfunc = is_call ? &add_func(target, 0, func.addr) : nullptr; const auto pfunc = is_call ? &add_func(target, 0, func.addr) : nullptr;
@ -537,9 +852,12 @@ std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& se
{ {
const u32 target = ppu_branch_target(op.aa ? 0 : iaddr, type == ppu_itype::B ? +op.ll : +op.simm16); const u32 target = ppu_branch_target(op.aa ? 0 : iaddr, type == ppu_itype::B ? +op.ll : +op.simm16);
if (target < func.addr || target >= func.addr + func.size) if (target >= start && target < end)
{ {
add_func(target, func.toc, func.addr); if (target < func.addr || target >= func.addr + func.size)
{
add_func(target, func.toc, func.addr);
}
} }
} }
else if (type == ppu_itype::BCCTR && !op.lk) else if (type == ppu_itype::BCCTR && !op.lk)

View File

@ -2,7 +2,8 @@
#include <map> #include <map>
#include "../Utilities/BitSet.h" #include "Utilities/BitSet.h"
#include "Utilities/BEType.h"
// PPU Function Attributes // PPU Function Attributes
enum class ppu_attr : u32 enum class ppu_attr : u32
@ -24,6 +25,27 @@ struct ppu_function
std::map<u32, u32> blocks; // Basic blocks: addr -> size std::map<u32, u32> blocks; // Basic blocks: addr -> size
}; };
// Aux
struct ppu_pattern
{
be_t<u32> opcode;
be_t<u32> mask;
ppu_pattern() = default;
ppu_pattern(u32 op)
: opcode(op)
, mask(0xffffffff)
{
}
ppu_pattern(u32 op, u32 ign)
: opcode(op & ~ign)
, mask(~ign)
{
}
};
extern void ppu_validate(const std::string& fname, const std::vector<ppu_function>& funcs, u32 reloc); extern void ppu_validate(const std::string& fname, const std::vector<ppu_function>& funcs, u32 reloc);
extern std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& segs, const std::vector<std::pair<u32, u32>>& secs, u32 entry, u32 lib_toc); extern std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& segs, const std::vector<std::pair<u32, u32>>& secs, u32 entry, u32 lib_toc);

View File

@ -731,13 +731,12 @@ static void ppu_load_imports(const std::shared_ptr<ppu_linkage_info>& link, u32
} }
} }
template<> std::shared_ptr<lv2_prx_t> ppu_load_prx(const ppu_prx_object& elf)
std::shared_ptr<lv2_prx_t> ppu_prx_loader::load() const
{ {
std::vector<std::pair<u32, u32>> segments; std::vector<std::pair<u32, u32>> segments;
std::vector<std::pair<u32, u32>> sections; // Unused std::vector<std::pair<u32, u32>> sections;
for (const auto& prog : progs) for (const auto& prog : elf.progs)
{ {
LOG_NOTICE(LOADER, "** Segment: p_type=0x%x, p_vaddr=0x%llx, p_filesz=0x%llx, p_memsz=0x%llx, flags=0x%x", prog.p_type, prog.p_vaddr, prog.p_filesz, prog.p_memsz, prog.p_flags); LOG_NOTICE(LOADER, "** Segment: p_type=0x%x, p_vaddr=0x%llx, p_filesz=0x%llx, p_memsz=0x%llx, flags=0x%x", prog.p_type, prog.p_vaddr, prog.p_filesz, prog.p_memsz, prog.p_flags);
@ -775,8 +774,30 @@ std::shared_ptr<lv2_prx_t> ppu_prx_loader::load() const
} }
} }
for (const auto& s : elf.shdrs)
{
LOG_NOTICE(LOADER, "** Section: sh_type=0x%x, addr=0x%llx, size=0x%llx, flags=0x%x", s.sh_type, s.sh_addr, s.sh_size, s.sh_flags);
const u32 addr = vm::cast(s.sh_addr);
const u32 size = vm::cast(s.sh_size);
if (s.sh_type == 1 && addr && size)
{
for (auto i = 0; i < segments.size(); i++)
{
const u32 saddr = static_cast<u32>(elf.progs[i].p_vaddr);
if (addr >= addr && addr < saddr + elf.progs[i].p_memsz)
{
// "Relocate" section
sections.emplace_back(std::make_pair(addr - saddr + segments[i].first, size));
break;
}
}
}
}
// Do relocations // Do relocations
for (auto& prog : progs) for (auto& prog : elf.progs)
{ {
switch (const u32 p_type = prog.p_type) switch (const u32 p_type = prog.p_type)
{ {
@ -831,9 +852,27 @@ std::shared_ptr<lv2_prx_t> ppu_prx_loader::load() const
} }
case 10: case 10:
{
const u32 value = vm::_ref<ppu_bf_t<u32, 6, 24>>(raddr) = static_cast<u32>(rdata - raddr) >> 2;
LOG_WARNING(LOADER, "**** RELOCATION(10): 0x%x <- 0x%06x (0x%llx)", raddr, value, rdata);
break;
}
case 44: case 44:
{
const u64 value = vm::_ref<u64>(raddr) = rdata - raddr;
LOG_TRACE(LOADER, "**** RELOCATION(44): 0x%x <- 0x%016llx (0x%llx)", raddr, value, rdata);
break;
}
case 57: case 57:
default: LOG_ERROR(LOADER, "**** RELOCATION(%u): Illegal/Unknown type! (addr=0x%x)", type, raddr); {
const u16 value = vm::_ref<ppu_bf_t<u16, 0, 14>>(raddr) = static_cast<u16>(rdata) >> 2;
LOG_WARNING(LOADER, "**** RELOCATION(57): 0x%x <- 0x%04x (0x%llx)", raddr, value, rdata);
break;
}
default: LOG_ERROR(LOADER, "**** RELOCATION(%u): Illegal/Unknown type! (addr=0x%x; 0x%llx)", type, raddr, rdata);
} }
} }
@ -848,7 +887,7 @@ std::shared_ptr<lv2_prx_t> ppu_prx_loader::load() const
// Create new PRX object // Create new PRX object
auto prx = idm::make_ptr<lv2_prx_t>(); auto prx = idm::make_ptr<lv2_prx_t>();
if (!progs.empty() && progs[0].p_paddr) if (!elf.progs.empty() && elf.progs[0].p_paddr)
{ {
struct ppu_prx_library_info struct ppu_prx_library_info
{ {
@ -863,7 +902,7 @@ std::shared_ptr<lv2_prx_t> ppu_prx_loader::load() const
}; };
// Access library information (TODO) // Access library information (TODO)
const auto& lib_info = vm::cptr<ppu_prx_library_info>(vm::cast(segments[0].first + progs[0].p_paddr - progs[0].p_offset, HERE)); const auto& lib_info = vm::cptr<ppu_prx_library_info>(vm::cast(segments[0].first + elf.progs[0].p_paddr - elf.progs[0].p_offset, HERE));
const auto& lib_name = std::string(lib_info->name); const auto& lib_name = std::string(lib_info->name);
LOG_WARNING(LOADER, "Library %s (rtoc=0x%x):", lib_name, lib_info->toc); LOG_WARNING(LOADER, "Library %s (rtoc=0x%x):", lib_name, lib_info->toc);
@ -872,7 +911,7 @@ std::shared_ptr<lv2_prx_t> ppu_prx_loader::load() const
ppu_load_imports(link, lib_info->imports_start, lib_info->imports_end); ppu_load_imports(link, lib_info->imports_start, lib_info->imports_end);
prx->funcs = ppu_analyse(segments, sections, 0, lib_info->toc); prx->funcs = ppu_analyse(segments, sections, prx->specials[0xbc9a0086], lib_info->toc);
} }
else else
{ {
@ -886,8 +925,7 @@ std::shared_ptr<lv2_prx_t> ppu_prx_loader::load() const
return prx; return prx;
} }
template<> void ppu_load_exec(const ppu_exec_object& elf)
void ppu_exec_loader::load() const
{ {
ppu_initialize_modules(); ppu_initialize_modules();
@ -909,7 +947,7 @@ void ppu_exec_loader::load() const
std::vector<ppu_function> exec_set; std::vector<ppu_function> exec_set;
// Allocate memory at fixed positions // Allocate memory at fixed positions
for (const auto& prog : progs) for (const auto& prog : elf.progs)
{ {
LOG_NOTICE(LOADER, "** Segment: p_type=0x%x, p_vaddr=0x%llx, p_filesz=0x%llx, p_memsz=0x%llx, flags=0x%x", prog.p_type, prog.p_vaddr, prog.p_filesz, prog.p_memsz, prog.p_flags); LOG_NOTICE(LOADER, "** Segment: p_type=0x%x, p_vaddr=0x%llx, p_filesz=0x%llx, p_memsz=0x%llx, flags=0x%x", prog.p_type, prog.p_vaddr, prog.p_filesz, prog.p_memsz, prog.p_flags);
@ -932,7 +970,7 @@ void ppu_exec_loader::load() const
} }
} }
for (const auto& s : shdrs) for (const auto& s : elf.shdrs)
{ {
LOG_NOTICE(LOADER, "** Section: sh_type=0x%x, addr=0x%llx, size=0x%llx, flags=0x%x", s.sh_type, s.sh_addr, s.sh_size, s.sh_flags); LOG_NOTICE(LOADER, "** Section: sh_type=0x%x, addr=0x%llx, size=0x%llx, flags=0x%x", s.sh_type, s.sh_addr, s.sh_size, s.sh_flags);
@ -946,7 +984,7 @@ void ppu_exec_loader::load() const
} }
// Load other programs // Load other programs
for (auto& prog : progs) for (auto& prog : elf.progs)
{ {
switch (const u32 p_type = prog.p_type) switch (const u32 p_type = prog.p_type)
{ {
@ -1057,28 +1095,28 @@ void ppu_exec_loader::load() const
if (g_cfg_load_liblv2) if (g_cfg_load_liblv2)
{ {
const ppu_prx_loader loader = fs::file(lle_dir + "/liblv2.sprx"); const ppu_prx_object obj = fs::file(lle_dir + "/liblv2.sprx");
if (loader == elf_error::ok) if (obj == elf_error::ok)
{ {
start_funcs.push_back(loader.load()->start.addr()); start_funcs.push_back(ppu_load_prx(obj)->start.addr());
} }
else else
{ {
throw fmt::exception("Failed to load liblv2.sprx: %s", loader.get_error()); throw fmt::exception("Failed to load liblv2.sprx: %s", obj.get_error());
} }
} }
else else
{ {
for (const auto& name : g_cfg_load_libs.get_set()) for (const auto& name : g_cfg_load_libs.get_set())
{ {
const ppu_prx_loader loader = fs::file(lle_dir + '/' + name); const ppu_prx_object obj = fs::file(lle_dir + '/' + name);
if (loader == elf_error::ok) if (obj == elf_error::ok)
{ {
LOG_WARNING(LOADER, "Loading library: %s", name); LOG_WARNING(LOADER, "Loading library: %s", name);
const auto prx = loader.load(); const auto prx = ppu_load_prx(obj);
// Register start function // Register start function
if (prx->start) if (prx->start)
@ -1093,7 +1131,7 @@ void ppu_exec_loader::load() const
} }
else else
{ {
LOG_FATAL(LOADER, "Failed to load %s: %s", name, loader.get_error()); LOG_FATAL(LOADER, "Failed to load %s: %s", name, obj.get_error());
} }
} }
} }
@ -1221,7 +1259,7 @@ void ppu_exec_loader::load() const
} }
// Analyse executable // Analyse executable
const auto funcs = ppu_analyse(segments, sections, static_cast<u32>(header.e_entry), 0); const auto funcs = ppu_analyse(segments, sections, static_cast<u32>(elf.header.e_entry), 0);
ppu_validate(vfs::get(Emu.GetPath()), funcs, 0); ppu_validate(vfs::get(Emu.GetPath()), funcs, 0);
@ -1287,7 +1325,7 @@ void ppu_exec_loader::load() const
*entry++ = MR(r12, r19); *entry++ = MR(r12, r19);
// Branch to initialization // Branch to initialization
make_branch(entry, static_cast<u32>(header.e_entry), true); make_branch(entry, static_cast<u32>(elf.header.e_entry), true);
// Register entry function (addr, size) // Register entry function (addr, size)
ppu_function entry_func; ppu_function entry_func;
@ -1296,7 +1334,7 @@ void ppu_exec_loader::load() const
exec_set.emplace_back(entry_func); exec_set.emplace_back(entry_func);
// Initialize recompiler // Initialize recompiler
ppu_initialize("", exec_set, static_cast<u32>(header.e_entry)); ppu_initialize("", exec_set, static_cast<u32>(elf.header.e_entry));
auto ppu = idm::make_ptr<PPUThread>("main_thread"); auto ppu = idm::make_ptr<PPUThread>("main_thread");

View File

@ -586,6 +586,11 @@ namespace ppu_instructions
r12, r13, r14, r15, r16, r17, r18, r19, r20, r21, r12, r13, r14, r15, r16, r17, r18, r19, r20, r21,
r22, r23, r24, r25, r26, r27, r28, r29, r30, r31, r22, r23, r24, r25, r26, r27, r28, r29, r30, r31,
}; };
enum
{
cr0, cr1, cr2, cr3, cr4, cr5, cr6, cr7,
};
} }
using namespace fields; using namespace fields;
@ -595,7 +600,7 @@ namespace ppu_instructions
inline u32 ORI(u32 rt, u32 ra, u32 ui) { ppu_opcode_t op{ 0x18u << 26 }; op.rd = rt; op.ra = ra; op.uimm16 = ui; return op.opcode; } inline u32 ORI(u32 rt, u32 ra, u32 ui) { ppu_opcode_t op{ 0x18u << 26 }; op.rd = rt; op.ra = ra; op.uimm16 = ui; return op.opcode; }
inline u32 ORIS(u32 rt, u32 ra, u32 ui) { ppu_opcode_t op{ 0x19u << 26 }; op.rd = rt; op.ra = ra; op.uimm16 = ui; return op.opcode; } inline u32 ORIS(u32 rt, u32 ra, u32 ui) { ppu_opcode_t op{ 0x19u << 26 }; op.rd = rt; op.ra = ra; op.uimm16 = ui; return op.opcode; }
inline u32 OR(u32 ra, u32 rs, u32 rb, bool rc = false) { ppu_opcode_t op{ 0x1fu << 26 | 0x1bcu << 1 }; op.rs = rs; op.ra = ra; op.rb = rb; op.rc = rc; return op.opcode; } inline u32 OR(u32 ra, u32 rs, u32 rb, bool rc = false) { ppu_opcode_t op{ 0x1fu << 26 | 0x1bcu << 1 }; op.rs = rs; op.ra = ra; op.rb = rb; op.rc = rc; return op.opcode; }
inline u32 SC(u32 lev) { ppu_opcode_t op{ 0x11u << 26 }; op.lev = lev; return op.opcode; } inline u32 SC(u32 lev) { ppu_opcode_t op{ 0x11u << 26 | 1 << 1 }; op.lev = lev; return op.opcode; }
inline u32 B(s32 li, bool aa = false, bool lk = false) { ppu_opcode_t op{ 0x12u << 26 }; op.ll = li; op.aa = aa; op.lk = lk; return op.opcode; } inline u32 B(s32 li, bool aa = false, bool lk = false) { ppu_opcode_t op{ 0x12u << 26 }; op.ll = li; op.aa = aa; op.lk = lk; return op.opcode; }
inline u32 BC(u32 bo, u32 bi, s32 bd, bool aa = false, bool lk = false) { ppu_opcode_t op{ 0x10u << 26 }; op.bo = bo; op.bi = bi; op.ds = bd / 4; op.aa = aa; op.lk = lk; return op.opcode; } inline u32 BC(u32 bo, u32 bi, s32 bd, bool aa = false, bool lk = false) { ppu_opcode_t op{ 0x10u << 26 }; op.bo = bo; op.bi = bi; op.ds = bd / 4; op.aa = aa; op.lk = lk; return op.opcode; }
inline u32 BCLR(u32 bo, u32 bi, u32 bh, bool lk = false) { ppu_opcode_t op{ 0x13u << 26 | 0x10u << 1 }; op.bo = bo; op.bi = bi; op.bh = bh; op.lk = lk; return op.opcode; } inline u32 BCLR(u32 bo, u32 bi, u32 bh, bool lk = false) { ppu_opcode_t op{ 0x13u << 26 | 0x10u << 1 }; op.bo = bo; op.bi = bi; op.bh = bh; op.lk = lk; return op.opcode; }
@ -607,8 +612,8 @@ namespace ppu_instructions
inline u32 STDU(u32 rs, u32 ra, s32 si) { ppu_opcode_t op{ 0x3eu << 26 | 1 }; op.rs = rs; op.ra = ra; op.ds = si / 4; return op.opcode; } inline u32 STDU(u32 rs, u32 ra, s32 si) { ppu_opcode_t op{ 0x3eu << 26 | 1 }; op.rs = rs; op.ra = ra; op.ds = si / 4; return op.opcode; }
inline u32 LD(u32 rt, u32 ra, s32 si) { ppu_opcode_t op{ 0x3au << 26 }; op.rd = rt; op.ra = ra; op.ds = si / 4; return op.opcode; } inline u32 LD(u32 rt, u32 ra, s32 si) { ppu_opcode_t op{ 0x3au << 26 }; op.rd = rt; op.ra = ra; op.ds = si / 4; return op.opcode; }
inline u32 LDU(u32 rt, u32 ra, s32 si) { ppu_opcode_t op{ 0x3au << 26 | 1 }; op.rd = rt; op.ra = ra; op.ds = si / 4; return op.opcode; } inline u32 LDU(u32 rt, u32 ra, s32 si) { ppu_opcode_t op{ 0x3au << 26 | 1 }; op.rd = rt; op.ra = ra; op.ds = si / 4; return op.opcode; }
//inline u32 CMPI(u32 bf, u32 l, u32 ra, u32 ui) { ppu_opcode_t op{ 0xbu << 26 }; op.crfd = bf; op.l10 = l; op.ra = ra; op.uimm16 = ui; return op.opcode; } inline u32 CMPI(u32 bf, u32 l, u32 ra, u32 ui) { ppu_opcode_t op{ 0xbu << 26 }; op.crfd = bf; op.l10 = l; op.ra = ra; op.uimm16 = ui; return op.opcode; }
//inline u32 CMPLI(u32 bf, u32 l, u32 ra, u32 ui) { ppu_opcode_t op{ 0xau << 26 }; op.crfd = bf; op.l10 = l; op.ra = ra; op.uimm16 = ui; return op.opcode; } inline u32 CMPLI(u32 bf, u32 l, u32 ra, u32 ui) { ppu_opcode_t op{ 0xau << 26 }; op.crfd = bf; op.l10 = l; op.ra = ra; op.uimm16 = ui; return op.opcode; }
inline u32 RLDICL(u32 ra, u32 rs, u32 sh, u32 mb, bool rc = false) { ppu_opcode_t op{ 30 << 26 }; op.ra = ra; op.rs = rs; op.sh64 = sh; op.mbe64 = mb; op.rc = rc; return op.opcode; } inline u32 RLDICL(u32 ra, u32 rs, u32 sh, u32 mb, bool rc = false) { ppu_opcode_t op{ 30 << 26 }; op.ra = ra; op.rs = rs; op.sh64 = sh; op.mbe64 = mb; op.rc = rc; return op.opcode; }
namespace implicts namespace implicts
@ -627,21 +632,21 @@ namespace ppu_instructions
inline u32 MFLR(u32 reg) { return MFSPR(reg, 8 << 5); } inline u32 MFLR(u32 reg) { return MFSPR(reg, 8 << 5); }
inline u32 MTLR(u32 reg) { return MTSPR(8 << 5, reg); } inline u32 MTLR(u32 reg) { return MTSPR(8 << 5, reg); }
//inline u32 BNE(u32 cr, s32 imm) { return BC(4, 2 | cr << 2, imm); } inline u32 BNE(u32 cr, s32 imm) { return BC(4, 2 | cr << 2, imm); }
//inline u32 BEQ(u32 cr, s32 imm) { return BC(12, 2 | cr << 2, imm); } inline u32 BEQ(u32 cr, s32 imm) { return BC(12, 2 | cr << 2, imm); }
//inline u32 BGT(u32 cr, s32 imm) { return BC(12, 1 | cr << 2, imm); } inline u32 BGT(u32 cr, s32 imm) { return BC(12, 1 | cr << 2, imm); }
//inline u32 BNE(s32 imm) { return BNE(cr0, imm); } inline u32 BNE(s32 imm) { return BNE(cr0, imm); }
//inline u32 BEQ(s32 imm) { return BEQ(cr0, imm); } inline u32 BEQ(s32 imm) { return BEQ(cr0, imm); }
//inline u32 BGT(s32 imm) { return BGT(cr0, imm); } inline u32 BGT(s32 imm) { return BGT(cr0, imm); }
//inline u32 CMPDI(u32 cr, u32 reg, u32 imm) { return CMPI(cr, 1, reg, imm); } inline u32 CMPDI(u32 cr, u32 reg, u32 imm) { return CMPI(cr, 1, reg, imm); }
//inline u32 CMPDI(u32 reg, u32 imm) { return CMPDI(cr0, reg, imm); } inline u32 CMPDI(u32 reg, u32 imm) { return CMPDI(cr0, reg, imm); }
//inline u32 CMPWI(u32 cr, u32 reg, u32 imm) { return CMPI(cr, 0, reg, imm); } inline u32 CMPWI(u32 cr, u32 reg, u32 imm) { return CMPI(cr, 0, reg, imm); }
//inline u32 CMPWI(u32 reg, u32 imm) { return CMPWI(cr0, reg, imm); } inline u32 CMPWI(u32 reg, u32 imm) { return CMPWI(cr0, reg, imm); }
//inline u32 CMPLDI(u32 cr, u32 reg, u32 imm) { return CMPLI(cr, 1, reg, imm); } inline u32 CMPLDI(u32 cr, u32 reg, u32 imm) { return CMPLI(cr, 1, reg, imm); }
//inline u32 CMPLDI(u32 reg, u32 imm) { return CMPLDI(cr0, reg, imm); } inline u32 CMPLDI(u32 reg, u32 imm) { return CMPLDI(cr0, reg, imm); }
//inline u32 CMPLWI(u32 cr, u32 reg, u32 imm) { return CMPLI(cr, 0, reg, imm); } inline u32 CMPLWI(u32 cr, u32 reg, u32 imm) { return CMPLI(cr, 0, reg, imm); }
//inline u32 CMPLWI(u32 reg, u32 imm) { return CMPLWI(cr0, reg, imm); } inline u32 CMPLWI(u32 reg, u32 imm) { return CMPLWI(cr0, reg, imm); }
inline u32 EXTRDI(u32 x, u32 y, u32 n, u32 b) { return RLDICL(x, y, b + n, 64 - b, false); } inline u32 EXTRDI(u32 x, u32 y, u32 n, u32 b) { return RLDICL(x, y, b + n, 64 - b, false); }
inline u32 SRDI(u32 x, u32 y, u32 n) { return RLDICL(x, y, 64 - n, n, false); } inline u32 SRDI(u32 x, u32 y, u32 n) { return RLDICL(x, y, 64 - n, n, false); }

View File

@ -566,7 +566,7 @@ extern void ppu_initialize(const std::string& name, const std::vector<ppu_functi
pm.add(createReassociatePass()); pm.add(createReassociatePass());
pm.add(createInstructionCombiningPass()); pm.add(createInstructionCombiningPass());
//pm.add(createBasicAAWrapperPass()); //pm.add(createBasicAAWrapperPass());
pm.add(new MemoryDependenceAnalysis()); //pm.add(new MemoryDependenceAnalysis());
pm.add(createLICMPass()); pm.add(createLICMPass());
pm.add(createLoopInstSimplifyPass()); pm.add(createLoopInstSimplifyPass());
pm.add(createGVNPass()); pm.add(createGVNPass());

View File

@ -234,12 +234,11 @@ bool RawSPUThread::write_reg(const u32 addr, const u32 value)
return false; return false;
} }
template<> void spu_load_exec(const spu_exec_object& elf)
void spu_exec_loader::load() const
{ {
auto spu = idm::make_ptr<RawSPUThread>("TEST_SPU"); auto spu = idm::make_ptr<RawSPUThread>("TEST_SPU");
for (const auto& prog : progs) for (const auto& prog : elf.progs)
{ {
if (prog.p_type == 0x1 /* LOAD */ && prog.p_memsz) if (prog.p_type == 0x1 /* LOAD */ && prog.p_memsz)
{ {
@ -248,5 +247,5 @@ void spu_exec_loader::load() const
} }
spu->cpu_init(); spu->cpu_init();
spu->npc = header.e_entry; spu->npc = elf.header.e_entry;
} }

View File

@ -8,20 +8,22 @@
#include "Emu/Cell/ErrorCodes.h" #include "Emu/Cell/ErrorCodes.h"
#include "sys_prx.h" #include "sys_prx.h"
extern std::shared_ptr<lv2_prx_t> ppu_load_prx(const ppu_prx_object&);
logs::channel sys_prx("sys_prx", logs::level::notice); logs::channel sys_prx("sys_prx", logs::level::notice);
s32 prx_load_module(std::string path, u64 flags, vm::ptr<sys_prx_load_module_option_t> pOpt) s32 prx_load_module(std::string path, u64 flags, vm::ptr<sys_prx_load_module_option_t> pOpt)
{ {
sys_prx.warning("prx_load_module(path='%s', flags=0x%llx, pOpt=*0x%x)", path.c_str(), flags, pOpt); sys_prx.warning("prx_load_module(path='%s', flags=0x%llx, pOpt=*0x%x)", path.c_str(), flags, pOpt);
const ppu_prx_loader loader = fs::file(vfs::get(path)); const ppu_prx_object obj = fs::file(vfs::get(path));
if (loader != elf_error::ok) if (obj != elf_error::ok)
{ {
return CELL_PRX_ERROR_ILLEGAL_LIBRARY; return CELL_PRX_ERROR_ILLEGAL_LIBRARY;
} }
const auto prx = loader.load(); const auto prx = ppu_load_prx(obj);
if (!prx) if (!prx)
{ {

View File

@ -15,14 +15,14 @@ logs::channel sys_spu("sys_spu", logs::level::notice);
void LoadSpuImage(const fs::file& stream, u32& spu_ep, u32 addr) void LoadSpuImage(const fs::file& stream, u32& spu_ep, u32 addr)
{ {
const spu_exec_loader loader = stream; const spu_exec_object obj = stream;
if (loader != elf_error::ok) if (obj != elf_error::ok)
{ {
throw fmt::exception("Failed to load SPU image: %s" HERE, loader.get_error()); throw fmt::exception("Failed to load SPU image: %s" HERE, obj.get_error());
} }
for (const auto& prog : loader.progs) for (const auto& prog : obj.progs)
{ {
if (prog.p_type == 0x1 /* LOAD */) if (prog.p_type == 0x1 /* LOAD */)
{ {
@ -30,7 +30,7 @@ void LoadSpuImage(const fs::file& stream, u32& spu_ep, u32 addr)
} }
} }
spu_ep = loader.header.e_entry; spu_ep = obj.header.e_entry;
} }
u32 LoadSpuImage(const fs::file& stream, u32& spu_ep) u32 LoadSpuImage(const fs::file& stream, u32& spu_ep)

View File

@ -355,8 +355,7 @@ static void arm_patch_refs(u32 refs, u32 addr)
} }
template<> void arm_load_exec(const arm_exec_object& elf)
void arm_exec_loader::load() const
{ {
arm_initialize_modules(); arm_initialize_modules();
@ -373,7 +372,7 @@ void arm_exec_loader::load() const
u32 tls_fsize{}; u32 tls_fsize{};
u32 tls_vsize{}; u32 tls_vsize{};
for (const auto& prog : progs) for (const auto& prog : elf.progs)
{ {
if (prog.p_type == 0x1 /* LOAD */ && prog.p_memsz) if (prog.p_type == 0x1 /* LOAD */ && prog.p_memsz)
{ {
@ -397,7 +396,7 @@ void arm_exec_loader::load() const
} }
} }
if (!module_info) module_info.set(start_addr + header.e_entry); if (!module_info) module_info.set(start_addr + elf.header.e_entry);
if (!libent) libent.set(start_addr + module_info->libent_top); if (!libent) libent.set(start_addr + module_info->libent_top);
if (!libstub) libstub.set(start_addr + module_info->libstub_top); if (!libstub) libstub.set(start_addr + module_info->libstub_top);

View File

@ -39,6 +39,11 @@ extern atomic_t<u32> g_ppu_core[2];
extern u64 get_system_time(); extern u64 get_system_time();
extern void ppu_load_exec(const ppu_exec_object&);
extern void spu_load_exec(const spu_exec_object&);
extern void arm_load_exec(const arm_exec_object&);
extern std::shared_ptr<struct lv2_prx_t> ppu_load_prx(const ppu_prx_object&);
fs::file g_tty; fs::file g_tty;
namespace rpcs3 namespace rpcs3
@ -173,10 +178,10 @@ void Emulator::Load()
} }
const fs::file elf_file(m_path); const fs::file elf_file(m_path);
ppu_exec_loader ppu_exec; ppu_exec_object ppu_exec;
ppu_prx_loader ppu_prx; ppu_prx_object ppu_prx;
spu_exec_loader spu_exec; spu_exec_object spu_exec;
arm_exec_loader arm_exec; arm_exec_object arm_exec;
if (!elf_file) if (!elf_file)
{ {
@ -230,7 +235,7 @@ void Emulator::Load()
vfs::dump(); vfs::dump();
ppu_exec.load(); ppu_load_exec(ppu_exec);
Emu.GetCallbackManager().Init(); Emu.GetCallbackManager().Init();
fxm::import<GSRender>(PURE_EXPR(Emu.GetCallbacks().get_gs_render())); // TODO: must be created in appropriate sys_rsx syscall fxm::import<GSRender>(PURE_EXPR(Emu.GetCallbacks().get_gs_render())); // TODO: must be created in appropriate sys_rsx syscall
@ -240,7 +245,7 @@ void Emulator::Load()
// PPU PRX (experimental) // PPU PRX (experimental)
m_status = Ready; m_status = Ready;
vm::ps3::init(); vm::ps3::init();
ppu_prx.load(); ppu_load_prx(ppu_prx);
GetCallbackManager().Init(); GetCallbackManager().Init();
} }
else if (spu_exec.open(elf_file) == elf_error::ok) else if (spu_exec.open(elf_file) == elf_error::ok)
@ -248,23 +253,23 @@ void Emulator::Load()
// SPU executable (experimental) // SPU executable (experimental)
m_status = Ready; m_status = Ready;
vm::ps3::init(); vm::ps3::init();
spu_exec.load(); spu_load_exec(spu_exec);
} }
else if (arm_exec.open(elf_file) == elf_error::ok) else if (arm_exec.open(elf_file) == elf_error::ok)
{ {
// ARMv7 executable // ARMv7 executable
m_status = Ready; m_status = Ready;
vm::psv::init(); vm::psv::init();
arm_exec.load(); arm_load_exec(arm_exec);
} }
else else
{ {
LOG_ERROR(LOADER, "Invalid or unsupported file format: %s", m_path); LOG_ERROR(LOADER, "Invalid or unsupported file format: %s", m_path);
LOG_WARNING(LOADER, "** ppu_exec_loader -> %s", ppu_exec.get_error()); LOG_WARNING(LOADER, "** ppu_exec -> %s", ppu_exec.get_error());
LOG_WARNING(LOADER, "** ppu_prx_loader -> %s", ppu_prx.get_error()); LOG_WARNING(LOADER, "** ppu_prx -> %s", ppu_prx.get_error());
LOG_WARNING(LOADER, "** spu_exec_loader -> %s", spu_exec.get_error()); LOG_WARNING(LOADER, "** spu_exec -> %s", spu_exec.get_error());
LOG_WARNING(LOADER, "** arm_exec_loader -> %s", arm_exec.get_error()); LOG_WARNING(LOADER, "** arm_exec -> %s", arm_exec.get_error());
return; return;
} }

View File

@ -340,7 +340,7 @@ SettingsDialog::SettingsDialog(wxWindow* parent)
for (const auto& prxf : fs::dir(lle_dir)) for (const auto& prxf : fs::dir(lle_dir))
{ {
// List found unselected modules // List found unselected modules
if (!prxf.is_directory && ppu_prx_loader(fs::file(lle_dir + prxf.name)) == elf_error::ok && !set.count(prxf.name)) if (!prxf.is_directory && ppu_prx_object(fs::file(lle_dir + prxf.name)) == elf_error::ok && !set.count(prxf.name))
{ {
lle_module_list_unselected.push_back(prxf.name); lle_module_list_unselected.push_back(prxf.name);
} }

View File

@ -127,14 +127,7 @@ struct elf_shdr
en_t<sz_t> sh_entsize; en_t<sz_t> sh_entsize;
}; };
// Default elf_loader::load() return type, specialized to change. // ELF loading error
template<typename T>
struct elf_load_result
{
using type = void;
};
// ELF loader errors
enum class elf_error enum class elf_error
{ {
ok = 0, ok = 0,
@ -154,7 +147,7 @@ enum class elf_error
header_os, header_os,
}; };
// ELF loader error information // ELF loading error information
template<> template<>
struct unveil<elf_error> struct unveil<elf_error>
{ {
@ -183,11 +176,11 @@ struct unveil<elf_error>
} }
}; };
// ELF loader with specified parameters. // ELF object with specified parameters.
// en_t: endianness (specify le_t or be_t) // en_t: endianness (specify le_t or be_t)
// sz_t: size (specify u32 for ELF32, u64 for ELF64) // sz_t: size (specify u32 for ELF32, u64 for ELF64)
template<template<typename T> class en_t, typename sz_t, elf_machine Machine, elf_os OS, elf_type Type> template<template<typename T> class en_t, typename sz_t, elf_machine Machine, elf_os OS, elf_type Type>
class elf_loader class elf_object
{ {
elf_error m_error{}; elf_error m_error{};
@ -208,9 +201,9 @@ public:
std::vector<shdr_t> shdrs; std::vector<shdr_t> shdrs;
public: public:
elf_loader() = default; elf_object() = default;
elf_loader(const fs::file& stream, u64 offset = 0) elf_object(const fs::file& stream, u64 offset = 0)
{ {
open(stream, offset); open(stream, offset);
} }
@ -346,14 +339,9 @@ public:
{ {
return m_error; return m_error;
} }
// Format-specific loader function (must be specialized)
typename elf_load_result<elf_loader>::type load() const;
}; };
using ppu_exec_loader = elf_loader<be_t, u64, elf_machine::ppc64, elf_os::none, elf_type::exec>; using ppu_exec_object = elf_object<be_t, u64, elf_machine::ppc64, elf_os::none, elf_type::exec>;
using ppu_prx_loader = elf_loader<be_t, u64, elf_machine::ppc64, elf_os::lv2, elf_type::prx>; using ppu_prx_object = elf_object<be_t, u64, elf_machine::ppc64, elf_os::lv2, elf_type::prx>;
using spu_exec_loader = elf_loader<be_t, u32, elf_machine::spu, elf_os::none, elf_type::exec>; using spu_exec_object = elf_object<be_t, u32, elf_machine::spu, elf_os::none, elf_type::exec>;
using arm_exec_loader = elf_loader<le_t, u32, elf_machine::arm, elf_os::none, elf_type::none>; using arm_exec_object = elf_object<le_t, u32, elf_machine::arm, elf_os::none, elf_type::none>;
template<> struct elf_load_result<ppu_prx_loader> { using type = std::shared_ptr<struct lv2_prx_t>; };