| | |
| | |
| | |
| |
|
| | #pragma once |
| |
|
| | #include "common/arch.h" |
| | #if CITRA_ARCH(x86_64) |
| |
|
| | #include <type_traits> |
| | #include <xbyak/xbyak.h> |
| | #include "common/x64/xbyak_abi.h" |
| |
|
| | namespace Common::X64 { |
| |
|
| | |
| | enum { |
| | CMP_EQ = 0, |
| | CMP_LT = 1, |
| | CMP_LE = 2, |
| | CMP_UNORD = 3, |
| | CMP_NEQ = 4, |
| | CMP_NLT = 5, |
| | CMP_NLE = 6, |
| | CMP_ORD = 7, |
| | }; |
| |
|
| | inline bool IsWithin2G(uintptr_t ref, uintptr_t target) { |
| | u64 distance = target - (ref + 5); |
| | return !(distance >= 0x8000'0000ULL && distance <= ~0x8000'0000ULL); |
| | } |
| |
|
| | inline bool IsWithin2G(const Xbyak::CodeGenerator& code, uintptr_t target) { |
| | return IsWithin2G(reinterpret_cast<uintptr_t>(code.getCurr()), target); |
| | } |
| |
|
| | template <typename T> |
| | inline void CallFarFunction(Xbyak::CodeGenerator& code, const T f) { |
| | static_assert(std::is_pointer_v<T>, "Argument must be a (function) pointer."); |
| | std::size_t addr = reinterpret_cast<std::size_t>(f); |
| | if (IsWithin2G(code, addr)) { |
| | code.call(f); |
| | } else { |
| | |
| | code.mov(ABI_RETURN, addr); |
| | code.call(ABI_RETURN); |
| | } |
| | } |
| |
|
| | } |
| |
|
| | #endif |
| |
|