Committed new register_native system
This commit is contained in:
		| @@ -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<<id); | ||||
|   | ||||
| @@ -93,6 +93,7 @@ public: | ||||
| 		inline bool isPaused() const { return ( (status == ps_paused) || (status == ps_stopped)); } | ||||
| 		//inline bool isFunctionPaused( int id ) const { return (paused_fun & (1<<id)) ? true : false; 	} | ||||
| 		inline bool isExecutable(int id) const { return (isValid() && !isPaused());	} | ||||
| 		void Finalize(); | ||||
| 		void pausePlugin(); | ||||
| 		void unpausePlugin(); | ||||
| 		void pauseFunction( int id ); | ||||
| @@ -108,9 +109,12 @@ private: | ||||
|  | ||||
|  | ||||
| public: | ||||
| 	CPluginMngr() { head = 0; pCounter = 0; } | ||||
| 	CPluginMngr() { head = 0; pCounter = 0; pNatives = NULL; m_Finalized=false;} | ||||
| 	~CPluginMngr() { clear(); } | ||||
|  | ||||
| 	bool m_Finalized; | ||||
| 	AMX_NATIVE_INFO *pNatives; | ||||
|  | ||||
| 	// Interface | ||||
|  | ||||
| 	CPlugin* loadPlugin(const char* path, const char* name, char* error, int debug); | ||||
| @@ -121,6 +125,7 @@ public: | ||||
| 	CPlugin* findPlugin(int index); | ||||
| 	CPlugin* findPlugin(const char* name); | ||||
| 	inline int getPluginsNum() const { return pCounter; } | ||||
| 	void Finalize(); | ||||
| 	void clear(); | ||||
|  | ||||
| 	class iterator { | ||||
|   | ||||
							
								
								
									
										101
									
								
								amxmodx/CStack.h
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										101
									
								
								amxmodx/CStack.h
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,101 @@ | ||||
| /* AMX Mod X | ||||
| * | ||||
| * by the AMX Mod X Development Team | ||||
| *  originally developed by OLO | ||||
| * | ||||
| * | ||||
| *  This program is free software; you can redistribute it and/or modify it | ||||
| *  under the terms of the GNU General Public License as published by the | ||||
| *  Free Software Foundation; either version 2 of the License, or (at | ||||
| *  your option) any later version. | ||||
| * | ||||
| *  This program is distributed in the hope that it will be useful, but | ||||
| *  WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||||
| *  General Public License for more details. | ||||
| * | ||||
| *  You should have received a copy of the GNU General Public License | ||||
| *  along with this program; if not, write to the Free Software Foundation, | ||||
| *  Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||||
| * | ||||
| *  In addition, as a special exception, the author gives permission to | ||||
| *  link the code of this program with the Half-Life Game Engine ("HL | ||||
| *  Engine") and Modified Game Libraries ("MODs") developed by Valve, | ||||
| *  L.L.C ("Valve"). You must obey the GNU General Public License in all | ||||
| *  respects for all of the code used other than the HL Engine and MODs | ||||
| *  from Valve. If you modify this file, you may extend this exception | ||||
| *  to your version of the file, but you are not obligated to do so. If | ||||
| *  you do not wish to do so, delete this exception statement from your | ||||
| *  version. | ||||
| */ | ||||
|  | ||||
| //by David "BAILOPAN" Anderson | ||||
| #ifndef _INCLUDE_CSTACK_H | ||||
| #define _INCLUDE_CSTACK_H | ||||
|  | ||||
| template <class T> | ||||
| 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 | ||||
|  | ||||
							
								
								
									
										
											BIN
										
									
								
								amxmodx/JIT/natives-x86.o
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								amxmodx/JIT/natives-x86.o
									
									
									
									
									
										Executable file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								amxmodx/JIT/natives-x86.obj
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								amxmodx/JIT/natives-x86.obj
									
									
									
									
									
										Executable file
									
								
							
										
											Binary file not shown.
										
									
								
							| @@ -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); | ||||
