From 1592f77fc309a0e16741a726f954832e623c42d6 Mon Sep 17 00:00:00 2001 From: Borja Ferrer Date: Fri, 4 May 2007 21:39:05 +0000 Subject: [PATCH] added new function calling module, wow --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40745 --- extensions/bintools/CallMaker.cpp | 52 ++ extensions/bintools/CallMaker.h | 48 ++ extensions/bintools/CallWrapper.cpp | 91 ++++ extensions/bintools/CallWrapper.h | 58 +++ extensions/bintools/Makefile | 87 ++++ extensions/bintools/extension.cpp | 39 ++ extensions/bintools/extension.h | 86 +++ extensions/bintools/jit_call.cpp | 609 ++++++++++++++++++++++ extensions/bintools/jit_call.h | 27 + extensions/bintools/msvc8/bintools.sln | 20 + extensions/bintools/msvc8/bintools.vcproj | 253 +++++++++ extensions/bintools/smsdk_config.h | 33 ++ extensions/bintools/smsdk_ext.cpp | 333 ++++++++++++ extensions/bintools/smsdk_ext.h | 196 +++++++ public/extensions/IBinTools.h | 178 +++++++ public/jit/x86/x86_macros.h | 91 ++++ 16 files changed, 2201 insertions(+) create mode 100644 extensions/bintools/CallMaker.cpp create mode 100644 extensions/bintools/CallMaker.h create mode 100644 extensions/bintools/CallWrapper.cpp create mode 100644 extensions/bintools/CallWrapper.h create mode 100644 extensions/bintools/Makefile create mode 100644 extensions/bintools/extension.cpp create mode 100644 extensions/bintools/extension.h create mode 100644 extensions/bintools/jit_call.cpp create mode 100644 extensions/bintools/jit_call.h create mode 100644 extensions/bintools/msvc8/bintools.sln create mode 100644 extensions/bintools/msvc8/bintools.vcproj create mode 100644 extensions/bintools/smsdk_config.h create mode 100644 extensions/bintools/smsdk_ext.cpp create mode 100644 extensions/bintools/smsdk_ext.h create mode 100644 public/extensions/IBinTools.h diff --git a/extensions/bintools/CallMaker.cpp b/extensions/bintools/CallMaker.cpp new file mode 100644 index 00000000..2a966fa9 --- /dev/null +++ b/extensions/bintools/CallMaker.cpp @@ -0,0 +1,52 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod, Copyright (C) 2004-2007 AlliedModders LLC. + * All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be + * used or modified under the Terms and Conditions of its License Agreement, + * which is found in public/licenses/LICENSE.txt. As of this notice, derivative + * works must be licensed under the GNU General Public License (version 2 or + * greater). A copy of the GPL is included under public/licenses/GPL.txt. + * + * To view the latest information, see: http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#include "CallMaker.h" +#include "CallWrapper.h" +#include "jit_call.h" + +ICallWrapper *CallMaker::CreateCall(void *address, + CallConvention cv, + const PassInfo *retInfo, + const PassInfo paramInfo[], + unsigned int numParams) +{ + CallWrapper *pWrapper = new CallWrapper(cv, paramInfo, retInfo, numParams); + pWrapper->m_Addrs[ADDR_CALLEE] = address; + + JIT_Compile(pWrapper, FuncAddr_Direct); + + return pWrapper; +} + +ICallWrapper *CallMaker::CreateVCall(unsigned int vtblIdx, + unsigned int vtblOffs, + unsigned int thisOffs, + const PassInfo *retInfo, + const PassInfo paramInfo[], + unsigned int numParams) +{ + CallWrapper *pWrapper = new CallWrapper(CallConv_ThisCall, paramInfo, retInfo, numParams); + pWrapper->m_VtInfo.thisOffs = thisOffs; + pWrapper->m_VtInfo.vtblIdx = vtblIdx; + pWrapper->m_VtInfo.vtblOffs = vtblOffs; + + JIT_Compile(pWrapper, FuncAddr_VTable); + + return pWrapper; +} \ No newline at end of file diff --git a/extensions/bintools/CallMaker.h b/extensions/bintools/CallMaker.h new file mode 100644 index 00000000..d142a683 --- /dev/null +++ b/extensions/bintools/CallMaker.h @@ -0,0 +1,48 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod, Copyright (C) 2004-2007 AlliedModders LLC. + * All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be + * used or modified under the Terms and Conditions of its License Agreement, + * which is found in public/licenses/LICENSE.txt. As of this notice, derivative + * works must be licensed under the GNU General Public License (version 2 or + * greater). A copy of the GPL is included under public/licenses/GPL.txt. + * + * To view the latest information, see: http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#ifndef _INCLUDE_SOURCEMOD_CALLMAKER_H_ +#define _INCLUDE_SOURCEMOD_CALLMAKER_H_ + +#include + +using namespace SourceMod; + +enum FuncAddrMethod +{ + FuncAddr_Direct, + FuncAddr_VTable +}; + +class CallMaker : public IBinTools +{ +public: //IBinTools + ICallWrapper *CreateCall(void *address, + CallConvention cv, + const PassInfo *retInfo, + const PassInfo paramInfo[], + unsigned int numParams); + ICallWrapper *CreateVCall(unsigned int vtblIdx, + unsigned int vtblOffs, + unsigned int thisOffs, + const PassInfo *retInfo, + const PassInfo paramInfo[], + unsigned int numParams); +}; + +#endif //_INCLUDE_SOURCEMOD_CALLMAKER_H_ diff --git a/extensions/bintools/CallWrapper.cpp b/extensions/bintools/CallWrapper.cpp new file mode 100644 index 00000000..15018160 --- /dev/null +++ b/extensions/bintools/CallWrapper.cpp @@ -0,0 +1,91 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod, Copyright (C) 2004-2007 AlliedModders LLC. + * All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be + * used or modified under the Terms and Conditions of its License Agreement, + * which is found in public/licenses/LICENSE.txt. As of this notice, derivative + * works must be licensed under the GNU General Public License (version 2 or + * greater). A copy of the GPL is included under public/licenses/GPL.txt. + * + * To view the latest information, see: http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#include "extension.h" +#include "CallWrapper.h" + +CallWrapper::CallWrapper(CallConvention cv, const PassInfo *paramInfo, const PassInfo *retInfo, unsigned int numParams) +{ + m_Cv = cv; + + if (numParams) + { + m_Params = new PassEncode[numParams]; + for (size_t i=0; iExecFree(m_Addrs[ADDR_CODEBASE]); +} + +CallConvention CallWrapper::GetCallConvention() +{ + return m_Cv; +} + +const PassEncode *CallWrapper::GetParamInfo(unsigned int num) +{ + return (num+1 > m_NumParams) ? NULL : &m_Params[num]; +} + +const PassInfo *CallWrapper::GetReturnInfo() +{ + return m_RetParam; +} + +unsigned int CallWrapper::GetParamCount() +{ + return m_NumParams; +} + +void CallWrapper::Execute(void *vParamStack, void *retBuffer) +{ + typedef void (*CALL_EXECUTE)(void *, void *); + CALL_EXECUTE fn = (CALL_EXECUTE)m_Addrs[ADDR_CODEBASE]; + fn(vParamStack, retBuffer); +} diff --git a/extensions/bintools/CallWrapper.h b/extensions/bintools/CallWrapper.h new file mode 100644 index 00000000..397ee7f0 --- /dev/null +++ b/extensions/bintools/CallWrapper.h @@ -0,0 +1,58 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod, Copyright (C) 2004-2007 AlliedModders LLC. + * All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be + * used or modified under the Terms and Conditions of its License Agreement, + * which is found in public/licenses/LICENSE.txt. As of this notice, derivative + * works must be licensed under the GNU General Public License (version 2 or + * greater). A copy of the GPL is included under public/licenses/GPL.txt. + * + * To view the latest information, see: http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#ifndef _INCLUDE_SOURCEMOD_CCALLWRAPPER_H_ +#define _INCLUDE_SOURCEMOD_CCALLWRAPPER_H_ + +#include + +using namespace SourceMod; + +#define ADDR_CALLEE 0 +#define ADDR_CODEBASE 1 + +struct VtableInfo +{ + unsigned int vtblIdx; + unsigned int vtblOffs; + unsigned int thisOffs; +}; + +class CallWrapper : public ICallWrapper +{ +public: + CallWrapper(CallConvention cv, const PassInfo *paramInfo, const PassInfo *retInfo, unsigned int numParams); + ~CallWrapper(); +public: //ICallWrapper + CallConvention GetCallConvention(); + const PassEncode *GetParamInfo(unsigned int num); + const PassInfo *GetReturnInfo(); + unsigned int GetParamCount(); + void Execute(void *vParamStack, void *retBuffer); +public: + inline void deleteThis() { delete this; } + void *m_Addrs[4]; + VtableInfo m_VtInfo; +private: + CallConvention m_Cv; + PassEncode *m_Params; + PassInfo *m_RetParam; + unsigned int m_NumParams; +}; + +#endif //_INCLUDE_SOURCEMOD_CCALLWRAPPER_H_ \ No newline at end of file diff --git a/extensions/bintools/Makefile b/extensions/bintools/Makefile new file mode 100644 index 00000000..e65ffeb1 --- /dev/null +++ b/extensions/bintools/Makefile @@ -0,0 +1,87 @@ +#(C)2004-2006 SourceMM Development Team +# Makefile written by David "BAILOPAN" Anderson + +SMSDK = ../.. +SRCDS = ~/srcds +SOURCEMM = ../../../../sourcemm + +##################################### +### EDIT BELOW FOR OTHER PROJECTS ### +##################################### + +PROJECT = sample + +#Uncomment for SourceMM-enabled extensions +#LINK_HL2 = $(HL2LIB)/tier1_i486.a vstdlib_i486.so tier0_i486.so + +OBJECTS = extension.cpp smsdk_ext.cpp + +############################################## +### CONFIGURE ANY OTHER FLAGS/OPTIONS HERE ### +############################################## + +C_OPT_FLAGS = -O3 -funroll-loops -s -pipe -fno-strict-aliasing +C_DEBUG_FLAGS = -g -ggdb3 +CPP_GCC4_FLAGS = -fvisibility=hidden -fvisibility-inlines-hidden +CPP = gcc-4.1 + +HL2PUB = $(HL2SDK)/public +HL2LIB = $(HL2SDK)/linux_sdk +HL2SDK = $(SOURCEMM)/hl2sdk +SMM_TRUNK = $(SOURCEMM)/trunk + +LINK = $(LINK_HL2) -static-libgcc + +INCLUDE = -I. -I.. -I$(HL2PUB) -I$(HL2PUB)/dlls -I$(HL2PUB)/engine -I$(HL2PUB)/tier0 -I$(HL2PUB)/tier1 \ + -I$(HL2PUB)/vstdlib -I$(HL2SDK)/tier1 -I$(SMM_TRUNK) -I$(SMM_TRUNK)/sourcehook -I$(SMM_TRUNK)/sourcemm \ + -I$(SMSDK)/public -I$(SMSDK)/public/sourcepawn -I$(SMSDK)/public/extensions \ + +CFLAGS = -D_LINUX -DNDEBUG -Dstricmp=strcasecmp -D_stricmp=strcasecmp -D_strnicmp=strncasecmp -Dstrnicmp=strncasecmp -D_snprintf=snprintf -D_vsnprintf=vsnprintf -D_alloca=alloca -Dstrcmpi=strcasecmp -Wall -Werror -fPIC -msse -DSOURCEMOD_BUILD -DHAVE_STDINT_H +CPPFLAGS = -Wno-non-virtual-dtor -fno-exceptions -fno-rtti + +################################################ +### DO NOT EDIT BELOW HERE FOR MOST PROJECTS ### +################################################ + +ifeq "$(DEBUG)" "true" + BIN_DIR = Debug + CFLAGS += $(C_DEBUG_FLAGS) +else + BIN_DIR = Release + CFLAGS += $(C_OPT_FLAGS) +endif + + +GCC_VERSION := $(shell $(CPP) -dumpversion >&1 | cut -b1) +ifeq "$(GCC_VERSION)" "4" + CPPFLAGS += $(CPP_GCC4_FLAGS) +endif + +BINARY = $(PROJECT).ext.so + +OBJ_LINUX := $(OBJECTS:%.cpp=$(BIN_DIR)/%.o) + +$(BIN_DIR)/%.o: %.cpp + $(CPP) $(INCLUDE) $(CFLAGS) $(CPPFLAGS) -o $@ -c $< + +all: + mkdir -p $(BIN_DIR) + ln -sf $(SRCDS)/bin/vstdlib_i486.so vstdlib_i486.so + ln -sf $(SRCDS)/bin/tier0_i486.so tier0_i486.so + $(MAKE) extension + rm -rf $(BINARY) + +extension: $(OBJ_LINUX) + $(CPP) $(INCLUDE) $(CFLAGS) $(CPPFLAGS) $(OBJ_LINUX) $(LINK) -shared -ldl -lm -o$(BIN_DIR)/$(BINARY) + +debug: + $(MAKE) all DEBUG=true + +default: all + +clean: + rm -rf Release/*.o + rm -rf Release/$(BINARY) + rm -rf Debug/*.o + rm -rf Debug/$(BINARY) + diff --git a/extensions/bintools/extension.cpp b/extensions/bintools/extension.cpp new file mode 100644 index 00000000..e1786feb --- /dev/null +++ b/extensions/bintools/extension.cpp @@ -0,0 +1,39 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod, Copyright (C) 2004-2007 AlliedModders LLC. + * All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be + * used or modified under the Terms and Conditions of its License Agreement, + * which is found in public/licenses/LICENSE.txt. As of this notice, derivative + * works must be licensed under the GNU General Public License (version 2 or + * greater). A copy of the GPL is included under public/licenses/GPL.txt. + * + * To view the latest information, see: http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#include "extension.h" +#include "CallMaker.h" + +/** + * @file extension.cpp + * @brief Implement extension code here. + */ + +BinTools g_BinTools; /**< Global singleton for your extension's main interface */ +CallMaker g_CallMaker; +ISourcePawnEngine *g_SPEngine; + +SMEXT_LINK(&g_BinTools); + +bool BinTools::SDK_OnLoad(char *error, size_t err_max, bool late) +{ + g_SPEngine = g_pSM->GetScriptingEngine(); + g_pShareSys->AddInterface(myself, &g_CallMaker); + + return true; +} diff --git a/extensions/bintools/extension.h b/extensions/bintools/extension.h new file mode 100644 index 00000000..148e1e16 --- /dev/null +++ b/extensions/bintools/extension.h @@ -0,0 +1,86 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod, Copyright (C) 2004-2007 AlliedModders LLC. + * All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be + * used or modified under the Terms and Conditions of its License Agreement, + * which is found in public/licenses/LICENSE.txt. As of this notice, derivative + * works must be licensed under the GNU General Public License (version 2 or + * greater). A copy of the GPL is included under public/licenses/GPL.txt. + * + * To view the latest information, see: http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#ifndef _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_ +#define _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_ + +/** + * @file extension.h + * @brief Sample extension code header. + */ + + +#include "smsdk_ext.h" + + +/** + * @brief Sample implementation of the SDK Extension. + * Note: Uncomment one of the pre-defined virtual functions in order to use it. + */ +class BinTools : public SDKExtension +{ +public: + /** + * @brief This is called after the initial loading sequence has been processed. + * + * @param error Error message buffer. + * @param err_max Size of error message buffer. + * @param late Whether or not the module was loaded after map load. + * @return True to succeed loading, false to fail. + */ + virtual bool SDK_OnLoad(char *error, size_t err_max, bool late); + + /** + * @brief This is called right before the extension is unloaded. + */ + //virtual void SDK_OnUnload(); + + /** + * @brief This is called once all known extensions have been loaded. + * Note: It is is a good idea to add natives here, if any are provided. + */ + //virtual void SDK_OnAllLoaded(); + + /** + * @brief Called when the pause state is changed. + */ + //virtual void SDK_OnPauseChange(bool paused); + + /** + * @brief this is called when Core wants to know if your extension is working. + * + * @param error Error message buffer. + * @param err_max Size of error message buffer. + * @return True if working, false otherwise. + */ + //virtual void QueryRunning(char *error, size_t maxlength); +public: +#if defined SMEXT_CONF_METAMOD + /** + * Read smext_base.h for documentation on these. + */ + + //virtual bool SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlen, bool late); + //virtual bool SDK_OnMetamodUnload(char *error, size_t err_max); + //virtual bool SDK_OnMetamodPauseChange(bool paused, char *error, size_t err_max); +#endif +}; + +extern ISourcePawnEngine *g_SPEngine; + +#endif //_INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_ diff --git a/extensions/bintools/jit_call.cpp b/extensions/bintools/jit_call.cpp new file mode 100644 index 00000000..f756c75b --- /dev/null +++ b/extensions/bintools/jit_call.cpp @@ -0,0 +1,609 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod, Copyright (C) 2004-2007 AlliedModders LLC. + * All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be + * used or modified under the Terms and Conditions of its License Agreement, + * which is found in public/licenses/LICENSE.txt. As of this notice, derivative + * works must be licensed under the GNU General Public License (version 2 or + * greater). A copy of the GPL is included under public/licenses/GPL.txt. + * + * To view the latest information, see: http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#include +#include "extension.h" +#include +#include +#include "jit_call.h" + +jit_uint32_t g_StackUsage = 0; +jit_uint32_t g_RegDecoder = 0; + +/******************** + * Assembly Helpers * + ********************/ + +inline jit_uint8_t _DecodeRegister3(jit_uint32_t val) +{ + switch (val % 3) + { + case 0: + { + return REG_EAX; + } + case 1: + { + return REG_EDX; + } + case 2: + { + return REG_ECX; + } + } + + /* Should never happen */ + return 0xFF; +} + +/******************** + * Assembly Opcodes * + ********************/ + +inline void Write_Execution_Prologue(JitWriter *jit, bool is_void, bool has_params) +{ + //push ebp + //mov ebp, esp + //if !is_void + // push edi + // mov edi, [ebp+12] + //if has_params + // push ebx + // mov ebx, [ebp+8] + IA32_Push_Reg(jit, REG_EBP); + IA32_Mov_Reg_Rm(jit, REG_EBP, REG_ESP, MOD_REG); + if (!is_void) + { + IA32_Push_Reg(jit, REG_EDI); + IA32_Mov_Reg_Rm_Disp8(jit, REG_EDI, REG_EBP, 12); + } + if (has_params) + { + IA32_Push_Reg(jit, REG_EBX); + IA32_Mov_Reg_Rm_Disp8(jit, REG_EBX, REG_EBP, 8); + } +} + +inline void Write_Function_Epilogue(JitWriter *jit, bool is_void, bool has_params) +{ + //if has_params + // pop ebx + //if !is_void + // pop edi + //mov esp, ebp + //pop ebp + //ret + if (has_params) + { + IA32_Pop_Reg(jit, REG_EBX); + } + if (!is_void) + { + IA32_Pop_Reg(jit, REG_EDI); + } + IA32_Mov_Reg_Rm(jit, REG_ESP, REG_EBP, MOD_REG); + IA32_Pop_Reg(jit, REG_EBP); + IA32_Return(jit); +} + +inline void Write_PushPOD(JitWriter *jit, const PassEncode *pEnc) +{ + jit_uint8_t reg = _DecodeRegister3(g_RegDecoder++); + + if (pEnc->info.flags & PASSFLAG_BYVAL) + { + switch (pEnc->info.size) + { + case 1: + { + //xor reg, reg + //mov reg, BYTE PTR [ebx+] + //push reg + IA32_Xor_Reg_Rm(jit, reg, reg, MOD_REG); + if (pEnc->offset < SCHAR_MAX) + { + IA32_Mov_Reg8_Rm8_Disp8(jit, reg, REG_EBX, (jit_int8_t)pEnc->offset); + } else if (!pEnc->offset) { + IA32_Mov_Reg8_Rm8(jit, reg, REG_EBX, MOD_MEM_REG); + } else { + IA32_Mov_Reg8_Rm8_Disp32(jit, reg, REG_EBX, pEnc->offset); + } + IA32_Push_Reg(jit, reg); + + g_StackUsage += 4; + break; + } + case 2: + { + //xor reg, reg + //mov reg, WORD PTR [ebx+] + //push reg + IA32_Xor_Reg_Rm(jit, reg, reg, MOD_REG); + jit->write_ubyte(IA32_16BIT_PREFIX); + if (pEnc->offset < SCHAR_MAX) + { + IA32_Mov_Reg_Rm_Disp8(jit, reg, REG_EBX, (jit_int8_t)pEnc->offset); + } else if (!pEnc->offset) { + IA32_Mov_Reg_Rm(jit, reg, REG_EBX, MOD_MEM_REG); + } else { + IA32_Mov_Reg_Rm_Disp32(jit, reg, REG_EBX, pEnc->offset); + } + IA32_Push_Reg(jit, reg); + + g_StackUsage += 4; + break; + } + case 4: + { + //mov reg, DWORD PTR [ebx+] + //push reg + if (pEnc->offset < SCHAR_MAX) + { + IA32_Mov_Reg_Rm_Disp8(jit, reg, REG_EBX, (jit_int8_t)pEnc->offset); + } else if (!pEnc->offset) { + IA32_Mov_Reg_Rm(jit, reg, REG_EBX, MOD_MEM_REG); + } else { + IA32_Mov_Reg_Rm_Disp32(jit, reg, REG_EBX, pEnc->offset); + } + IA32_Push_Reg(jit, reg); + + g_StackUsage += 4; + break; + } + case 8: + { + //mov reg, DWORD PTR [ebx++4] + //mov reg2, DWORD PTR [ebx+] + //push reg + //push reg2 + jit_uint8_t reg2 = _DecodeRegister3(g_RegDecoder++); + + if (pEnc->offset+4 < SCHAR_MAX) + { + IA32_Mov_Reg_Rm_Disp8(jit, reg, REG_EBX, (jit_int8_t)(pEnc->offset+4)); + } else { + IA32_Mov_Reg_Rm_Disp32(jit, reg, REG_EBX, pEnc->offset+4); + } + if (pEnc->offset < SCHAR_MAX) + { + IA32_Mov_Reg_Rm_Disp8(jit, reg2, REG_EBX, (jit_int8_t)pEnc->offset); + } else if (!pEnc->offset) { + IA32_Mov_Reg_Rm(jit, reg, REG_EBX, MOD_MEM_REG); + } else { + IA32_Mov_Reg_Rm_Disp32(jit, reg2, REG_EBX, pEnc->offset); + } + IA32_Push_Reg(jit, reg); + IA32_Push_Reg(jit, reg2); + + g_StackUsage += 8; + break; + } + } + } else if (pEnc->info.flags & PASSFLAG_BYREF) { + //lea reg, [ebx+] + //push reg + if (!pEnc->offset) + { + IA32_Push_Reg(jit, REG_EBX); + g_StackUsage += 4; + return; + } + if (pEnc->offset < SCHAR_MAX) + { + IA32_Lea_DispRegImm8(jit, reg, REG_EBX, (jit_int8_t)pEnc->offset); + } else { + IA32_Lea_DispRegImm32(jit, reg, REG_EBX, pEnc->offset); + } + IA32_Push_Reg(jit, reg); + + g_StackUsage += 4; + } +} + +inline void Write_PushFloat(JitWriter *jit, const PassEncode *pEnc) +{ + if (pEnc->info.flags & PASSFLAG_BYVAL) + { + switch (pEnc->info.size) + { + case 4: + { + //fld DWORD PTR [ebx+] + //push reg + //fstp DWORD PTR [esp] + if (pEnc->offset < SCHAR_MAX) + { + IA32_Fld_Mem32_Disp8(jit, REG_EBX, (jit_int8_t)pEnc->offset); + } else { + IA32_Fld_Mem32_Disp32(jit, REG_EBX, pEnc->offset); + } + IA32_Push_Reg(jit, _DecodeRegister3(g_RegDecoder++)); + IA32_Fstp_Mem32(jit, REG_ESP, REG_NOIDX, NOSCALE); + g_StackUsage += 4; + break; + } + case 8: + { + //fld QWORD PTR [ebx+] + //sub esp, 8 + //fstp QWORD PTR [esp] + if (pEnc->offset < SCHAR_MAX) + { + IA32_Fld_Mem64_Disp8(jit, REG_EBX, (jit_int8_t)pEnc->offset); + } else { + IA32_Fld_Mem64_Disp32(jit, REG_EBX, pEnc->offset); + } + IA32_Sub_Rm_Imm8(jit, REG_ESP, 8, MOD_REG); + IA32_Fstp_Mem64(jit, REG_ESP, REG_NOIDX, NOSCALE); + g_StackUsage += 8; + break; + } + } + } else if (pEnc->info.flags & PASSFLAG_BYREF) { + //lea reg, [ebx+] + //push reg + if (!pEnc->offset) + { + IA32_Push_Reg(jit, REG_EBX); + g_StackUsage += 4; + return; + } + + jit_uint8_t reg = _DecodeRegister3(g_RegDecoder++); + if (pEnc->offset < SCHAR_MAX) + { + IA32_Lea_DispRegImm8(jit, reg, REG_EBX, (jit_int8_t)pEnc->offset); + } else { + IA32_Lea_DispRegImm32(jit, reg, REG_EBX, pEnc->offset); + } + IA32_Push_Reg(jit, reg); + + g_StackUsage += 4; + } +} + +inline void Write_PushObject(JitWriter *jit, const PassEncode *pEnc) +{ + if (pEnc->info.flags & PASSFLAG_BYVAL) + { +#ifdef PLATFORM_POSIX + if (pEnc->info.flags & PASSFLAG_ODTOR) + { + goto push_byref; + } +#endif + jit_uint32_t dwords = pEnc->info.size >> 2; + jit_uint32_t bytes = pEnc->info.size & 0x3; + + //sub esp, + //cld + //push edi + //push esi + //lea edi, [esp+8] + //lea esi, [ebx+] + //if dwords + // mov ecx, + // rep movsd + //if bytes + // mov ecx, + // rep movsb + //pop esi + //pop edi + if (pEnc->info.size < SCHAR_MAX) + { + IA32_Sub_Rm_Imm8(jit, REG_ESP, (jit_int8_t)pEnc->info.size, MOD_REG); + } else { + IA32_Sub_Rm_Imm32(jit, REG_ESP, pEnc->info.size, MOD_REG); + } + IA32_Cld(jit); + IA32_Push_Reg(jit, REG_EDI); + IA32_Push_Reg(jit, REG_ESI); + IA32_Lea_Reg_DispRegMultImm8(jit, REG_EDI, REG_NOIDX, REG_ESP, NOSCALE, 8); + if (pEnc->offset < SCHAR_MAX) + { + IA32_Lea_DispRegImm8(jit, REG_ESI, REG_EBX, (jit_int8_t)pEnc->offset); + } else if (!pEnc->offset) { + IA32_Mov_Reg_Rm(jit, REG_ESI, REG_EBX, MOD_REG); + } else { + IA32_Lea_DispRegImm32(jit, REG_ESI, REG_EBX, pEnc->offset); + } + if (dwords) + { + IA32_Mov_Reg_Imm32(jit, REG_ECX, dwords); + IA32_Rep(jit); + IA32_Movsd(jit); + } + if (bytes) + { + IA32_Mov_Reg_Imm32(jit, REG_ECX, bytes); + IA32_Rep(jit); + IA32_Movsb(jit); + } + IA32_Pop_Reg(jit, REG_ESI); + IA32_Pop_Reg(jit, REG_EDI); + + g_StackUsage += pEnc->info.size; + } else if (pEnc->info.flags & PASSFLAG_BYREF) { +#ifdef PLATFORM_POSIX +push_byref: +#endif + if (!pEnc->offset) + { + IA32_Push_Reg(jit, REG_EBX); + g_StackUsage += 4; + return; + } + + //lea reg, [ebx+] + //push reg + jit_uint8_t reg = _DecodeRegister3(g_RegDecoder++); + if (pEnc->offset < SCHAR_MAX) + { + IA32_Lea_DispRegImm8(jit, reg, REG_EBX, (jit_int8_t)pEnc->offset); + } else { + IA32_Lea_DispRegImm32(jit, reg, REG_EBX, pEnc->offset); + } + IA32_Push_Reg(jit, reg); + + g_StackUsage += 4; + } +} + +inline void Write_PushThisPtr(JitWriter *jit) +{ +#ifdef PLATFORM_POSIX + //mov reg, [ebx] + //push reg + jit_uint8_t reg = _DecodeRegister3(g_RegDecoder++); + + IA32_Mov_Reg_Rm(jit, reg, REG_EBX, MOD_MEM_REG); + IA32_Push_Reg(jit, reg); + + g_StackUsage += 4; +#elif defined PLATFORM_WINDOWS + //mov ecx, [ebx] + IA32_Mov_Reg_Rm(jit, REG_ECX, REG_EBX, MOD_MEM_REG); +#endif +} + +inline void Write_PushRetBuffer(JitWriter *jit) +{ + //push edi + IA32_Push_Reg(jit, REG_EDI); +} + +inline void Write_CallFunction(JitWriter *jit, FuncAddrMethod method, CallWrapper *pWrapper) +{ + if (method == FuncAddr_Direct) + { + //call + jitoffs_t call = IA32_Call_Imm32(jit, 0); + IA32_Write_Jump32_Abs(jit, call, pWrapper->m_Addrs[ADDR_CALLEE]); + } else if (method == FuncAddr_VTable) { + //*(this + thisOffs + vtblOffs)[vtblIdx] + //mov edx, [ebx] + //mov eax, [edx++] + //mov edx, [eax+*4] + //call edx + jit_uint32_t total_offs = pWrapper->m_VtInfo.thisOffs + pWrapper->m_VtInfo.vtblOffs; + jit_uint32_t vfunc_pos = pWrapper->m_VtInfo.vtblIdx * 4; + + IA32_Mov_Reg_Rm(jit, REG_EDX, REG_EBX, MOD_MEM_REG); + if (total_offs < SCHAR_MAX) + { + IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, REG_EDX, (jit_int8_t)total_offs); + } else if (!total_offs) { + IA32_Mov_Reg_Rm(jit, REG_EAX, REG_EDX, MOD_MEM_REG); + } else { + IA32_Mov_Reg_Rm_Disp32(jit, REG_EAX, REG_EDX, total_offs); + } + if (vfunc_pos < SCHAR_MAX) + { + IA32_Mov_Reg_Rm_Disp8(jit, REG_EDX, REG_EAX, (jit_int8_t)vfunc_pos); + } else if (!vfunc_pos) { + IA32_Mov_Reg_Rm(jit, REG_EDX, REG_EAX, MOD_MEM_REG); + } else { + IA32_Mov_Reg_Rm_Disp32(jit, REG_EDX, REG_EAX, vfunc_pos); + } + IA32_Call_Reg(jit, REG_EDX); + } +} + +inline void Write_RectifyStack(JitWriter *jit, jit_uint32_t value) +{ + //add esp, + if (value < SCHAR_MAX) + { + IA32_Add_Rm_Imm8(jit, REG_ESP, (jit_int8_t)value, MOD_REG); + } else { + IA32_Add_Rm_Imm32(jit, REG_ESP, value, MOD_REG); + } +} + +inline void Write_MovRet2Buf(JitWriter *jit, const PassInfo *pRet) +{ + if (pRet->type == PassType_Float) + { + switch (pRet->size) + { + case 4: + { + //fstp DWORD PTR [edi] + IA32_Fstp_Mem32(jit, REG_EDI, REG_NOIDX, NOSCALE); + break; + } + case 8: + { + //fstp QWORD PTR [edi] + IA32_Fstp_Mem64(jit, REG_EDI, REG_NOIDX, NOSCALE); + break; + } + } + return; + } + + switch (pRet->size) + { + case 1: + { + //mov BYTE PTR [edi], al + IA32_Mov_Rm8_Reg8(jit, REG_EDI, REG_EAX, MOD_MEM_REG); + break; + } + case 2: + { + //mov WORD PTR [edi], ax + jit->write_ubyte(IA32_16BIT_PREFIX); + IA32_Mov_Rm_Reg(jit, REG_EDI, REG_EAX, MOD_MEM_REG); + break; + } + case 4: + { + //mov DWORD PTR [edi], eax + IA32_Mov_Rm_Reg(jit, REG_EDI, REG_EAX, MOD_MEM_REG); + break; + } + case 8: + { + //mov DWORD PTR [edi], eax + //mov DWORD PTR [edi+4], edx + IA32_Mov_Rm_Reg(jit, REG_EDI, REG_EAX, MOD_MEM_REG); + IA32_Mov_Rm_Reg_Disp8(jit, REG_EDI, REG_EDX, 4); + break; + } + } +} + +/****************************** + * Assembly Compiler Function * + ******************************/ + +void JIT_Compile(CallWrapper *pWrapper, FuncAddrMethod method) +{ + JitWriter writer; + JitWriter *jit = &writer; + + jit_uint32_t CodeSize = 0; + bool Needs_Retbuf = false; + CallConvention Convention = pWrapper->GetCallConvention(); + jit_uint32_t ParamCount = pWrapper->GetParamCount(); + const PassInfo *pRet = pWrapper->GetReturnInfo(); + + writer.outbase = NULL; + writer.outptr = NULL; + +jit_rewind: + /* Write function prologue */ + Write_Execution_Prologue(jit, (pRet) ? false : true, (ParamCount) ? true : false); + + /* Write parameter push code */ + for (jit_int32_t i=ParamCount-1; i>=0; i--) + { + const PassEncode *pEnc = pWrapper->GetParamInfo(i); + switch (pEnc->info.type) + { + case PassType_Basic: + { + Write_PushPOD(jit, pEnc); + break; + } + case PassType_Float: + { + Write_PushFloat(jit, pEnc); + break; + } + case PassType_Object: + { + Write_PushObject(jit, pEnc); + break; + } + } + } + + /* Prepare the this ptr if applicable */ + if (Convention == CallConv_ThisCall) + { + Write_PushThisPtr(jit); + } + + /* Skip the return buffer stuff if this is a void function */ + if (!pRet) + { + goto skip_retbuffer; + } + + if ((pRet->type == PassType_Object) && (pRet->flags & PASSFLAG_BYVAL)) + { +#ifdef PLATFORM_POSIX + Needs_Retbuf = true; +#elif defined PLATFORM_WINDOWS + if ((Convention == CallConv_ThisCall) || + ((Convention == CallConv_Cdecl) && + ((pRet->size > 8) || (pRet->flags & PASSFLAG_ODTOR|PASSFLAG_OCTOR|PASSFLAG_OASSIGNOP)))) + { + Needs_Retbuf = true; + } +#endif + } + + /* Prepare the return buffer in case we are returning objects by value. */ + if (Needs_Retbuf) + { + Write_PushRetBuffer(jit); + } + +skip_retbuffer: + /* Write the calling code */ + Write_CallFunction(jit, method, pWrapper); + + /* Clean up the calling stack */ +#ifdef PLATFORM_WINDOWS + if ((ParamCount || Needs_Retbuf) && (Convention == CallConv_Cdecl)) + { + /* Pop all parameters from the stack + hidden return pointer */ + jit_uint32_t total = (Needs_Retbuf) ? g_StackUsage + sizeof(void *) : g_StackUsage; + Write_RectifyStack(jit, total); +#elif defined PLATFORM_POSIX + if (ParamCount) + { + /* Pop all parameters from the stack */ + Write_RectifyStack(jit, g_StackUsage); +#endif + } + + /* Copy the return type to the return buffer if the function is not void */ + if (pRet && !Needs_Retbuf) + { + Write_MovRet2Buf(jit, pRet); + } + + /* Write Function Epilogue */ + Write_Function_Epilogue(jit, (pRet) ? false : true, (ParamCount) ? true : false); + + if (writer.outbase == NULL) + { + CodeSize = writer.get_outputpos(); + writer.outbase = (jitcode_t)g_SPEngine->ExecAlloc(CodeSize); + writer.outptr = writer.outbase; + pWrapper->m_Addrs[ADDR_CODEBASE] = writer.outbase; + g_StackUsage = 0; + g_RegDecoder = 0; + Needs_Retbuf = false; + goto jit_rewind; + } +} diff --git a/extensions/bintools/jit_call.h b/extensions/bintools/jit_call.h new file mode 100644 index 00000000..5efc8a93 --- /dev/null +++ b/extensions/bintools/jit_call.h @@ -0,0 +1,27 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod, Copyright (C) 2004-2007 AlliedModders LLC. + * All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be + * used or modified under the Terms and Conditions of its License Agreement, + * which is found in public/licenses/LICENSE.txt. As of this notice, derivative + * works must be licensed under the GNU General Public License (version 2 or + * greater). A copy of the GPL is included under public/licenses/GPL.txt. + * + * To view the latest information, see: http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#ifndef _INCLUDE_SOURCEMOD_JIT_CALL_H_ +#define _INCLUDE_SOURCEMOD_JIT_CALL_H_ + +#include "CallMaker.h" +#include "CallWrapper.h" + +void JIT_Compile(CallWrapper *pWrapper, FuncAddrMethod method); + +#endif //_INCLUDE_SOURCEMOD_JIT_CALL_H_ \ No newline at end of file diff --git a/extensions/bintools/msvc8/bintools.sln b/extensions/bintools/msvc8/bintools.sln new file mode 100644 index 00000000..44048bb2 --- /dev/null +++ b/extensions/bintools/msvc8/bintools.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bintools", "bintools.vcproj", "{B3E797CF-4E77-4C9D-B8A8-7589B6902206}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Debug|Win32.ActiveCfg = Debug|Win32 + {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Debug|Win32.Build.0 = Debug|Win32 + {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Release|Win32.ActiveCfg = Release|Win32 + {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/extensions/bintools/msvc8/bintools.vcproj b/extensions/bintools/msvc8/bintools.vcproj new file mode 100644 index 00000000..18fece5e --- /dev/null +++ b/extensions/bintools/msvc8/bintools.vcproj @@ -0,0 +1,253 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/extensions/bintools/smsdk_config.h b/extensions/bintools/smsdk_config.h new file mode 100644 index 00000000..dfc8a925 --- /dev/null +++ b/extensions/bintools/smsdk_config.h @@ -0,0 +1,33 @@ +// vim: set ts=4 : +#ifndef _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_ +#define _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_ + +/** + * @file smsdk_config.h + * @brief Contains macros for configuring basic extension information. + */ + +/* Basic information exposed publically */ +#define SMEXT_CONF_NAME "Sample Extension" +#define SMEXT_CONF_DESCRIPTION "Sample extension to help developers" +#define SMEXT_CONF_VERSION "0.0.0.0" +#define SMEXT_CONF_AUTHOR "AlliedModders" +#define SMEXT_CONF_URL "http://www.sourcemod.net/" +#define SMEXT_CONF_LOGTAG "SAMPLE" +#define SMEXT_CONF_LICENSE "GPL" +#define SMEXT_CONF_DATESTRING __DATE__ + +/** + * @brief Exposes plugin's main interface. + */ +#define SMEXT_LINK(name) SDKExtension *g_pExtensionIface = name; + +/** + * @brief Sets whether or not this plugin required Metamod. + * NOTE: Uncomment to enable, comment to disable. + * NOTE: This is enabled automatically if a Metamod build is chosen in + * the Visual Studio project. + */ +//#define SMEXT_CONF_METAMOD + +#endif //_INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_ diff --git a/extensions/bintools/smsdk_ext.cpp b/extensions/bintools/smsdk_ext.cpp new file mode 100644 index 00000000..ed2de4ae --- /dev/null +++ b/extensions/bintools/smsdk_ext.cpp @@ -0,0 +1,333 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod, Copyright (C) 2004-2007 AlliedModders LLC. + * All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be used + * or modified under the Terms and Conditions of its License Agreement, which is found + * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins + * may change at any time. To view the latest information, see: + * http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#include +#include +#include "smsdk_ext.h" + +/** + * @file smsdk_ext.cpp + * @brief Contains wrappers for making Extensions easier to write. + */ + +IShareSys *g_pShareSys = NULL; /**< Share system */ +IExtension *myself = NULL; /**< Ourself */ +IHandleSys *g_pHandleSys = NULL; /**< Handle system */ +ISourceMod *g_pSM = NULL; /**< SourceMod helpers */ +IForwardManager *g_pForwards = NULL; /**< Forward system */ + +/** Exports the main interface */ +PLATFORM_EXTERN_C IExtensionInterface *GetSMExtAPI() +{ + return g_pExtensionIface; +} + +SDKExtension::SDKExtension() +{ +#if defined SMEXT_CONF_METAMOD + m_SourceMMLoaded = false; + m_WeAreUnloaded = false; + m_WeGotPauseChange = false; +#endif +} + +bool SDKExtension::OnExtensionLoad(IExtension *me, IShareSys *sys, char *error, size_t err_max, bool late) +{ + g_pShareSys = sys; + myself = me; + +#if defined SMEXT_CONF_METAMOD + m_WeAreUnloaded = true; + + if (!m_SourceMMLoaded) + { + if (error) + { + snprintf(error, err_max, "Metamod attach failed"); + } + return false; + } +#endif + + SM_GET_IFACE(HANDLESYSTEM, g_pHandleSys); + SM_GET_IFACE(SOURCEMOD, g_pSM); + SM_GET_IFACE(FORWARDMANAGER, g_pForwards); + + if (SDK_OnLoad(error, err_max, late)) + { +#if defined SMEXT_CONF_METAMOD + m_WeAreUnloaded = true; +#endif + return true; + } + + return false; +} + +bool SDKExtension::IsMetamodExtension() +{ +#if defined SMEXT_CONF_METAMOD + return true; +#else + return false; +#endif +} + +void SDKExtension::OnExtensionPauseChange(bool state) +{ +#if defined SMEXT_CONF_METAMOD + m_WeGotPauseChange = true; +#endif + SDK_OnPauseChange(state); +} + +void SDKExtension::OnExtensionsAllLoaded() +{ + SDK_OnAllLoaded(); +} + +void SDKExtension::OnExtensionUnload() +{ +#if defined SMEXT_CONF_METAMOD + m_WeAreUnloaded = true; +#endif + SDK_OnUnload(); +} + +const char *SDKExtension::GetExtensionAuthor() +{ + return SMEXT_CONF_AUTHOR; +} + +const char *SDKExtension::GetExtensionDateString() +{ + return SMEXT_CONF_DATESTRING; +} + +const char *SDKExtension::GetExtensionDescription() +{ + return SMEXT_CONF_DESCRIPTION; +} + +const char *SDKExtension::GetExtensionVerString() +{ + return SMEXT_CONF_VERSION; +} + +const char *SDKExtension::GetExtensionName() +{ + return SMEXT_CONF_NAME; +} + +const char *SDKExtension::GetExtensionTag() +{ + return SMEXT_CONF_LOGTAG; +} + +const char *SDKExtension::GetExtensionURL() +{ + return SMEXT_CONF_URL; +} + +bool SDKExtension::SDK_OnLoad(char *error, size_t err_max, bool late) +{ + return true; +} + +void SDKExtension::SDK_OnUnload() +{ +} + +void SDKExtension::SDK_OnPauseChange(bool paused) +{ +} + +void SDKExtension::SDK_OnAllLoaded() +{ +} + +#if defined SMEXT_CONF_METAMOD + +PluginId g_PLID = 0; /**< Metamod plugin ID */ +ISmmPlugin *g_PLAPI = NULL; /**< Metamod plugin API */ +SourceHook::ISourceHook *g_SHPtr = NULL; /**< SourceHook pointer */ +ISmmAPI *g_SMAPI = NULL; /**< SourceMM API pointer */ + +IVEngineServer *engine = NULL; /**< IVEngineServer pointer */ +IServerGameDLL *gamedll = NULL; /**< IServerGameDLL pointer */ + +/** Exposes the extension to Metamod */ +SMM_API void *PL_EXPOSURE(const char *name, int *code) +{ + if (name && !strcmp(name, PLAPI_NAME)) + { + if (code) + { + *code = IFACE_OK; + } + return static_cast(g_pExtensionIface); + } + + if (code) + { + *code = IFACE_FAILED; + } + + return NULL; +} + +bool SDKExtension::Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen, bool late) +{ + PLUGIN_SAVEVARS(); + + GET_V_IFACE_ANY(serverFactory, gamedll, IServerGameDLL, INTERFACEVERSION_SERVERGAMEDLL); + GET_V_IFACE_CURRENT(engineFactory, engine, IVEngineServer, INTERFACEVERSION_VENGINESERVER); + + m_SourceMMLoaded = true; + + return SDK_OnMetamodLoad(ismm, error, maxlen, late); +} + +bool SDKExtension::Unload(char *error, size_t maxlen) +{ + if (!m_WeAreUnloaded) + { + if (error) + { + snprintf(error, maxlen, "This extension must be unloaded by SourceMod."); + } + return false; + } + + return SDK_OnMetamodUnload(error, maxlen); +} + +bool SDKExtension::Pause(char *error, size_t maxlen) +{ + if (!m_WeGotPauseChange) + { + if (error) + { + snprintf(error, maxlen, "This extension must be paused by SourceMod."); + } + return false; + } + + m_WeGotPauseChange = false; + + return SDK_OnMetamodPauseChange(true, error, maxlen); +} + +bool SDKExtension::Unpause(char *error, size_t maxlen) +{ + if (!m_WeGotPauseChange) + { + if (error) + { + snprintf(error, maxlen, "This extension must be unpaused by SourceMod."); + } + return false; + } + + m_WeGotPauseChange = false; + + return SDK_OnMetamodPauseChange(false, error, maxlen); +} + +const char *SDKExtension::GetAuthor() +{ + return GetExtensionAuthor(); +} + +const char *SDKExtension::GetDate() +{ + return GetExtensionDateString(); +} + +const char *SDKExtension::GetDescription() +{ + return GetExtensionDescription(); +} + +const char *SDKExtension::GetLicense() +{ + return SMEXT_CONF_LICENSE; +} + +const char *SDKExtension::GetLogTag() +{ + return GetExtensionTag(); +} + +const char *SDKExtension::GetName() +{ + return GetExtensionName(); +} + +const char *SDKExtension::GetURL() +{ + return GetExtensionURL(); +} + +const char *SDKExtension::GetVersion() +{ + return GetExtensionVerString(); +} + +bool SDKExtension::SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlen, bool late) +{ + return true; +} + +bool SDKExtension::SDK_OnMetamodUnload(char *error, size_t err_max) +{ + return true; +} + +bool SDKExtension::SDK_OnMetamodPauseChange(bool paused, char *error, size_t err_max) +{ + return true; +} + +#endif + +/* Overload a few things to prevent libstdc++ linking */ +#if defined __linux__ +extern "C" void __cxa_pure_virtual(void) +{ +} + +void *operator new(size_t size) +{ + return malloc(size); +} + +void *operator new[](size_t size) +{ + return malloc(size); +} + +void operator delete(void *ptr) +{ + free(ptr); +} + +void operator delete[](void * ptr) +{ + free(ptr); +} +#endif + diff --git a/extensions/bintools/smsdk_ext.h b/extensions/bintools/smsdk_ext.h new file mode 100644 index 00000000..d763460e --- /dev/null +++ b/extensions/bintools/smsdk_ext.h @@ -0,0 +1,196 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod, Copyright (C) 2004-2007 AlliedModders LLC. + * All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be used + * or modified under the Terms and Conditions of its License Agreement, which is found + * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins + * may change at any time. To view the latest information, see: + * http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#ifndef _INCLUDE_SOURCEMOD_EXTENSION_BASESDK_H_ +#define _INCLUDE_SOURCEMOD_EXTENSION_BASESDK_H_ + +/** + * @file smsdk_ext.h + * @brief Contains wrappers for making Extensions easier to write. + */ + +#include "smsdk_config.h" +#include +#include +#include +#include +#include +#include + +#if defined SMEXT_CONF_METAMOD +#include +#include +#endif + +using namespace SourceMod; +using namespace SourcePawn; + +class SDKExtension : +#if defined SMEXT_CONF_METAMOD + public ISmmPlugin, +#endif + public IExtensionInterface +{ +public: + /** Constructor */ + SDKExtension(); +public: + /** + * @brief This is called after the initial loading sequence has been processed. + * + * @param error Error message buffer. + * @param err_max Size of error message buffer. + * @param late Whether or not the module was loaded after map load. + * @return True to succeed loading, false to fail. + */ + virtual bool SDK_OnLoad(char *error, size_t err_max, bool late); + + /** + * @brief This is called right before the extension is unloaded. + */ + virtual void SDK_OnUnload(); + + /** + * @brief This is called once all known extensions have been loaded. + */ + virtual void SDK_OnAllLoaded(); + + /** + * @brief Called when the pause state is changed. + */ + virtual void SDK_OnPauseChange(bool paused); + +#if defined SMEXT_CONF_METAMOD + /** + * @brief Called when Metamod is attached, before the extension version is called. + * + * @param error Error buffer. + * @param err_max Maximum size of error buffer. + * @param late Whether or not Metamod considers this a late load. + * @return True to succeed, false to fail. + */ + virtual bool SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlen, bool late); + + /** + * @brief Called when Metamod is detaching, after the extension version is called. + * NOTE: By default this is blocked unless sent from SourceMod. + * + * @param error Error buffer. + * @param err_max Maximum size of error buffer. + * @return True to succeed, false to fail. + */ + virtual bool SDK_OnMetamodUnload(char *error, size_t err_max); + + /** + * @brief Called when Metamod's pause state is changing. + * NOTE: By default this is blocked unless sent from SourceMod. + * + * @param paused Pause state being set. + * @param error Error buffer. + * @param err_max Maximum size of error buffer. + * @return True to succeed, false to fail. + */ + virtual bool SDK_OnMetamodPauseChange(bool paused, char *error, size_t err_max); +#endif + +public: //IExtensionInterface + virtual bool OnExtensionLoad(IExtension *me, IShareSys *sys, char *error, size_t err_max, bool late); + virtual void OnExtensionUnload(); + virtual void OnExtensionsAllLoaded(); + + /** Returns whether or not this is a Metamod-based extension */ + virtual bool IsMetamodExtension(); + + /** + * @brief Called when the pause state changes. + * + * @param state True if being paused, false if being unpaused. + */ + virtual void OnExtensionPauseChange(bool state); + + /** Returns name */ + virtual const char *GetExtensionName(); + /** Returns URL */ + virtual const char *GetExtensionURL(); + /** Returns log tag */ + virtual const char *GetExtensionTag(); + /** Returns author */ + virtual const char *GetExtensionAuthor(); + /** Returns version string */ + virtual const char *GetExtensionVerString(); + /** Returns description string */ + virtual const char *GetExtensionDescription(); + /** Returns date string */ + virtual const char *GetExtensionDateString(); +#if defined SMEXT_CONF_METAMOD +public: //ISmmPlugin + /** Called when the extension is attached to Metamod. */ + virtual bool Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlength, bool late); + /** Returns the author to MM */ + virtual const char *GetAuthor(); + /** Returns the name to MM */ + virtual const char *GetName(); + /** Returns the description to MM */ + virtual const char *GetDescription(); + /** Returns the URL to MM */ + virtual const char *GetURL(); + /** Returns the license to MM */ + virtual const char *GetLicense(); + /** Returns the version string to MM */ + virtual const char *GetVersion(); + /** Returns the date string to MM */ + virtual const char *GetDate(); + /** Returns the logtag to MM */ + virtual const char *GetLogTag(); + /** Called on unload */ + virtual bool Unload(char *error, size_t maxlen); + /** Called on pause */ + virtual bool Pause(char *error, size_t maxlen); + /** Called on unpause */ + virtual bool Unpause(char *error, size_t maxlen); +private: + bool m_SourceMMLoaded; + bool m_WeAreUnloaded; + bool m_WeGotPauseChange; +#endif +}; + +extern SDKExtension *g_pExtensionIface; + +extern IShareSys *g_pShareSys; +extern IExtension *myself; +extern IHandleSys *g_pHandleSys; +extern ISourceMod *g_pSM; +extern IForwardManager *g_pForwards; + +#if defined SMEXT_CONF_METAMOD +PLUGIN_GLOBALVARS(); +extern IVEngineServer *engine; +extern IServerGameDLL *gamedll; +#endif + +/** Creates a SourceMod interface macro pair */ +#define SM_MKIFACE(name) SMINTERFACE_##name##_NAME, SMINTERFACE_##name##_VERSION +/** Automates retrieving SourceMod interfaces */ +#define SM_GET_IFACE(prefix,addr) \ + if (!g_pShareSys->RequestInterface(SM_MKIFACE(prefix), myself, (SMInterface **)&addr)) { \ + if (error) { \ + snprintf(error, err_max, "Could not find interface: %s", SMINTERFACE_##prefix##_NAME); \ + } \ + return false; \ + } + +#endif //_INCLUDE_SOURCEMOD_EXTENSION_BASESDK_H_ diff --git a/public/extensions/IBinTools.h b/public/extensions/IBinTools.h new file mode 100644 index 00000000..a18affea --- /dev/null +++ b/public/extensions/IBinTools.h @@ -0,0 +1,178 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod, Copyright (C) 2004-2007 AlliedModders LLC. + * All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be + * used or modified under the Terms and Conditions of its License Agreement, + * which is found in public/licenses/LICENSE.txt. As of this notice, derivative + * works must be licensed under the GNU General Public License (version 2 or + * greater). A copy of the GPL is included under public/licenses/GPL.txt. + * + * To view the latest information, see: http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#ifndef _INCLUDE_SMEXT_BINTOOLS_H_ +#define _INCLUDE_SMEXT_BINTOOLS_H_ + +#include + +#define SMINTERFACE_BINTOOLS_NAME "IBinTools" +#define SMINTERFACE_BINTOOLS_VERSION 1 + +/** + * @brief Function calling encoding utilities + * @file IBinTools.h + */ + +namespace SourceMod +{ + /** + * @brief Supported calling conventions + */ + enum CallConvention + { + CallConv_ThisCall, /**< This call (object pointer required) */ + CallConv_Cdecl, /**< Standard C call */ + }; + + /** + * @brief Describes how a parameter should be passed + */ + enum PassType + { + PassType_Basic, /**< Plain old register data (pointers, integers) */ + PassType_Float, /**< Floating point data */ + PassType_Object, /**< Object or structure */ + }; + + #define PASSFLAG_BYVAL (1<<0) /**< Passing by value */ + #define PASSFLAG_BYREF (1<<1) /**< Passing by reference */ + #define PASSFLAG_ODTOR (1<<2) /**< Object has a destructor */ + #define PASSFLAG_OCTOR (1<<3) /**< Object has a constructor */ + #define PASSFLAG_OASSIGNOP (1<<4) /**< Object has an assignment operator */ + + /** + * @brief Parameter passing information + */ + struct PassInfo + { + PassType type; /**< PassType value */ + unsigned int flags; /**< Pass/return flags */ + size_t size; /**< Size of the data being passed */ + }; + + /** + * @brief Parameter encoding information + */ + struct PassEncode + { + PassInfo info; /**< Parameter information */ + size_t offset; /**< Offset into the virtual stack */ + }; + + /** + * @brief Wraps a C/C++ call. + */ + class ICallWrapper + { + public: + /** + * @brief Returns the calling convention. + * + * @return CallConvention value. + */ + virtual CallConvention GetCallConvention() =0; + + /** + * @brief Returns parameter info. + * + * @param num Parameter number to get (starting from 0). + * @return A PassInfo pointer. + */ + virtual const PassEncode *GetParamInfo(unsigned int num) =0; + + /** + * @brief Returns return type info. + * + * @return A PassInfo pointer. + */ + virtual const PassInfo *GetReturnInfo() =0; + + /** + * @brief Returns the number of parameters. + */ + virtual unsigned int GetParamCount() =0; + + /** + * @brief Execute the contained function. + */ + virtual void Execute(void *vParamStack, void *retBuffer) =0; + }; + + /** + * @brief Binary tools interface. + */ + class IBinTools : public SMInterface + { + public: + virtual const char *GetInterfaceName() + { + return SMINTERFACE_BINTOOLS_NAME; + } + virtual unsigned int GetInterfaceVersion() + { + return SMINTERFACE_BINTOOLS_VERSION; + } + public: + /** + * @brief Creates a call decoder. + * + * Note: CallConv_ThisCall requires an implicit first parameter + * of PassType_Basic / PASSFLAG_BYVAL / sizeof(void *). However, + * this should only be given to the Execute() function, and never + * listed in the paramInfo array. + * + * @param address Address to use as a call. + * @param cv Calling convention. + * @param retInfo Return type information, or NULL for void. + * @param paramInfo Array of parameters. + * @param numParams Number of parameters in the array. + * @return A new ICallWrapper function. + */ + virtual ICallWrapper *CreateCall(void *address, + CallConvention cv, + const PassInfo *retInfo, + const PassInfo paramInfo[], + unsigned int numParams) =0; + + /** + * @brief Creates a vtable call decoder. + * + * Note: CallConv_ThisCall requires an implicit first parameter + * of PassType_Basic / PASSFLAG_BYVAL / sizeof(void *). However, + * this should only be given to the Execute() function, and never + * listed in the paramInfo array. + * + * @param vtblIdx Index into the virtual table. + * @param vtblOffs Offset of the virtual table. + * @param thisOffs Offset of the this pointer of the virtual table. + * @param retInfo Return type information, or NULL for void. + * @param paramInfo Array of parameters. + * @param numParams Number of parameters in the array. + * @return A new ICallWrapper function. + */ + virtual ICallWrapper *CreateVCall(unsigned int vtblIdx, + unsigned int vtblOffs, + unsigned int thisOffs, + const PassInfo *retInfo, + const PassInfo paramInfo[], + unsigned int numParams) =0; + }; +} + +#endif //_INCLUDE_SMEXT_BINTOOLS_H_ diff --git a/public/jit/x86/x86_macros.h b/public/jit/x86/x86_macros.h index 0f020b32..7f307a8d 100644 --- a/public/jit/x86/x86_macros.h +++ b/public/jit/x86/x86_macros.h @@ -92,6 +92,8 @@ #define IA32_MOV_RM8_REG 0x88 // encoding is /r #define IA32_MOV_RM_REG 0x89 // encoding is /r #define IA32_MOV_REG_MEM 0x8B // encoding is /r +#define IA32_MOV_REG8_RM8 0x8A // encoding is /r +#define IA32_MOV_RM8_REG8 0x88 // encoding is /r #define IA32_MOV_RM_IMM32 0xC7 // encoding is /0 #define IA32_CMP_RM_IMM32 0x81 // encoding is /7 #define IA32_CMP_RM_IMM8 0x83 // encoding is /7 @@ -149,6 +151,10 @@ #define IA32_POPAD 0x61 // no extra encoding #define IA32_NOP 0x90 // no extra encoding #define IA32_INT3 0xCC // no extra encoding +#define IA32_FSTP_MEM32 0xD9 // encoding is /3 +#define IA32_FSTP_MEM64 0xDD // encoding is /3 +#define IA32_FLD_MEM32 0xD9 // encoding is /0 +#define IA32_FLD_MEM64 0xDD // encoding is /0 inline jit_uint8_t ia32_modrm(jit_uint8_t mode, jit_uint8_t reg, jit_uint8_t rm) { @@ -629,6 +635,19 @@ inline void IA32_Lea_Reg_DispRegMultImm8(JitWriter *jit, jit->write_byte(val); } +inline void IA32_Lea_Reg_DispRegMultImm32(JitWriter *jit, + jit_uint8_t dest, + jit_uint8_t src_base, + jit_uint8_t src_index, + jit_uint8_t scale, + jit_int32_t val) +{ + jit->write_ubyte(IA32_LEA_REG_MEM); + jit->write_ubyte(ia32_modrm(MOD_DISP32, dest, REG_SIB)); + jit->write_ubyte(ia32_sib(scale, src_index, src_base)); + jit->write_int32(val); +} + inline void IA32_Lea_Reg_RegMultImm32(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src_index, @@ -716,6 +735,12 @@ inline void IA32_Mov_Reg_Rm(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, j jit->write_ubyte(ia32_modrm(mode, dest, src)); } +inline void IA32_Mov_Reg8_Rm8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode) +{ + jit->write_ubyte(IA32_MOV_REG8_RM8); + jit->write_ubyte(ia32_modrm(mode, dest, src)); +} + inline void IA32_Mov_Reg_Rm_Disp8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int8_t disp) { jit->write_ubyte(IA32_MOV_REG_MEM); @@ -723,6 +748,13 @@ inline void IA32_Mov_Reg_Rm_Disp8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t jit->write_byte(disp); } +inline void IA32_Mov_Reg8_Rm8_Disp8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int8_t disp) +{ + jit->write_ubyte(IA32_MOV_REG8_RM8); + jit->write_ubyte(ia32_modrm(MOD_DISP8, dest, src)); + jit->write_byte(disp); +} + inline void IA32_Mov_Reg_Esp_Disp8(JitWriter *jit, jit_uint8_t dest, jit_int8_t disp) { jit->write_ubyte(IA32_MOV_REG_MEM); @@ -738,6 +770,13 @@ inline void IA32_Mov_Reg_Rm_Disp32(JitWriter *jit, jit_uint8_t dest, jit_uint8_t jit->write_int32(disp); } +inline void IA32_Mov_Reg8_Rm8_Disp32(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int32_t disp) +{ + jit->write_ubyte(IA32_MOV_REG8_RM8); + jit->write_ubyte(ia32_modrm(MOD_DISP32, dest, src)); + jit->write_int32(disp); +} + inline void IA32_Mov_Reg_Rm_Disp_Reg(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src_base, @@ -784,6 +823,12 @@ inline void IA32_Mov_Rm_Reg(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, j jit->write_ubyte(ia32_modrm(mode, src, dest)); } +inline void IA32_Mov_Rm8_Reg8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode) +{ + jit->write_ubyte(IA32_MOV_RM8_REG8); + jit->write_ubyte(ia32_modrm(mode, src, dest)); +} + inline void IA32_Mov_Rm_Reg_Disp8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int8_t disp) { jit->write_ubyte(IA32_MOV_RM_REG); @@ -890,6 +935,52 @@ inline void IA32_Mov_RmEBP_Imm32_Disp_Reg(JitWriter *jit, jit->write_int32(val); } +/** +* Floating Point Instructions +*/ + +inline void IA32_Fstp_Mem32(JitWriter *jit, jit_uint8_t dest_base, jit_uint8_t dest_index, jit_uint8_t dest_scale) +{ + jit->write_ubyte(IA32_FSTP_MEM32); + jit->write_ubyte(ia32_modrm(MOD_MEM_REG, 3, REG_SIB)); + jit->write_ubyte(ia32_sib(dest_scale, dest_index, dest_base)); +} + +inline void IA32_Fstp_Mem64(JitWriter *jit, jit_uint8_t dest_base, jit_uint8_t dest_index, jit_uint8_t dest_scale) +{ + jit->write_ubyte(IA32_FSTP_MEM64); + jit->write_ubyte(ia32_modrm(MOD_MEM_REG, 3, REG_SIB)); + jit->write_ubyte(ia32_sib(dest_scale, dest_index, dest_base)); +} + +inline void IA32_Fld_Mem32_Disp8(JitWriter *jit, jit_uint8_t dest, jit_int8_t val) +{ + jit->write_ubyte(IA32_FLD_MEM32); + jit->write_ubyte(ia32_modrm(MOD_DISP8, 0, dest)); + jit->write_byte(val); +} + +inline void IA32_Fld_Mem64_Disp8(JitWriter *jit, jit_uint8_t dest, jit_int8_t val) +{ + jit->write_ubyte(IA32_FLD_MEM64); + jit->write_ubyte(ia32_modrm(MOD_DISP8, 0, dest)); + jit->write_byte(val); +} + +inline void IA32_Fld_Mem32_Disp32(JitWriter *jit, jit_uint8_t dest, jit_int32_t val) +{ + jit->write_ubyte(IA32_FLD_MEM32); + jit->write_ubyte(ia32_modrm(MOD_DISP32, 0, dest)); + jit->write_int32(val); +} + +inline void IA32_Fld_Mem64_Disp32(JitWriter *jit, jit_uint8_t dest, jit_int32_t val) +{ + jit->write_ubyte(IA32_FLD_MEM64); + jit->write_ubyte(ia32_modrm(MOD_DISP32, 0, dest)); + jit->write_int32(val); +} + /** * Branching/Jumping */