mirror of
https://github.com/RPCS3/rpcs3.git
synced 2024-11-23 03:02:53 +01:00
PPU LLVM: relocation support
This commit is contained in:
parent
9fccb47e7c
commit
f0d184f38b
@ -10,7 +10,6 @@
|
||||
namespace vm { using namespace ps3; }
|
||||
|
||||
const ppu_decoder<ppu_itype> s_ppu_itype;
|
||||
const ppu_decoder<ppu_iname> s_ppu_iname;
|
||||
|
||||
template<>
|
||||
void fmt_class_string<ppu_attr>::format(std::string& out, u64 arg)
|
||||
@ -36,10 +35,10 @@ void fmt_class_string<bs_t<ppu_attr>>::format(std::string& out, u64 arg)
|
||||
format_bitset(out, arg, "[", ",", "]", &fmt_class_string<ppu_attr>::format);
|
||||
}
|
||||
|
||||
void ppu_validate(const std::string& fname, const std::vector<ppu_function>& funcs, u32 reloc)
|
||||
void ppu_module::validate(u32 reloc)
|
||||
{
|
||||
// Load custom PRX configuration if available
|
||||
if (fs::file yml{fname + ".yml"})
|
||||
if (fs::file yml{path + ".yml"})
|
||||
{
|
||||
const auto cfg = YAML::Load(yml.to_string());
|
||||
|
||||
@ -57,14 +56,14 @@ void ppu_validate(const std::string& fname, const std::vector<ppu_function>& fun
|
||||
|
||||
while (addr > found && index + 1 < funcs.size())
|
||||
{
|
||||
LOG_WARNING(LOADER, "%s.yml : unexpected function at 0x%x (0x%x, 0x%x)", fname, found, addr, size);
|
||||
LOG_WARNING(LOADER, "%s.yml : unexpected function at 0x%x (0x%x, 0x%x)", path, found, addr, size);
|
||||
index++;
|
||||
found = funcs[index].addr - reloc;
|
||||
}
|
||||
|
||||
if (addr < found)
|
||||
{
|
||||
LOG_ERROR(LOADER, "%s.yml : function not found (0x%x, 0x%x)", fname, addr, size);
|
||||
LOG_ERROR(LOADER, "%s.yml : function not found (0x%x, 0x%x)", path, addr, size);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -72,7 +71,7 @@ void ppu_validate(const std::string& fname, const std::vector<ppu_function>& fun
|
||||
{
|
||||
if (size + 4 != funcs[index].size || vm::read32(addr + size) != ppu_instructions::NOP())
|
||||
{
|
||||
LOG_ERROR(LOADER, "%s.yml : function size mismatch at 0x%x(size=0x%x) (0x%x, 0x%x)", fname, found, funcs[index].size, addr, size);
|
||||
LOG_ERROR(LOADER, "%s.yml : function size mismatch at 0x%x(size=0x%x) (0x%x, 0x%x)", path, found, funcs[index].size, addr, size);
|
||||
}
|
||||
}
|
||||
|
||||
@ -80,7 +79,7 @@ void ppu_validate(const std::string& fname, const std::vector<ppu_function>& fun
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR(LOADER, "%s.yml : function not found at the end (0x%x, 0x%x)", fname, addr, size);
|
||||
LOG_ERROR(LOADER, "%s.yml : function not found at the end (0x%x, 0x%x)", path, addr, size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -94,13 +93,13 @@ void ppu_validate(const std::string& fname, const std::vector<ppu_function>& fun
|
||||
{
|
||||
if (funcs[index].size)
|
||||
{
|
||||
LOG_ERROR(LOADER, "%s.yml : function not covered at 0x%x (size=0x%x)", fname, funcs[index].addr, funcs[index].size);
|
||||
LOG_ERROR(LOADER, "%s.yml : function not covered at 0x%x (size=0x%x)", path, funcs[index].addr, funcs[index].size);
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
LOG_SUCCESS(LOADER, "%s.yml : validation completed", fname);
|
||||
LOG_SUCCESS(LOADER, "%s.yml : validation completed", path);
|
||||
}
|
||||
}
|
||||
|
||||
@ -522,17 +521,17 @@ namespace ppu_patterns
|
||||
};
|
||||
}
|
||||
|
||||
std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& segs, const std::vector<std::pair<u32, u32>>& secs, u32 lib_toc, u32 entry)
|
||||
void ppu_module::analyse(u32 lib_toc, u32 entry)
|
||||
{
|
||||
// Assume first segment is executable
|
||||
const u32 start = segs[0].first;
|
||||
const u32 end = segs[0].first + segs[0].second;
|
||||
const u32 start = segs[0].addr;
|
||||
const u32 end = segs[0].addr + segs[0].size;
|
||||
|
||||
// Known TOCs (usually only 1)
|
||||
std::unordered_set<u32> TOCs;
|
||||
|
||||
// Known functions
|
||||
std::map<u32, ppu_function> funcs;
|
||||
std::map<u32, ppu_function> fmap;
|
||||
|
||||
// Function analysis workload
|
||||
std::vector<std::reference_wrapper<ppu_function>> func_queue;
|
||||
@ -543,7 +542,7 @@ std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& se
|
||||
// Register new function
|
||||
auto add_func = [&](u32 addr, u32 toc, u32 caller) -> ppu_function&
|
||||
{
|
||||
ppu_function& func = funcs[addr];
|
||||
ppu_function& func = fmap[addr];
|
||||
|
||||
if (caller)
|
||||
{
|
||||
@ -586,7 +585,7 @@ std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& se
|
||||
// Grope for OPD section (TODO: optimization, better constraints)
|
||||
for (const auto& seg : segs)
|
||||
{
|
||||
for (vm::cptr<u32> ptr = vm::cast(seg.first); ptr.addr() < seg.first + seg.second; ptr++)
|
||||
for (vm::cptr<u32> ptr = vm::cast(seg.addr); ptr.addr() < seg.addr + seg.size; ptr++)
|
||||
{
|
||||
if (ptr[0] >= start && ptr[0] < end && ptr[0] % 4 == 0 && ptr[1] == toc)
|
||||
{
|
||||
@ -602,7 +601,7 @@ std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& se
|
||||
// Get next reliable function address
|
||||
auto get_limit = [&](u32 addr) -> u32
|
||||
{
|
||||
for (auto it = funcs.lower_bound(addr), end = funcs.end(); it != end; it++)
|
||||
for (auto it = fmap.lower_bound(addr), end = fmap.end(); it != end; it++)
|
||||
{
|
||||
if (test(it->second.attr, ppu_attr::known_addr))
|
||||
{
|
||||
@ -616,7 +615,7 @@ std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& se
|
||||
// Find references indiscriminately
|
||||
for (const auto& seg : segs)
|
||||
{
|
||||
for (vm::cptr<u32> ptr = vm::cast(seg.first); ptr.addr() < seg.first + seg.second; ptr++)
|
||||
for (vm::cptr<u32> ptr = vm::cast(seg.addr); ptr.addr() < seg.addr + seg.size; ptr++)
|
||||
{
|
||||
const u32 value = *ptr;
|
||||
|
||||
@ -627,7 +626,7 @@ std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& se
|
||||
|
||||
for (const auto& _seg : segs)
|
||||
{
|
||||
if (value >= _seg.first && value < _seg.first + _seg.second)
|
||||
if (value >= _seg.addr && value < _seg.addr + _seg.size)
|
||||
{
|
||||
addr_heap.emplace(value);
|
||||
break;
|
||||
@ -639,10 +638,10 @@ std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& se
|
||||
// Find OPD section
|
||||
for (const auto& sec : secs)
|
||||
{
|
||||
vm::cptr<void> sec_end = vm::cast(sec.first + sec.second);
|
||||
vm::cptr<void> sec_end = vm::cast(sec.addr + sec.size);
|
||||
|
||||
// Probe
|
||||
for (vm::cptr<u32> ptr = vm::cast(sec.first); ptr < sec_end; ptr += 2)
|
||||
for (vm::cptr<u32> ptr = vm::cast(sec.addr); ptr < sec_end; ptr += 2)
|
||||
{
|
||||
if (ptr + 6 <= sec_end && !ptr[0] && !ptr[2] && ptr[1] == ptr[4] && ptr[3] == ptr[5])
|
||||
{
|
||||
@ -677,10 +676,10 @@ std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& se
|
||||
}
|
||||
}
|
||||
|
||||
if (sec_end) LOG_NOTICE(PPU, "Reading OPD section at 0x%x...", sec.first);
|
||||
if (sec_end) LOG_NOTICE(PPU, "Reading OPD section at 0x%x...", sec.addr);
|
||||
|
||||
// Mine
|
||||
for (vm::cptr<u32> ptr = vm::cast(sec.first); ptr < sec_end; ptr += 2)
|
||||
for (vm::cptr<u32> ptr = vm::cast(sec.addr); ptr < sec_end; ptr += 2)
|
||||
{
|
||||
// Special case: see "Probe"
|
||||
if (!ptr[0]) ptr += 4;
|
||||
@ -709,7 +708,7 @@ std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& se
|
||||
}
|
||||
|
||||
// Clean TOCs
|
||||
for (auto&& pair : funcs)
|
||||
for (auto&& pair : fmap)
|
||||
{
|
||||
if (pair.second.toc == -1)
|
||||
{
|
||||
@ -720,12 +719,12 @@ std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& se
|
||||
// Find .eh_frame section
|
||||
for (const auto& sec : secs)
|
||||
{
|
||||
vm::cptr<void> sec_end = vm::cast(sec.first + sec.second);
|
||||
vm::cptr<void> sec_end = vm::cast(sec.addr + sec.size);
|
||||
|
||||
// Probe
|
||||
for (vm::cptr<u32> ptr = vm::cast(sec.first); ptr < sec_end;)
|
||||
for (vm::cptr<u32> ptr = vm::cast(sec.addr); ptr < sec_end;)
|
||||
{
|
||||
if (ptr % 4 || ptr.addr() < sec.first || ptr >= sec_end)
|
||||
if (ptr % 4 || ptr.addr() < sec.addr || ptr >= sec_end)
|
||||
{
|
||||
sec_end.set(0);
|
||||
break;
|
||||
@ -749,7 +748,7 @@ std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& se
|
||||
{
|
||||
const u32 cie_off = ptr.addr() - ptr[1] + 4;
|
||||
|
||||
if (cie_off % 4 || cie_off < sec.first || cie_off >= sec_end.addr())
|
||||
if (cie_off % 4 || cie_off < sec.addr || cie_off >= sec_end.addr())
|
||||
{
|
||||
sec_end.set(0);
|
||||
break;
|
||||
@ -759,10 +758,10 @@ std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& se
|
||||
ptr = vm::cast(ptr.addr() + size);
|
||||
}
|
||||
|
||||
if (sec_end && sec.second > 4) LOG_NOTICE(PPU, "Reading .eh_frame section at 0x%x...", sec.first);
|
||||
if (sec_end && sec.size > 4) LOG_NOTICE(PPU, "Reading .eh_frame section at 0x%x...", sec.addr);
|
||||
|
||||
// Mine
|
||||
for (vm::cptr<u32> ptr = vm::cast(sec.first); ptr < sec_end; ptr = vm::cast(ptr.addr() + ptr[0] + 4))
|
||||
for (vm::cptr<u32> ptr = vm::cast(sec.addr); ptr < sec_end; ptr = vm::cast(ptr.addr() + ptr[0] + 4))
|
||||
{
|
||||
if (ptr[0] == 0)
|
||||
{
|
||||
@ -837,7 +836,7 @@ std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& se
|
||||
{
|
||||
for (u32 addr : func.callers)
|
||||
{
|
||||
ppu_function& caller = funcs[addr];
|
||||
ppu_function& caller = fmap[addr];
|
||||
|
||||
if (!caller.toc)
|
||||
{
|
||||
@ -847,7 +846,7 @@ std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& se
|
||||
|
||||
for (u32 addr : func.calls)
|
||||
{
|
||||
ppu_function& callee = funcs[addr];
|
||||
ppu_function& callee = fmap[addr];
|
||||
|
||||
if (!callee.toc)
|
||||
{
|
||||
@ -1077,10 +1076,10 @@ std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& se
|
||||
if (test(func.attr, ppu_attr::no_size))
|
||||
{
|
||||
// Get next function
|
||||
const auto _next = funcs.lower_bound(func.blocks.crbegin()->first + 1);
|
||||
const auto _next = fmap.lower_bound(func.blocks.crbegin()->first + 1);
|
||||
|
||||
// Get limit
|
||||
const u32 func_end2 = _next == funcs.end() ? func_end : std::min<u32>(_next->first, func_end);
|
||||
const u32 func_end2 = _next == fmap.end() ? func_end : std::min<u32>(_next->first, func_end);
|
||||
|
||||
// Set more block entries
|
||||
std::for_each(addr_heap.lower_bound(func.addr), addr_heap.lower_bound(func_end2), add_block);
|
||||
@ -1322,14 +1321,14 @@ std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& se
|
||||
}
|
||||
|
||||
// Function shrinkage, disabled (TODO: it's potentially dangerous but improvable)
|
||||
for (auto& _pair : funcs)
|
||||
for (auto& _pair : fmap)
|
||||
{
|
||||
auto& func = _pair.second;
|
||||
|
||||
// Get next function addr
|
||||
const auto _next = funcs.lower_bound(_pair.first + 1);
|
||||
const auto _next = fmap.lower_bound(_pair.first + 1);
|
||||
|
||||
const u32 next = _next == funcs.end() ? end : _next->first;
|
||||
const u32 next = _next == fmap.end() ? end : _next->first;
|
||||
|
||||
// Just ensure that functions don't overlap
|
||||
if (func.addr + func.size > next)
|
||||
@ -1415,7 +1414,7 @@ std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& se
|
||||
{
|
||||
lib_toc = *TOCs.begin();
|
||||
|
||||
for (auto&& pair : funcs)
|
||||
for (auto&& pair : fmap)
|
||||
{
|
||||
if (pair.second.toc == 0)
|
||||
{
|
||||
@ -1425,16 +1424,12 @@ std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& se
|
||||
}
|
||||
|
||||
// Convert map to vector (destructive)
|
||||
std::vector<ppu_function> result;
|
||||
|
||||
for (auto&& pair : funcs)
|
||||
for (auto&& pair : fmap)
|
||||
{
|
||||
auto& func = pair.second;
|
||||
LOG_TRACE(PPU, "Function %s (size=0x%x, toc=0x%x, attr %#x)", func.name, func.size, func.toc, func.attr);
|
||||
result.emplace_back(std::move(func));
|
||||
funcs.emplace_back(std::move(func));
|
||||
}
|
||||
|
||||
LOG_NOTICE(PPU, "Function analysis: %zu functions (%zu enqueued)", result.size(), func_queue.size());
|
||||
|
||||
return result;
|
||||
LOG_NOTICE(PPU, "Function analysis: %zu functions (%zu enqueued)", funcs.size(), func_queue.size());
|
||||
}
|
||||
|
@ -38,11 +38,9 @@ struct ppu_function
|
||||
// PPU Relocation Information
|
||||
struct ppu_reloc
|
||||
{
|
||||
u32 addr;
|
||||
u32 type;
|
||||
u32 off;
|
||||
u32 ptr;
|
||||
u8 index_value;
|
||||
u8 index_addr;
|
||||
u64 data;
|
||||
};
|
||||
|
||||
// PPU Segment Information
|
||||
@ -58,10 +56,14 @@ struct ppu_segment
|
||||
struct ppu_module
|
||||
{
|
||||
std::string name;
|
||||
std::vector<ppu_reloc> rels;
|
||||
std::string path;
|
||||
std::vector<ppu_reloc> relocs;
|
||||
std::vector<ppu_segment> segs;
|
||||
std::vector<ppu_segment> secs;
|
||||
std::vector<ppu_function> funcs;
|
||||
std::vector<ppu_segment> sections;
|
||||
|
||||
void analyse(u32 lib_toc, u32 entry);
|
||||
void validate(u32 reloc);
|
||||
};
|
||||
|
||||
// Aux
|
||||
@ -131,10 +133,6 @@ struct ppu_pattern_matrix
|
||||
}
|
||||
};
|
||||
|
||||
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 lib_toc, u32 entry);
|
||||
|
||||
// PPU Instruction Type
|
||||
struct ppu_itype
|
||||
{
|
||||
|
@ -112,7 +112,7 @@ struct ppu_linkage_info
|
||||
bool hle = false;
|
||||
u32 export_addr = 0;
|
||||
std::set<u32> imports;
|
||||
std::set<u32> weak_imports;
|
||||
std::set<u32> frefss;
|
||||
};
|
||||
|
||||
// FNID -> (export; [imports...])
|
||||
@ -342,9 +342,8 @@ static void ppu_initialize_modules(const std::shared_ptr<ppu_linkage_info>& link
|
||||
}
|
||||
}
|
||||
|
||||
// Link variables/weak imports, looks to be literally the same as vrefs
|
||||
// Don't use bool flag in VREFs, originally it didn't have it
|
||||
static void ppu_patch_refs(u32 fref, u32 faddr)
|
||||
// Resolve relocations for variable/function linkage.
|
||||
static void ppu_patch_refs(std::vector<ppu_reloc>* out_relocs, u32 fref, u32 faddr)
|
||||
{
|
||||
struct ref_t
|
||||
{
|
||||
@ -357,42 +356,52 @@ static void ppu_patch_refs(u32 fref, u32 faddr)
|
||||
{
|
||||
if (ref->addend) LOG_WARNING(LOADER, "**** REF(%u): Addend value(0x%x, 0x%x)", ref->type, ref->addr, ref->addend);
|
||||
|
||||
const auto ref_import = vm::ptr<u32>::make(faddr + ref->addend);
|
||||
const u32 raddr = ref->addr;
|
||||
const u32 rtype = ref->type;
|
||||
const u32 rdata = faddr + ref->addend;
|
||||
|
||||
const auto addr = faddr + ref->addend;
|
||||
if (out_relocs)
|
||||
{
|
||||
// Register relocation with unpredictable target (data=0)
|
||||
ppu_reloc _rel;
|
||||
_rel.addr = raddr;
|
||||
_rel.type = rtype;
|
||||
_rel.data = 0;
|
||||
out_relocs->emplace_back(_rel);
|
||||
}
|
||||
|
||||
// OPs are probably similar to relocations
|
||||
switch (u32 type = ref->type)
|
||||
// OPs must be similar to relocations
|
||||
switch (rtype)
|
||||
{
|
||||
case 0x1:
|
||||
case 1:
|
||||
{
|
||||
const u32 value = vm::_ref<u32>(ref->addr) = addr;
|
||||
const u32 value = vm::_ref<u32>(ref->addr) = rdata;
|
||||
LOG_TRACE(LOADER, "**** REF(1): 0x%x <- 0x%x", ref->addr, value);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x4:
|
||||
case 4:
|
||||
{
|
||||
const u16 value = vm::_ref<u16>(ref->addr) = static_cast<u16>(addr);
|
||||
const u16 value = vm::_ref<u16>(ref->addr) = static_cast<u16>(rdata);
|
||||
LOG_TRACE(LOADER, "**** REF(4): 0x%x <- 0x%04x (0x%llx)", ref->addr, value, faddr);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x6:
|
||||
case 6:
|
||||
{
|
||||
const u16 value = vm::_ref<u16>(ref->addr) = static_cast<u16>(addr >> 16) + (addr & 0x8000 ? 1 : 0);
|
||||
const u16 value = vm::_ref<u16>(ref->addr) = static_cast<u16>(rdata >> 16) + (rdata & 0x8000 ? 1 : 0);
|
||||
LOG_TRACE(LOADER, "**** REF(6): 0x%x <- 0x%04x (0x%llx)", ref->addr, value, faddr);
|
||||
break;
|
||||
}
|
||||
|
||||
case 57:
|
||||
{
|
||||
const u16 value = vm::_ref<ppu_bf_t<be_t<u16>, 0, 14>>(ref->addr) = static_cast<u16>(addr) >> 2;
|
||||
const u16 value = vm::_ref<ppu_bf_t<be_t<u16>, 0, 14>>(ref->addr) = static_cast<u16>(rdata) >> 2;
|
||||
LOG_TRACE(LOADER, "**** REF(57): 0x%x <- 0x%04x (0x%llx)", ref->addr, value, faddr);
|
||||
break;
|
||||
}
|
||||
|
||||
default: LOG_ERROR(LOADER, "**** REF(%u): Unknown/Illegal type (0x%x, 0x%x)", ref->type, ref->addr, ref->addend);
|
||||
default: LOG_ERROR(LOADER, "**** REF(%u): Unknown/Illegal type (0x%x, 0x%x)", rtype, raddr, ref->addend);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -523,9 +532,9 @@ static auto ppu_load_exports(const std::shared_ptr<ppu_linkage_info>& link, u32
|
||||
//LOG_WARNING(LOADER, "Exported function '%s' in module '%s'", ppu_get_function_name(module_name, fnid), module_name);
|
||||
}
|
||||
|
||||
for (const u32 weak_import_addr : flink.weak_imports)
|
||||
for (const u32 fref : flink.frefss)
|
||||
{
|
||||
ppu_patch_refs(weak_import_addr, faddr);
|
||||
ppu_patch_refs(nullptr, fref, faddr);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -557,7 +566,7 @@ static auto ppu_load_exports(const std::shared_ptr<ppu_linkage_info>& link, u32
|
||||
// Fix imports
|
||||
for (const auto vref : vlink.imports)
|
||||
{
|
||||
ppu_patch_refs(vref, vaddr);
|
||||
ppu_patch_refs(nullptr, vref, vaddr);
|
||||
//LOG_WARNING(LOADER, "Exported variable '%s' in module '%s'", ppu_get_variable_name(module_name, vnid), module_name);
|
||||
}
|
||||
}
|
||||
@ -569,7 +578,7 @@ static auto ppu_load_exports(const std::shared_ptr<ppu_linkage_info>& link, u32
|
||||
return result;
|
||||
}
|
||||
|
||||
static void ppu_load_imports(const std::shared_ptr<ppu_linkage_info>& link, u32 imports_start, u32 imports_end)
|
||||
static void ppu_load_imports(std::vector<ppu_reloc>& relocs, const std::shared_ptr<ppu_linkage_info>& link, u32 imports_start, u32 imports_end)
|
||||
{
|
||||
for (u32 addr = imports_start; addr < imports_end;)
|
||||
{
|
||||
@ -577,7 +586,7 @@ static void ppu_load_imports(const std::shared_ptr<ppu_linkage_info>& link, u32
|
||||
|
||||
const std::string module_name(lib.name.get_ptr());
|
||||
|
||||
LOG_NOTICE(LOADER, "** Imported module '%s' (0x%x, 0x%x)", module_name, lib.unk4, lib.unk5);
|
||||
LOG_NOTICE(LOADER, "** Imported module '%s' (ver=0x%x, attr=0x%x, 0x%x, 0x%x) [0x%x]", module_name, lib.version, lib.attributes, lib.unk4, lib.unk5, addr);
|
||||
|
||||
if (lib.num_tlsvar)
|
||||
{
|
||||
@ -607,21 +616,17 @@ static void ppu_load_imports(const std::shared_ptr<ppu_linkage_info>& link, u32
|
||||
flink.imports.emplace(faddr);
|
||||
mlink.imported = true;
|
||||
|
||||
// Link if available
|
||||
if (flink.export_addr)
|
||||
{
|
||||
vm::write32(faddr, flink.export_addr);
|
||||
}
|
||||
else
|
||||
{
|
||||
vm::write32(faddr, ppu_function_manager::addr);
|
||||
}
|
||||
// Link address (special HLE function by default)
|
||||
const u32 link_addr = flink.export_addr ? flink.export_addr : ppu_function_manager::addr;
|
||||
|
||||
//weak imports, possibly
|
||||
if (((lib.attributes & 0x2000) == 0x2000) && fnids[i + lib.num_func] != 0) //0x2000 seems to be correct flag
|
||||
// Write import table
|
||||
vm::write32(faddr, link_addr);
|
||||
|
||||
// Patch refs if necessary (0x2000 seems to be correct flag indicating the presence of additional info)
|
||||
if (const u32 frefs = (lib.attributes & 0x2000) ? +fnids[i + lib.num_func] : 0)
|
||||
{
|
||||
flink.weak_imports.emplace(fnids[i + lib.num_func]);
|
||||
ppu_patch_refs(fnids[i + lib.num_func], flink.export_addr);
|
||||
flink.frefss.emplace(frefs);
|
||||
ppu_patch_refs(&relocs, frefs, link_addr);
|
||||
}
|
||||
|
||||
//LOG_WARNING(LOADER, "Imported function '%s' in module '%s' (0x%x)", ppu_get_function_name(module_name, fnid), module_name, faddr);
|
||||
@ -644,10 +649,7 @@ static void ppu_load_imports(const std::shared_ptr<ppu_linkage_info>& link, u32
|
||||
mlink.imported = true;
|
||||
|
||||
// Link if available
|
||||
if (vlink.export_addr)
|
||||
{
|
||||
ppu_patch_refs(vref, vlink.export_addr);
|
||||
}
|
||||
ppu_patch_refs(&relocs, vref, vlink.export_addr);
|
||||
|
||||
//LOG_WARNING(LOADER, "Imported variable '%s' in module '%s' (0x%x)", ppu_get_variable_name(module_name, vnid), module_name, vlink.first);
|
||||
}
|
||||
@ -656,10 +658,13 @@ static void ppu_load_imports(const std::shared_ptr<ppu_linkage_info>& link, u32
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<lv2_prx> ppu_load_prx(const ppu_prx_object& elf, const std::string& name)
|
||||
std::shared_ptr<lv2_prx> ppu_load_prx(const ppu_prx_object& elf, const std::string& path)
|
||||
{
|
||||
std::vector<std::pair<u32, u32>> segments;
|
||||
std::vector<std::pair<u32, u32>> sections;
|
||||
// Create new PRX object
|
||||
const auto prx = idm::make_ptr<lv2_obj, lv2_prx>();
|
||||
|
||||
// Access linkage information object
|
||||
const auto link = fxm::get_always<ppu_linkage_info>();
|
||||
|
||||
for (const auto& prog : elf.progs)
|
||||
{
|
||||
@ -693,7 +698,12 @@ std::shared_ptr<lv2_prx> ppu_load_prx(const ppu_prx_object& elf, const std::stri
|
||||
ppu_register_range(addr, mem_size);
|
||||
}
|
||||
|
||||
segments.emplace_back(std::make_pair(addr, mem_size));
|
||||
ppu_segment _seg;
|
||||
_seg.addr = addr;
|
||||
_seg.size = mem_size;
|
||||
_seg.type = p_type;
|
||||
_seg.flags = prog.p_flags;
|
||||
prx->segs.emplace_back(_seg);
|
||||
}
|
||||
|
||||
break;
|
||||
@ -714,13 +724,18 @@ std::shared_ptr<lv2_prx> ppu_load_prx(const ppu_prx_object& elf, const std::stri
|
||||
|
||||
if (s.sh_type == 1 && addr && size) // TODO: some sections with addr=0 are valid
|
||||
{
|
||||
for (auto i = 0; i < segments.size(); i++)
|
||||
for (auto i = 0; i < prx->segs.size(); i++)
|
||||
{
|
||||
const u32 saddr = static_cast<u32>(elf.progs[i].p_vaddr);
|
||||
if (addr >= saddr && addr < saddr + elf.progs[i].p_memsz)
|
||||
{
|
||||
// "Relocate" section
|
||||
sections.emplace_back(std::make_pair(addr - saddr + segments[i].first, size));
|
||||
ppu_segment _sec;
|
||||
_sec.addr = addr - saddr + prx->segs[i].addr;
|
||||
_sec.size = size;
|
||||
_sec.type = s.sh_type;
|
||||
_sec.flags = s.sh_flags & 7;
|
||||
prx->secs.emplace_back(_sec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -749,10 +764,13 @@ std::shared_ptr<lv2_prx> ppu_load_prx(const ppu_prx_object& elf, const std::stri
|
||||
{
|
||||
const auto& rel = reinterpret_cast<const ppu_prx_relocation_info&>(prog.bin[i]);
|
||||
|
||||
const u32 raddr = vm::cast(segments.at(rel.index_addr).first + rel.offset, HERE);
|
||||
const u64 rdata = segments.at(rel.index_value).first + rel.ptr.addr();
|
||||
ppu_reloc _rel;
|
||||
const u32 raddr = _rel.addr = vm::cast(prx->segs.at(rel.index_addr).addr + rel.offset, HERE);
|
||||
const u32 rtype = _rel.type = rel.type;
|
||||
const u64 rdata = _rel.data = prx->segs.at(rel.index_value).addr + rel.ptr.addr();
|
||||
prx->relocs.emplace_back(_rel);
|
||||
|
||||
switch (const u32 type = rel.type)
|
||||
switch (rtype)
|
||||
{
|
||||
case 1: // R_PPC64_ADDR32
|
||||
{
|
||||
@ -817,7 +835,12 @@ std::shared_ptr<lv2_prx> ppu_load_prx(const ppu_prx_object& elf, const std::stri
|
||||
break;
|
||||
}
|
||||
|
||||
default: LOG_ERROR(LOADER, "**** RELOCATION(%u): Illegal/Unknown type! (addr=0x%x; 0x%llx)", type, raddr, rdata);
|
||||
default: LOG_ERROR(LOADER, "**** RELOCATION(%u): Illegal/Unknown type! (addr=0x%x; 0x%llx)", rtype, raddr, rdata);
|
||||
}
|
||||
|
||||
if (rdata == 0)
|
||||
{
|
||||
LOG_TODO(LOADER, "**** RELOCATION(%u): 0x%x <- (zero-based value)", rtype, raddr);
|
||||
}
|
||||
}
|
||||
|
||||
@ -826,12 +849,6 @@ std::shared_ptr<lv2_prx> ppu_load_prx(const ppu_prx_object& elf, const std::stri
|
||||
}
|
||||
}
|
||||
|
||||
// Access linkage information object
|
||||
const auto link = fxm::get_always<ppu_linkage_info>();
|
||||
|
||||
// Create new PRX object
|
||||
auto prx = idm::make_ptr<lv2_obj, lv2_prx>();
|
||||
|
||||
if (!elf.progs.empty() && elf.progs[0].p_paddr)
|
||||
{
|
||||
struct ppu_prx_library_info
|
||||
@ -847,16 +864,16 @@ std::shared_ptr<lv2_prx> ppu_load_prx(const ppu_prx_object& elf, const std::stri
|
||||
};
|
||||
|
||||
// Access library information (TODO)
|
||||
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_info = vm::cptr<ppu_prx_library_info>(vm::cast(prx->segs[0].addr + 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);
|
||||
|
||||
prx->specials = ppu_load_exports(link, lib_info->exports_start, lib_info->exports_end);
|
||||
|
||||
ppu_load_imports(link, lib_info->imports_start, lib_info->imports_end);
|
||||
ppu_load_imports(prx->relocs, link, lib_info->imports_start, lib_info->imports_end);
|
||||
|
||||
prx->funcs = ppu_analyse(segments, sections, lib_info->toc, 0);
|
||||
prx->analyse(lib_info->toc, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -868,7 +885,8 @@ std::shared_ptr<lv2_prx> ppu_load_prx(const ppu_prx_object& elf, const std::stri
|
||||
prx->exit.set(prx->specials[0x3ab9a95e]);
|
||||
prx->prologue.set(prx->specials[0x0D10FD3F]);
|
||||
prx->epilogue.set(prx->specials[0x330F7005]);
|
||||
prx->name = name;
|
||||
prx->name = path.substr(path.find_last_of('/') + 1);
|
||||
prx->path = path;
|
||||
return prx;
|
||||
}
|
||||
|
||||
@ -879,15 +897,12 @@ void ppu_load_exec(const ppu_exec_object& elf)
|
||||
LOG_TODO(LOADER, "'Hook static functions' option deactivated");
|
||||
}
|
||||
|
||||
// Set for delayed initialization in ppu_initialize()
|
||||
const auto _main = fxm::make<ppu_module>();
|
||||
|
||||
// Access linkage information object
|
||||
const auto link = fxm::get_always<ppu_linkage_info>();
|
||||
|
||||
// Segment info
|
||||
std::vector<std::pair<u32, u32>> segments;
|
||||
|
||||
// Section info (optional)
|
||||
std::vector<std::pair<u32, u32>> sections;
|
||||
|
||||
// TLS information
|
||||
u32 tls_vaddr = 0;
|
||||
u32 tls_fsize = 0;
|
||||
@ -904,10 +919,13 @@ void ppu_load_exec(const ppu_exec_object& elf)
|
||||
{
|
||||
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);
|
||||
|
||||
const u32 addr = vm::cast(prog.p_vaddr, HERE);
|
||||
const u32 size = ::narrow<u32>(prog.p_memsz, "p_memsz" HERE);
|
||||
|
||||
if (prog.p_type == 0x1 /* LOAD */ && prog.p_memsz)
|
||||
ppu_segment _seg;
|
||||
const u32 addr = _seg.addr = vm::cast(prog.p_vaddr, HERE);
|
||||
const u32 size = _seg.size = ::narrow<u32>(prog.p_memsz, "p_memsz" HERE);
|
||||
const u32 type = _seg.type = prog.p_type;
|
||||
const u32 flag = _seg.flags = prog.p_flags;
|
||||
|
||||
if (type == 0x1 /* LOAD */ && prog.p_memsz)
|
||||
{
|
||||
if (prog.bin.size() > size || prog.bin.size() != prog.p_filesz)
|
||||
fmt::throw_exception("Invalid binary size (0x%llx, memsz=0x%x)", prog.bin.size(), size);
|
||||
@ -924,7 +942,8 @@ void ppu_load_exec(const ppu_exec_object& elf)
|
||||
ppu_register_range(addr, size);
|
||||
}
|
||||
|
||||
segments.emplace_back(std::make_pair(addr, size));
|
||||
// Store only LOAD segments (TODO)
|
||||
_main->segs.emplace_back(_seg);
|
||||
}
|
||||
}
|
||||
|
||||
@ -933,12 +952,15 @@ void ppu_load_exec(const ppu_exec_object& elf)
|
||||
{
|
||||
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);
|
||||
ppu_segment _sec;
|
||||
const u32 addr = _sec.addr = vm::cast(s.sh_addr);
|
||||
const u32 size = _sec.size = vm::cast(s.sh_size);
|
||||
const u32 type = _sec.type = s.sh_type;
|
||||
const u32 flag = _sec.flags = s.sh_flags & 7;
|
||||
|
||||
if (s.sh_type == 1 && addr && size)
|
||||
{
|
||||
sections.emplace_back(std::make_pair(addr, size));
|
||||
_main->secs.emplace_back(_sec);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1038,7 +1060,7 @@ void ppu_load_exec(const ppu_exec_object& elf)
|
||||
}
|
||||
|
||||
ppu_load_exports(link, proc_prx_param.libent_start, proc_prx_param.libent_end);
|
||||
ppu_load_imports(link, proc_prx_param.libstub_start, proc_prx_param.libstub_end);
|
||||
ppu_load_imports(_main->relocs, link, proc_prx_param.libstub_start, proc_prx_param.libstub_end);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -1209,7 +1231,7 @@ void ppu_load_exec(const ppu_exec_object& elf)
|
||||
{
|
||||
LOG_WARNING(LOADER, "Loading library: %s", name);
|
||||
|
||||
auto prx = ppu_load_prx(obj, name);
|
||||
auto prx = ppu_load_prx(obj, lle_dir + name);
|
||||
|
||||
if (prx->funcs.empty())
|
||||
{
|
||||
@ -1218,7 +1240,7 @@ void ppu_load_exec(const ppu_exec_object& elf)
|
||||
else
|
||||
{
|
||||
// TODO: fix arguments
|
||||
ppu_validate(lle_dir + name, prx->funcs, prx->funcs[0].addr);
|
||||
prx->validate(prx->funcs[0].addr);
|
||||
}
|
||||
|
||||
loaded_modules.emplace_back(std::move(prx));
|
||||
@ -1230,17 +1252,15 @@ void ppu_load_exec(const ppu_exec_object& elf)
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// Analyse executable (TODO)
|
||||
ppu_module _main;
|
||||
_main.funcs = ppu_analyse(segments, sections, 0, elf.header.e_entry);
|
||||
// Set path (TODO)
|
||||
_main->name = "";
|
||||
_main->path = vfs::get(Emu.GetPath());
|
||||
|
||||
// Validate analyser results (not required)
|
||||
ppu_validate(vfs::get(Emu.GetPath()), _main.funcs, 0);
|
||||
// Analyse executable (TODO)
|
||||
_main->analyse(0, static_cast<u32>(elf.header.e_entry));
|
||||
|
||||
// Set for delayed initialization in ppu_initialize()
|
||||
fxm::make<ppu_module>(std::move(_main));
|
||||
}
|
||||
// Validate analyser results (not required)
|
||||
_main->validate(0);
|
||||
|
||||
// Set SDK version
|
||||
g_ps3_sdk_version = sdk_version;
|
||||
@ -1262,7 +1282,7 @@ void ppu_load_exec(const ppu_exec_object& elf)
|
||||
*argv++ = arg_addr;
|
||||
}
|
||||
|
||||
argv -= args.size();
|
||||
argv -= ::size32(args);
|
||||
|
||||
// Initialize main thread
|
||||
auto ppu = idm::make_ptr<ppu_thread>("main_thread", primary_prio, primary_stacksize);
|
||||
|
@ -982,24 +982,31 @@ extern void ppu_initialize(const ppu_module& info)
|
||||
// Worker threads
|
||||
std::vector<std::thread> jthreads;
|
||||
|
||||
// Global variables (pointers) to initialize
|
||||
std::vector<std::pair<std::string, void*>> globals;
|
||||
// Global variables to initialize
|
||||
std::vector<std::pair<std::string, u64>> globals;
|
||||
|
||||
// Split module into fragments <= 1 MiB
|
||||
std::size_t fpos = 0;
|
||||
|
||||
// Copy module information
|
||||
ppu_module part = info;
|
||||
// Difference between function name and current location
|
||||
const u32 reloc = info.name.empty() ? 0 : info.segs.at(0).addr;
|
||||
|
||||
while (fpos < info.funcs.size())
|
||||
{
|
||||
// First function in current module part
|
||||
const auto fstart = fpos;
|
||||
|
||||
std::size_t bsize = 0;
|
||||
|
||||
// Copy module information (TODO: optimize)
|
||||
ppu_module part = info;
|
||||
part.funcs.clear();
|
||||
part.funcs.reserve(16000);
|
||||
|
||||
// Unique suffix for each module part
|
||||
const u32 suffix = info.funcs.at(fstart).addr - reloc;
|
||||
|
||||
// Overall block size in bytes
|
||||
std::size_t bsize = 0;
|
||||
|
||||
while (fpos < info.funcs.size())
|
||||
{
|
||||
auto& func = info.funcs[fpos];
|
||||
@ -1018,28 +1025,28 @@ extern void ppu_initialize(const ppu_module& info)
|
||||
entry.addr = block.first;
|
||||
entry.size = block.second;
|
||||
entry.toc = func.toc;
|
||||
fmt::append(entry.name, "__0x%x", block.first);
|
||||
fmt::append(entry.name, "__0x%x", block.first - reloc);
|
||||
part.funcs.emplace_back(std::move(entry));
|
||||
}
|
||||
|
||||
fpos++;
|
||||
}
|
||||
|
||||
part.name.clear();
|
||||
// Version, module name and hash: vX-liblv2.sprx-0123456789ABCDEF.obj
|
||||
std::string obj_name = "v2";
|
||||
|
||||
if (info.name.size())
|
||||
{
|
||||
part.name += '-';
|
||||
part.name += info.name;
|
||||
obj_name += '-';
|
||||
obj_name += info.name;
|
||||
}
|
||||
|
||||
if (fstart || fpos < info.funcs.size())
|
||||
{
|
||||
fmt::append(part.name, "+%06X", info.funcs.at(fstart).addr);
|
||||
fmt::append(obj_name, "+%06X", suffix);
|
||||
}
|
||||
|
||||
// Compute module hash
|
||||
std::string obj_name;
|
||||
{
|
||||
sha1_context ctx;
|
||||
u8 output[20];
|
||||
@ -1052,28 +1059,32 @@ extern void ppu_initialize(const ppu_module& info)
|
||||
continue;
|
||||
}
|
||||
|
||||
const be_t<u32> addr = func.addr;
|
||||
const be_t<u32> addr = func.addr - reloc;
|
||||
const be_t<u32> size = func.size;
|
||||
sha1_update(&ctx, reinterpret_cast<const u8*>(&addr), sizeof(addr));
|
||||
sha1_update(&ctx, reinterpret_cast<const u8*>(&size), sizeof(size));
|
||||
|
||||
for (const auto& block : func.blocks)
|
||||
{
|
||||
if (block.second == 0)
|
||||
if (block.second == 0 || reloc)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// TODO: relocations must be taken into account (TODO)
|
||||
sha1_update(&ctx, vm::ps3::_ptr<const u8>(block.first), block.second);
|
||||
}
|
||||
|
||||
if (reloc)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
sha1_update(&ctx, vm::ps3::_ptr<const u8>(func.addr), func.size);
|
||||
}
|
||||
|
||||
sha1_finish(&ctx, output);
|
||||
|
||||
// Version, module name and hash: vX-liblv2.sprx-0123456789ABCDEF.obj
|
||||
fmt::append(obj_name, "v2%s-%016X-%s.obj", part.name, reinterpret_cast<be_t<u64>&>(output), jit.cpu());
|
||||
fmt::append(obj_name, "-%016X-%s.obj", reinterpret_cast<be_t<u64>&>(output), jit.cpu());
|
||||
}
|
||||
|
||||
if (Emu.IsStopped())
|
||||
@ -1081,19 +1092,49 @@ extern void ppu_initialize(const ppu_module& info)
|
||||
break;
|
||||
}
|
||||
|
||||
globals.emplace_back(fmt::format("__mptr%x", part.funcs[0].addr), vm::g_base_addr);
|
||||
globals.emplace_back(fmt::format("__cptr%x", part.funcs[0].addr), vm::g_exec_addr);
|
||||
globals.emplace_back(fmt::format("__mptr%x", suffix), (u64)vm::g_base_addr);
|
||||
globals.emplace_back(fmt::format("__cptr%x", suffix), (u64)vm::g_exec_addr);
|
||||
|
||||
// Initialize segments for relocations
|
||||
for (u32 i = 0; i < info.segs.size(); i++)
|
||||
{
|
||||
globals.emplace_back(fmt::format("__seg%u_%x", i, suffix), info.segs[i].addr);
|
||||
}
|
||||
|
||||
// Get cache path for this executable
|
||||
std::string cache_path;
|
||||
|
||||
if (info.name.empty())
|
||||
{
|
||||
cache_path = Emu.GetCachePath();
|
||||
}
|
||||
else
|
||||
{
|
||||
cache_path = vfs::get("/dev_flash/");
|
||||
|
||||
if (info.path.compare(0, cache_path.size(), cache_path) == 0)
|
||||
{
|
||||
// Remove prefix for dev_flash files
|
||||
cache_path.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
cache_path = Emu.GetTitleID();
|
||||
}
|
||||
|
||||
cache_path = fs::get_data_dir(cache_path, info.path);
|
||||
}
|
||||
|
||||
// Check object file
|
||||
if (fs::is_file(Emu.GetCachePath() + obj_name))
|
||||
if (fs::is_file(cache_path + obj_name))
|
||||
{
|
||||
semaphore_lock lock(jmutex);
|
||||
ppu_initialize2(jit, part, Emu.GetCachePath(), obj_name);
|
||||
ppu_initialize2(jit, part, cache_path, obj_name);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Create worker thread for compilation
|
||||
jthreads.emplace_back([&jit, &jmutex, &jcores, obj_name = obj_name, part = std::move(part)]()
|
||||
jthreads.emplace_back([&jit, &jmutex, &jcores, obj_name = obj_name, part = std::move(part), cache_path = std::move(cache_path)]()
|
||||
{
|
||||
// Set low priority
|
||||
thread_ctrl::set_native_priority(-1);
|
||||
@ -1109,17 +1150,17 @@ extern void ppu_initialize(const ppu_module& info)
|
||||
|
||||
// Use another JIT instance
|
||||
jit_compiler jit2({}, g_cfg.core.llvm_cpu);
|
||||
ppu_initialize2(jit2, part, Emu.GetCachePath(), obj_name);
|
||||
ppu_initialize2(jit2, part, cache_path, obj_name);
|
||||
}
|
||||
|
||||
if (Emu.IsStopped())
|
||||
if (Emu.IsStopped() || !fs::is_file(cache_path + obj_name))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Proceed with original JIT instance
|
||||
semaphore_lock lock(jmutex);
|
||||
ppu_initialize2(jit, part, Emu.GetCachePath(), obj_name);
|
||||
ppu_initialize2(jit, part, cache_path, obj_name);
|
||||
});
|
||||
}
|
||||
|
||||
@ -1145,7 +1186,7 @@ extern void ppu_initialize(const ppu_module& info)
|
||||
{
|
||||
if (block.second)
|
||||
{
|
||||
ppu_ref(block.first) = ::narrow<u32>(jit.get(fmt::format("__0x%x", block.first)));
|
||||
ppu_ref(block.first) = ::narrow<u32>(jit.get(fmt::format("__0x%x", block.first - reloc)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1155,7 +1196,7 @@ extern void ppu_initialize(const ppu_module& info)
|
||||
{
|
||||
if (u64 addr = jit.get(var.first))
|
||||
{
|
||||
*reinterpret_cast<void**>(addr) = var.second;
|
||||
*reinterpret_cast<u64*>(addr) = var.second;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@ -1256,10 +1297,16 @@ static void ppu_initialize2(jit_compiler& jit, const ppu_module& module_part, co
|
||||
});
|
||||
|
||||
// Translate
|
||||
const auto func = translator.Translate(module_part.funcs[fi]);
|
||||
|
||||
// Run optimization passes
|
||||
pm.run(*func);
|
||||
if (const auto func = translator.Translate(module_part.funcs[fi]))
|
||||
{
|
||||
// Run optimization passes
|
||||
pm.run(*func);
|
||||
}
|
||||
else
|
||||
{
|
||||
Emu.Pause();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
#ifdef LLVM_AVAILABLE
|
||||
#ifdef LLVM_AVAILABLE
|
||||
|
||||
#include "PPUTranslator.h"
|
||||
#include "PPUThread.h"
|
||||
@ -18,8 +18,11 @@ PPUTranslator::PPUTranslator(LLVMContext& context, Module* module, const ppu_mod
|
||||
, m_info(info)
|
||||
, m_pure_attr(AttributeSet::get(m_context, AttributeSet::FunctionIndex, {Attribute::NoUnwind, Attribute::ReadNone}))
|
||||
{
|
||||
// There is no weak linkage on JIT, so let's create variables with different names for each module part
|
||||
const u32 gsuffix = m_info.name.empty() ? info.funcs[0].addr : info.funcs[0].addr - m_info.segs[0].addr;
|
||||
|
||||
// Memory base
|
||||
m_base = new GlobalVariable(*module, ArrayType::get(GetType<char>(), 0x100000000)->getPointerTo(), true, GlobalValue::ExternalLinkage, 0, fmt::format("__mptr%x", info.funcs[0].addr));
|
||||
m_base = new GlobalVariable(*module, ArrayType::get(GetType<char>(), 0x100000000)->getPointerTo(), true, GlobalValue::ExternalLinkage, 0, fmt::format("__mptr%x", gsuffix));
|
||||
m_base->setInitializer(ConstantPointerNull::get(cast<PointerType>(m_base->getType()->getPointerElementType())));
|
||||
m_base->setExternallyInitialized(true);
|
||||
|
||||
@ -44,7 +47,7 @@ PPUTranslator::PPUTranslator(LLVMContext& context, Module* module, const ppu_mod
|
||||
m_thread_type = StructType::create(m_context, thread_struct, "context_t");
|
||||
|
||||
// Callable
|
||||
m_call = new GlobalVariable(*module, ArrayType::get(GetType<u32>(), 0x40000000)->getPointerTo(), true, GlobalValue::ExternalLinkage, 0, fmt::format("__cptr%x", info.funcs[0].addr));
|
||||
m_call = new GlobalVariable(*module, ArrayType::get(GetType<u32>(), 0x40000000)->getPointerTo(), true, GlobalValue::ExternalLinkage, 0, fmt::format("__cptr%x", gsuffix));
|
||||
m_call->setInitializer(ConstantPointerNull::get(cast<PointerType>(m_call->getType()->getPointerElementType())));
|
||||
m_call->setExternallyInitialized(true);
|
||||
|
||||
@ -55,6 +58,56 @@ PPUTranslator::PPUTranslator(LLVMContext& context, Module* module, const ppu_mod
|
||||
// Metadata for branch weights
|
||||
m_md_likely = MDTuple::get(m_context, {md_name, md_high, md_low});
|
||||
m_md_unlikely = MDTuple::get(m_context, {md_name, md_low, md_high});
|
||||
|
||||
// Create segment variables
|
||||
for (const auto& seg : m_info.segs)
|
||||
{
|
||||
auto gv = new GlobalVariable(*module, GetType<u64>(), true, GlobalValue::ExternalLinkage, 0, fmt::format("__seg%u_%x", m_segs.size(), gsuffix));
|
||||
gv->setInitializer(ConstantInt::get(GetType<u64>(), seg.addr));
|
||||
gv->setExternallyInitialized(true);
|
||||
m_segs.emplace_back(gv);
|
||||
}
|
||||
|
||||
// Sort relevant relocations (TODO)
|
||||
const auto caddr = m_info.segs[0].addr;
|
||||
const auto cend = caddr + m_info.segs[0].size;
|
||||
|
||||
for (const auto& rel : m_info.relocs)
|
||||
{
|
||||
if (rel.addr >= caddr && rel.addr < cend)
|
||||
{
|
||||
// Check relocation type
|
||||
switch (rel.type)
|
||||
{
|
||||
case 20:
|
||||
case 22:
|
||||
case 38:
|
||||
case 43:
|
||||
case 44:
|
||||
case 45:
|
||||
case 46:
|
||||
case 51:
|
||||
case 68:
|
||||
case 73:
|
||||
case 78:
|
||||
{
|
||||
LOG_ERROR(PPU, "64-bit relocation at 0x%x (%u)", rel.addr, rel.type);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Align relocation address (TODO)
|
||||
if (!m_relocs.emplace(rel.addr & ~3, &rel).second)
|
||||
{
|
||||
LOG_ERROR(PPU, "Relocation repeated at 0x%x (%u)", rel.addr, rel.type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_info.name.empty())
|
||||
{
|
||||
m_reloc = &m_info.segs[0];
|
||||
}
|
||||
}
|
||||
|
||||
PPUTranslator::~PPUTranslator()
|
||||
@ -69,8 +122,6 @@ Type* PPUTranslator::GetContextType()
|
||||
Function* PPUTranslator::Translate(const ppu_function& info)
|
||||
{
|
||||
m_function = m_module->getFunction(info.name);
|
||||
m_start_addr = info.addr;
|
||||
m_end_addr = info.addr + info.size;
|
||||
|
||||
std::fill(std::begin(m_globals), std::end(m_globals), nullptr);
|
||||
std::fill(std::begin(m_locals), std::end(m_locals), nullptr);
|
||||
@ -78,6 +129,10 @@ Function* PPUTranslator::Translate(const ppu_function& info)
|
||||
IRBuilder<> irb(m_entry = BasicBlock::Create(m_context, "__entry", m_function));
|
||||
m_ir = &irb;
|
||||
|
||||
// Instruction address is (m_addr + base)
|
||||
const u64 base = m_reloc ? m_reloc->addr : 0;
|
||||
m_addr = info.addr - base;
|
||||
|
||||
m_thread = &*m_function->getArgumentList().begin();
|
||||
m_base_loaded = m_ir->CreateLoad(m_base);
|
||||
|
||||
@ -90,7 +145,7 @@ Function* PPUTranslator::Translate(const ppu_function& info)
|
||||
|
||||
// Create tail call to the check function
|
||||
m_ir->SetInsertPoint(vcheck);
|
||||
Call(GetType<void>(), "__check", m_thread, m_ir->getInt64(m_start_addr))->setTailCallKind(llvm::CallInst::TCK_Tail);
|
||||
Call(GetType<void>(), "__check", m_thread, GetAddr())->setTailCallKind(llvm::CallInst::TCK_Tail);
|
||||
m_ir->CreateRetVoid();
|
||||
m_ir->SetInsertPoint(m_body);
|
||||
|
||||
@ -104,28 +159,58 @@ Function* PPUTranslator::Translate(const ppu_function& info)
|
||||
}
|
||||
|
||||
// Process the instructions
|
||||
for (m_current_addr = block.first; m_current_addr < block.first + block.second; m_current_addr += 4)
|
||||
for (m_addr = block.first - base; m_addr < block.first + block.second - base; m_addr += 4)
|
||||
{
|
||||
if (m_body->getTerminator())
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
const u32 op = vm::ps3::read32(vm::cast(m_current_addr));
|
||||
// Find the relocation at current address
|
||||
const auto rel_found = m_relocs.find(m_addr + base);
|
||||
|
||||
if (rel_found != m_relocs.end())
|
||||
{
|
||||
m_rel = rel_found->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_rel = nullptr;
|
||||
}
|
||||
|
||||
const u32 op = vm::ps3::read32(vm::cast(m_addr + base));
|
||||
(this->*(s_ppu_decoder.decode(op)))({op});
|
||||
|
||||
if (m_rel)
|
||||
{
|
||||
// This is very bæd
|
||||
LOG_ERROR(PPU, "LLVM: [0x%x] Unsupported relocation(%u) in '%s'. Please report.", rel_found->first, m_rel->type, m_info.name);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// Finalize current block if necessary (create branch to the next address)
|
||||
if (!m_body->getTerminator())
|
||||
{
|
||||
FlushRegisters();
|
||||
CallFunction(m_current_addr);
|
||||
CallFunction(m_addr);
|
||||
}
|
||||
}
|
||||
|
||||
return m_function;
|
||||
}
|
||||
|
||||
Value* PPUTranslator::GetAddr(u64 _add)
|
||||
{
|
||||
if (m_reloc)
|
||||
{
|
||||
// Load segment address from global variable, compute actual instruction address
|
||||
return m_ir->CreateAdd(m_ir->getInt64(m_addr + _add), m_ir->CreateLoad(m_segs[m_reloc - m_info.segs.data()]));
|
||||
}
|
||||
|
||||
return m_ir->getInt64(m_addr + _add);
|
||||
}
|
||||
|
||||
Type* PPUTranslator::ScaleType(Type* type, s32 pow2)
|
||||
{
|
||||
verify(HERE), (type->getScalarType()->isIntegerTy());
|
||||
@ -159,9 +244,9 @@ void PPUTranslator::CallFunction(u64 target, Value* indirect)
|
||||
|
||||
if (!indirect)
|
||||
{
|
||||
if (target < 0x10000 || target >= -0x10000)
|
||||
if ((!m_reloc && target < 0x10000) || target >= -0x10000)
|
||||
{
|
||||
Trap(m_current_addr);
|
||||
Trap();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -414,11 +499,11 @@ void PPUTranslator::UseCondition(MDNode* hint, Value* cond)
|
||||
|
||||
if (cond)
|
||||
{
|
||||
const auto local = BasicBlock::Create(m_context, fmt::format("loc_%llx.cond", m_current_addr), m_function);
|
||||
const auto next = BasicBlock::Create(m_context, fmt::format("loc_%llx.next", m_current_addr), m_function);
|
||||
const auto local = BasicBlock::Create(m_context, "__cond", m_function);
|
||||
const auto next = BasicBlock::Create(m_context, "__next", m_function);
|
||||
m_ir->CreateCondBr(cond, local, next, hint);
|
||||
m_ir->SetInsertPoint(next);
|
||||
CallFunction(m_current_addr + 4);
|
||||
CallFunction(m_addr + 4);
|
||||
m_ir->SetInsertPoint(local);
|
||||
}
|
||||
}
|
||||
@ -462,7 +547,7 @@ void PPUTranslator::WriteMemory(Value* addr, Value* value, bool is_be, u32 align
|
||||
|
||||
void PPUTranslator::CompilationError(const std::string& error)
|
||||
{
|
||||
LOG_ERROR(PPU, "[0x%08llx] 0x%08llx: Error: %s", m_start_addr, m_current_addr, error);
|
||||
LOG_ERROR(PPU, "LLVM: [0x%08x] Error: %s", m_addr + (m_reloc ? m_reloc->addr : 0), error);
|
||||
}
|
||||
|
||||
|
||||
@ -1535,13 +1620,13 @@ void PPUTranslator::VXOR(ppu_opcode_t op)
|
||||
void PPUTranslator::TDI(ppu_opcode_t op)
|
||||
{
|
||||
UseCondition(m_md_unlikely, CheckTrapCondition(op.bo, GetGpr(op.ra), m_ir->getInt64(op.simm16)));
|
||||
Trap(m_current_addr);
|
||||
Trap();
|
||||
}
|
||||
|
||||
void PPUTranslator::TWI(ppu_opcode_t op)
|
||||
{
|
||||
UseCondition(m_md_unlikely, CheckTrapCondition(op.bo, GetGpr(op.ra, 32), m_ir->getInt32(op.simm16)));
|
||||
Trap(m_current_addr);
|
||||
Trap();
|
||||
}
|
||||
|
||||
void PPUTranslator::MULLI(ppu_opcode_t op)
|
||||
@ -1570,8 +1655,15 @@ void PPUTranslator::CMPI(ppu_opcode_t op)
|
||||
|
||||
void PPUTranslator::ADDIC(ppu_opcode_t op)
|
||||
{
|
||||
Value* imm = m_ir->getInt64(op.simm16);
|
||||
|
||||
if (m_rel && m_rel->type == 4)
|
||||
{
|
||||
imm = SExt(ReadMemory(GetAddr(+2), GetType<u16>()), GetType<u64>());
|
||||
m_rel = nullptr;
|
||||
}
|
||||
|
||||
const auto a = GetGpr(op.ra);
|
||||
const auto imm = m_ir->getInt64(op.simm16);
|
||||
const auto result = m_ir->CreateAdd(a, imm);
|
||||
SetGpr(op.rd, result);
|
||||
SetCarry(m_ir->CreateICmpULT(result, imm));
|
||||
@ -1580,25 +1672,44 @@ void PPUTranslator::ADDIC(ppu_opcode_t op)
|
||||
|
||||
void PPUTranslator::ADDI(ppu_opcode_t op)
|
||||
{
|
||||
const auto imm = m_ir->getInt64(op.simm16);
|
||||
Value* imm = m_ir->getInt64(op.simm16);
|
||||
|
||||
if (m_rel && m_rel->type == 4)
|
||||
{
|
||||
imm = SExt(ReadMemory(GetAddr(+2), GetType<u16>()), GetType<u64>());
|
||||
m_rel = nullptr;
|
||||
}
|
||||
|
||||
SetGpr(op.rd, op.ra ? m_ir->CreateAdd(GetGpr(op.ra), imm) : imm);
|
||||
}
|
||||
|
||||
void PPUTranslator::ADDIS(ppu_opcode_t op)
|
||||
{
|
||||
const auto imm = m_ir->getInt64(op.simm16 << 16);
|
||||
Value* imm = m_ir->getInt64(op.simm16 << 16);
|
||||
|
||||
if (m_rel && m_rel->type == 6)
|
||||
{
|
||||
imm = m_ir->CreateShl(SExt(ReadMemory(GetAddr(+2), GetType<u16>()), GetType<u64>()), 16);
|
||||
m_rel = nullptr;
|
||||
}
|
||||
|
||||
SetGpr(op.rd, op.ra ? m_ir->CreateAdd(GetGpr(op.ra), imm) : imm);
|
||||
}
|
||||
|
||||
void PPUTranslator::BC(ppu_opcode_t op)
|
||||
{
|
||||
const u64 target = (op.aa ? 0 : m_current_addr) + op.bt14;
|
||||
const u64 target = (op.aa ? 0 : m_addr) + op.bt14;
|
||||
|
||||
if (op.aa && m_reloc)
|
||||
{
|
||||
CompilationError("Branch with absolute address");
|
||||
}
|
||||
|
||||
UseCondition(CheckBranchProbability(op.bo), CheckBranchCondition(op.bo, op.bi));
|
||||
|
||||
if (op.lk)
|
||||
{
|
||||
m_ir->CreateStore(m_ir->getInt64(m_current_addr + 4), m_ir->CreateStructGEP(nullptr, m_thread, &m_lr - m_locals));
|
||||
m_ir->CreateStore(GetAddr(+4), m_ir->CreateStructGEP(nullptr, m_thread, &m_lr - m_locals));
|
||||
}
|
||||
|
||||
CallFunction(target);
|
||||
@ -1612,7 +1723,7 @@ void PPUTranslator::SC(ppu_opcode_t op)
|
||||
}
|
||||
|
||||
const auto num = GetGpr(11);
|
||||
RegStore(m_ir->getInt32(m_current_addr), m_cia);
|
||||
RegStore(Trunc(GetAddr()), m_cia);
|
||||
FlushRegisters();
|
||||
|
||||
if (!op.lev && isa<ConstantInt>(num))
|
||||
@ -1635,11 +1746,16 @@ void PPUTranslator::SC(ppu_opcode_t op)
|
||||
|
||||
void PPUTranslator::B(ppu_opcode_t op)
|
||||
{
|
||||
const u64 target = (op.aa ? 0 : m_current_addr) + op.bt24;
|
||||
const u64 target = (op.aa ? 0 : m_addr) + op.bt24;
|
||||
|
||||
if (op.aa && m_reloc)
|
||||
{
|
||||
CompilationError("Branch with absolute address");
|
||||
}
|
||||
|
||||
if (op.lk)
|
||||
{
|
||||
RegStore(m_ir->getInt64(m_current_addr + 4), m_lr);
|
||||
RegStore(GetAddr(+4), m_lr);
|
||||
}
|
||||
|
||||
FlushRegisters();
|
||||
@ -1663,7 +1779,7 @@ void PPUTranslator::BCLR(ppu_opcode_t op)
|
||||
|
||||
if (op.lk)
|
||||
{
|
||||
m_ir->CreateStore(m_ir->getInt64(m_current_addr + 4), m_ir->CreateStructGEP(nullptr, m_thread, &m_lr - m_locals));
|
||||
m_ir->CreateStore(GetAddr(+4), m_ir->CreateStructGEP(nullptr, m_thread, &m_lr - m_locals));
|
||||
}
|
||||
|
||||
CallFunction(0, target);
|
||||
@ -1726,7 +1842,7 @@ void PPUTranslator::BCCTR(ppu_opcode_t op)
|
||||
|
||||
if (op.lk)
|
||||
{
|
||||
m_ir->CreateStore(m_ir->getInt64(m_current_addr + 4), m_ir->CreateStructGEP(nullptr, m_thread, &m_lr - m_locals));
|
||||
m_ir->CreateStore(GetAddr(+4), m_ir->CreateStructGEP(nullptr, m_thread, &m_lr - m_locals));
|
||||
}
|
||||
|
||||
CallFunction(0, target);
|
||||
@ -1870,12 +1986,34 @@ void PPUTranslator::RLWNM(ppu_opcode_t op)
|
||||
|
||||
void PPUTranslator::ORI(ppu_opcode_t op)
|
||||
{
|
||||
SetGpr(op.ra, m_ir->CreateOr(GetGpr(op.rs), op.uimm16));
|
||||
Value* imm = m_ir->getInt64(op.uimm16);
|
||||
|
||||
if (m_rel && m_rel->type == 4)
|
||||
{
|
||||
imm = ZExt(ReadMemory(GetAddr(+2), GetType<u16>()), GetType<u64>());
|
||||
m_rel = nullptr;
|
||||
}
|
||||
|
||||
SetGpr(op.ra, m_ir->CreateOr(GetGpr(op.rs), imm));
|
||||
}
|
||||
|
||||
void PPUTranslator::ORIS(ppu_opcode_t op)
|
||||
{
|
||||
SetGpr(op.ra, m_ir->CreateOr(GetGpr(op.rs), op.uimm16 << 16));
|
||||
Value* imm = m_ir->getInt64(op.uimm16 << 16);
|
||||
|
||||
if (m_rel && m_rel->type == 5)
|
||||
{
|
||||
imm = m_ir->CreateShl(ZExt(ReadMemory(GetAddr(+2), GetType<u16>()), GetType<u64>()), 16);
|
||||
m_rel = nullptr;
|
||||
}
|
||||
|
||||
if (m_rel && m_rel->type == 6)
|
||||
{
|
||||
imm = m_ir->CreateShl(ZExt(ReadMemory(GetAddr(+2), GetType<u16>()), GetType<u64>()), 16);
|
||||
m_rel = nullptr;
|
||||
}
|
||||
|
||||
SetGpr(op.ra, m_ir->CreateOr(GetGpr(op.rs), imm));
|
||||
}
|
||||
|
||||
void PPUTranslator::XORI(ppu_opcode_t op)
|
||||
@ -2050,7 +2188,7 @@ void PPUTranslator::TW(ppu_opcode_t op)
|
||||
FlushRegisters();
|
||||
}
|
||||
|
||||
Trap(m_current_addr);
|
||||
Trap();
|
||||
}
|
||||
|
||||
void PPUTranslator::LVSL(ppu_opcode_t op)
|
||||
@ -2266,7 +2404,7 @@ void PPUTranslator::ANDC(ppu_opcode_t op)
|
||||
void PPUTranslator::TD(ppu_opcode_t op)
|
||||
{
|
||||
UseCondition(m_md_unlikely, CheckTrapCondition(op.bo, GetGpr(op.ra), GetGpr(op.rb)));
|
||||
Trap(m_current_addr);
|
||||
Trap();
|
||||
}
|
||||
|
||||
void PPUTranslator::LVEWX(ppu_opcode_t op)
|
||||
@ -3136,84 +3274,196 @@ void PPUTranslator::DCBZ(ppu_opcode_t op)
|
||||
|
||||
void PPUTranslator::LWZ(ppu_opcode_t op)
|
||||
{
|
||||
SetGpr(op.rd, ReadMemory(op.ra ? m_ir->CreateAdd(GetGpr(op.ra), m_ir->getInt64(op.simm16)) : m_ir->getInt64(op.simm16), GetType<u32>()));
|
||||
Value* imm = m_ir->getInt64(op.simm16);
|
||||
|
||||
if (m_rel && m_rel->type == 4)
|
||||
{
|
||||
imm = SExt(ReadMemory(GetAddr(+2), GetType<u16>()), GetType<u64>());
|
||||
m_rel = nullptr;
|
||||
}
|
||||
|
||||
SetGpr(op.rd, ReadMemory(op.ra ? m_ir->CreateAdd(GetGpr(op.ra), imm) : imm, GetType<u32>()));
|
||||
}
|
||||
|
||||
void PPUTranslator::LWZU(ppu_opcode_t op)
|
||||
{
|
||||
const auto addr = m_ir->CreateAdd(GetGpr(op.ra), m_ir->getInt64(op.simm16));
|
||||
Value* imm = m_ir->getInt64(op.simm16);
|
||||
|
||||
if (m_rel && m_rel->type == 4)
|
||||
{
|
||||
imm = SExt(ReadMemory(GetAddr(+2), GetType<u16>()), GetType<u64>());
|
||||
m_rel = nullptr;
|
||||
}
|
||||
|
||||
const auto addr = m_ir->CreateAdd(GetGpr(op.ra), imm);
|
||||
SetGpr(op.rd, ReadMemory(addr, GetType<u32>()));
|
||||
SetGpr(op.ra, addr);
|
||||
}
|
||||
|
||||
void PPUTranslator::LBZ(ppu_opcode_t op)
|
||||
{
|
||||
SetGpr(op.rd, ReadMemory(op.ra ? m_ir->CreateAdd(GetGpr(op.ra), m_ir->getInt64(op.simm16)) : m_ir->getInt64(op.simm16), GetType<u8>()));
|
||||
Value* imm = m_ir->getInt64(op.simm16);
|
||||
|
||||
if (m_rel && m_rel->type == 4)
|
||||
{
|
||||
imm = SExt(ReadMemory(GetAddr(+2), GetType<u16>()), GetType<u64>());
|
||||
m_rel = nullptr;
|
||||
}
|
||||
|
||||
SetGpr(op.rd, ReadMemory(op.ra ? m_ir->CreateAdd(GetGpr(op.ra), imm) : imm, GetType<u8>()));
|
||||
}
|
||||
|
||||
void PPUTranslator::LBZU(ppu_opcode_t op)
|
||||
{
|
||||
const auto addr = m_ir->CreateAdd(GetGpr(op.ra), m_ir->getInt64(op.simm16));
|
||||
Value* imm = m_ir->getInt64(op.simm16);
|
||||
|
||||
if (m_rel && m_rel->type == 4)
|
||||
{
|
||||
imm = SExt(ReadMemory(GetAddr(+2), GetType<u16>()), GetType<u64>());
|
||||
m_rel = nullptr;
|
||||
}
|
||||
|
||||
const auto addr = m_ir->CreateAdd(GetGpr(op.ra), imm);
|
||||
SetGpr(op.rd, ReadMemory(addr, GetType<u8>()));
|
||||
SetGpr(op.ra, addr);
|
||||
}
|
||||
|
||||
void PPUTranslator::STW(ppu_opcode_t op)
|
||||
{
|
||||
WriteMemory(op.ra ? m_ir->CreateAdd(GetGpr(op.ra), m_ir->getInt64(op.simm16)) : m_ir->getInt64(op.simm16), GetGpr(op.rs, 32));
|
||||
Value* imm = m_ir->getInt64(op.simm16);
|
||||
|
||||
if (m_rel && m_rel->type == 4)
|
||||
{
|
||||
imm = SExt(ReadMemory(GetAddr(+2), GetType<u16>()), GetType<u64>());
|
||||
m_rel = nullptr;
|
||||
}
|
||||
|
||||
WriteMemory(op.ra ? m_ir->CreateAdd(GetGpr(op.ra), imm) : imm, GetGpr(op.rs, 32));
|
||||
}
|
||||
|
||||
void PPUTranslator::STWU(ppu_opcode_t op)
|
||||
{
|
||||
const auto addr = m_ir->CreateAdd(GetGpr(op.ra), m_ir->getInt64(op.simm16));
|
||||
Value* imm = m_ir->getInt64(op.simm16);
|
||||
|
||||
if (m_rel && m_rel->type == 4)
|
||||
{
|
||||
imm = SExt(ReadMemory(GetAddr(+2), GetType<u16>()), GetType<u64>());
|
||||
m_rel = nullptr;
|
||||
}
|
||||
|
||||
const auto addr = m_ir->CreateAdd(GetGpr(op.ra), imm);
|
||||
WriteMemory(addr, GetGpr(op.rs, 32));
|
||||
SetGpr(op.ra, addr);
|
||||
}
|
||||
|
||||
void PPUTranslator::STB(ppu_opcode_t op)
|
||||
{
|
||||
WriteMemory(op.ra ? m_ir->CreateAdd(GetGpr(op.ra), m_ir->getInt64(op.simm16)) : m_ir->getInt64(op.simm16), GetGpr(op.rs, 8));
|
||||
Value* imm = m_ir->getInt64(op.simm16);
|
||||
|
||||
if (m_rel && m_rel->type == 4)
|
||||
{
|
||||
imm = SExt(ReadMemory(GetAddr(+2), GetType<u16>()), GetType<u64>());
|
||||
m_rel = nullptr;
|
||||
}
|
||||
|
||||
WriteMemory(op.ra ? m_ir->CreateAdd(GetGpr(op.ra), imm) : imm, GetGpr(op.rs, 8));
|
||||
}
|
||||
|
||||
void PPUTranslator::STBU(ppu_opcode_t op)
|
||||
{
|
||||
const auto addr = m_ir->CreateAdd(GetGpr(op.ra), m_ir->getInt64(op.simm16));
|
||||
Value* imm = m_ir->getInt64(op.simm16);
|
||||
|
||||
if (m_rel && m_rel->type == 4)
|
||||
{
|
||||
imm = SExt(ReadMemory(GetAddr(+2), GetType<u16>()), GetType<u64>());
|
||||
m_rel = nullptr;
|
||||
}
|
||||
|
||||
const auto addr = m_ir->CreateAdd(GetGpr(op.ra), imm);
|
||||
WriteMemory(addr, GetGpr(op.rs, 8));
|
||||
SetGpr(op.ra, addr);
|
||||
}
|
||||
|
||||
void PPUTranslator::LHZ(ppu_opcode_t op)
|
||||
{
|
||||
SetGpr(op.rd, ReadMemory(op.ra ? m_ir->CreateAdd(GetGpr(op.ra), m_ir->getInt64(op.simm16)) : m_ir->getInt64(op.simm16), GetType<u16>()));
|
||||
Value* imm = m_ir->getInt64(op.simm16);
|
||||
|
||||
if (m_rel && m_rel->type == 4)
|
||||
{
|
||||
imm = SExt(ReadMemory(GetAddr(+2), GetType<u16>()), GetType<u64>());
|
||||
m_rel = nullptr;
|
||||
}
|
||||
|
||||
SetGpr(op.rd, ReadMemory(op.ra ? m_ir->CreateAdd(GetGpr(op.ra), imm) : imm, GetType<u16>()));
|
||||
}
|
||||
|
||||
void PPUTranslator::LHZU(ppu_opcode_t op)
|
||||
{
|
||||
const auto addr = m_ir->CreateAdd(GetGpr(op.ra), m_ir->getInt64(op.simm16));
|
||||
Value* imm = m_ir->getInt64(op.simm16);
|
||||
|
||||
if (m_rel && m_rel->type == 4)
|
||||
{
|
||||
imm = SExt(ReadMemory(GetAddr(+2), GetType<u16>()), GetType<u64>());
|
||||
m_rel = nullptr;
|
||||
}
|
||||
|
||||
const auto addr = m_ir->CreateAdd(GetGpr(op.ra), imm);
|
||||
SetGpr(op.rd, ReadMemory(addr, GetType<u16>()));
|
||||
SetGpr(op.ra, addr);
|
||||
}
|
||||
|
||||
void PPUTranslator::LHA(ppu_opcode_t op)
|
||||
{
|
||||
SetGpr(op.rd, SExt(ReadMemory(op.ra ? m_ir->CreateAdd(GetGpr(op.ra), m_ir->getInt64(op.simm16)) : m_ir->getInt64(op.simm16), GetType<s16>()), GetType<s64>()));
|
||||
Value* imm = m_ir->getInt64(op.simm16);
|
||||
|
||||
if (m_rel && m_rel->type == 4)
|
||||
{
|
||||
imm = SExt(ReadMemory(GetAddr(+2), GetType<u16>()), GetType<u64>());
|
||||
m_rel = nullptr;
|
||||
}
|
||||
|
||||
SetGpr(op.rd, SExt(ReadMemory(op.ra ? m_ir->CreateAdd(GetGpr(op.ra), imm) : imm, GetType<s16>()), GetType<s64>()));
|
||||
}
|
||||
|
||||
void PPUTranslator::LHAU(ppu_opcode_t op)
|
||||
{
|
||||
const auto addr = m_ir->CreateAdd(GetGpr(op.ra), m_ir->getInt64(op.simm16));
|
||||
Value* imm = m_ir->getInt64(op.simm16);
|
||||
|
||||
if (m_rel && m_rel->type == 4)
|
||||
{
|
||||
imm = SExt(ReadMemory(GetAddr(+2), GetType<u16>()), GetType<u64>());
|
||||
m_rel = nullptr;
|
||||
}
|
||||
|
||||
const auto addr = m_ir->CreateAdd(GetGpr(op.ra), imm);
|
||||
SetGpr(op.rd, SExt(ReadMemory(addr, GetType<s16>()), GetType<s64>()));
|
||||
SetGpr(op.ra, addr);
|
||||
}
|
||||
|
||||
void PPUTranslator::STH(ppu_opcode_t op)
|
||||
{
|
||||
WriteMemory(op.ra ? m_ir->CreateAdd(GetGpr(op.ra), m_ir->getInt64(op.simm16)) : m_ir->getInt64(op.simm16), GetGpr(op.rs, 16));
|
||||
Value* imm = m_ir->getInt64(op.simm16);
|
||||
|
||||
if (m_rel && m_rel->type == 4)
|
||||
{
|
||||
imm = SExt(ReadMemory(GetAddr(+2), GetType<u16>()), GetType<u64>());
|
||||
m_rel = nullptr;
|
||||
}
|
||||
|
||||
WriteMemory(op.ra ? m_ir->CreateAdd(GetGpr(op.ra), imm) : imm, GetGpr(op.rs, 16));
|
||||
}
|
||||
|
||||
void PPUTranslator::STHU(ppu_opcode_t op)
|
||||
{
|
||||
const auto addr = m_ir->CreateAdd(GetGpr(op.ra), m_ir->getInt64(op.simm16));
|
||||
Value* imm = m_ir->getInt64(op.simm16);
|
||||
|
||||
if (m_rel && m_rel->type == 4)
|
||||
{
|
||||
imm = SExt(ReadMemory(GetAddr(+2), GetType<u16>()), GetType<u64>());
|
||||
m_rel = nullptr;
|
||||
}
|
||||
|
||||
const auto addr = m_ir->CreateAdd(GetGpr(op.ra), imm);
|
||||
WriteMemory(addr, GetGpr(op.rs, 16));
|
||||
SetGpr(op.ra, addr);
|
||||
}
|
||||
@ -3236,77 +3486,181 @@ void PPUTranslator::STMW(ppu_opcode_t op)
|
||||
|
||||
void PPUTranslator::LFS(ppu_opcode_t op)
|
||||
{
|
||||
SetFpr(op.frd, ReadMemory(op.ra ? m_ir->CreateAdd(GetGpr(op.ra), m_ir->getInt64(op.simm16)) : m_ir->getInt64(op.simm16), GetType<f32>()));
|
||||
Value* imm = m_ir->getInt64(op.simm16);
|
||||
|
||||
if (m_rel && m_rel->type == 4)
|
||||
{
|
||||
imm = SExt(ReadMemory(GetAddr(+2), GetType<u16>()), GetType<u64>());
|
||||
m_rel = nullptr;
|
||||
}
|
||||
|
||||
SetFpr(op.frd, ReadMemory(op.ra ? m_ir->CreateAdd(GetGpr(op.ra), imm) : imm, GetType<f32>()));
|
||||
}
|
||||
|
||||
void PPUTranslator::LFSU(ppu_opcode_t op)
|
||||
{
|
||||
const auto addr = m_ir->CreateAdd(GetGpr(op.ra), m_ir->getInt64(op.simm16));
|
||||
Value* imm = m_ir->getInt64(op.simm16);
|
||||
|
||||
if (m_rel && m_rel->type == 4)
|
||||
{
|
||||
imm = SExt(ReadMemory(GetAddr(+2), GetType<u16>()), GetType<u64>());
|
||||
m_rel = nullptr;
|
||||
}
|
||||
|
||||
const auto addr = m_ir->CreateAdd(GetGpr(op.ra), imm);
|
||||
SetFpr(op.frd, ReadMemory(addr, GetType<f32>()));
|
||||
SetGpr(op.ra, addr);
|
||||
}
|
||||
|
||||
void PPUTranslator::LFD(ppu_opcode_t op)
|
||||
{
|
||||
SetFpr(op.frd, ReadMemory(op.ra ? m_ir->CreateAdd(GetGpr(op.ra), m_ir->getInt64(op.simm16)) : m_ir->getInt64(op.simm16), GetType<f64>()));
|
||||
Value* imm = m_ir->getInt64(op.simm16);
|
||||
|
||||
if (m_rel && m_rel->type == 4)
|
||||
{
|
||||
imm = SExt(ReadMemory(GetAddr(+2), GetType<u16>()), GetType<u64>());
|
||||
m_rel = nullptr;
|
||||
}
|
||||
|
||||
SetFpr(op.frd, ReadMemory(op.ra ? m_ir->CreateAdd(GetGpr(op.ra), imm) : imm, GetType<f64>()));
|
||||
}
|
||||
|
||||
void PPUTranslator::LFDU(ppu_opcode_t op)
|
||||
{
|
||||
const auto addr = m_ir->CreateAdd(GetGpr(op.ra), m_ir->getInt64(op.simm16));
|
||||
Value* imm = m_ir->getInt64(op.simm16);
|
||||
|
||||
if (m_rel && m_rel->type == 4)
|
||||
{
|
||||
imm = SExt(ReadMemory(GetAddr(+2), GetType<u16>()), GetType<u64>());
|
||||
m_rel = nullptr;
|
||||
}
|
||||
|
||||
const auto addr = m_ir->CreateAdd(GetGpr(op.ra), imm);
|
||||
SetFpr(op.frd, ReadMemory(addr, GetType<f64>()));
|
||||
SetGpr(op.ra, addr);
|
||||
}
|
||||
|
||||
void PPUTranslator::STFS(ppu_opcode_t op)
|
||||
{
|
||||
WriteMemory(op.ra ? m_ir->CreateAdd(GetGpr(op.ra), m_ir->getInt64(op.simm16)) : m_ir->getInt64(op.simm16), GetFpr(op.frs, 32));
|
||||
Value* imm = m_ir->getInt64(op.simm16);
|
||||
|
||||
if (m_rel && m_rel->type == 4)
|
||||
{
|
||||
imm = SExt(ReadMemory(GetAddr(+2), GetType<u16>()), GetType<u64>());
|
||||
m_rel = nullptr;
|
||||
}
|
||||
|
||||
WriteMemory(op.ra ? m_ir->CreateAdd(GetGpr(op.ra), imm) : imm, GetFpr(op.frs, 32));
|
||||
}
|
||||
|
||||
void PPUTranslator::STFSU(ppu_opcode_t op)
|
||||
{
|
||||
const auto addr = m_ir->CreateAdd(GetGpr(op.ra), m_ir->getInt64(op.simm16));
|
||||
Value* imm = m_ir->getInt64(op.simm16);
|
||||
|
||||
if (m_rel && m_rel->type == 4)
|
||||
{
|
||||
imm = SExt(ReadMemory(GetAddr(+2), GetType<u16>()), GetType<u64>());
|
||||
m_rel = nullptr;
|
||||
}
|
||||
|
||||
const auto addr = m_ir->CreateAdd(GetGpr(op.ra), imm);
|
||||
WriteMemory(addr, GetFpr(op.frs, 32));
|
||||
SetGpr(op.ra, addr);
|
||||
}
|
||||
|
||||
void PPUTranslator::STFD(ppu_opcode_t op)
|
||||
{
|
||||
WriteMemory(op.ra ? m_ir->CreateAdd(GetGpr(op.ra), m_ir->getInt64(op.simm16)) : m_ir->getInt64(op.simm16), GetFpr(op.frs));
|
||||
Value* imm = m_ir->getInt64(op.simm16);
|
||||
|
||||
if (m_rel && m_rel->type == 4)
|
||||
{
|
||||
imm = SExt(ReadMemory(GetAddr(+2), GetType<u16>()), GetType<u64>());
|
||||
m_rel = nullptr;
|
||||
}
|
||||
|
||||
WriteMemory(op.ra ? m_ir->CreateAdd(GetGpr(op.ra), imm) : imm, GetFpr(op.frs));
|
||||
}
|
||||
|
||||
void PPUTranslator::STFDU(ppu_opcode_t op)
|
||||
{
|
||||
const auto addr = m_ir->CreateAdd(GetGpr(op.ra), m_ir->getInt64(op.simm16));
|
||||
Value* imm = m_ir->getInt64(op.simm16);
|
||||
|
||||
if (m_rel && m_rel->type == 4)
|
||||
{
|
||||
imm = SExt(ReadMemory(GetAddr(+2), GetType<u16>()), GetType<u64>());
|
||||
m_rel = nullptr;
|
||||
}
|
||||
|
||||
const auto addr = m_ir->CreateAdd(GetGpr(op.ra), imm);
|
||||
WriteMemory(addr, GetFpr(op.frs));
|
||||
SetGpr(op.ra, addr);
|
||||
}
|
||||
|
||||
void PPUTranslator::LD(ppu_opcode_t op)
|
||||
{
|
||||
SetGpr(op.rd, ReadMemory(op.ra ? m_ir->CreateAdd(GetGpr(op.ra), m_ir->getInt64(op.ds << 2)) : m_ir->getInt64(op.ds << 2), GetType<u64>()));
|
||||
Value* imm = m_ir->getInt64(op.ds << 2);
|
||||
|
||||
if (m_rel && m_rel->type == 57)
|
||||
{
|
||||
imm = m_ir->CreateAnd(SExt(ReadMemory(GetAddr(+2), GetType<u16>()), GetType<u64>()), ~3);
|
||||
m_rel = nullptr;
|
||||
}
|
||||
|
||||
SetGpr(op.rd, ReadMemory(op.ra ? m_ir->CreateAdd(GetGpr(op.ra), imm) : imm, GetType<u64>()));
|
||||
}
|
||||
|
||||
void PPUTranslator::LDU(ppu_opcode_t op)
|
||||
{
|
||||
const auto addr = m_ir->CreateAdd(GetGpr(op.ra), m_ir->getInt64(op.ds << 2));
|
||||
Value* imm = m_ir->getInt64(op.ds << 2);
|
||||
|
||||
if (m_rel && m_rel->type == 57)
|
||||
{
|
||||
imm = m_ir->CreateAnd(SExt(ReadMemory(GetAddr(+2), GetType<u16>()), GetType<u64>()), ~3);
|
||||
m_rel = nullptr;
|
||||
}
|
||||
|
||||
const auto addr = m_ir->CreateAdd(GetGpr(op.ra), imm);
|
||||
SetGpr(op.rd, ReadMemory(addr, GetType<u64>()));
|
||||
SetGpr(op.ra, addr);
|
||||
}
|
||||
|
||||
void PPUTranslator::LWA(ppu_opcode_t op)
|
||||
{
|
||||
SetGpr(op.rd, SExt(ReadMemory(op.ra ? m_ir->CreateAdd(GetGpr(op.ra), m_ir->getInt64(op.ds << 2)) : m_ir->getInt64(op.ds << 2), GetType<s32>())));
|
||||
Value* imm = m_ir->getInt64(op.ds << 2);
|
||||
|
||||
if (m_rel && m_rel->type == 57)
|
||||
{
|
||||
imm = m_ir->CreateAnd(SExt(ReadMemory(GetAddr(+2), GetType<u16>()), GetType<u64>()), ~3);
|
||||
m_rel = nullptr;
|
||||
}
|
||||
|
||||
SetGpr(op.rd, SExt(ReadMemory(op.ra ? m_ir->CreateAdd(GetGpr(op.ra), imm) : imm, GetType<s32>())));
|
||||
}
|
||||
|
||||
void PPUTranslator::STD(ppu_opcode_t op)
|
||||
{
|
||||
WriteMemory(op.ra ? m_ir->CreateAdd(GetGpr(op.ra), m_ir->getInt64(op.ds << 2)) : m_ir->getInt64(op.ds << 2), GetGpr(op.rs));
|
||||
Value* imm = m_ir->getInt64(op.ds << 2);
|
||||
|
||||
if (m_rel && m_rel->type == 57)
|
||||
{
|
||||
imm = m_ir->CreateAnd(SExt(ReadMemory(GetAddr(+2), GetType<u16>()), GetType<u64>()), ~3);
|
||||
m_rel = nullptr;
|
||||
}
|
||||
|
||||
WriteMemory(op.ra ? m_ir->CreateAdd(GetGpr(op.ra), imm) : imm, GetGpr(op.rs));
|
||||
}
|
||||
|
||||
void PPUTranslator::STDU(ppu_opcode_t op)
|
||||
{
|
||||
const auto addr = m_ir->CreateAdd(GetGpr(op.ra), m_ir->getInt64(op.ds << 2));
|
||||
Value* imm = m_ir->getInt64(op.ds << 2);
|
||||
|
||||
if (m_rel && m_rel->type == 57)
|
||||
{
|
||||
imm = m_ir->CreateAnd(SExt(ReadMemory(GetAddr(+2), GetType<u16>()), GetType<u64>()), ~3);
|
||||
m_rel = nullptr;
|
||||
}
|
||||
|
||||
const auto addr = m_ir->CreateAdd(GetGpr(op.ra), imm);
|
||||
WriteMemory(addr, GetGpr(op.rs));
|
||||
SetGpr(op.ra, addr);
|
||||
}
|
||||
@ -3862,7 +4216,7 @@ void PPUTranslator::FCFID(ppu_opcode_t op)
|
||||
void PPUTranslator::UNK(ppu_opcode_t op)
|
||||
{
|
||||
FlushRegisters();
|
||||
Call(GetType<void>(), "__error", m_thread, m_ir->getInt64(m_current_addr), m_ir->getInt32(op.opcode))->setTailCallKind(llvm::CallInst::TCK_Tail);
|
||||
Call(GetType<void>(), "__error", m_thread, GetAddr(), m_ir->getInt32(op.opcode))->setTailCallKind(llvm::CallInst::TCK_Tail);
|
||||
m_ir->CreateRetVoid();
|
||||
}
|
||||
|
||||
@ -4123,9 +4477,9 @@ Value* PPUTranslator::CheckTrapCondition(u32 to, Value* left, Value* right)
|
||||
return trap_condition;
|
||||
}
|
||||
|
||||
void PPUTranslator::Trap(u64 addr)
|
||||
void PPUTranslator::Trap()
|
||||
{
|
||||
Call(GetType<void>(), "__trap", m_thread, m_ir->getInt64(m_current_addr))->setTailCallKind(llvm::CallInst::TCK_Tail);
|
||||
Call(GetType<void>(), "__trap", m_thread, GetAddr())->setTailCallKind(llvm::CallInst::TCK_Tail);
|
||||
m_ir->CreateRetVoid();
|
||||
}
|
||||
|
||||
|
@ -116,6 +116,9 @@ class PPUTranslator final //: public CPUTranslator
|
||||
// PPU Module
|
||||
const ppu_module& m_info;
|
||||
|
||||
// Relevant relocations
|
||||
std::map<u64, const ppu_reloc*> m_relocs;
|
||||
|
||||
// Attributes for function calls which are "pure" and may be optimized away if their results are unused
|
||||
const llvm::AttributeSet m_pure_attr;
|
||||
|
||||
@ -125,14 +128,23 @@ class PPUTranslator final //: public CPUTranslator
|
||||
// LLVM function
|
||||
llvm::Function* m_function;
|
||||
|
||||
// Function range
|
||||
u64 m_start_addr, m_end_addr, m_current_addr;
|
||||
|
||||
llvm::MDNode* m_md_unlikely;
|
||||
llvm::MDNode* m_md_likely;
|
||||
|
||||
// Current position-independent address
|
||||
u64 m_addr = 0;
|
||||
|
||||
// Relocation info
|
||||
const ppu_segment* m_reloc = nullptr;
|
||||
|
||||
// Set by instruction code after processing the relocation
|
||||
const ppu_reloc* m_rel = nullptr;
|
||||
|
||||
/* Variables */
|
||||
|
||||
// Segments
|
||||
std::vector<llvm::GlobalVariable*> m_segs;
|
||||
|
||||
// Memory base
|
||||
llvm::GlobalVariable* m_base;
|
||||
llvm::Value* m_base_loaded;
|
||||
@ -179,6 +191,9 @@ class PPUTranslator final //: public CPUTranslator
|
||||
#undef DEF_VALUE
|
||||
public:
|
||||
|
||||
// Get current instruction address
|
||||
llvm::Value* GetAddr(u64 _add = 0);
|
||||
|
||||
// Change integer size for integer or integer vector type (by 2^degree)
|
||||
llvm::Type* ScaleType(llvm::Type*, s32 pow2 = 0);
|
||||
|
||||
@ -346,8 +361,8 @@ public:
|
||||
// Check condition for trap instructions
|
||||
llvm::Value* CheckTrapCondition(u32 to, llvm::Value* left, llvm::Value* right);
|
||||
|
||||
// Emit trap
|
||||
void Trap(u64 addr);
|
||||
// Emit trap for current address
|
||||
void Trap();
|
||||
|
||||
// Get condition for branch instructions
|
||||
llvm::Value* CheckBranchCondition(u32 bo, u32 bi);
|
||||
|
@ -109,7 +109,7 @@ error_code prx_load_module(std::string path, u64 flags, vm::ptr<sys_prx_load_mod
|
||||
return CELL_PRX_ERROR_ILLEGAL_LIBRARY;
|
||||
}
|
||||
|
||||
const auto prx = ppu_load_prx(obj, path.substr(path.find_last_of('/') + 1));
|
||||
const auto prx = ppu_load_prx(obj, vfs::get(path));
|
||||
|
||||
if (!prx)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user