mirror of
https://github.com/geode-sdk/geode.git
synced 2024-12-02 12:17:10 -05:00
125 lines
3.9 KiB
C++
125 lines
3.9 KiB
C++
#include "platform_macro.h"
|
|
#if defined(TARGET_ARCH_ARM64)
|
|
|
|
#include "dobby_internal.h"
|
|
|
|
#include "core/modules/assembler/assembler-arm64.h"
|
|
#include "core/modules/codegen/codegen-arm64.h"
|
|
|
|
#include "InstructionRelocation/arm64/ARM64InstructionRelocation.h"
|
|
|
|
#include "MemoryAllocator/NearMemoryArena.h"
|
|
#include "InterceptRouting/RoutingPlugin/RoutingPlugin.h"
|
|
|
|
using namespace zz::arm64;
|
|
|
|
CodeBufferBase *GenerateNormalTrampolineBuffer(addr_t from, addr_t to) {
|
|
TurboAssembler turbo_assembler_((void *)from);
|
|
#define _ turbo_assembler_.
|
|
|
|
uint64_t distance = llabs((int64_t)(from - to));
|
|
uint64_t adrp_range = ((uint64_t)1 << (2 + 19 + 12 - 1));
|
|
if (distance < adrp_range) {
|
|
// adrp, add, br
|
|
_ AdrpAdd(TMP_REG_0, from, to);
|
|
_ br(TMP_REG_0);
|
|
DLOG(0, "Trampoline use [Adrp, Add, Br] combine");
|
|
} else {
|
|
// ldr, br, branch-address
|
|
CodeGen codegen(&turbo_assembler_);
|
|
codegen.LiteralLdrBranch((uint64_t)to);
|
|
DLOG(0, "Trampoline use [Ldr, Br, Label] combine");
|
|
}
|
|
|
|
CodeBufferBase *result = NULL;
|
|
result = turbo_assembler_.GetCodeBuffer()->Copy();
|
|
return result;
|
|
}
|
|
|
|
#define ARM64_B_XXX_RANGE ((1 << 25) << 2) // signed
|
|
|
|
// If BranchType is B_Branch and the branch_range of `B` is not enough, build the transfer to forward the b branch, if
|
|
static AssemblyCodeChunk *GenerateFastForwardTrampoline(addr_t source_address, addr_t target_address) {
|
|
AssemblyCodeChunk *cchunk = NULL;
|
|
|
|
TurboAssembler turbo_assembler_(0);
|
|
|
|
// Use adrp + add branch
|
|
cchunk = NearMemoryArena::AllocateCodeChunk((addr_t)source_address, ARM64_B_XXX_RANGE, 3 * 4);
|
|
if (cchunk == nullptr) {
|
|
ERROR_LOG("Can't found near code chunk");
|
|
return NULL;
|
|
}
|
|
|
|
// Use adrp + add branch
|
|
uint64_t distance = llabs((int64_t)((addr_t)cchunk->address - target_address));
|
|
uint64_t adrp_range = ((uint64_t)1 << (2 + 19 + 12 - 1));
|
|
if (distance < adrp_range) { // Use adrp + add branch == (3 * 4) trampoline size
|
|
_ AdrpAdd(TMP_REG_0, (addr_t)cchunk->address, target_address);
|
|
_ br(TMP_REG_0);
|
|
DLOG(0, "Forward Trampoline use [Adrp, Add, Br] combine");
|
|
} else {
|
|
delete cchunk;
|
|
cchunk = NULL;
|
|
}
|
|
|
|
// Use absolute branch
|
|
if (cchunk == NULL) {
|
|
#if 0
|
|
// Use literal ldr == (4 * 4) trampoline size
|
|
CodeGen codegen(&turbo_assembler_);
|
|
// forward trampoline => target address
|
|
codegen.LiteralLdrBranch(target_address);
|
|
DLOG(0, "Forward Trampoline use [Ldr, Br, Label] combine");
|
|
#else
|
|
// Use mov + br == (4 * 5) trampoline size
|
|
#define _ turbo_assembler_.
|
|
_ Mov(TMP_REG_0, target_address);
|
|
_ br(TMP_REG_0);
|
|
DLOG(0, "Forward Trampoline use [Mov, Br] combine");
|
|
#endif
|
|
|
|
size_t tramp_size = turbo_assembler_.GetCodeBuffer()->getSize();
|
|
cchunk = NearMemoryArena::AllocateCodeChunk((addr_t)source_address, ARM64_B_XXX_RANGE, tramp_size);
|
|
if (cchunk == nullptr) {
|
|
ERROR_LOG("Can't found near code chunk");
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
turbo_assembler_.SetRealizedAddress(cchunk->address);
|
|
|
|
AssemblyCodeChunk *result = NULL;
|
|
result = AssemblyCodeBuilder::FinalizeFromTurboAssembler(&turbo_assembler_);
|
|
|
|
{ // release
|
|
delete cchunk;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
CodeBufferBase *GenerateNearTrampolineBuffer(InterceptRouting *routing, addr_t src, addr_t dst) {
|
|
CodeBufferBase *result = NULL;
|
|
|
|
TurboAssembler turbo_assembler_((void *)src);
|
|
#define _ turbo_assembler_.
|
|
|
|
// branch to trampoline_target directly
|
|
if (llabs((long long)dst - (long long)src) < ARM64_B_XXX_RANGE) {
|
|
_ b(dst - src);
|
|
} else {
|
|
AssemblyCodeChunk *fast_forward_trampoline = NULL;
|
|
fast_forward_trampoline = GenerateFastForwardTrampoline(src, dst);
|
|
if (!fast_forward_trampoline)
|
|
return NULL;
|
|
// trampoline => fast_forward_trampoline
|
|
addr_t fast_forward_trampoline_addr = fast_forward_trampoline->raw_instruction_start();
|
|
_ b(fast_forward_trampoline_addr - src);
|
|
}
|
|
|
|
// free the original trampoline
|
|
result = turbo_assembler_.GetCodeBuffer()->Copy();
|
|
return result;
|
|
}
|
|
|
|
#endif
|