From abfca025d576e2f54e461a260be7714bcac234db Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sun, 31 Jul 2005 20:11:58 +0000 Subject: [PATCH] Committed new register_native system --- amxmodx/CPlugin.cpp | 53 +++++ amxmodx/CPlugin.h | 7 +- amxmodx/CStack.h | 101 +++++++++ amxmodx/JIT/natives-x86.o | Bin 0 -> 1184 bytes amxmodx/JIT/natives-x86.obj | Bin 0 -> 823 bytes amxmodx/amx.cpp | 10 +- amxmodx/amx.h | 1 + amxmodx/meta_api.cpp | 3 + amxmodx/modules.cpp | 42 +++- amxmodx/modules.h | 1 + amxmodx/msvc/amxmodx_mm.vcproj | 11 +- amxmodx/natives-amd64.asm | 85 +++++++ amxmodx/natives-x86.asm | 14 +- amxmodx/natives.cpp | 397 +++++++++++++++++++++++++++++++++ amxmodx/natives.h | 39 ++++ 15 files changed, 745 insertions(+), 19 deletions(-) create mode 100755 amxmodx/CStack.h create mode 100755 amxmodx/JIT/natives-x86.o create mode 100755 amxmodx/JIT/natives-x86.obj create mode 100755 amxmodx/natives-amd64.asm create mode 100755 amxmodx/natives.cpp create mode 100755 amxmodx/natives.h diff --git a/amxmodx/CPlugin.cpp b/amxmodx/CPlugin.cpp index 4f29b639..b1aae408 100755 --- a/amxmodx/CPlugin.cpp +++ b/amxmodx/CPlugin.cpp @@ -34,6 +34,9 @@ #include "CForward.h" #include "CFile.h" #include "amx.h" +#include "natives.h" + +extern const char *no_function; CPluginMngr::CPlugin* CPluginMngr::loadPlugin(const char* path, const char* name, char* error, int debug) { CPlugin** a = &head; @@ -49,6 +52,25 @@ void CPluginMngr::unloadPlugin( CPlugin** a ) { --pCounter; } +void CPluginMngr::Finalize() +{ + if (m_Finalized) + return; + pNatives = BuildNativeTable(); + + CPlugin *a = head; + while (a) + { + if (a->getStatusCode() == ps_running) + { + amx_Register(a->getAMX(), pNatives, -1); + a->Finalize(); + } + a=a->next; + } + m_Finalized = true; +} + int CPluginMngr::loadPluginsFromFile( const char* filename ) { char file[256]; @@ -102,6 +124,12 @@ void CPluginMngr::clear() { CPlugin**a = &head; while ( *a ) unloadPlugin(a); + m_Finalized = false; + if (pNatives) + { + delete [] pNatives; + pNatives = NULL; + } } CPluginMngr::CPlugin* CPluginMngr::findPluginFast(AMX *amx) @@ -191,6 +219,31 @@ CPluginMngr::CPlugin::~CPlugin( ) unload_amxscript( &amx, &code ); } +void CPluginMngr::CPlugin::Finalize() +{ + char buffer[128]; + + int old_status = status; + if (CheckModules(&amx, buffer)) + { + if ( amx_Register(&amx, core_Natives, -1) != AMX_ERR_NONE ) + { + status = ps_bad_load; + sprintf(buffer, "Plugin uses an unknown function (name \"%s\") - check your modules.ini.", no_function); + errorMsg.assign(buffer); + amx.error = AMX_ERR_NOTFOUND; + } + } else { + status = ps_bad_load; + errorMsg.assign(buffer); + amx.error = AMX_ERR_NOTFOUND; + } + if (old_status != status) + { + AMXXLOG_Log("[AMXX] Plugin \"%s\" failed to load: %s", name.c_str(), errorMsg.c_str()); + } +} + void CPluginMngr::CPlugin::pauseFunction( int id ) { if (isValid()){ paused_fun |= (1< +class CStack +{ +public: + struct CStackItem + { + public: + T item; + CStackItem *prev; + }; +public: + CStack() + { + mSize = 0; + mStack = NULL; + } + ~CStack() + { + CStackItem *p, *t; + p = mStack; + while (p) + { + t = p->prev; + delete p; + p = t; + } + mStack = NULL; + } + bool empty() + { + return (mSize==0); + } + + void push(const T & v) + { + CStackItem *p = new CStackItem; + p->item = v; + p->prev = mStack; + mStack = p; + mSize++; + } + + void pop() + { + CStackItem *p = mStack; + mStack = p->prev; + delete p; + mSize--; + } + + T & top() + { + return mStack->item; + } + + size_t size() + { + return mSize; + } +private: + CStackItem *mStack; + size_t mSize; +}; + +#endif //_INCLUDE_CQUEUE_H + diff --git a/amxmodx/JIT/natives-x86.o b/amxmodx/JIT/natives-x86.o new file mode 100755 index 0000000000000000000000000000000000000000..221831c8c879c2431554548ea22971a0c0f8b8e5 GIT binary patch literal 1184 zcmcgrO-mb56uqO-q>zOQ-LwlsSEbM)P!Xk4j5k}en3DP$T{p``Glb^Agl{}5F+g)QLTpb%}Rg)SId@%`+8Hg|-bF1vS!b9U1{h$&!o9GVR2qmwG zy~wPhZ$tImS&Px{mhS2Qj~i5kfgfyC1|6e$r6}Ie7xXI{|An5PYg7ges}?u}|7Z_4 z!AInb^{F2I23(!b`uiSU2Uq8_e$m6pbAr;o@SlehzW-?iO cA+v1ZA9kz#edF7DjFAD%O5Bn7N#eQ08&R6U{Qv*} literal 0 HcmV?d00001 diff --git a/amxmodx/JIT/natives-x86.obj b/amxmodx/JIT/natives-x86.obj new file mode 100755 index 0000000000000000000000000000000000000000..9e8fde4b9a1b97ebc203a425007f1cae5060b111 GIT binary patch literal 823 zcmeZaWMmNg^Tx@Jk%2*w0Rr?&QY%WJY!Gz}h;4wF38)4H*nn7pAs`{N^J%v$$KrS( zcLzu+_ApQ+JgmExW1lsUyHg5C{Q0~D$ZtN*((TIA$sQMvP`INa%tYvaDbN2>j)4E7 zAVZpu@PLij0n!+I7)UVC!3uVuHB3Ov#vl!6`M_COa8@0hwI0sWOUukj1@b`P-+u;% zbjG~IlFYKyV%-W0Grh#(T%b5|Xo5nCnGqD8pfE%Ly~L#A{G3v7p#KM&!wi;Ufhqv$ z0=bZZK?qDTFd#$}p`r*8eGCyhpa>{J5NbgFLluce5`oyB4-^6E1nGi^v;bM5C?eC4 zL?A9)fg!RRC<2OIh&jiBti;@kig=gGyhP8u%o2upR4$z7o0y%7BnjriCEZH%l942_ zaDz({i;xZX%`Z#!PfIIKMHU3A literal 0 HcmV?d00001 diff --git a/amxmodx/amx.cpp b/amxmodx/amx.cpp index b7f69a73..23cb6030 100755 --- a/amxmodx/amx.cpp +++ b/amxmodx/amx.cpp @@ -1747,8 +1747,9 @@ static const void * const amx_opcodelist[] = { if (amx->callback==NULL) return AMX_ERR_CALLBACK; - if ((amx->flags & AMX_FLAG_NTVREG)==0) - return AMX_ERR_NOTFOUND; + if (!(amx->flags & AMX_FLAG_PRENIT)) + if ((amx->flags & AMX_FLAG_NTVREG)==0) + return AMX_ERR_NOTFOUND; if ((amx->flags & AMX_FLAG_RELOC)==0) return AMX_ERR_INIT; assert((amx->flags & AMX_FLAG_BROWSE)==0); @@ -2678,8 +2679,9 @@ int AMXAPI amx_Exec(AMX *amx, cell *retval, int index) if (amx->callback==NULL) return AMX_ERR_CALLBACK; - if ((amx->flags & AMX_FLAG_NTVREG)==0) - return AMX_ERR_NOTFOUND; + if (!(amx->flags & AMX_FLAG_PRENIT)) + if ((amx->flags & AMX_FLAG_NTVREG)==0) + return AMX_ERR_NOTFOUND; if ((amx->flags & AMX_FLAG_RELOC)==0) return AMX_ERR_INIT; assert((amx->flags & AMX_FLAG_BROWSE)==0); diff --git a/amxmodx/amx.h b/amxmodx/amx.h index 4160e20d..fb44c6b8 100755 --- a/amxmodx/amx.h +++ b/amxmodx/amx.h @@ -320,6 +320,7 @@ enum { #define AMX_FLAG_COMPACT 0x04 /* compact encoding */ #define AMX_FLAG_BYTEOPC 0x08 /* opcode is a byte (not a cell) */ #define AMX_FLAG_NOCHECKS 0x10 /* no array bounds checking; no STMT opcode */ +#define AMX_FLAG_PRENIT 0x100 /* pre-initialized, do not check natives */ #define AMX_FLAG_NTVREG 0x1000 /* all native functions are registered */ #define AMX_FLAG_JITC 0x2000 /* abstract machine is JIT compiled */ #define AMX_FLAG_BROWSE 0x4000 /* busy browsing */ diff --git a/amxmodx/meta_api.cpp b/amxmodx/meta_api.cpp index eb185646..1aeb8fe8 100755 --- a/amxmodx/meta_api.cpp +++ b/amxmodx/meta_api.cpp @@ -33,6 +33,7 @@ #include "amxmodx.h" #include "fakemeta.h" #include "newmenus.h" +#include "natives.h" plugin_info_t Plugin_info = { META_INTERFACE_VERSION, // ifvers @@ -266,6 +267,7 @@ int C_Spawn( edict_t *pent ) { // ###### Load AMX scripts g_plugins.loadPluginsFromFile( get_localinfo("amxx_plugins", "addons/amxmodx/configs/plugins.ini") ); + g_plugins.Finalize(); // Register forwards FF_PluginInit = registerForward("plugin_init", ET_IGNORE, FP_DONE); @@ -454,6 +456,7 @@ void C_ServerDeactivate_Post() { g_vault.clear(); g_xvars.clear(); g_plugins.clear(); + ClearPluginLibraries(); char file[256]; g_langMngr.Save(build_pathname_r(file, sizeof(file)-1, "%s/languages.dat", get_localinfo("amxx_datadir", "addons/amxmodx/data"))); g_langMngr.SaveCache(build_pathname_r(file, sizeof(file)-1, "%s/dictionary.cache", get_localinfo("amxx_datadir", "addons/amxmodx/data"))); diff --git a/amxmodx/modules.cpp b/amxmodx/modules.cpp index 8000fece..a3ca6483 100755 --- a/amxmodx/modules.cpp +++ b/amxmodx/modules.cpp @@ -41,6 +41,7 @@ #include "amxxfile.h" #include "amxdbg.h" #include "newmenus.h" +#include "natives.h" CList g_modules; CList g_loadedscripts; @@ -439,7 +440,25 @@ int load_amxscript(AMX *amx, void **program, const char *filename, char error[64 } g_loadedscripts.put( aa ); - return set_amxnatives(amx,error); + + set_amxnatives(amx,error); + + if (g_plugins.m_Finalized) + { + amx_Register(amx, g_plugins.pNatives, -1); + if (CheckModules(amx, error)) + { + if ( amx_Register(amx, core_Natives, -1) != AMX_ERR_NONE ) + { + sprintf(error, "Plugin uses an unknown function (name \"%s\") - check your modules.ini.", no_function); + return (amx->error = AMX_ERR_NOTFOUND); + } + } else { + return (amx->error = AMX_ERR_NOTFOUND); + } + } + + return (amx->error = AMX_ERR_NONE); } const char *StrCaseStr(const char *as, const char *bs) @@ -519,6 +538,8 @@ int CheckModules(AMX *amx, char error[128]) } } } + if (!found) + found = LibraryExists(buffer); if (!found) { sprintf(error, "Module \"%s\" required for plugin. Check modules.ini.", buffer); @@ -546,19 +567,24 @@ int set_amxnatives(AMX* amx,char error[128]) amx_Register(amx, time_Natives, -1); amx_Register(amx, vault_Natives, -1); amx_Register(amx, g_NewMenuNatives, -1); + amx_Register(amx, g_NativeNatives, -1); - if (CheckModules(amx, error)) + //we're not actually gonna check these here anymore + amx->flags |= AMX_FLAG_PRENIT; + + int idx; + cell retval; + if (amx_FindPublic(amx, "plugin_natives", &idx)==AMX_ERR_NONE) { - if ( amx_Register(amx, core_Natives, -1) != AMX_ERR_NONE ) + if (amx_Exec(amx, &retval, idx)!=AMX_ERR_NONE) { - sprintf(error, "Plugin uses an unknown function (name \"%s\") - check your modules.ini.", no_function); - return (amx->error = AMX_ERR_NATIVE); + //someday clear libraries that this added } - - return AMX_ERR_NONE; } - return (amx->error = AMX_ERR_NATIVE); + amx->flags &= ~(AMX_FLAG_PRENIT); + + return (amx->error = AMX_ERR_NONE); } int unload_amxscript(AMX* amx, void** program) diff --git a/amxmodx/modules.h b/amxmodx/modules.h index 727f8010..b8ba550d 100755 --- a/amxmodx/modules.h +++ b/amxmodx/modules.h @@ -48,5 +48,6 @@ #define RELOAD_MODULE 0 #define STATIC_MODULE 1 +int CheckModules(AMX *amx, char error[128]); #endif // __MODULES_H__ diff --git a/amxmodx/msvc/amxmodx_mm.vcproj b/amxmodx/msvc/amxmodx_mm.vcproj index 0ac5f288..4ffc1ab2 100755 --- a/amxmodx/msvc/amxmodx_mm.vcproj +++ b/amxmodx/msvc/amxmodx_mm.vcproj @@ -319,7 +319,7 @@ + + @@ -772,6 +775,9 @@ + + @@ -796,6 +802,9 @@ + + diff --git a/amxmodx/natives-amd64.asm b/amxmodx/natives-amd64.asm new file mode 100755 index 00000000..446233a7 --- /dev/null +++ b/amxmodx/natives-amd64.asm @@ -0,0 +1,85 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; (C)2005 by David "BAILOPAN" Anderson ; +; register_native functions for amd64 ;;;;;; +; Based on the concept by Julien "dJeyL" Laurent ; +; Thanks to T(+)rget for pushing me to implement this ; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;;Licensed under the GNU General Public License, version 2 +;;This is a portion of AMX Mod X +;; and is maintained by the AMX Mod X development team. + +;;Initializes the global variable + +BITS 64 + +section .text + +global amxx_DynaInit, _amxx_DynaInit +;void amxx_DynaInit(void *ptr); +amxx_DynaInit: +_amxx_DynaInit: + mov rax, rdi ;get pointer, first param is in rdi + mov [GLOBAL_GATE], rax ;store + + mov rax, 1 + ret + +;;Assembles the gateway function +global amxx_DynaMake, _amxx_DynaMake +;int amxx_DynaMake(char *buffer, int id); +amxx_DynaMake: +_amxx_DynaMake: + ;we're not damaging the stack I think so we should be safe with no prologue + + ;save these two we're about to destroy them + push rsi ;push id + push rdi ;push buffer + + mov rsi, _amxx_DynaFuncStart + mov rcx, _amxx_DynaFuncEnd - _amxx_DynaFuncStart + cld ;clear direction flag (just in case) + rep movsb + + pop rdi ;get buffer as destination + pop rax ;get id + ;align us to mov rsi, 1234... - on x86-64 this is 2 bytes after the differential + add rdi, (_amxx_DynaMoveOffset-_amxx_DynaFuncStart) + 2 + mov [rdi], qword rax + + mov rax, 1 + ret + +;;The gateway function we will re-assemble +;; This is similar to dJeyL's but a tad more elegant, as it's written in pure assembly +;; and NASM > GAS :') +global amxx_DynaFunc, _amxx_DynaFunc +;int amxx_DynaFunc(AMX *amx, cell *params); +amxx_DynaFunc: +_amxx_DynaFunc: +_amxx_DynaFuncStart: + push rbp + mov rbp, rsp + + ;we're given an amx and params... we're also hardcoded for this though: + mov rdx, rsi ;move 2nd param to 3rd + mov rsi, rdi ;move 1st param to 2nd + ;this old trick, we'll move in the real pointer in a bit. +_amxx_DynaMoveOffset: + mov rsi, qword 1234567812345678h + call [GLOBAL_GATE] ;pass through teh global gateway. + + pop rbp + ret +_amxx_DynaFuncEnd: + +;;Just returns the buffer size required +global _amxx_DynaCodesize, amxx_DynaCodesize +;int amxx_DynaCodesize() +amxx_DynaCodesize: +_amxx_DynaCodesize: + ; on x86 is this 17 bytes + mov rax, _amxx_DynaFuncEnd - _amxx_DynaFuncStart + ret + +GLOBAL_GATE DQ 0 diff --git a/amxmodx/natives-x86.asm b/amxmodx/natives-x86.asm index 9b4b79a2..91d4b693 100755 --- a/amxmodx/natives-x86.asm +++ b/amxmodx/natives-x86.asm @@ -1,7 +1,7 @@ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; (C)2005 by David "BAILOPAN" Anderson ; -; register_native functions for x86 ;;;;;; -; Based on the concept by Julien "dJeyL" Laurent ; +; (C)2005 by David "BAILOPAN" Anderson ; +; register_native functions for x86 ;;;;;; +; Based on the concept by Julien "dJeyL" Laurent ; ; Thanks to T(+)rget for pushing me to implement this ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -11,6 +11,8 @@ ;;Initializes the global variable +section .text + global amxx_DynaInit, _amxx_DynaInit ;void amxx_DynaInit(void *ptr); amxx_DynaInit: @@ -43,8 +45,8 @@ _amxx_DynaMake: rep movsb mov edi, [ebp+8] ;get buffer again - ;align us to mov eax, 1234 - add edi, _amxx_DynaMoveOffset + 1 + ;align us to mov eax, 1234 - on x86 this is 4 bytes + add edi, (_amxx_DynaMoveOffset-_amxx_DynaFuncStart) + 1 mov eax, [ebp+12] mov [edi], eax @@ -73,6 +75,7 @@ _amxx_DynaMoveOffset: push dword [ebp+8] ;push amx push eax ;push the id call [GLOBAL_GATE] ;pass through teh global gateway. + add esp, 12 ;reset stack oops pop ebp ret @@ -86,6 +89,7 @@ _amxx_DynaCodesize: push ebp mov ebp, esp + ; on x86 is this 17 bytes mov eax, _amxx_DynaFuncEnd - _amxx_DynaFuncStart pop ebp diff --git a/amxmodx/natives.cpp b/amxmodx/natives.cpp new file mode 100755 index 00000000..53e4ac25 --- /dev/null +++ b/amxmodx/natives.cpp @@ -0,0 +1,397 @@ +#include "amxmodx.h" +#include "CStack.h" +#include "natives.h" + +CVector g_RegNatives; +CStack g_NativeStack; +CVector g_Libraries; +static char g_errorStr[512] = {0}; +static int g_errorNum = 0; +bool g_Initialized = false; + +int amxx_DynaCallback(int idx, AMX *amx, cell *params) +{ + if (idx < 0 || idx >= (int)g_RegNatives.size()) + { + LogError(amx, AMX_ERR_NATIVE, "Invalid dynamic native called"); + return 0; + } + + regnative *pNative = g_RegNatives[idx]; + int numParams = params[0] / sizeof(cell); + + if (numParams > CALLFUNC_MAXPARAMS) + { + LogError(amx, AMX_ERR_NATIVE, "Called dynanative with too many parameters (%d)", CALLFUNC_MAXPARAMS); + return 0; + } + + //parameter stack + pNative->caller = amx; + + CPluginMngr::CPlugin *pPlugin = g_plugins.findPluginFast(amx); + + int err = 0; + cell ret = 0; + g_errorNum = 0; + g_NativeStack.push(pNative); + if (pNative->style == 0) + { + amx_Push(pNative->amx, numParams); + amx_Push(pNative->amx, pPlugin->getId()); + for (int i=numParams; i>=1; i--) + pNative->params[i] = params[i]; + } else if (pNative->style == 1) { + //use dJeyL's system .. very clever! + for (int i=numParams; i>=1; i--) + amx_Push(pNative->amx, params[i]); + } + if ( (err=amx_Exec(pNative->amx, &ret, pNative->func)) != AMX_ERR_NONE) + { + g_NativeStack.pop(); + LogError(pNative->amx, err, ""); + return 0; + } + if (g_errorNum) + { + g_NativeStack.pop(); + LogError(amx, g_errorNum, g_errorStr); + return ret; + } + g_NativeStack.pop(); + + return ret; +} + +AMX_NATIVE_INFO *BuildNativeTable() +{ + if (g_RegNatives.size() < 1) + return NULL; + + AMX_NATIVE_INFO *pNatives = new AMX_NATIVE_INFO[g_RegNatives.size() + 1]; + + AMX_NATIVE_INFO info; + regnative *pNative; + for (size_t i=0; iname.c_str(); + info.func = reinterpret_cast(pNative->pfn); + pNatives[i] = info; + } + pNatives[g_RegNatives.size()].name = NULL; + pNatives[g_RegNatives.size()].func = NULL; + + //this needs to be deleted + return pNatives; +} + +static cell AMX_NATIVE_CALL log_error(AMX *amx, cell *params) +{ + int len; + char *err = format_amxstring(amx, params, 2, len); + + _snprintf(g_errorStr, sizeof(g_errorStr), "%s", err); + g_errorNum = params[1]; + + return 1; +} + +//get_string(param, dest[], len) +static cell AMX_NATIVE_CALL get_string(AMX *amx, cell *params) +{ + if (!g_NativeStack.size()) + { + LogError(amx, AMX_ERR_NATIVE, "Not currently in a dynamic native"); + return 0; + } + regnative *pNative = g_NativeStack.top(); + if (pNative->style) + { + LogError(amx, AMX_ERR_NATIVE, "Wrong style of dynamic native"); + return 0; + } + int p = params[1]; + + int len; + char *str = get_amxstring(pNative->caller, pNative->params[p], 0, len); + return set_amxstring(amx, params[2], str, params[3]); +} + +//set_string(param, source[], maxlen) +static cell AMX_NATIVE_CALL set_string(AMX *amx, cell *params) +{ + if (!g_NativeStack.size()) + { + LogError(amx, AMX_ERR_NATIVE, "Not currently in a dynamic native"); + return 0; + } + regnative *pNative = g_NativeStack.top(); + if (pNative->style) + { + LogError(amx, AMX_ERR_NATIVE, "Wrong style of dynamic native"); + return 0; + } + int p = params[1]; + + int len; + char *str = get_amxstring(amx, params[2], 0, len); + + return set_amxstring(pNative->caller, pNative->params[p], str, params[3]); +} + +//get a byvalue parameter +//get_param(num) +static cell AMX_NATIVE_CALL get_param(AMX *amx, cell *params) +{ + if (!g_NativeStack.size()) + { + LogError(amx, AMX_ERR_NATIVE, "Not currently in a dynamic native"); + return 0; + } + regnative *pNative = g_NativeStack.top(); + if (pNative->style) + { + LogError(amx, AMX_ERR_NATIVE, "Wrong style of dynamic native"); + return 0; + } + int p = params[1]; + + return pNative->params[p]; +} + +//get_param_byref(num) +static cell AMX_NATIVE_CALL get_param_byref(AMX *amx, cell *params) +{ + if (!g_NativeStack.size()) + { + LogError(amx, AMX_ERR_NATIVE, "Not currently in a dynamic native"); + return 0; + } + regnative *pNative = g_NativeStack.top(); + if (pNative->style) + { + LogError(amx, AMX_ERR_NATIVE, "Wrong style of dynamic native"); + return 0; + } + int p = params[1]; + + cell *addr = get_amxaddr(pNative->caller, pNative->params[p]); + + return addr[0]; +} + +//set_param_byref(num, val) +static cell AMX_NATIVE_CALL set_param_byref(AMX *amx, cell *params) +{ + if (!g_NativeStack.size()) + { + LogError(amx, AMX_ERR_NATIVE, "Not currently in a dynamic native"); + return 0; + } + regnative *pNative = g_NativeStack.top(); + if (pNative->style) + { + LogError(amx, AMX_ERR_NATIVE, "Wrong style of dynamic native"); + return 0; + } + int p = params[1]; + + cell *addr = get_amxaddr(pNative->caller, pNative->params[p]); + + addr[0] = params[2]; + + return 1; +} + +//get_array(param, dest[], size) +static cell AMX_NATIVE_CALL get_array(AMX *amx, cell *params) +{ + if (!g_NativeStack.size()) + { + LogError(amx, AMX_ERR_NATIVE, "Not currently in a dynamic native"); + return 0; + } + regnative *pNative = g_NativeStack.top(); + if (pNative->style) + { + LogError(amx, AMX_ERR_NATIVE, "Wrong style of dynamic native"); + return 0; + } + int p = params[1]; + + cell *source = get_amxaddr(pNative->caller, pNative->params[p]); + cell *dest = get_amxaddr(amx, params[2]); + + int size = params[3]; + + while (size-->0) + *dest = *source; + + return 1; +} + +//set_array(param, source[], size) +static cell AMX_NATIVE_CALL set_array(AMX *amx, cell *params) +{ + if (!g_NativeStack.size()) + { + LogError(amx, AMX_ERR_NATIVE, "Not currently in a dynamic native"); + return 0; + } + regnative *pNative = g_NativeStack.top(); + if (pNative->style) + { + LogError(amx, AMX_ERR_NATIVE, "Wrong style of dynamic native"); + return 0; + } + int p = params[1]; + + cell *dest = get_amxaddr(pNative->caller, pNative->params[p]); + cell *source = get_amxaddr(amx, params[2]); + + int size = params[3]; + + while (size-->0) + *dest = *source; + + return 1; +} + +//This is basically right from dJeyL's lib_convert function +//This awesome hack modifies the stack frame to have an address offset +// that will align to the other plugin's memory. +//I've no idea how he thought of this, but it's great. No idea how well it works. +static cell AMX_NATIVE_CALL param_convert(AMX *amx, cell *params) +{ + if (!g_NativeStack.size()) + { + LogError(amx, AMX_ERR_NATIVE, "Not currently in a dynamic native"); + return 0; + } + regnative *pNative = g_NativeStack.top(); + if (pNative->style != 1) + { + LogError(amx, AMX_ERR_NATIVE, "Wrong style of dynamic native"); + return 0; + } + cell p = params[1]; + + AMX *caller = pNative->caller; + + unsigned char *data =amx->base+(int)((AMX_HEADER *)amx->base)->dat; + unsigned char *realdata = caller->base+(int)((AMX_HEADER *)caller->base)->dat; + + * (cell *)(data+(int)amx->frm+(p+2)*sizeof(cell)) -= (cell)data-(cell)realdata; + + return 1; +} + +static cell AMX_NATIVE_CALL register_library(AMX *amx, cell *params) +{ + int len; + char *lib = get_amxstring(amx, params[1], 0, len); + + AddPluginLibrary(lib); + + return 1; +} + +//register_native(const name[], const handler[]) +static cell AMX_NATIVE_CALL register_native(AMX *amx, cell *params) +{ + if (!g_Initialized) + amxx_DynaInit(static_cast(amxx_DynaCallback)); + + g_Initialized = true; + + int len; + char *name = get_amxstring(amx, params[1], 0, len); + char *func = get_amxstring(amx, params[2], 1, len); + + int idx, err; + if ( (err=amx_FindPublic(amx, func, &idx)) != AMX_ERR_NONE) + { + LogError(amx, err, "Function \"%s\" was not found", func); + return 0; + } + + regnative *pNative = new regnative; + pNative->amx = amx; + pNative->func = idx; + + //we'll apply a safety buffer too + //make our function + int size = amxx_DynaCodesize(); +#ifndef __linux__ + DWORD temp; + pNative->pfn = new char[size + 10]; + VirtualProtect(pNative->pfn, size+10, PAGE_EXECUTE_READWRITE, &temp); +#else + pNative->pfn = (unsigned char *)memalign(sysconf(_SC_PAGESIZE), amx->code_size); + mprotect((void *)pNative->pfn, size+10, PROT_READ|PROT_WRITE|PROT_EXEC); +#endif + + int id = (int)g_RegNatives.size(); + + amxx_DynaMake(pNative->pfn, id); + pNative->func = idx; + pNative->style = params[3]; + + g_RegNatives.push_back(pNative); + + pNative->name.assign(name); + + return 1; +} + +bool LibraryExists(const char *name) +{ + for (size_t i=0; ipfn; + delete g_RegNatives[i]; + } + g_RegNatives.clear(); +} + +AMX_NATIVE_INFO g_NativeNatives[] = { + {"register_native", register_native}, + {"log_error", log_error}, + {"register_library",register_library}, + {"get_string", get_string}, + {"set_string", set_string}, + {"get_param", get_param}, + {"get_param_byref", get_param_byref}, + {"set_param_byref", set_param_byref}, + {"get_array", set_array}, + {"set_array", set_array}, + //these are dummy functions for floats ;p + {"get_param_f", get_param}, + {"get_float_byref", get_param_byref}, + {"set_float_byref", set_param_byref}, + {"get_array_f", get_array}, + {"set_array_f", set_array}, + {"param_convert", param_convert}, + ////////////////////////// + {NULL, NULL}, +}; diff --git a/amxmodx/natives.h b/amxmodx/natives.h new file mode 100755 index 00000000..dda06435 --- /dev/null +++ b/amxmodx/natives.h @@ -0,0 +1,39 @@ +#ifndef _INCLUDE_NATIVES_H +#define _INCLUDE_NATIVES_H + +//only 16 for now sorry +#define CALLFUNC_MAXPARAMS 16 + +#define CALLFUNC_FLAG_BYREF 1 +#define CALLFUNC_FLAG_BYREF_REUSED 2 + +#define N_CELL 1 +#define N_ARRAY 2 +#define N_BYREF 3 +#define N_VARARG 4 + +struct regnative +{ + AMX *amx; + String name; + char *pfn; + int func; + AMX *caller; + int style; + cell params[CALLFUNC_MAXPARAMS]; +}; + +extern "C" void amxx_DynaInit(void *ptr); +extern "C" void amxx_DynaMake(char *buffer, int id); +extern "C" int amxx_DynaFunc(AMX *amx, cell *params); +extern "C" int amxx_DynaCodesize(); + +AMX_NATIVE_INFO *BuildNativeTable(); +void AddPluginLibrary(const char *name); +void ClearPluginLibraries(); +bool LibraryExists(const char *name); + +//I couldn't resist :) +extern AMX_NATIVE_INFO g_NativeNatives[]; + +#endif //_INCLUDE_NATIVES_H