Skip to content
This repository has been archived by the owner on Mar 5, 2024. It is now read-only.

Commit

Permalink
oaknut: Fix page boundary error in ADP
Browse files Browse the repository at this point in the history
  • Loading branch information
merryhime committed Nov 17, 2023
1 parent d0ca9a2 commit d8634ea
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 6 deletions.
2 changes: 1 addition & 1 deletion include/oaknut/impl/offset.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ struct PageOffset {

static std::uint32_t encode(std::uintptr_t current_addr, std::uintptr_t target)
{
std::uint64_t diff = static_cast<std::uint64_t>((static_cast<std::int64_t>(target - current_addr) >> shift_amount));
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));
if (detail::sign_extend<bitsize>(diff) != diff)
throw OaknutException{ExceptionType::OffsetOutOfRange};
diff &= detail::mask_from_size(bitsize);
Expand Down
42 changes: 37 additions & 5 deletions tests/basic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -138,11 +138,19 @@ TEST_CASE("ADR", "[slow]")
}
}

TEST_CASE("PageOffset")
TEST_CASE("PageOffset (rollover)")
{
REQUIRE(PageOffset<21, 12>::encode(0x0000000088e74000, 0xffffffffd167dece) == 0xd2202);
}

TEST_CASE("PageOffset (page boundary)")
{
REQUIRE(PageOffset<21, 12>::encode(0x0001000000000002, 0x0001000000000001) == 0);
REQUIRE(PageOffset<21, 12>::encode(0x0001000000000001, 0x0001000000000002) == 0);
REQUIRE(PageOffset<21, 12>::encode(0x0001000000001000, 0x0001000000000fff) == 0x1fffff);
REQUIRE(PageOffset<21, 12>::encode(0x0001000000000fff, 0x0001000000001000) == 0x080000);
}

TEST_CASE("ADRP", "[slow]")
{
CodeBlock mem{4096};
Expand All @@ -166,15 +174,39 @@ TEST_CASE("ADRP", "[slow]")
}
}

TEST_CASE("ADRL", "[slow]")
TEST_CASE("ADRL (near)")
{
CodeBlock mem{4096};
std::uint32_t* const mem_ptr = mem.ptr() + 42; // create small offset for testing

for (int i = -0x4000; i < 0x4000; i++) {
const std::int64_t diff = i;
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.ADRL(X0, reinterpret_cast<void*>(value));
code.RET();
mem.protect();
mem.invalidate_all();

INFO(i);
REQUIRE(f() == static_cast<std::uint64_t>(value));
}
}

TEST_CASE("ADRL (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>(-4294967296, 4294967295);
const std::intptr_t value = reinterpret_cast<std::intptr_t>(mem.ptr()) + diff;
const std::int64_t diff = RandInt<std::int64_t>(-4294967296 + 100, 4294967295 - 100);
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();
Expand Down

0 comments on commit d8634ea

Please sign in to comment.