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)
.setMCJITMemoryManager(std::make_unique<MemoryManager>(std::move(table)))
.setOptLevel(llvm::CodeGenOpt::Aggressive)
.setRelocationModel(llvm::Reloc::PIC_)
.setCodeModel((u64)s_memory <= 0x60000000 ? llvm::CodeModel::Medium : llvm::CodeModel::Large) // TODO
.setMCPU(llvm::sys::getHostCPUName())
.create());

View File

@ -2022,15 +2022,15 @@ s32 spursTasksetLoadElf(SPUThread& spu, u32* entryPoint, u32* lowestLoadAddr, u6
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;
}
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)
{
@ -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) // ???
{
@ -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;
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)
{
// Assume first segment is executable
const u32 start = segs[0].first;
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)
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)
add_toc(start_toc);
// Find eh_frame section
// Find .eh_frame section
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)
const u32 size = ptr[5]; // Function size (64 bit)
// Null terminator
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());
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({}, {}))
{
// 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);
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 &&
@ -244,13 +539,17 @@ std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& se
(ptr[3] & 0xfc000001) == B({}, {}))
{
// 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 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);
continue;
if (target >= start && target < end)
{
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 &&
@ -269,6 +568,15 @@ std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& se
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 &&
(ptr[0] & 0xffff0000) == LI(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)
{
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 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);
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)

View File

@ -2,7 +2,8 @@
#include <map>
#include "../Utilities/BitSet.h"
#include "Utilities/BitSet.h"
#include "Utilities/BEType.h"
// PPU Function Attributes
enum class ppu_attr : u32
@ -24,6 +25,27 @@ struct ppu_function
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 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_prx_loader::load() const
std::shared_ptr<lv2_prx_t> ppu_load_prx(const ppu_prx_object& elf)
{
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);
@ -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
for (auto& prog : progs)
for (auto& prog : elf.progs)
{
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:
{
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:
{
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:
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
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
{
@ -863,7 +902,7 @@ std::shared_ptr<lv2_prx_t> ppu_prx_loader::load() const
};
// 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);
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);
prx->funcs = ppu_analyse(segments, sections, 0, lib_info->toc);
prx->funcs = ppu_analyse(segments, sections, prx->specials[0xbc9a0086], lib_info->toc);
}
else
{
@ -886,8 +925,7 @@ std::shared_ptr<lv2_prx_t> ppu_prx_loader::load() const
return prx;
}
template<>
void ppu_exec_loader::load() const
void ppu_load_exec(const ppu_exec_object& elf)
{
ppu_initialize_modules();
@ -909,7 +947,7 @@ void ppu_exec_loader::load() const
std::vector<ppu_function> exec_set;
// 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);
@ -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);
@ -946,7 +984,7 @@ void ppu_exec_loader::load() const
}
// Load other programs
for (auto& prog : progs)
for (auto& prog : elf.progs)
{
switch (const u32 p_type = prog.p_type)
{
@ -1057,28 +1095,28 @@ void ppu_exec_loader::load() const
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
{
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
{
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);
const auto prx = loader.load();
const auto prx = ppu_load_prx(obj);
// Register start function
if (prx->start)
@ -1093,7 +1131,7 @@ void ppu_exec_loader::load() const
}
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
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);
@ -1287,7 +1325,7 @@ void ppu_exec_loader::load() const
*entry++ = MR(r12, r19);
// 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)
ppu_function entry_func;
@ -1296,7 +1334,7 @@ void ppu_exec_loader::load() const
exec_set.emplace_back(entry_func);
// 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");

View File

@ -586,6 +586,11 @@ namespace ppu_instructions
r12, r13, r14, r15, r16, r17, r18, r19, r20, r21,
r22, r23, r24, r25, r26, r27, r28, r29, r30, r31,
};
enum
{
cr0, cr1, cr2, cr3, cr4, cr5, cr6, cr7,
};
}
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 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 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 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; }
@ -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 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 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 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 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
@ -627,21 +632,21 @@ namespace ppu_instructions
inline u32 MFLR(u32 reg) { return MFSPR(reg, 8 << 5); }
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 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 BNE(s32 imm) { return BNE(cr0, imm); }
//inline u32 BEQ(s32 imm) { return BEQ(cr0, imm); }
//inline u32 BGT(s32 imm) { return BGT(cr0, 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 BGT(u32 cr, s32 imm) { return BC(12, 1 | cr << 2, imm); }
inline u32 BNE(s32 imm) { return BNE(cr0, imm); }
inline u32 BEQ(s32 imm) { return BEQ(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 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 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 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 reg, u32 imm) { return CMPLWI(cr0, 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 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 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 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 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); }

View File

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

View File

@ -234,12 +234,11 @@ bool RawSPUThread::write_reg(const u32 addr, const u32 value)
return false;
}
template<>
void spu_exec_loader::load() const
void spu_load_exec(const spu_exec_object& elf)
{
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)
{
@ -248,5 +247,5 @@ void spu_exec_loader::load() const
}
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 "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);
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);
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;
}
const auto prx = loader.load();
const auto prx = ppu_load_prx(obj);
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)
{
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 */)
{
@ -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)

