summaryrefslogtreecommitdiffstatshomepage
path: root/src/lib/util
diff options
context:
space:
mode:
author Vas Crabb <vas@vastheman.com>2021-09-22 09:42:10 +1000
committer Vas Crabb <vas@vastheman.com>2021-09-22 09:42:10 +1000
commit45d893eaa55fd4db870642f406cba4a8cbac04b4 (patch)
tree06e1c3901df8e19722661b6063413bd29f2171d7 /src/lib/util
parent2bfa21eb2a6fd9af7429a347026c50aec045f590 (diff)
util/delegate.cpp: Recognise a couple more MSVC thunks.
The MSVC C++ ABI doesn't reserve the first vtable entry for classes without a virtual destructor, so the instruction to load the virtual member function address may not need an immediate displacement. Also recognise virtual member function call thunks for AArch64.
Diffstat (limited to 'src/lib/util')
-rw-r--r--src/lib/util/delegate.cpp35
1 files changed, 29 insertions, 6 deletions
diff --git a/src/lib/util/delegate.cpp b/src/lib/util/delegate.cpp
index 346ba1283a0..cedb8e60bd8 100644
--- a/src/lib/util/delegate.cpp
+++ b/src/lib/util/delegate.cpp
@@ -142,25 +142,27 @@ delegate_generic_function delegate_mfp_msvc::adjust_this_pointer(delegate_generi
object = reinterpret_cast<delegate_generic_class *>(byteptr);
// walk past recognisable thunks
- std::uint8_t const *func = reinterpret_cast<std::uint8_t const *>(m_function);
#if defined(__x86_64__) || defined(_M_X64)
+ std::uint8_t const *func = reinterpret_cast<std::uint8_t const *>(m_function);
while (true)
{
if (0xe9 == func[0])
{
- // absolute jump with 32-bit displacement
+ // relative jump with 32-bit displacement (typically a resolved PLT entry)
LOG("Found relative jump at %p ", func);
func += 5 + *reinterpret_cast<std::int32_t const *>(func + 1);
LOG("redirecting to %p\n", func);
}
- else if ((0x48 == func[0]) && (0x8b == func[1]) && (0x01 == func[2]) && (0xff == func[3]) && ((0x60 == func[4]) || (0xa0 == func[4])))
+ else if ((0x48 == func[0]) && (0x8b == func[1]) && (0x01 == func[2]) && (0xff == func[3]) && ((0x20 == func[4]) || (0x60 == func[4]) || (0xa0 == func[4])))
{
// virtual function call thunk - mov rax,QWORD PTR [rcx] ; jmp QWORD PTR [rax+...]
LOG("Found virtual member function thunk at %p ", func);
std::uint8_t const *const vptr = *reinterpret_cast<std::uint8_t const *const *>(object);
- if (0x60 == func[4])
+ if (0x20 == func[4]) // no displacement
+ func = *reinterpret_cast<std::uint8_t const *const *>(vptr);
+ else if (0x60 == func[4]) // 8-bit displacement
func = *reinterpret_cast<std::uint8_t const *const *>(vptr + *reinterpret_cast<std::int8_t const *>(func + 5));
- else
+ else // 32-bit displacement
func = *reinterpret_cast<std::uint8_t const *const *>(vptr + *reinterpret_cast<std::int32_t const *>(func + 5));
LOG("redirecting to %p\n", func);
}
@@ -170,8 +172,29 @@ delegate_generic_function delegate_mfp_msvc::adjust_this_pointer(delegate_generi
break;
}
}
-#endif
return reinterpret_cast<delegate_generic_function>(std::uintptr_t(func));
+#elif defined(__aarch64__) || defined(_M_ARM64)
+ std::uint32_t const *func = reinterpret_cast<std::uint32_t const *>(m_function);
+ while (true)
+ {
+ if ((0xf9400010 == func[0]) && (0xf9400210 == (func[1] & 0xffc003ff)) && (0xd61f0200 == func[2]))
+ {
+ // virtual function call thunk - ldr xip0,[x0] ; ldr xip0,[x0,#...] ; br xip0
+ LOG("Found virtual member function thunk at %p ", func);
+ std::uint32_t const *const *const vptr = *reinterpret_cast<std::uint32_t const *const *const *>(object);
+ func = vptr[(func[1] & 0x003ffc00) >> 10];
+ LOG("redirecting to %p\n", func);
+ }
+ else
+ {
+ // not something we can easily bypass
+ break;
+ }
+ }
+ return reinterpret_cast<delegate_generic_function>(std::uintptr_t(func));
+#else
+ return reinterpret_cast<delegate_generic_function>(m_function);
+#endif
}
} // namespace util::detail