64-bit support for CSGO on Linux and macOS (#705)
This commit is contained in:
@@ -41,6 +41,8 @@
|
||||
#define PAGE_EXECUTE_READWRITE PROT_READ|PROT_WRITE|PROT_EXEC
|
||||
#endif
|
||||
|
||||
#include <jit/x86/x86_macros.h>
|
||||
|
||||
struct patch_t
|
||||
{
|
||||
patch_t()
|
||||
@@ -68,13 +70,50 @@ inline void SetMemPatchable(void *address, size_t size)
|
||||
ProtectMemory(address, (int)size, PAGE_EXECUTE_READWRITE);
|
||||
}
|
||||
|
||||
inline void PatchRelJump32(unsigned char *target, void *callback)
|
||||
{
|
||||
SetMemPatchable(target, 5);
|
||||
|
||||
// jmp <32-bit displacement>
|
||||
target[0] = IA32_JMP_IMM32;
|
||||
*(int32_t *)(&target[1]) = int32_t((unsigned char *)callback - (target + 5));
|
||||
}
|
||||
|
||||
inline void PatchAbsJump64(unsigned char *target, void *callback)
|
||||
{
|
||||
int i = 0;
|
||||
SetMemPatchable(target, 14);
|
||||
|
||||
// push <lower 32-bits> ; allocates 64-bit stack space on x64
|
||||
// mov [rsp+4], <upper 32-bits> ; unnecessary if upper bits are 0
|
||||
// ret ; jump to address on stack
|
||||
target[i++] = IA32_PUSH_IMM32;
|
||||
*(int32_t *)(&target[i]) = int32_t(int64_t(callback));
|
||||
i += 4;
|
||||
if ((int64_t(callback) >> 32) != 0)
|
||||
{
|
||||
target[i++] = IA32_MOV_RM_IMM32;
|
||||
target[i++] = ia32_modrm(MOD_DISP8, 0, kREG_SIB);
|
||||
target[i++] = ia32_sib(NOSCALE, kREG_NOIDX, kREG_ESP);
|
||||
target[i++] = 0x04;
|
||||
*(int32_t *)(&target[i]) = (int64_t(callback) >> 32);
|
||||
i += 4;
|
||||
}
|
||||
target[i] = IA32_RET;
|
||||
}
|
||||
|
||||
inline void DoGatePatch(unsigned char *target, void *callback)
|
||||
{
|
||||
SetMemPatchable(target, 20);
|
||||
|
||||
target[0] = 0xFF; /* JMP */
|
||||
target[1] = 0x25; /* MEM32 */
|
||||
*(void **)(&target[2]) = callback;
|
||||
#if defined(_WIN64) || defined(__x86_64__)
|
||||
int64_t diff = int64_t(callback) - (int64_t(target) + 5);
|
||||
int32_t upperBits = (diff >> 32);
|
||||
if (upperBits == 0 || upperBits == -1)
|
||||
PatchRelJump32(target, callback);
|
||||
else
|
||||
PatchAbsJump64(target, callback);
|
||||
#else
|
||||
PatchRelJump32(target, callback);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void ApplyPatch(void *address, int offset, const patch_t *patch, patch_t *restore)
|
||||
|
||||
+70
-10
@@ -35,6 +35,58 @@
|
||||
ISourcePawnEngine *CDetourManager::spengine = NULL;
|
||||
IGameConfig *CDetourManager::gameconf = NULL;
|
||||
|
||||
// Push 64-bit value onto the stack using two instructions.
|
||||
//
|
||||
// Pushing 0xF00DF00DF00DF00D:
|
||||
// push 0xF00DF00D
|
||||
// mov [rsp+4], 0xF00DF00D
|
||||
static inline void X64_Push_Imm64(JitWriter *jit, jit_int64_t val)
|
||||
{
|
||||
jit->write_ubyte(IA32_PUSH_IMM32);
|
||||
jit->write_int32(jit_int32_t(val));
|
||||
if ((val >> 32) != 0)
|
||||
IA32_Mov_ESP_Disp8_Imm32(jit, 4, (val >> 32));
|
||||
}
|
||||
|
||||
// Jump to absolute 64-bit address using multiple instructions.
|
||||
//
|
||||
// Jumping to address 0xF00DF00DF00DF00D:
|
||||
// push 0xF00DF00D
|
||||
// mov [rsp+4], 0xF00DF00D
|
||||
// ret
|
||||
static inline void X64_Jump_Abs(JitWriter *jit, void *dest)
|
||||
{
|
||||
X64_Push_Imm64(jit, jit_int64_t(dest));
|
||||
IA32_Return(jit);
|
||||
}
|
||||
|
||||
static inline void RelativeJump32(JitWriter *jit, void *target)
|
||||
{
|
||||
jitoffs_t call = IA32_Jump_Imm32(jit, 0);
|
||||
IA32_Write_Jump32_Abs(jit, call, target);
|
||||
}
|
||||
|
||||
#if defined(_WIN64) || defined(__x86_64__)
|
||||
static inline bool IsShortJump(JitWriter *jit, void *target)
|
||||
{
|
||||
int64_t diff = int64_t(target) - (int64_t(jit->outbase) + jit->get_outputpos() + OP_JMP_SIZE);
|
||||
int32_t upperBits = (diff >> 32);
|
||||
return upperBits == 0 || upperBits == -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline void AbsJump(JitWriter *jit, void *target)
|
||||
{
|
||||
#if defined(_WIN64) || defined(__x86_64__)
|
||||
if (IsShortJump(jit, target))
|
||||
RelativeJump32(jit, target);
|
||||
else
|
||||
X64_Jump_Abs(jit, target);
|
||||
#else
|
||||
RelativeJump32(jit, target);
|
||||
#endif
|
||||
}
|
||||
|
||||
void CDetourManager::Init(ISourcePawnEngine *spengine, IGameConfig *gameconf)
|
||||
{
|
||||
CDetourManager::spengine = spengine;
|
||||
@@ -147,13 +199,12 @@ bool CDetour::CreateDetour()
|
||||
return false;
|
||||
}
|
||||
|
||||
detour_restore.bytes = copy_bytes((unsigned char *)detour_address, NULL, OP_JMP_SIZE+1);
|
||||
|
||||
/* First, save restore bits */
|
||||
for (size_t i=0; i<detour_restore.bytes; i++)
|
||||
{
|
||||
detour_restore.patch[i] = ((unsigned char *)detour_address)[i];
|
||||
}
|
||||
#if defined(_WIN64) || defined(__x86_64__)
|
||||
int shortBytes = copy_bytes((unsigned char *)detour_address, NULL, OP_JMP_SIZE);
|
||||
detour_restore.bytes = copy_bytes((unsigned char *)detour_address, NULL, X64_ABS_SIZE);
|
||||
#else
|
||||
detour_restore.bytes = copy_bytes((unsigned char *)detour_address, NULL, OP_JMP_SIZE);
|
||||
#endif
|
||||
|
||||
JitWriter wr;
|
||||
JitWriter *jit = ≀
|
||||
@@ -167,13 +218,22 @@ jit_rewind:
|
||||
/* Patch old bytes in */
|
||||
if (wr.outbase != NULL)
|
||||
{
|
||||
#if defined(_WIN64) || defined(__x86_64__)
|
||||
wr.outptr += shortBytes;
|
||||
bool isShort = IsShortJump(jit, detour_address);
|
||||
wr.outptr -= shortBytes;
|
||||
if (isShort)
|
||||
detour_restore.bytes = shortBytes;
|
||||
#endif
|
||||
/* Save restore bits */
|
||||
memcpy(detour_restore.patch, detour_address, detour_restore.bytes);
|
||||
|
||||
copy_bytes((unsigned char *)detour_address, (unsigned char*)wr.outptr, detour_restore.bytes);
|
||||
}
|
||||
wr.outptr += detour_restore.bytes;
|
||||
|
||||
/* Return to the original function */
|
||||
jitoffs_t call = IA32_Jump_Imm32(jit, 0);
|
||||
IA32_Write_Jump32_Abs(jit, call, (unsigned char *)detour_address + detour_restore.bytes);
|
||||
AbsJump(jit, (unsigned char *)detour_address + detour_restore.bytes);
|
||||
|
||||
if (wr.outbase == NULL)
|
||||
{
|
||||
@@ -211,7 +271,7 @@ void CDetour::EnableDetour()
|
||||
{
|
||||
if (!detoured)
|
||||
{
|
||||
DoGatePatch((unsigned char *)detour_address, &detour_callback);
|
||||
DoGatePatch((unsigned char *)detour_address, detour_callback);
|
||||
detoured = true;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user