|   | ||||
| @@ -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 */ | ||||
|   | ||||
| @@ -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"))); | ||||
|   | ||||
| @@ -41,6 +41,7 @@ | ||||
| #include "amxxfile.h" | ||||
| #include "amxdbg.h" | ||||
| #include "newmenus.h" | ||||
| #include "natives.h" | ||||
|  | ||||
| CList<CModule,const char*> g_modules; | ||||
| CList<CScript,AMX*> 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) | ||||
|   | ||||
| @@ -48,5 +48,6 @@ | ||||
| #define RELOAD_MODULE 0 | ||||
| #define STATIC_MODULE 1 | ||||
|  | ||||
| int CheckModules(AMX *amx, char error[128]); | ||||
|  | ||||
| #endif // __MODULES_H__ | ||||
|   | ||||
| @@ -319,7 +319,7 @@ | ||||
| 			<Tool | ||||
| 				Name="VCLinkerTool" | ||||
| 				AdditionalOptions="/MACHINE:I386" | ||||
| 				AdditionalDependencies="..\zlib\zlib.lib ..\JIT\amxjitsn.obj ..\JIT\amxexecn.obj" | ||||
| 				AdditionalDependencies="..\zlib\zlib.lib ..\JIT\amxjitsn.obj ..\JIT\amxexecn.obj ..\JIT\natives-x86.obj" | ||||
| 				OutputFile="jitdebug/amxmodx_mm.dll" | ||||
| 				Version="0.1" | ||||
| 				LinkIncremental="1" | ||||
| @@ -659,6 +659,9 @@ | ||||
| 			<File | ||||
| 				RelativePath="..\modules.cpp"> | ||||
| 			</File> | ||||
| 			<File | ||||
| 				RelativePath="..\natives.cpp"> | ||||
| 			</File> | ||||
| 			<File | ||||
| 				RelativePath="..\newmenus.cpp"> | ||||
| 			</File> | ||||
| @@ -772,6 +775,9 @@ | ||||
| 			<File | ||||
| 				RelativePath="..\CQueue.h"> | ||||
| 			</File> | ||||
| 			<File | ||||
| 				RelativePath="..\CStack.h"> | ||||
| 			</File> | ||||
| 			<File | ||||
| 				RelativePath="..\CString.h"> | ||||
| 			</File> | ||||
| @@ -796,6 +802,9 @@ | ||||
| 			<File | ||||
| 				RelativePath="..\modules.h"> | ||||
| 			</File> | ||||
| 			<File | ||||
| 				RelativePath="..\natives.h"> | ||||
| 			</File> | ||||
| 			<File | ||||
| 				RelativePath="..\newmenus.h"> | ||||
| 			</File> | ||||
|   | ||||
							
								
								
									
										85
									
								
								amxmodx/natives-amd64.asm
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										85
									
								
								amxmodx/natives-amd64.asm
									
									
									
									
									
										Executable file
									
								
							| @@ -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 | ||||
| @@ -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 | ||||
|   | ||||
							
								
								
									
										397
									
								
								amxmodx/natives.cpp
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										397
									
								
								amxmodx/natives.cpp
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,397 @@ | ||||
| #include "amxmodx.h" | ||||
| #include "CStack.h" | ||||
| #include "natives.h" | ||||
|  | ||||
| CVector<regnative *> g_RegNatives; | ||||
| CStack<regnative *> g_NativeStack; | ||||
| CVector<String> 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; i<g_RegNatives.size(); i++) | ||||
| 	{ | ||||
| 		pNative = g_RegNatives[i]; | ||||
| 		info.name = pNative->name.c_str(); | ||||
| 		info.func = reinterpret_cast<AMX_NATIVE>(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<void *>(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; i<g_Libraries.size(); i++) | ||||
| 	{ | ||||
| 		if (stricmp(g_Libraries[i].c_str(), name)==0) | ||||
| 			return true; | ||||
| 	} | ||||
|  | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| void AddPluginLibrary(const char *name) | ||||
| { | ||||
| 	String f(name); | ||||
| 	g_Libraries.push_back(f); | ||||
| } | ||||
|  | ||||
| void ClearPluginLibraries() | ||||
| { | ||||
| 	g_Libraries.clear(); | ||||
|  | ||||
| 	for (size_t i=0; i<g_RegNatives.size(); i++) | ||||
| 	{ | ||||
| 		delete g_RegNatives[i]->pfn; | ||||
| 		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}, | ||||
| }; | ||||
							
								
								
									
										39
									
								
								amxmodx/natives.h
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										39
									
								
								amxmodx/natives.h
									
									
									
									
									
										Executable file
									
								
							| @@ -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 | ||||
		Reference in New Issue
	
	Block a user