From 409f53eaed31b12761b58c158d4a75e69389c1f9 Mon Sep 17 00:00:00 2001 From: ethan Date: Sun, 11 Oct 2026 15:24:53 -0700 Subject: [PATCH] fix(relinker): filter non-reference RIP-relative FF operations --- core/relinker/CMakeLists.txt | 12 ++++++ .../src/analysis/CallSiteResolver.cpp | 3 +- .../relinker/tests/CallSiteResolverTests.cpp | 41 +++++++++++++++++++ 3 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 core/relinker/relinker/tests/CallSiteResolverTests.cpp diff --git a/core/relinker/CMakeLists.txt b/core/relinker/CMakeLists.txt index 095915729..ce383621e 100644 --- a/core/relinker/CMakeLists.txt +++ b/core/relinker/CMakeLists.txt @@ -303,6 +303,18 @@ if(BUILD_TESTING) ${CMAKE_CURRENT_SOURCE_DIR}/io/include ) add_test(NAME amd64_only_converter COMMAND amd64_only_converter_tests) + add_test_executable(call_site_resolver_tests + ${CMAKE_CURRENT_SOURCE_DIR}/relinker/tests/CallSiteResolverTests.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/relinker/src/analysis/CallSiteResolver.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/codegen/src/InstructionScanner.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/codegen/src/x86/X64InstructionDecoder.cpp + ) + target_include_directories(call_site_resolver_tests PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/domain/include + ${CMAKE_CURRENT_SOURCE_DIR}/relinker/include + ${CMAKE_CURRENT_SOURCE_DIR}/codegen/include + ) + add_test(NAME call_site_resolver COMMAND call_site_resolver_tests) add_test_executable(decoder_length_tests ${CMAKE_CURRENT_SOURCE_DIR}/codegen/tests/DecoderLengthTests.cpp ${CMAKE_CURRENT_SOURCE_DIR}/codegen/src/x86/X64InstructionDecoder.cpp diff --git a/core/relinker/relinker/src/analysis/CallSiteResolver.cpp b/core/relinker/relinker/src/analysis/CallSiteResolver.cpp index 6f08ab26f..5dafdf912 100644 --- a/core/relinker/relinker/src/analysis/CallSiteResolver.cpp +++ b/core/relinker/relinker/src/analysis/CallSiteResolver.cpp @@ -27,7 +27,8 @@ bool isRipRelativeFF(const std::vector& text, const Codegen::Instr std::uint8_t modrm = text[cur + 1]; std::uint8_t mod = (modrm >> ModRmModShift) & ModRmModMask; std::uint8_t rm = modrm & ModRmRmMask; - return mod == ModRmModIndirect && rm == ModRmRmRipRelative; + const auto operation = (modrm >> ModRmRegShift) & ModRmRegMask; + return mod == ModRmModIndirect && rm == ModRmRmRipRelative && (operation >= 2 && operation <= 6); } break; } diff --git a/core/relinker/relinker/tests/CallSiteResolverTests.cpp b/core/relinker/relinker/tests/CallSiteResolverTests.cpp new file mode 100644 index 000000000..f780307eb --- /dev/null +++ b/core/relinker/relinker/tests/CallSiteResolverTests.cpp @@ -0,0 +1,41 @@ +#include +#include +#include +#include +#include +#include +#include + +namespace { + +void require(bool condition, const std::string& name) { + if (!condition) throw std::runtime_error(name); +} + +void check(const std::string& name, std::initializer_list instruction, bool expected) { + auto resolver = Relinker::MakeCallSiteResolver(); + const std::vector text(instruction); + const auto sites = resolver->ResolveCallSites(text, 0x1000, 0x1100, 8); + require(sites == (expected ? std::vector{0x1000} : std::vector{}), name); + require(resolver->ResolveCallSites(text, 0x1000, 0x1200, 8).empty(), name + " unexpected address"); +} + +} + +int main() { + try { + check("indirect call", {0xff, 0x15, 0xfa, 0, 0, 0}, true); + check("indirect tail jump", {0xff, 0x25, 0xfa, 0, 0, 0}, true); + check("far indirect call", {0xff, 0x1d, 0xfa, 0, 0, 0}, true); + check("far indirect jump", {0xff, 0x2d, 0xfa, 0, 0, 0}, true); + check("RIP-relative function pointer load", {0x48, 0x8b, 0x05, 0xf9, 0, 0, 0}, true); + check("increment memory", {0xff, 0x05, 0xfa, 0, 0, 0}, false); + check("decrement memory", {0xff, 0x0d, 0xfa, 0, 0, 0}, false); + check("push memory", {0xff, 0x35, 0xfa, 0, 0, 0}, true); + std::cout << "Call-site resolver tests passed\n"; + return 0; + } catch (const std::exception& error) { + std::cerr << "call_site_resolver_tests: " << error.what() << '\n'; + return 1; + } +}