| | |
| | |
| | |
| |
|
| | #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 |
| |
|