mirror of
https://github.com/RPCS3/rpcs3.git
synced 2024-12-27 06:21:02 +00:00
Make it work with LLVM
Allow multiple entries for a single code.
This commit is contained in:
parent
f572e29a13
commit
7df093c94b
@ -703,8 +703,6 @@ static usz apply_modification(std::basic_string<u32>& applied, const patch_engin
|
||||
}
|
||||
case patch_type::code_alloc:
|
||||
{
|
||||
relocate_instructions_at = 0;
|
||||
|
||||
const u32 out_branch = vm::try_get_addr(dst + (offset & -4)).first;
|
||||
|
||||
// Allow only if points to a PPU executable instruction
|
||||
@ -715,6 +713,13 @@ static usz apply_modification(std::basic_string<u32>& applied, const patch_engin
|
||||
|
||||
const u32 alloc_size = utils::align(static_cast<u32>(p.value.long_value + 1) * 4, 0x10000);
|
||||
|
||||
// Check if should maybe reuse previous code cave allocation (0 size)
|
||||
if (alloc_size - 4 != 0)
|
||||
{
|
||||
// Nope
|
||||
relocate_instructions_at = 0;
|
||||
}
|
||||
|
||||
// Always executable
|
||||
u64 flags = vm::alloc_executable | vm::alloc_unwritable;
|
||||
|
||||
@ -738,7 +743,7 @@ static usz apply_modification(std::basic_string<u32>& applied, const patch_engin
|
||||
|
||||
// Range allowed for absolute branches to operate at
|
||||
// It takes into account that we need to put a branch for return at the end of memory space
|
||||
const u32 addr = p.alloc_addr = alloc_map->alloc(alloc_size, nullptr, 0x10000, flags);
|
||||
const u32 addr = p.alloc_addr = (relocate_instructions_at ? relocate_instructions_at : alloc_map->alloc(alloc_size, nullptr, 0x10000, flags));
|
||||
|
||||
if (!addr)
|
||||
{
|
||||
@ -751,8 +756,12 @@ static usz apply_modification(std::basic_string<u32>& applied, const patch_engin
|
||||
// NOP filled
|
||||
std::fill_n(vm::get_super_ptr<u32>(addr), p.value.long_value, 0x60000000);
|
||||
|
||||
// Register code
|
||||
ppu_register_range(addr, alloc_size);
|
||||
// Check if already registered by previous code allocation
|
||||
if (relocate_instructions_at != addr)
|
||||
{
|
||||
// Register code
|
||||
ppu_register_range(addr, alloc_size);
|
||||
}
|
||||
|
||||
resval = out_branch & -4;
|
||||
|
||||
@ -772,8 +781,6 @@ static usz apply_modification(std::basic_string<u32>& applied, const patch_engin
|
||||
continue;
|
||||
}
|
||||
|
||||
// Write address of the allocated memory to the code entry
|
||||
*vm::get_super_ptr<u32>(resval) = addr;
|
||||
relocate_instructions_at = addr;
|
||||
break;
|
||||
}
|
||||
|
@ -617,34 +617,20 @@ struct ppu_far_jumps_t
|
||||
bool with_toc;
|
||||
std::string module_name;
|
||||
ppu_intrp_func_t func;
|
||||
};
|
||||
|
||||
ppu_far_jumps_t(int) noexcept {}
|
||||
|
||||
std::unordered_map<u32, all_info_t> vals;
|
||||
::jit_runtime rt;
|
||||
|
||||
mutable shared_mutex mutex;
|
||||
|
||||
// Get target address, 'ppu' is used in ppu_far_jump in order to modify registers
|
||||
u32 get_target(const u32 pc, ppu_thread* ppu = nullptr)
|
||||
{
|
||||
reader_lock lock(mutex);
|
||||
|
||||
if (auto it = vals.find(pc); it != vals.end())
|
||||
|
||||
u32 get_target(u32 pc, ppu_thread* ppu = nullptr) const
|
||||
{
|
||||
all_info_t& all_info = it->second;
|
||||
u32 target = all_info.target;
|
||||
u32 direct_target = this->target;
|
||||
|
||||
bool link = all_info.link;
|
||||
bool from_opd = all_info.with_toc;
|
||||
bool to_link = this->link;
|
||||
bool from_opd = this->with_toc;
|
||||
|
||||
if (!all_info.module_name.empty())
|
||||
if (!this->module_name.empty())
|
||||
{
|
||||
target = ppu_get_exported_func_addr(target, all_info.module_name);
|
||||
direct_target = ppu_get_exported_func_addr(direct_target, this->module_name);
|
||||
}
|
||||
|
||||
if (from_opd && !vm::check_addr<sizeof(ppu_func_opd_t)>(target))
|
||||
if (from_opd && !vm::check_addr<sizeof(ppu_func_opd_t)>(direct_target))
|
||||
{
|
||||
// Avoid reading unmapped memory under mutex
|
||||
from_opd = false;
|
||||
@ -652,11 +638,11 @@ struct ppu_far_jumps_t
|
||||
|
||||
if (from_opd)
|
||||
{
|
||||
auto& opd = vm::_ref<ppu_func_opd_t>(target);
|
||||
target = opd.addr;
|
||||
auto& opd = vm::_ref<ppu_func_opd_t>(direct_target);
|
||||
direct_target = opd.addr;
|
||||
|
||||
// We modify LR to custom values here
|
||||
link = false;
|
||||
to_link = false;
|
||||
|
||||
if (ppu)
|
||||
{
|
||||
@ -670,20 +656,71 @@ struct ppu_far_jumps_t
|
||||
saved_info.saved_lr = std::exchange(ppu->lr, g_fxo->get<ppu_function_manager>().func_addr(FIND_FUNC(ppu_return_from_far_jump), true));
|
||||
saved_info.saved_r2 = std::exchange(ppu->gpr[2], opd.rtoc);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (link && ppu)
|
||||
if (to_link && ppu)
|
||||
{
|
||||
ppu->lr = pc + 4;
|
||||
}
|
||||
|
||||
return target;
|
||||
return direct_target;
|
||||
}
|
||||
};
|
||||
|
||||
ppu_far_jumps_t(int) noexcept {}
|
||||
|
||||
std::map<u32, all_info_t> vals;
|
||||
::jit_runtime rt;
|
||||
|
||||
mutable shared_mutex mutex;
|
||||
|
||||
// Get target address, 'ppu' is used in ppu_far_jump in order to modify registers
|
||||
u32 get_target(u32 pc, ppu_thread* ppu = nullptr)
|
||||
{
|
||||
reader_lock lock(mutex);
|
||||
|
||||
if (auto it = vals.find(pc); it != vals.end())
|
||||
{
|
||||
all_info_t& all_info = it->second;
|
||||
return all_info.get_target(pc, ppu);
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
// Get function patches in range (entry -> target)
|
||||
std::vector<std::pair<u32, u32>> get_targets(u32 pc, u32 size)
|
||||
{
|
||||
std::vector<std::pair<u32, u32>> targets;
|
||||
|
||||
reader_lock lock(mutex);
|
||||
|
||||
auto it = vals.lower_bound(pc);
|
||||
|
||||
if (it == vals.end())
|
||||
{
|
||||
return targets;
|
||||
}
|
||||
|
||||
if (it->first >= pc + size)
|
||||
{
|
||||
return targets;
|
||||
}
|
||||
|
||||
for (auto end = vals.lower_bound(pc + size); it != end; it++)
|
||||
{
|
||||
all_info_t& all_info = it->second;
|
||||
|
||||
if (u32 target = all_info.get_target(it->first))
|
||||
{
|
||||
targets.emplace_back(it->first, target);
|
||||
}
|
||||
}
|
||||
|
||||
return targets;
|
||||
}
|
||||
|
||||
// Generate a mini-function which updates PC (for LLVM) and jumps to ppu_far_jump to handle redirections
|
||||
template <bool Locked = true>
|
||||
ppu_intrp_func_t gen_jump(u32 pc)
|
||||
{
|
||||
@ -1019,7 +1056,7 @@ void ppu_thread::dump_regs(std::string& ret) const
|
||||
|
||||
if (const_value != reg)
|
||||
{
|
||||
// Expectation of pretictable code path has not been met (such as a branch directly to the instruction)
|
||||
// Expectation of predictable code path has not been met (such as a branch directly to the instruction)
|
||||
is_const = false;
|
||||
}
|
||||
|
||||
@ -3478,14 +3515,25 @@ bool ppu_initialize(const ppu_module& info, bool check_only)
|
||||
}
|
||||
}
|
||||
|
||||
if (jit)
|
||||
if (g_fxo->is_init<ppu_far_jumps_t>())
|
||||
{
|
||||
const auto far_jump = ppu_get_far_jump(func.addr) ? g_fxo->get<ppu_far_jumps_t>().gen_jump(func.addr) : nullptr;
|
||||
auto targets = g_fxo->get<ppu_far_jumps_t>().get_targets(func.addr, func.size);
|
||||
|
||||
if (far_jump)
|
||||
for (auto [source, target] : targets)
|
||||
{
|
||||
auto far_jump = ensure(g_fxo->get<ppu_far_jumps_t>().gen_jump(source));
|
||||
|
||||
if (source == func.addr && jit)
|
||||
{
|
||||
jit->update_global_mapping(fmt::format("__0x%x", func.addr - reloc), reinterpret_cast<u64>(far_jump));
|
||||
}
|
||||
|
||||
ppu_register_function_at(source, 4, far_jump);
|
||||
}
|
||||
|
||||
if (!targets.empty())
|
||||
{
|
||||
// Replace the function with ppu_far_jump
|
||||
jit->update_global_mapping(fmt::format("__0x%x", func.addr - reloc), reinterpret_cast<u64>(far_jump));
|
||||
fpos++;
|
||||
continue;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user