mirror of
https://github.com/RPCS3/rpcs3.git
synced 2024-11-21 10:12:32 +01:00
aarch64: Support calloc patch blocks
This commit is contained in:
parent
4d193ecb6a
commit
c80342e8d4
@ -1,7 +1,9 @@
|
||||
#include "bin_patch.h"
|
||||
#include "ppu_patch.h"
|
||||
#include "File.h"
|
||||
#include "Config.h"
|
||||
#include "version.h"
|
||||
#include "Emu/IdManager.h"
|
||||
#include "Emu/Memory/vm.h"
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/VFS.h"
|
||||
@ -896,10 +898,6 @@ void patch_engine::append_title_patches(std::string_view title_id)
|
||||
load(m_map, fmt::format("%s%s_patch.yml", get_patches_path(), title_id));
|
||||
}
|
||||
|
||||
void ppu_register_range(u32 addr, u32 size);
|
||||
bool ppu_form_branch_to_code(u32 entry, u32 target, bool link = false, bool with_toc = false, std::string module_name = {});
|
||||
u32 ppu_generate_id(std::string_view name);
|
||||
|
||||
void unmap_vm_area(std::shared_ptr<vm::block_t>& ptr)
|
||||
{
|
||||
if (ptr && ptr->flags & (1ull << 62))
|
||||
@ -1216,6 +1214,10 @@ static usz apply_modification(std::basic_string<u32>& applied, patch_engine::pat
|
||||
continue;
|
||||
}
|
||||
|
||||
// Record the insertion point as a faux block.
|
||||
g_fxo->need<ppu_patch_block_registry_t>();
|
||||
g_fxo->get<ppu_patch_block_registry_t>().block_addresses.insert(resval);
|
||||
|
||||
relocate_instructions_at = addr;
|
||||
break;
|
||||
}
|
||||
|
20
Utilities/ppu_patch.h
Normal file
20
Utilities/ppu_patch.h
Normal file
@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#include <util/types.hpp>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
// Patch utilities specific to PPU code
|
||||
struct ppu_patch_block_registry_t
|
||||
{
|
||||
ppu_patch_block_registry_t() = default;
|
||||
ppu_patch_block_registry_t(const ppu_patch_block_registry_t&) = delete;
|
||||
ppu_patch_block_registry_t& operator=(const ppu_patch_block_registry_t&) = delete;
|
||||
|
||||
std::unordered_set<u32> block_addresses{};
|
||||
};
|
||||
|
||||
void ppu_register_range(u32 addr, u32 size);
|
||||
bool ppu_form_branch_to_code(u32 entry, u32 target, bool link = false, bool with_toc = false, std::string module_name = {});
|
||||
u32 ppu_generate_id(std::string_view name);
|
@ -1,6 +1,5 @@
|
||||
#include "stdafx.h"
|
||||
|
||||
|
||||
#include "AArch64JIT.h"
|
||||
#include "AArch64ASM.h"
|
||||
|
||||
@ -415,9 +414,9 @@ namespace aarch64
|
||||
ensure(llvm::isa<llvm::ReturnInst>(where));
|
||||
irb->SetInsertPoint(llvm::dyn_cast<llvm::Instruction>(where));
|
||||
|
||||
if (instruction_info.callee_is_GHC && // Calls to C++ ABI will always return
|
||||
!instruction_info.is_indirect && // We don't know enough when calling indirectly to know if we'll return or not
|
||||
instruction_info.callee_name.find("-pp-") == umax) // Skip branch patch-points as those are just indirect calls. TODO: Move this to instruction decode.
|
||||
if (instruction_info.callee_is_GHC && // Calls to C++ ABI will always return
|
||||
!instruction_info.is_indirect && // We don't know enough when calling indirectly to know if we'll return or not
|
||||
!is_faux_function(instruction_info.callee_name)) // Ignore branch patch-points and imposter functions. Their behavior is unreliable.
|
||||
{
|
||||
// We're making a one-way call. This branch shouldn't even bother linking as it will never return here.
|
||||
ASMBlock c;
|
||||
@ -487,6 +486,24 @@ namespace aarch64
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GHC_frame_preservation_pass::is_faux_function(const std::string& function_name)
|
||||
{
|
||||
// Is it a branch patch-point?
|
||||
if (function_name.find("-pp-") != umax)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Now we search the known imposters list
|
||||
if (m_config.faux_function_list.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto& x = m_config.faux_function_list;
|
||||
return std::find(x.begin(), x.end(), function_name) != x.end();
|
||||
}
|
||||
|
||||
void GHC_frame_preservation_pass::process_leaf_function(llvm::IRBuilder<>* irb, llvm::Function& f)
|
||||
{
|
||||
for (auto &bb : f)
|
||||
|
@ -41,12 +41,13 @@ namespace aarch64
|
||||
|
||||
struct config_t
|
||||
{
|
||||
bool debug_info = false; // Record debug information
|
||||
bool use_stack_frames = true; // Allocate a stack frame for each function. The gateway can alternatively manage a global stack to use as scratch.
|
||||
bool optimize = true; // Optimize instructions when possible. Set to false when debugging.
|
||||
bool debug_info = false; // Record debug information
|
||||
bool use_stack_frames = true; // Allocate a stack frame for each function. The gateway can alternatively manage a global stack to use as scratch.
|
||||
bool optimize = true; // Optimize instructions when possible. Set to false when debugging.
|
||||
u32 hypervisor_context_offset = 0; // Offset within the "thread" object where we can find the hypervisor context (registers configured at gateway).
|
||||
std::function<bool(const std::string&)> exclusion_callback; // [Optional] Callback run on each function before transform. Return "true" to exclude from frame processing.
|
||||
std::vector<std::pair<std::string, gpr>> base_register_lookup; // [Optional] Function lookup table to determine the location of the "thread" context.
|
||||
std::vector<std::string> faux_function_list; // [Optional] List of faux block names to treat as untrusted - typically fake functions representing codecaves.
|
||||
};
|
||||
|
||||
protected:
|
||||
@ -64,6 +65,8 @@ namespace aarch64
|
||||
|
||||
bool is_inlined_call(const llvm::CallInst* ci);
|
||||
|
||||
bool is_faux_function(const std::string& function_name);
|
||||
|
||||
gpr get_base_register_for_call(const std::string& callee_name, gpr default_reg = gpr::x19);
|
||||
|
||||
void process_leaf_function(llvm::IRBuilder<>* irb, llvm::Function& f);
|
||||
|
@ -18,6 +18,8 @@
|
||||
|
||||
#ifdef ARCH_ARM64
|
||||
#include "Emu/CPU/Backends/AArch64/AArch64JIT.h"
|
||||
#include "Emu/IdManager.h"
|
||||
#include "Utilities/ppu_patch.h"
|
||||
#endif
|
||||
|
||||
using namespace llvm;
|
||||
@ -48,13 +50,22 @@ PPUTranslator::PPUTranslator(LLVMContext& context, Module* _module, const ppu_mo
|
||||
{ "__", aarch64::x19 } // Probably link table entries
|
||||
};
|
||||
|
||||
// Build list of imposter functions built by the patch manager.
|
||||
g_fxo->need<ppu_patch_block_registry_t>();
|
||||
std::vector<std::string> faux_functions_list;
|
||||
for (const auto& a : g_fxo->get<ppu_patch_block_registry_t>().block_addresses)
|
||||
{
|
||||
faux_functions_list.push_back(fmt::format("__0x%x", a));
|
||||
}
|
||||
|
||||
aarch64::GHC_frame_preservation_pass::config_t config =
|
||||
{
|
||||
.debug_info = false, // Set to "true" to insert debug frames on x27
|
||||
.use_stack_frames = false, // We don't need this since the PPU GW allocates global scratch on the stack
|
||||
.hypervisor_context_offset = ::offset32(&ppu_thread::hv_ctx),
|
||||
.exclusion_callback = {}, // Unused, we don't have special exclusion functions on PPU
|
||||
.base_register_lookup = base_reg_lookup
|
||||
.base_register_lookup = base_reg_lookup,
|
||||
.faux_function_list = std::move(faux_functions_list)
|
||||
};
|
||||
|
||||
// Create transform pass
|
||||
|
Loading…
Reference in New Issue
Block a user