mirror of
https://github.com/yuzu-mirror/oaknut.git
synced 2026-01-31 19:24:13 +01:00
oaknut: Fix edgecases in MOVP2R on +/-4GiB boundary
This commit is contained in:
parent
d8634eaa1f
commit
316d8869e8
|
|
@ -85,6 +85,12 @@ struct PageOffset {
|
|||
return static_cast<std::uint32_t>(((diff & 3) << (bitsize - 2)) | (diff >> 2));
|
||||
}
|
||||
|
||||
static bool valid(std::uintptr_t current_addr, std::uintptr_t target)
|
||||
{
|
||||
std::uint64_t diff = static_cast<std::uint64_t>((static_cast<std::int64_t>(target) >> shift_amount) - (static_cast<std::int64_t>(current_addr) >> shift_amount));
|
||||
return detail::sign_extend<bitsize>(diff) == diff;
|
||||
}
|
||||
|
||||
private:
|
||||
template<typename Policy>
|
||||
friend class BasicCodeGenerator;
|
||||
|
|
|
|||
|
|
@ -161,10 +161,10 @@ public:
|
|||
void MOVP2R(XReg xd, const void* addr)
|
||||
{
|
||||
if constexpr (Policy::has_absolute_addresses) {
|
||||
int64_t diff = reinterpret_cast<uint64_t>(addr) - Policy::current_address();
|
||||
const int64_t diff = reinterpret_cast<std::uint64_t>(addr) - Policy::current_address();
|
||||
if (diff >= -0xF'FFFF && diff <= 0xF'FFFF) {
|
||||
ADR(xd, addr);
|
||||
} else if (diff >= -int64_t{0xFFFF'FFFF} && diff <= int64_t{0xFFFF'FFFF}) {
|
||||
} else if (PageOffset<21, 12>::valid(Policy::current_address(), reinterpret_cast<std::uintptr_t>(addr))) {
|
||||
ADRL(xd, addr);
|
||||
} else {
|
||||
MOV(xd, reinterpret_cast<uint64_t>(addr));
|
||||
|
|
|
|||
|
|
@ -220,16 +220,17 @@ TEST_CASE("ADRL (far)", "[slow]")
|
|||
}
|
||||
}
|
||||
|
||||
TEST_CASE("MOVP2R", "[slow]")
|
||||
TEST_CASE("MOVP2R (far)", "[slow]")
|
||||
{
|
||||
CodeBlock mem{4096};
|
||||
std::uint32_t* const mem_ptr = mem.ptr() + 42; // create small offset for testing
|
||||
|
||||
for (int i = 0; i < 0x200000; i++) {
|
||||
const std::int64_t diff = RandInt<std::int64_t>(std::numeric_limits<std::int64_t>::min(),
|
||||
std::numeric_limits<std::int64_t>::max());
|
||||
const std::intptr_t value = reinterpret_cast<std::intptr_t>(mem.ptr()) + diff;
|
||||
const std::intptr_t value = reinterpret_cast<std::intptr_t>(mem_ptr) + diff;
|
||||
|
||||
CodeGenerator code{mem.ptr()};
|
||||
CodeGenerator code{mem_ptr};
|
||||
|
||||
auto f = code.ptr<std::uint64_t (*)()>();
|
||||
mem.unprotect();
|
||||
|
|
@ -241,3 +242,28 @@ TEST_CASE("MOVP2R", "[slow]")
|
|||
REQUIRE(f() == static_cast<std::uint64_t>(value));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("MOVP2R (4GiB boundary)")
|
||||
{
|
||||
CodeBlock mem{4096};
|
||||
std::uint32_t* const mem_ptr = mem.ptr() + 42; // create small offset for testing
|
||||
|
||||
for (std::int64_t i = 0xFFFF'F000; i < 0x1'0000'1000; i++) {
|
||||
const auto test = [&](std::int64_t diff) {
|
||||
const std::intptr_t value = reinterpret_cast<std::intptr_t>(mem_ptr) + diff;
|
||||
|
||||
CodeGenerator code{mem_ptr};
|
||||
|
||||
auto f = code.ptr<std::uint64_t (*)()>();
|
||||
mem.unprotect();
|
||||
code.MOVP2R(X0, reinterpret_cast<void*>(value));
|
||||
code.RET();
|
||||
mem.protect();
|
||||
mem.invalidate_all();
|
||||
|
||||
REQUIRE(f() == static_cast<std::uint64_t>(value));
|
||||
};
|
||||
test(i);
|
||||
test(-i);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue