Add support for custom calling convention passing arguments in registers

If the compiler decided to pass an argument in a register on an internal function instead of pushing it on the stack to save time, allow us to specify the register the parameter is going to be in.

DHookAddParam received another parameter to set the register.
This commit is contained in:
Peace-Maker 2018-01-23 03:15:03 +01:00
parent 5d21350e9e
commit 1b9fa3743f
17 changed files with 555 additions and 36 deletions

View File

@ -67,9 +67,11 @@ typedef struct DataTypeSized_s {
{ {
type = DATA_TYPE_POINTER; type = DATA_TYPE_POINTER;
size = 0; size = 0;
custom_register = None;
} }
DataType_t type; DataType_t type;
size_t size; size_t size;
Register_t custom_register;
} DataTypeSized_t; } DataTypeSized_t;
@ -184,6 +186,11 @@ public:
virtual int GetArgStackSize() = 0; virtual int GetArgStackSize() = 0;
virtual void** GetStackArgumentPtr(CRegisters* pRegisters) = 0; virtual void** GetStackArgumentPtr(CRegisters* pRegisters) = 0;
/*
Returns the number of bytes that the buffer to store all the arguments in that are passed in a register.
*/
virtual int GetArgRegisterSize() = 0;
/* /*
Returns a pointer to the argument at the given index. Returns a pointer to the argument at the given index.

View File

@ -78,6 +78,16 @@ ke::Vector<Register_t> x86MsCdecl::GetRegisters()
} }
} }
// Save all the custom calling convention registers as well.
for (unsigned int i = 0; i < m_vecArgTypes.length(); i++)
{
if (m_vecArgTypes[i].custom_register == None)
continue;
// TODO: Make sure the list is unique? Set?
registers.append(m_vecArgTypes[i].custom_register);
}
return registers; return registers;
} }
@ -92,6 +102,7 @@ int x86MsCdecl::GetArgStackSize()
for (unsigned int i = 0; i < m_vecArgTypes.length(); i++) for (unsigned int i = 0; i < m_vecArgTypes.length(); i++)
{ {
if (m_vecArgTypes[i].custom_register == None)
iArgStackSize += m_vecArgTypes[i].size; iArgStackSize += m_vecArgTypes[i].size;
} }
@ -103,11 +114,35 @@ void** x86MsCdecl::GetStackArgumentPtr(CRegisters* pRegisters)
return (void **)(pRegisters->m_esp->GetValue<unsigned long>() + 4); return (void **)(pRegisters->m_esp->GetValue<unsigned long>() + 4);
} }
int x86MsCdecl::GetArgRegisterSize()
{
int iArgRegisterSize = 0;
for (unsigned int i = 0; i < m_vecArgTypes.length(); i++)
{
if (m_vecArgTypes[i].custom_register != None)
iArgRegisterSize += m_vecArgTypes[i].size;
}
return iArgRegisterSize;
}
void* x86MsCdecl::GetArgumentPtr(int iIndex, CRegisters* pRegisters) void* x86MsCdecl::GetArgumentPtr(int iIndex, CRegisters* pRegisters)
{ {
// Check if this argument was passed in a register.
if (m_vecArgTypes[iIndex].custom_register != None)
{
CRegister *pRegister = pRegisters->GetRegister(m_vecArgTypes[iIndex].custom_register);
if (!pRegister)
return NULL;
return pRegister->m_pAddress;
}
int iOffset = 4; int iOffset = 4;
for(int i=0; i < iIndex; i++) for(int i=0; i < iIndex; i++)
{ {
if (m_vecArgTypes[i].custom_register == None)
iOffset += m_vecArgTypes[i].size; iOffset += m_vecArgTypes[i].size;
} }

View File

@ -70,6 +70,7 @@ public:
virtual int GetPopSize(); virtual int GetPopSize();
virtual int GetArgStackSize(); virtual int GetArgStackSize();
virtual void** GetStackArgumentPtr(CRegisters* pRegisters); virtual void** GetStackArgumentPtr(CRegisters* pRegisters);
virtual int GetArgRegisterSize();
virtual void* GetArgumentPtr(int iIndex, CRegisters* pRegisters); virtual void* GetArgumentPtr(int iIndex, CRegisters* pRegisters);
virtual void ArgumentPtrChanged(int iIndex, CRegisters* pRegisters, void* pArgumentPtr); virtual void ArgumentPtrChanged(int iIndex, CRegisters* pRegisters, void* pArgumentPtr);

View File

@ -78,6 +78,16 @@ ke::Vector<Register_t> x86MsStdcall::GetRegisters()
} }
} }
// Save all the custom calling convention registers as well.
for (unsigned int i = 0; i < m_vecArgTypes.length(); i++)
{
if (m_vecArgTypes[i].custom_register == None)
continue;
// TODO: Make sure the list is unique? Set?
registers.append(m_vecArgTypes[i].custom_register);
}
return registers; return registers;
} }
@ -87,6 +97,7 @@ int x86MsStdcall::GetPopSize()
for(unsigned int i=0; i < m_vecArgTypes.length(); i++) for(unsigned int i=0; i < m_vecArgTypes.length(); i++)
{ {
if (m_vecArgTypes[i].custom_register == None)
iPopSize += m_vecArgTypes[i].size; iPopSize += m_vecArgTypes[i].size;
} }
@ -99,6 +110,7 @@ int x86MsStdcall::GetArgStackSize()
for (unsigned int i = 0; i < m_vecArgTypes.length(); i++) for (unsigned int i = 0; i < m_vecArgTypes.length(); i++)
{ {
if (m_vecArgTypes[i].custom_register == None)
iArgStackSize += m_vecArgTypes[i].size; iArgStackSize += m_vecArgTypes[i].size;
} }
@ -110,15 +122,39 @@ void** x86MsStdcall::GetStackArgumentPtr(CRegisters* pRegisters)
return (void **)(pRegisters->m_esp->GetValue<unsigned long>() + 4); return (void **)(pRegisters->m_esp->GetValue<unsigned long>() + 4);
} }
int x86MsStdcall::GetArgRegisterSize()
{
int iArgRegisterSize = 0;
for (unsigned int i = 0; i < m_vecArgTypes.length(); i++)
{
if (m_vecArgTypes[i].custom_register != None)
iArgRegisterSize += m_vecArgTypes[i].size;
}
return iArgRegisterSize;
}
void* x86MsStdcall::GetArgumentPtr(int iIndex, CRegisters* pRegisters) void* x86MsStdcall::GetArgumentPtr(int iIndex, CRegisters* pRegisters)
{ {
int iOffset = 4; // Check if this argument was passed in a register.
for(int i=0; i < iIndex; i++) if (m_vecArgTypes[iIndex].custom_register != None)
{ {
CRegister *pRegister = pRegisters->GetRegister(m_vecArgTypes[iIndex].custom_register);
if (!pRegister)
return NULL;
return pRegister->m_pAddress;
}
int iOffset = 4;
for (int i = 0; i < iIndex; i++)
{
if (m_vecArgTypes[i].custom_register == None)
iOffset += m_vecArgTypes[i].size; iOffset += m_vecArgTypes[i].size;
} }
return (void *) (pRegisters->m_esp->GetValue<unsigned long>() + iOffset); return (void *)(pRegisters->m_esp->GetValue<unsigned long>() + iOffset);
} }
void x86MsStdcall::ArgumentPtrChanged(int iIndex, CRegisters* pRegisters, void* pArgumentPtr) void x86MsStdcall::ArgumentPtrChanged(int iIndex, CRegisters* pRegisters, void* pArgumentPtr)

View File

@ -70,6 +70,7 @@ public:
virtual int GetPopSize(); virtual int GetPopSize();
virtual int GetArgStackSize(); virtual int GetArgStackSize();
virtual void** GetStackArgumentPtr(CRegisters* pRegisters); virtual void** GetStackArgumentPtr(CRegisters* pRegisters);
virtual int GetArgRegisterSize();
virtual void* GetArgumentPtr(int iIndex, CRegisters* pRegisters); virtual void* GetArgumentPtr(int iIndex, CRegisters* pRegisters);
virtual void ArgumentPtrChanged(int iIndex, CRegisters* pRegisters, void* pArgumentPtr); virtual void ArgumentPtrChanged(int iIndex, CRegisters* pRegisters, void* pArgumentPtr);

View File

@ -66,6 +66,7 @@ ke::Vector<Register_t> x86MsThiscall::GetRegisters()
ke::Vector<Register_t> registers; ke::Vector<Register_t> registers;
registers.append(ESP); registers.append(ESP);
// TODO: Allow custom this register.
registers.append(ECX); registers.append(ECX);
if (m_returnType.type == DATA_TYPE_FLOAT || m_returnType.type == DATA_TYPE_DOUBLE) if (m_returnType.type == DATA_TYPE_FLOAT || m_returnType.type == DATA_TYPE_DOUBLE)
@ -81,6 +82,16 @@ ke::Vector<Register_t> x86MsThiscall::GetRegisters()
} }
} }
// Save all the custom calling convention registers as well.
for (unsigned int i = 0; i < m_vecArgTypes.length(); i++)
{
if (m_vecArgTypes[i].custom_register == None)
continue;
// TODO: Make sure the list is unique? Set?
registers.append(m_vecArgTypes[i].custom_register);
}
return registers; return registers;
} }
@ -93,6 +104,8 @@ int x86MsThiscall::GetPopSize()
for(unsigned int i=0; i < m_vecArgTypes.length(); i++) for(unsigned int i=0; i < m_vecArgTypes.length(); i++)
{ {
// Only pop arguments that are actually on the stack.
if (m_vecArgTypes[i].custom_register == None)
iPopSize += m_vecArgTypes[i].size; iPopSize += m_vecArgTypes[i].size;
} }
@ -105,6 +118,7 @@ int x86MsThiscall::GetArgStackSize()
for (unsigned int i = 0; i < m_vecArgTypes.length(); i++) for (unsigned int i = 0; i < m_vecArgTypes.length(); i++)
{ {
if (m_vecArgTypes[i].custom_register == None)
iArgStackSize += m_vecArgTypes[i].size; iArgStackSize += m_vecArgTypes[i].size;
} }
@ -116,16 +130,41 @@ void** x86MsThiscall::GetStackArgumentPtr(CRegisters* pRegisters)
return (void **)(pRegisters->m_esp->GetValue<unsigned long>() + 4); return (void **)(pRegisters->m_esp->GetValue<unsigned long>() + 4);
} }
int x86MsThiscall::GetArgRegisterSize()
{
int iArgRegisterSize = 0;
for (unsigned int i = 0; i < m_vecArgTypes.length(); i++)
{
if (m_vecArgTypes[i].custom_register != None)
iArgRegisterSize += m_vecArgTypes[i].size;
}
return iArgRegisterSize;
}
void* x86MsThiscall::GetArgumentPtr(int iIndex, CRegisters* pRegisters) void* x86MsThiscall::GetArgumentPtr(int iIndex, CRegisters* pRegisters)
{ {
if (iIndex == 0) if (iIndex == 0)
{ {
// TODO: Allow custom this register.
return pRegisters->m_ecx->m_pAddress; return pRegisters->m_ecx->m_pAddress;
} }
// Check if this argument was passed in a register.
if (m_vecArgTypes[iIndex-1].custom_register != None)
{
CRegister *pRegister = pRegisters->GetRegister(m_vecArgTypes[iIndex-1].custom_register);
if (!pRegister)
return NULL;
return pRegister->m_pAddress;
}
int iOffset = 4; int iOffset = 4;
for(int i=0; i < iIndex-1; i++) for(int i=0; i < iIndex-1; i++)
{ {
if (m_vecArgTypes[i].custom_register == None)
iOffset += m_vecArgTypes[i].size; iOffset += m_vecArgTypes[i].size;
} }

View File

@ -69,8 +69,9 @@ public:
virtual ke::Vector<Register_t> GetRegisters(); virtual ke::Vector<Register_t> GetRegisters();
virtual int GetPopSize(); virtual int GetPopSize();
virtual int x86MsThiscall::GetArgStackSize(); virtual int GetArgStackSize();
virtual void** GetStackArgumentPtr(CRegisters* pRegisters); virtual void** GetStackArgumentPtr(CRegisters* pRegisters);
virtual int GetArgRegisterSize();
virtual void* GetArgumentPtr(int iIndex, CRegisters* pRegisters); virtual void* GetArgumentPtr(int iIndex, CRegisters* pRegisters);
virtual void ArgumentPtrChanged(int iIndex, CRegisters* pRegisters, void* pArgumentPtr); virtual void ArgumentPtrChanged(int iIndex, CRegisters* pRegisters, void* pArgumentPtr);

View File

@ -379,3 +379,127 @@ void CRegisters::DeleteRegister(CRegister* pRegister)
delete pRegister; delete pRegister;
} }
} }
CRegister* CRegisters::GetRegister(Register_t reg)
{
switch (reg)
{
case AL:
return m_al;
case CL:
return m_cl;
case DL:
return m_dl;
case BL:
return m_bl;
case AH:
return m_ah;
case CH:
return m_ch;
case DH:
return m_dh;
case BH:
return m_bh;
case AX:
return m_ax;
case CX:
return m_cx;
case DX:
return m_dx;
case BX:
return m_bx;
case SP:
return m_sp;
case BP:
return m_bp;
case SI:
return m_si;
case DI:
return m_di;
case EAX:
return m_eax;
case ECX:
return m_ecx;
case EDX:
return m_edx;
case EBX:
return m_ebx;
case ESP:
return m_esp;
case EBP:
return m_ebp;
case ESI:
return m_esi;
case EDI:
return m_edi;
case MM0:
return m_mm0;
case MM1:
return m_mm1;
case MM2:
return m_mm2;
case MM3:
return m_mm3;
case MM4:
return m_mm4;
case MM5:
return m_mm5;
case MM6:
return m_mm6;
case MM7:
return m_mm7;
case XMM0:
return m_xmm0;
case XMM1:
return m_xmm1;
case XMM2:
return m_xmm2;
case XMM3:
return m_xmm3;
case XMM4:
return m_xmm4;
case XMM5:
return m_xmm5;
case XMM6:
return m_xmm6;
case XMM7:
return m_xmm7;
case CS:
return m_cs;
case SS:
return m_ss;
case DS:
return m_ds;
case ES:
return m_es;
case FS:
return m_fs;
case GS:
return m_gs;
case ST0:
return m_st0;
case ST1:
return m_st1;
case ST2:
return m_st2;
case ST3:
return m_st3;
case ST4:
return m_st4;
case ST5:
return m_st5;
case ST6:
return m_st6;
case ST7:
return m_st7;
default:
return NULL;
}
}

View File

@ -43,6 +43,9 @@
// ============================================================================ // ============================================================================
enum Register_t enum Register_t
{ {
// No register at all.
None,
// ======================================================================== // ========================================================================
// >> 8-bit General purpose registers // >> 8-bit General purpose registers
// ======================================================================== // ========================================================================
@ -263,6 +266,8 @@ public:
CRegisters(ke::Vector<Register_t> registers); CRegisters(ke::Vector<Register_t> registers);
~CRegisters(); ~CRegisters();
CRegister* GetRegister(Register_t reg);
private: private:
CRegister* CreateRegister(ke::Vector<Register_t>& registers, Register_t reg, int iSize); CRegister* CreateRegister(ke::Vector<Register_t>& registers, Register_t reg, int iSize);
void DeleteRegister(CRegister* pRegister); void DeleteRegister(CRegister* pRegister);

View File

@ -189,12 +189,15 @@ ICallingConvention *ConstructCallingConvention(HookSetup *setup)
DataTypeSized_t type; DataTypeSized_t type;
type.type = DynamicHooks_ConvertParamTypeFrom(info.type); type.type = DynamicHooks_ConvertParamTypeFrom(info.type);
type.size = info.size; type.size = info.size;
type.custom_register = info.custom_register;
vecArgTypes.append(type); vecArgTypes.append(type);
} }
DataTypeSized_t returnType; DataTypeSized_t returnType;
returnType.type = DynamicHooks_ConvertReturnTypeFrom(setup->returnType); returnType.type = DynamicHooks_ConvertReturnTypeFrom(setup->returnType);
returnType.size = 0; returnType.size = 0;
// TODO: Add support for a custom return register.
returnType.custom_register = None;
ICallingConvention *pCallConv = nullptr; ICallingConvention *pCallConv = nullptr;
switch (setup->callConv) switch (setup->callConv)
@ -213,6 +216,32 @@ ICallingConvention *ConstructCallingConvention(HookSetup *setup)
return pCallConv; return pCallConv;
} }
bool UpdateRegisterArgumentSizes(CHook* pDetour, HookSetup *setup)
{
// The registers the arguments are passed in might not be the same size as the actual parameter type.
// Update the type info to the size of the register that's now holding that argument,
// so we can copy the whole value.
ICallingConvention* callingConvention = pDetour->m_pCallingConvention;
ke::Vector<DataTypeSized_t> &argTypes = callingConvention->m_vecArgTypes;
int numArgs = argTypes.length();
for (int i = 0; i < numArgs; i++)
{
if (argTypes[i].custom_register == None)
continue;
CRegister *reg = pDetour->m_pRegisters->GetRegister(argTypes[i].custom_register);
// That register can't be handled yet.
if (!reg)
return false;
argTypes[i].size = reg->m_iSize;
setup->params[i].size = reg->m_iSize;
}
return true;
}
ReturnAction_t HandleDetour(HookType_t hookType, CHook* pDetour) ReturnAction_t HandleDetour(HookType_t hookType, CHook* pDetour)
{ {
DetourMap *map; DetourMap *map;
@ -536,24 +565,43 @@ HookParamsStruct *CDynamicHooksSourcePawn::GetParamStruct()
HookParamsStruct *params = new HookParamsStruct(); HookParamsStruct *params = new HookParamsStruct();
params->dg = this; params->dg = this;
size_t paramsSize = this->m_pDetour->m_pCallingConvention->GetArgStackSize(); ICallingConvention* callingConvention = m_pDetour->m_pCallingConvention;
ke::Vector<DataTypeSized_t> &argTypes = m_pDetour->m_pCallingConvention->m_vecArgTypes; size_t stackSize = callingConvention->GetArgStackSize();
size_t paramsSize = stackSize + callingConvention->GetArgRegisterSize();
ke::Vector<DataTypeSized_t> &argTypes = callingConvention->m_vecArgTypes;
int numArgs = argTypes.length(); int numArgs = argTypes.length();
params->orgParams = (void **)malloc(paramsSize); params->orgParams = (void **)malloc(paramsSize);
params->newParams = (void **)malloc(paramsSize); params->newParams = (void **)malloc(paramsSize);
params->isChanged = (bool *)malloc(numArgs * sizeof(bool)); params->isChanged = (bool *)malloc(numArgs * sizeof(bool));
size_t offset = 0; // Save old stack parameters
for (int i = 0; i < numArgs; i++) if (stackSize > 0)
{ {
void *pArgPtr = m_pDetour->m_pCallingConvention->GetStackArgumentPtr(m_pDetour->m_pRegisters); void *pArgPtr = m_pDetour->m_pCallingConvention->GetStackArgumentPtr(m_pDetour->m_pRegisters);
memcpy(params->orgParams, pArgPtr, paramsSize); memcpy(params->orgParams, pArgPtr, stackSize);
}
*(void **)((intptr_t)params->newParams + offset) = NULL; memset(params->newParams, NULL, paramsSize);
params->isChanged[i] = false; memset(params->isChanged, false, numArgs * sizeof(bool));
offset += argTypes[i].size; int firstArg = 0;
// TODO: Support custom register for this ptr.
if (callConv == CallConv_THISCALL)
firstArg = 1;
// Save the old parameters passed in a register.
size_t offset = stackSize;
for (int i = 0; i < numArgs; i++)
{
// We already saved the stack arguments.
if (argTypes[i].custom_register == None)
continue;
int size = argTypes[i].size;
void *regAddr = callingConvention->GetArgumentPtr(i + firstArg, m_pDetour->m_pRegisters);
memcpy(params->orgParams + offset, regAddr, size);
offset += size;
} }
return params; return params;
@ -565,23 +613,34 @@ void CDynamicHooksSourcePawn::UpdateParamsFromStruct(HookParamsStruct *params)
if (!params) if (!params)
return; return;
ke::Vector<DataTypeSized_t> &argTypes = m_pDetour->m_pCallingConvention->m_vecArgTypes; ICallingConvention* callingConvention = m_pDetour->m_pCallingConvention;
size_t stackSize = callingConvention->GetArgStackSize();
ke::Vector<DataTypeSized_t> &argTypes = callingConvention->m_vecArgTypes;
int numArgs = argTypes.length(); int numArgs = argTypes.length();
int firstArg = 0; int firstArg = 0;
// TODO: Support custom register for this ptr.
if (callConv == CallConv_THISCALL) if (callConv == CallConv_THISCALL)
firstArg = 1; firstArg = 1;
size_t offset = 0; size_t stackOffset = 0;
size_t registerOffset = stackSize;
size_t offset;
for (int i = 0; i < numArgs; i++) for (int i = 0; i < numArgs; i++)
{ {
int size = argTypes[i].size;; int size = argTypes[i].size;
if (params->isChanged[i]) if (params->isChanged[i])
{ {
offset = argTypes[i].custom_register == None ? stackOffset : registerOffset;
void *paramAddr = (void *)((intptr_t)params->newParams + offset); void *paramAddr = (void *)((intptr_t)params->newParams + offset);
void *stackAddr = m_pDetour->m_pCallingConvention->GetArgumentPtr(i + firstArg, m_pDetour->m_pRegisters); void *stackAddr = callingConvention->GetArgumentPtr(i + firstArg, m_pDetour->m_pRegisters);
memcpy(stackAddr, paramAddr, size); memcpy(stackAddr, paramAddr, size);
} }
offset += size;
if (argTypes[i].custom_register == None)
stackOffset += size;
else
registerOffset += size;
} }
} }

View File

@ -33,6 +33,7 @@ public:
}; };
ICallingConvention *ConstructCallingConvention(HookSetup *setup); ICallingConvention *ConstructCallingConvention(HookSetup *setup);
bool UpdateRegisterArgumentSizes(CHook* pDetour, HookSetup *setup);
ReturnAction_t HandleDetour(HookType_t hookType, CHook* pDetour); ReturnAction_t HandleDetour(HookType_t hookType, CHook* pDetour);
bool AddDetourPluginHook(HookType_t hookType, CHook *pDetour, HookSetup *setup, IPluginFunction *pCallback); bool AddDetourPluginHook(HookType_t hookType, CHook *pDetour, HookSetup *setup, IPluginFunction *pCallback);
bool RemoveDetourPluginHook(HookType_t hookType, CHook *pDetour, IPluginFunction *pCallback); bool RemoveDetourPluginHook(HookType_t hookType, CHook *pDetour, IPluginFunction *pCallback);

View File

@ -119,7 +119,7 @@ cell_t Native_SetFromConf(IPluginContext *pContext, const cell_t *params)
} }
//native bool:DHookAddParam(Handle:setup, HookParamType:type); OLD //native bool:DHookAddParam(Handle:setup, HookParamType:type); OLD
//native bool:DHookAddParam(Handle:setup, HookParamType:type, size=-1, DHookPassFlag:flag=DHookPass_ByVal); //native bool:DHookAddParam(Handle:setup, HookParamType:type, size=-1, DHookPassFlag:flag=DHookPass_ByVal, DHookRegister custom_register=DHookRegister_Default);
cell_t Native_AddParam(IPluginContext *pContext, const cell_t *params) cell_t Native_AddParam(IPluginContext *pContext, const cell_t *params)
{ {
HookSetup *setup; HookSetup *setup;
@ -142,6 +142,23 @@ cell_t Native_AddParam(IPluginContext *pContext, const cell_t *params)
info.flags = PASSFLAG_BYVAL; info.flags = PASSFLAG_BYVAL;
} }
if (params[0] >= 5)
{
PluginRegister custom_register = (PluginRegister)params[5];
info.custom_register = DynamicHooks_ConvertRegisterFrom(custom_register);
// Stay future proof.
if (info.custom_register == None && custom_register != DHookRegister_Default)
return pContext->ThrowNativeError("Unhandled DHookRegister %d", params[5]);
if (info.custom_register != None && info.type == HookParamType_Object)
return pContext->ThrowNativeError("Can't pass an object in a register.");
}
else
{
info.custom_register = None;
}
if(params[0] >= 3 && params[3] != -1) if(params[0] >= 3 && params[3] != -1)
{ {
info.size = params[3]; info.size = params[3];
@ -195,6 +212,8 @@ cell_t Native_EnableDetour(IPluginContext *pContext, const cell_t *params)
{ {
ICallingConvention *pCallConv = ConstructCallingConvention(setup); ICallingConvention *pCallConv = ConstructCallingConvention(setup);
pDetour = pDetourManager->HookFunction(setup->funcAddr, pCallConv); pDetour = pDetourManager->HookFunction(setup->funcAddr, pCallConv);
if (!UpdateRegisterArgumentSizes(pDetour, setup))
return pContext->ThrowNativeError("A custom register for a parameter isn't supported.");
} }
// Register our pre/post handler. // Register our pre/post handler.

View File

@ -6,7 +6,7 @@
Handle hFlashbangDetonateDetour; Handle hFlashbangDetonateDetour;
Handle hFlashbangDeafen; Handle hFlashbangDeafen;
Handle hPercentageOfFlashForPlayer; //Handle hPercentageOfFlashForPlayer;
public void OnPluginStart() public void OnPluginStart()
{ {
@ -40,7 +40,7 @@ public void OnPluginStart()
if (!DHookSetFromConf(hFlashbangDeafen, temp, SDKConf_Signature, "Deafen")) if (!DHookSetFromConf(hFlashbangDeafen, temp, SDKConf_Signature, "Deafen"))
SetFailState("Failed to load Deafen signature from gamedata"); SetFailState("Failed to load Deafen signature from gamedata");
DHookAddParam(hFlashbangDeafen, HookParamType_Float); DHookAddParam(hFlashbangDeafen, HookParamType_Float, .custom_register=DHookRegister_XMM1);
if (!DHookEnableDetour(hFlashbangDeafen, false, Detour_OnDeafen)) if (!DHookEnableDetour(hFlashbangDeafen, false, Detour_OnDeafen))
SetFailState("Failed to detour Deafen."); SetFailState("Failed to detour Deafen.");
@ -51,7 +51,7 @@ public void OnPluginStart()
PrintToServer("CCSPlayer::Deafen detoured!"); PrintToServer("CCSPlayer::Deafen detoured!");
hPercentageOfFlashForPlayer = DHookCreateDetour(Address_Null, CallConv_CDECL, ReturnType_Float, ThisPointer_Ignore); /*hPercentageOfFlashForPlayer = DHookCreateDetour(Address_Null, CallConv_CDECL, ReturnType_Float, ThisPointer_Ignore);
if (!hPercentageOfFlashForPlayer) if (!hPercentageOfFlashForPlayer)
SetFailState("Failed to setup detour for PercentageOfFlashForPlayer"); SetFailState("Failed to setup detour for PercentageOfFlashForPlayer");
@ -68,7 +68,7 @@ public void OnPluginStart()
if (!DHookEnableDetour(hPercentageOfFlashForPlayer, true, Detour_OnPercentageOfFlashForPlayer_Post)) if (!DHookEnableDetour(hPercentageOfFlashForPlayer, true, Detour_OnPercentageOfFlashForPlayer_Post))
SetFailState("Failed to detour PercentageOfFlashForPlayer post."); SetFailState("Failed to detour PercentageOfFlashForPlayer post.");
PrintToServer("PercentageOfFlashForPlayer detoured!"); PrintToServer("PercentageOfFlashForPlayer detoured!");*/
} }
public MRESReturn Detour_OnFlashbangDetonate(int pThis) public MRESReturn Detour_OnFlashbangDetonate(int pThis)

