diff options
author | Michael Smith <mikesmiffy128@gmail.com> | 2023-08-20 16:20:03 +0100 |
---|---|---|
committer | Michael Smith <mikesmiffy128@gmail.com> | 2023-08-27 00:46:09 +0100 |
commit | a1998f2f7ce4153d670e2e5cb5018366517cc1ca (patch) | |
tree | 4d899fbad24c728c0b51f183c61ed6a7fb213c04 /src/hook.c | |
parent | 38fa6c52a8a26ac178a3e1f80a8317740b8e82b3 (diff) |
Get things at least compiling under Linux
Nothing really works yet, but at least test.h and fastspin are fixed and
some of the issues with RTTI and libdl and stuff are maybe kind of
sorted, subject to more testing later.
The main issue now seems to be the cvar interface not quite lining up
and crashing pretty much immediately. That'll probably take a lot more
debugging to figure out, which likely still won't be a priority for
quite a while.
Diffstat (limited to 'src/hook.c')
-rw-r--r-- | src/hook.c | 45 |
1 files changed, 20 insertions, 25 deletions
@@ -27,8 +27,6 @@ // Almost certainly breaks in some weird cases. Oh well! Most of the time, // vtable hooking is more reliable, this is only for, uh, emergencies. -#if defined(_WIN32) && !defined(_WIN64) - #if defined(__GNUC__) || defined(__clang__) __attribute__((aligned(4096))) #elif defined(_MSC_VER) @@ -45,6 +43,18 @@ bool hook_init(void) { return os_mprot(trampolines, sizeof(trampolines), PAGE_EXECUTE_READWRITE); } +static inline void iflush(void *p, int len) { +#if defined(_WIN32) + // -1 is the current process, and it's a constant in the WDK, so it's + // assumed we can safely avoid the useless GetCurrentProcess call + FlushInstructionCache((void *)-1, p, len); +#elif defined(__GNUC__) + __builtin___clear_cache((char *)p, (char *)p + len); +#else +#error no way to flush instruction cache +#endif +} + void *hook_inline(void *func_, void *target) { uchar *func = func_; // dumb hack: if we hit some thunk that immediately jumps elsewhere (which @@ -74,30 +84,21 @@ void *hook_inline(void *func_, void *target) { } } // for simplicity, just bump alloc the trampoline. no need to free anyway - if (nexttrampoline - trampolines > sizeof(trampolines) - len - 6) goto nosp; - // TODO(opt): stop pretending to be thread-safe, it's just slowing us down - uchar *trampoline = (uchar *)InterlockedExchangeAdd( - (volatile long *)&nexttrampoline, len + 6); - // avoid TOCTOU - if (trampoline - trampolines > sizeof(trampolines) - len - 6) { -nosp: con_warn("hook_inline: out of trampoline space\n"); + if (nexttrampoline - trampolines > sizeof(trampolines) - len - 6) { + con_warn("hook_inline: out of trampoline space\n"); return 0; } + uchar *trampoline = nexttrampoline; + nexttrampoline += len + 6; // NOT thread-safe. we don't need that anyway! *trampoline++ = len; // stick length in front for quicker unhooking memcpy(trampoline, func, len); trampoline[len] = X86_JMPIW; uint diff = func - (trampoline + 5); // goto the continuation memcpy(trampoline + len + 1, &diff, 4); - uchar jmp[8]; - jmp[0] = X86_JMPIW; diff = (uchar *)target - (func + 5); // goto the hook target - memcpy(jmp + 1, &diff, 4); - // pad with original bytes so we can do an 8-byte atomic write - memcpy(jmp + 5, func + 5, 3); - *(volatile uvlong *)func = *(uvlong *)jmp; // (assuming function is aligned) - // -1 is the current process, and it's a constant in the WDK, so it's - // assumed we can safely avoid the useless GetCurrentProcess call - FlushInstructionCache((void *)-1, func, len); + func[0] = X86_JMPIW; + memcpy(func + 1, &diff, 4); + iflush(func, 5); return trampoline; } @@ -107,13 +108,7 @@ void unhook_inline(void *orig) { int off = mem_load32(p + len + 1); uchar *q = p + off + 5; memcpy(q, p, 5); // XXX: not atomic atm! (does any of it even need to be?) - FlushInstructionCache((void *)-1, q, 5); + iflush(q, 5); } -#else - -// TODO(linux): Implement for Linux and/or x86_64 when needed... - -#endif - // vi: sw=4 ts=4 noet tw=80 cc=80 |