| |
| |
| |
|
|
| #pragma once |
|
|
| #include "common/arch.h" |
| #if CITRA_ARCH(arm64) |
|
|
| #include <type_traits> |
| #include <oaknut/oaknut.hpp> |
| #include "common/aarch64/oaknut_abi.h" |
|
|
| namespace Common::A64 { |
|
|
| |
| inline bool IsWithin128M(uintptr_t ref, uintptr_t target) { |
| const u64 distance = target - (ref + 4); |
| return !(distance >= 0x800'0000ULL && distance <= ~0x800'0000ULL); |
| } |
|
|
| inline bool IsWithin128M(const oaknut::CodeGenerator& code, uintptr_t target) { |
| return IsWithin128M(code.xptr<uintptr_t>(), target); |
| } |
|
|
| template <typename T> |
| inline void CallFarFunction(oaknut::CodeGenerator& code, const T f) { |
| static_assert(std::is_pointer_v<T>, "Argument must be a (function) pointer."); |
| const std::uintptr_t addr = reinterpret_cast<std::uintptr_t>(f); |
| if (IsWithin128M(code, addr)) { |
| code.BL(reinterpret_cast<const void*>(f)); |
| } else { |
| |
| |
| |
| code.MOVP2R(oaknut::util::X16, reinterpret_cast<const void*>(f)); |
| code.BLR(oaknut::util::X16); |
| } |
| } |
|
|
| } |
|
|
| #endif |
|
|