View File

@ -98,6 +98,45 @@ enum DHookPassFlag
DHookPass_OASSIGNOP = (1<<4), /**< Object has an assignment operator */ DHookPass_OASSIGNOP = (1<<4), /**< Object has an assignment operator */
}; };
enum DHookRegister
{
// Don't change the register and use the default for the calling convention.
DHookRegister_Default,
// 8-bit general purpose registers
DHookRegister_AL,
DHookRegister_CL,
DHookRegister_DL,
DHookRegister_BL,
DHookRegister_AH,
DHookRegister_CH,
DHookRegister_DH,
DHookRegister_BH,
// 32-bit general purpose registers
DHookRegister_EAX,
DHookRegister_ECX,
DHookRegister_EDX,
DHookRegister_EBX,
DHookRegister_ESP,
DHookRegister_EBP,
DHookRegister_ESI,
DHookRegister_EDI,
// 128-bit XMM registers
DHookRegister_XMM0,
DHookRegister_XMM1,
DHookRegister_XMM2,
DHookRegister_XMM3,
DHookRegister_XMM4,
DHookRegister_XMM5,
DHookRegister_XMM6,
DHookRegister_XMM7,
// 80-bit FPU registers
DHookRegister_ST0
};
typeset ListenCB typeset ListenCB
{ {
//Deleted //Deleted
@ -198,7 +237,8 @@ native bool DHookDisableDetour(Handle setup, bool post, DHookCallback callback);
* @error Invalid setup handle or too many params added (request upping the max in thread) * @error Invalid setup handle or too many params added (request upping the max in thread)
* @noreturn * @noreturn
*/ */
native void DHookAddParam(Handle setup, HookParamType type, int size=-1, DHookPassFlag flag=DHookPass_ByVal); native void DHookAddParam(Handle setup, HookParamType type, int size=-1, DHookPassFlag flag=DHookPass_ByVal, DHookRegister custom_register=DHookRegister_Default);
//native void DHookAddParam(Handle setup, HookParamType type, int size=-1, DHookPassFlag flag=DHookPass_ByVal);
//native DHookAddParam(Handle:setup, HookParamType:type); //native DHookAddParam(Handle:setup, HookParamType:type);
/* Hook entity /* Hook entity

110
util.cpp
View File

@ -13,23 +13,62 @@ void * GetObjectAddr(HookParamType type, unsigned int flags, void **params, size
} }
size_t GetParamOffset(HookParamsStruct *paramStruct, unsigned int index) size_t GetStackParamOffset(HookParamsStruct *paramStruct, unsigned int index)
{ {
assert(paramStruct->dg->params[index].custom_register == None);
size_t offset = 0; size_t offset = 0;
for (unsigned int i = 0; i < index; i++) for (unsigned int i = 0; i < index; i++)
{ {
// Only care for arguments on the stack before us.
if (paramStruct->dg->params[i].custom_register != None)
continue;
#ifndef WIN32 #ifndef WIN32
if (paramStruct->dg->params.at(i).type == HookParamType_Object && (paramStruct->dg->params.at(i).flags & PASSFLAG_ODTOR)) //Passed by refrence if (paramStruct->dg->params[i].type == HookParamType_Object && (paramStruct->dg->params[i].flags & PASSFLAG_ODTOR)) //Passed by refrence
{ {
offset += sizeof(void *); offset += sizeof(void *);
continue; continue;
} }
#endif #endif
offset += paramStruct->dg->params.at(i).size; offset += paramStruct->dg->params[i].size;
} }
return offset; return offset;
} }
size_t GetRegisterParamOffset(HookParamsStruct *paramStruct, unsigned int index)
{
// TODO: Fix this up and get a pointer to the CDetour
assert(paramStruct->dg->params[index].custom_register != None);
// Need to get the size of the stack arguments first. Register arguments are stored after them in the buffer.
size_t stackSize = 0;
for (int i = paramStruct->dg->params.size() - 1; i >= 0; i--)
{
if (paramStruct->dg->params[i].custom_register == None)
stackSize += paramStruct->dg->params[i].size;
}
size_t offset = stackSize;
for (unsigned int i = 0; i < index; i++)
{
// Only care for arguments passed through a register as well before us.
if (paramStruct->dg->params[i].custom_register == None)
continue;
offset += paramStruct->dg->params[i].size;
}
return offset;
}
size_t GetParamOffset(HookParamsStruct *paramStruct, unsigned int index)
{
if (paramStruct->dg->params[index].custom_register == None)
return GetStackParamOffset(paramStruct, index);
else
return GetRegisterParamOffset(paramStruct, index);
}
size_t GetParamTypeSize(HookParamType type) size_t GetParamTypeSize(HookParamType type)
{ {
return sizeof(void *); return sizeof(void *);
@ -99,3 +138,68 @@ DataType_t DynamicHooks_ConvertReturnTypeFrom(ReturnType type)
return DATA_TYPE_VOID; return DATA_TYPE_VOID;
} }
Register_t DynamicHooks_ConvertRegisterFrom(PluginRegister reg)
{
switch (reg)
{
case DHookRegister_Default:
return None;
case DHookRegister_AL:
return AL;
case DHookRegister_CL:
return CL;
case DHookRegister_DL:
return DL;
case DHookRegister_BL:
return BL;
case DHookRegister_AH:
return AH;
case DHookRegister_CH:
return CH;
case DHookRegister_DH:
return DH;
case DHookRegister_BH:
return BH;
case DHookRegister_EAX:
return EAX;
case DHookRegister_ECX:
return ECX;
case DHookRegister_EDX:
return EDX;
case DHookRegister_EBX:
return EBX;
case DHookRegister_ESP:
return ESP;
case DHookRegister_EBP:
return EBP;
case DHookRegister_ESI:
return ESI;
case DHookRegister_EDI:
return EDI;
case DHookRegister_XMM0:
return XMM0;
case DHookRegister_XMM1:
return XMM1;
case DHookRegister_XMM2:
return XMM2;
case DHookRegister_XMM3:
return XMM3;
case DHookRegister_XMM4:
return XMM4;
case DHookRegister_XMM5:
return XMM5;
case DHookRegister_XMM6:
return XMM6;
case DHookRegister_XMM7:
return XMM7;
case DHookRegister_ST0:
return ST0;
}
return None;
}

40
util.h
View File

@ -4,6 +4,45 @@
#include "vhook.h" #include "vhook.h"
#include "convention.h" #include "convention.h"
enum PluginRegister
{
// Don't change the register and use the default for the calling convention.
DHookRegister_Default,
// 8-bit general purpose registers
DHookRegister_AL,
DHookRegister_CL,
DHookRegister_DL,
DHookRegister_BL,
DHookRegister_AH,
DHookRegister_CH,
DHookRegister_DH,
DHookRegister_BH,
// 32-bit general purpose registers
DHookRegister_EAX,
DHookRegister_ECX,
DHookRegister_EDX,
DHookRegister_EBX,
DHookRegister_ESP,
DHookRegister_EBP,
DHookRegister_ESI,
DHookRegister_EDI,
// 128-bit XMM registers
DHookRegister_XMM0,
DHookRegister_XMM1,
DHookRegister_XMM2,
DHookRegister_XMM3,
DHookRegister_XMM4,
DHookRegister_XMM5,
DHookRegister_XMM6,
DHookRegister_XMM7,
// 80-bit FPU registers
DHookRegister_ST0
};
size_t GetParamOffset(HookParamsStruct *params, unsigned int index); size_t GetParamOffset(HookParamsStruct *params, unsigned int index);
void * GetObjectAddr(HookParamType type, unsigned int flags, void **params, size_t offset); void * GetObjectAddr(HookParamType type, unsigned int flags, void **params, size_t offset);
size_t GetParamTypeSize(HookParamType type); size_t GetParamTypeSize(HookParamType type);
@ -11,4 +50,5 @@ size_t GetParamsSize(DHooksCallback *dg);
DataType_t DynamicHooks_ConvertParamTypeFrom(HookParamType type); DataType_t DynamicHooks_ConvertParamTypeFrom(HookParamType type);
DataType_t DynamicHooks_ConvertReturnTypeFrom(ReturnType type); DataType_t DynamicHooks_ConvertReturnTypeFrom(ReturnType type);
Register_t DynamicHooks_ConvertRegisterFrom(PluginRegister reg);
#endif #endif

View File

@ -5,6 +5,7 @@
#include <sourcehook.h> #include <sourcehook.h>
#include <sh_vector.h> #include <sh_vector.h>
#include <sourcehook_pibuilder.h> #include <sourcehook_pibuilder.h>
#include <registers.h>
enum CallingConvention enum CallingConvention
{ {
@ -92,6 +93,7 @@ struct ParamInfo
size_t size; size_t size;
unsigned int flags; unsigned int flags;
SourceHook::PassInfo::PassType pass_type; SourceHook::PassInfo::PassType pass_type;
Register_t custom_register;
}; };
#ifdef WIN32 #ifdef WIN32
@ -216,6 +218,11 @@ public:
this->callback = nullptr; this->callback = nullptr;
}; };
~HookSetup(){}; ~HookSetup(){};
bool IsVirtual()
{
return this->offset != -1;
}
public: public:
unsigned int returnFlag; unsigned int returnFlag;
ReturnType returnType; ReturnType returnType;