View File

@ -355,8 +355,7 @@ static void arm_patch_refs(u32 refs, u32 addr)
}
template<>
void arm_exec_loader::load() const
void arm_load_exec(const arm_exec_object& elf)
{
arm_initialize_modules();
@ -373,7 +372,7 @@ void arm_exec_loader::load() const
u32 tls_fsize{};
u32 tls_vsize{};
for (const auto& prog : progs)
for (const auto& prog : elf.progs)
{
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 (!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 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;
namespace rpcs3
@ -173,10 +178,10 @@ void Emulator::Load()
}
const fs::file elf_file(m_path);
ppu_exec_loader ppu_exec;
ppu_prx_loader ppu_prx;
spu_exec_loader spu_exec;
arm_exec_loader arm_exec;
ppu_exec_object ppu_exec;
ppu_prx_object ppu_prx;
spu_exec_object spu_exec;
arm_exec_object arm_exec;
if (!elf_file)
{
@ -230,7 +235,7 @@ void Emulator::Load()
vfs::dump();
ppu_exec.load();
ppu_load_exec(ppu_exec);
Emu.GetCallbackManager().Init();
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)
m_status = Ready;
vm::ps3::init();
ppu_prx.load();
ppu_load_prx(ppu_prx);
GetCallbackManager().Init();
}
else if (spu_exec.open(elf_file) == elf_error::ok)
@ -248,23 +253,23 @@ void Emulator::Load()
// SPU executable (experimental)
m_status = Ready;
vm::ps3::init();
spu_exec.load();
spu_load_exec(spu_exec);
}
else if (arm_exec.open(elf_file) == elf_error::ok)
{
// ARMv7 executable
m_status = Ready;
vm::psv::init();
arm_exec.load();
arm_load_exec(arm_exec);
}
else
{
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_prx_loader -> %s", ppu_prx.get_error());
LOG_WARNING(LOADER, "** spu_exec_loader -> %s", spu_exec.get_error());
LOG_WARNING(LOADER, "** arm_exec_loader -> %s", arm_exec.get_error());
LOG_WARNING(LOADER, "** ppu_exec -> %s", ppu_exec.get_error());
LOG_WARNING(LOADER, "** ppu_prx -> %s", ppu_prx.get_error());
LOG_WARNING(LOADER, "** spu_exec -> %s", spu_exec.get_error());
LOG_WARNING(LOADER, "** arm_exec -> %s", arm_exec.get_error());
return;
}

View File

@ -340,7 +340,7 @@ SettingsDialog::SettingsDialog(wxWindow* parent)
for (const auto& prxf : fs::dir(lle_dir))
{
// 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);
}

View File

@ -127,14 +127,7 @@ struct elf_shdr
en_t<sz_t> sh_entsize;
};
// Default elf_loader::load() return type, specialized to change.
template<typename T>
struct elf_load_result
{
using type = void;
};
// ELF loader errors
// ELF loading error
enum class elf_error
{
ok = 0,
@ -154,7 +147,7 @@ enum class elf_error
header_os,
};
// ELF loader error information
// ELF loading error information
template<>
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)
// 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>
class elf_loader
class elf_object
{
elf_error m_error{};
@ -208,9 +201,9 @@ public:
std::vector<shdr_t> shdrs;
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);
}
@ -346,14 +339,9 @@ public:
{
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_prx_loader = elf_loader<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 arm_exec_loader = elf_loader<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>; };
using ppu_exec_object = elf_object<be_t, u64, elf_machine::ppc64, elf_os::none, elf_type::exec>;
using ppu_prx_object = elf_object<be_t, u64, elf_machine::ppc64, elf_os::lv2, elf_type::prx>;
using spu_exec_object = elf_object<be_t, u32, elf_machine::spu, elf_os::none, elf_type::exec>;
using arm_exec_object = elf_object<le_t, u32, elf_machine::arm, elf_os::none, elf_type::none>;