From 891fa5352e2ccaacf39d57bd7a395f17b2bec70b Mon Sep 17 00:00:00 2001 From: Peace-Maker Date: Thu, 20 Jun 2019 02:14:07 +0200 Subject: [PATCH] Add support for the "fastcall" calling convention Callee cleans the stack and first two arguments are passed in registers ecx and edx. You could emulate this by choosing stdcall and setting the custom_registers on the arguments manually, but this is easier. --- AMBuildScript | 1 + DynamicHooks/conventions/x86MsFastcall.cpp | 58 ++++++++++++++++++ DynamicHooks/conventions/x86MsFastcall.h | 69 ++++++++++++++++++++++ dynhooks_sourcepawn.cpp | 8 +++ msvc10/sdk.vcxproj | 1 + msvc10/sdk.vcxproj.filters | 3 + signatures.cpp | 2 + sourcemod/scripting/include/dhooks.inc | 1 + vhook.h | 1 + 9 files changed, 144 insertions(+) create mode 100644 DynamicHooks/conventions/x86MsFastcall.cpp create mode 100644 DynamicHooks/conventions/x86MsFastcall.h diff --git a/AMBuildScript b/AMBuildScript index 27473cf..80e519e 100644 --- a/AMBuildScript +++ b/AMBuildScript @@ -270,6 +270,7 @@ program.sources += [ os.path.join('DynamicHooks', 'utilities.cpp'), os.path.join('DynamicHooks', 'conventions', 'x86MsCdecl.cpp'), os.path.join('DynamicHooks', 'conventions', 'x86MsStdcall.cpp'), + os.path.join('DynamicHooks', 'conventions', 'x86MsFastcall.cpp'), ] if builder.target_platform == 'windows': diff --git a/DynamicHooks/conventions/x86MsFastcall.cpp b/DynamicHooks/conventions/x86MsFastcall.cpp new file mode 100644 index 0000000..0b9d8c0 --- /dev/null +++ b/DynamicHooks/conventions/x86MsFastcall.cpp @@ -0,0 +1,58 @@ +/** +* ============================================================================= +* DynamicHooks +* Copyright (C) 2015 Robin Gohmert. All rights reserved. +* ============================================================================= +* +* This software is provided 'as-is', without any express or implied warranty. +* In no event will the authors be held liable for any damages arising from +* the use of this software. +* +* Permission is granted to anyone to use this software for any purpose, +* including commercial applications, and to alter it and redistribute it +* freely, subject to the following restrictions: +* +* 1. The origin of this software must not be misrepresented; you must not +* claim that you wrote the original software. If you use this software in a +* product, an acknowledgment in the product documentation would be +* appreciated but is not required. +* +* 2. Altered source versions must be plainly marked as such, and must not be +* misrepresented as being the original software. +* +* 3. This notice may not be removed or altered from any source distribution. +* +* asm.h/cpp from devmaster.net (thanks cybermind) edited by pRED* to handle gcc +* -fPIC thunks correctly +* +* Idea and trampoline code taken from DynDetours (thanks your-name-here). +*/ + +// ============================================================================ +// >> INCLUDES +// ============================================================================ +#include "x86MsFastcall.h" + + +// ============================================================================ +// >> x86MsFastcall +// ============================================================================ +x86MsFastcall::x86MsFastcall(ke::Vector &vecArgTypes, DataTypeSized_t returnType, int iAlignment) : + x86MsStdcall(vecArgTypes, returnType, iAlignment) +{ + // First argument is passed in ecx. + if (m_vecArgTypes.length() > 0) { + DataTypeSized_t &type = m_vecArgTypes[0]; + // Don't force the register on the user. + // Why choose Fastcall if you set your own argument registers though.. + if (type.custom_register == None) + type.custom_register = ECX; + } + + // Second argument is passed in edx. + if (m_vecArgTypes.length() > 1) { + DataTypeSized_t &type = m_vecArgTypes[1]; + if (type.custom_register == None) + type.custom_register = EDX; + } +} diff --git a/DynamicHooks/conventions/x86MsFastcall.h b/DynamicHooks/conventions/x86MsFastcall.h new file mode 100644 index 0000000..83fdf94 --- /dev/null +++ b/DynamicHooks/conventions/x86MsFastcall.h @@ -0,0 +1,69 @@ +/** +* ============================================================================= +* DynamicHooks +* Copyright (C) 2015 Robin Gohmert. All rights reserved. +* ============================================================================= +* +* This software is provided 'as-is', without any express or implied warranty. +* In no event will the authors be held liable for any damages arising from +* the use of this software. +* +* Permission is granted to anyone to use this software for any purpose, +* including commercial applications, and to alter it and redistribute it +* freely, subject to the following restrictions: +* +* 1. The origin of this software must not be misrepresented; you must not +* claim that you wrote the original software. If you use this software in a +* product, an acknowledgment in the product documentation would be +* appreciated but is not required. +* +* 2. Altered source versions must be plainly marked as such, and must not be +* misrepresented as being the original software. +* +* 3. This notice may not be removed or altered from any source distribution. +* +* asm.h/cpp from devmaster.net (thanks cybermind) edited by pRED* to handle gcc +* -fPIC thunks correctly +* +* Idea and trampoline code taken from DynDetours (thanks your-name-here). +*/ + +#ifndef _X86_MS_FASTCALL_H +#define _X86_MS_FASTCALL_H + +// ============================================================================ +// >> INCLUDES +// ============================================================================ +#include "x86MsStdcall.h" + + +// ============================================================================ +// >> CLASSES +// ============================================================================ +/* +Source: DynCall manual and Windows docs + +Registers: + - eax = return value + - edx = return value + - esp = stack pointer + - st0 = floating point return value + +Parameter passing: + - first parameter in ecx, second parameter in edx, rest on the stack + - stack parameter order: right-to-left + - callee cleans up the stack + - alignment: 4 bytes + +Return values: + - return values of pointer or intergral type (<= 32 bits) are returned via the eax register + - integers > 32 bits are returned via the eax and edx registers + - floating pointer types are returned via the st0 register +*/ +class x86MsFastcall: public x86MsStdcall +{ +public: + x86MsFastcall(ke::Vector &vecArgTypes, DataTypeSized_t returnType, int iAlignment=4); +}; + +#endif // _X86_MS_FASTCALL_H \ No newline at end of file diff --git a/dynhooks_sourcepawn.cpp b/dynhooks_sourcepawn.cpp index 9892200..55abc2b 100644 --- a/dynhooks_sourcepawn.cpp +++ b/dynhooks_sourcepawn.cpp @@ -6,17 +6,22 @@ #include "conventions/x86MsCdecl.h" #include "conventions/x86MsThiscall.h" #include "conventions/x86MsStdcall.h" +#include "conventions/x86MsFastcall.h" typedef x86MsCdecl x86DetourCdecl; typedef x86MsThiscall x86DetourThisCall; typedef x86MsStdcall x86DetourStdCall; +typedef x86MsFastcall x86DetourFastCall; #elif defined KE_LINUX #include "conventions/x86GccCdecl.h" #include "conventions/x86GccThiscall.h" #include "conventions/x86MsStdcall.h" +#include "conventions/x86MsFastcall.h" typedef x86GccCdecl x86DetourCdecl; typedef x86GccThiscall x86DetourThisCall; // Uhm, stdcall on linux? typedef x86MsStdcall x86DetourStdCall; +// Uhumm, fastcall on linux? +typedef x86MsFastcall x86DetourFastCall; #else #error "Unsupported platform." #endif @@ -213,6 +218,9 @@ ICallingConvention *ConstructCallingConvention(HookSetup *setup) case CallConv_STDCALL: pCallConv = new x86DetourStdCall(vecArgTypes, returnType); break; + case CallConv_FASTCALL: + pCallConv = new x86DetourFastCall(vecArgTypes, returnType); + break; default: smutils->LogError(myself, "Unknown calling convention %d.", setup->callConv); break; diff --git a/msvc10/sdk.vcxproj b/msvc10/sdk.vcxproj index 057532c..a9b4bbc 100644 --- a/msvc10/sdk.vcxproj +++ b/msvc10/sdk.vcxproj @@ -111,6 +111,7 @@ + diff --git a/msvc10/sdk.vcxproj.filters b/msvc10/sdk.vcxproj.filters index 8d8b328..1335156 100644 --- a/msvc10/sdk.vcxproj.filters +++ b/msvc10/sdk.vcxproj.filters @@ -38,6 +38,9 @@ DynamicHooks\conventions + + DynamicHooks\conventions + diff --git a/signatures.cpp b/signatures.cpp index 1433649..36cf5cf 100644 --- a/signatures.cpp +++ b/signatures.cpp @@ -190,6 +190,8 @@ SMCResult SignatureGameConfig::ReadSMC_KeyValue(const SMCStates *states, const c callConv = CallConv_THISCALL; else if (!strcmp(value, "stdcall")) callConv = CallConv_STDCALL; + else if (!strcmp(value, "fastcall")) + callConv = CallConv_FASTCALL; else { smutils->LogError(myself, "Invalid calling convention \"%s\": line: %i col: %i", value, states->line, states->col); diff --git a/sourcemod/scripting/include/dhooks.inc b/sourcemod/scripting/include/dhooks.inc index 065ee41..9f59605 100644 --- a/sourcemod/scripting/include/dhooks.inc +++ b/sourcemod/scripting/include/dhooks.inc @@ -77,6 +77,7 @@ enum CallingConvention CallConv_CDECL, CallConv_THISCALL, CallConv_STDCALL, + CallConv_FASTCALL, }; enum MRESReturn diff --git a/vhook.h b/vhook.h index 99da530..43ee47d 100644 --- a/vhook.h +++ b/vhook.h @@ -12,6 +12,7 @@ enum CallingConvention CallConv_CDECL, CallConv_THISCALL, CallConv_STDCALL, + CallConv_FASTCALL, }; enum MRESReturn