From 4609cb409b9d3679de9d120e17796156e546dd52 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 25 Jul 2005 06:03:43 +0000 Subject: [PATCH] Whoa! Merged in Pawn! (Small 3.0) Removed debug handling (will add back in soon) Ported all amx_Exec()s to forward systems Deprecated AMX Mod module support (incompatible with Pawn anyway!) Deprecated many file natives (unused) Deprecated some functionality of pause/unpause Fixed some memory deallocation bugs (thanks fysh) Bumped module API version to 3 (no new M/SDK yet!) Bumped AMX Mod X version to 1.5! Merged in CVector changes --- amxmodx/CEvent.cpp | 31 +- amxmodx/CForward.cpp | 22 +- amxmodx/CLogEvent.cpp | 4 +- amxmodx/CMenu.cpp | 2 +- amxmodx/CModule.cpp | 139 +-- amxmodx/CModule.h | 12 +- amxmodx/CPlugin.cpp | 53 +- amxmodx/CPlugin.h | 6 +- amxmodx/CVector.h | 14 +- amxmodx/JIT/amxexecn.o | Bin 0 -> 12160 bytes amxmodx/JIT/amxexecn.obj | Bin 0 -> 11735 bytes amxmodx/JIT/amxjitsn.o | Bin 0 -> 26528 bytes amxmodx/JIT/amxjitsn.obj | Bin 0 -> 27061 bytes amxmodx/JIT/jits.o | Bin 27470 -> 0 bytes amxmodx/JIT/jits.obj | Bin 27480 -> 0 bytes amxmodx/amx.cpp | 1548 ++++++++++++------------ amxmodx/amx.h | 275 +++-- amxmodx/amxcore.cpp | 218 +--- amxmodx/amxdefn.asm | 86 ++ amxmodx/amxexecn.asm | 585 +-------- amxmodx/{JIT/jits.asm => amxjitsn.asm} | 463 +++---- amxmodx/amxmodx.cpp | 134 +- amxmodx/amxmodx.h | 5 +- amxmodx/file.cpp | 38 +- amxmodx/float.cpp | 2 +- amxmodx/meta_api.cpp | 61 +- amxmodx/modules.cpp | 164 +-- amxmodx/modules.h | 127 -- amxmodx/msvc/amxmodx_mm.vcproj | 15 +- amxmodx/srvcmd.cpp | 58 +- amxmodx/string.cpp | 13 +- amxmodx/version.rc | 8 +- 32 files changed, 1501 insertions(+), 2582 deletions(-) create mode 100755 amxmodx/JIT/amxexecn.o create mode 100755 amxmodx/JIT/amxexecn.obj create mode 100755 amxmodx/JIT/amxjitsn.o create mode 100755 amxmodx/JIT/amxjitsn.obj delete mode 100755 amxmodx/JIT/jits.o delete mode 100755 amxmodx/JIT/jits.obj create mode 100755 amxmodx/amxdefn.asm rename amxmodx/{JIT/jits.asm => amxjitsn.asm} (85%) diff --git a/amxmodx/CEvent.cpp b/amxmodx/CEvent.cpp index 82d02de3..769ae38e 100755 --- a/amxmodx/CEvent.cpp +++ b/amxmodx/CEvent.cpp @@ -396,40 +396,21 @@ void EventsMngr::parseValue(const char *sz) void EventsMngr::executeEvents() { - int err; - if (!m_ParseFun) { return; } -#ifdef ENABLEEXEPTIONS - try + for (ClEventVecIter iter = m_ParseFun->begin(); iter; ++iter) { -#endif // #ifdef ENABLEEXEPTIONS - for (ClEventVecIter iter = m_ParseFun->begin(); iter; ++iter) + if ( (*iter).m_Done ) { - if ( (*iter).m_Done ) - { - (*iter).m_Done = false; - continue; - } - - (*iter).m_Stamp = (float)*m_Timer; - - if ((err = amx_Exec((*iter).m_Plugin->getAMX(), NULL, (*iter).m_Func, 1, m_ParseVault ? m_ParseVault[0].iValue : 0)) != AMX_ERR_NONE) - { - LogError((*iter).m_Plugin->getAMX(), err, ""); - } + (*iter).m_Done = false; + continue; } - -#ifdef ENABLEEXEPTIONS + (*iter).m_Stamp = (float)*m_Timer; + executeForwards((*iter).m_Func, m_ParseVault ? m_ParseVault[0].iValue : 0); } - catch( ... ) - { - AMXXLOG_Log( "[AMXX] fatal error at event execution"); - } -#endif // #ifdef ENABLEEXEPTIONS m_CurrentMsgType = -1; m_ParseFun = NULL; diff --git a/amxmodx/CForward.cpp b/amxmodx/CForward.cpp index 4bbbc66b..6641d4ff 100755 --- a/amxmodx/CForward.cpp +++ b/amxmodx/CForward.cpp @@ -71,7 +71,7 @@ cell CForward::execute(cell *params, ForwardPreparedArray *preparedArrays) if (iter->pPlugin->isExecutable(iter->func)) { // handle strings & arrays - int i; + int i, ax=0; for (i = 0; i < m_NumParams; ++i) { if (m_ParamTypes[i] == FP_STRING || m_ParamTypes[i] == FP_STRINGEX) @@ -80,7 +80,7 @@ cell CForward::execute(cell *params, ForwardPreparedArray *preparedArrays) amx_Allot(iter->pPlugin->getAMX(), (m_ParamTypes[i] == FP_STRING) ? strlen(reinterpret_cast(params[i]))+1 : STRINGEX_MAXLENGTH, &realParams[i], &tmp); - amx_SetString(tmp, (const char *)(params[i]), 0, 0); + amx_SetStringOld(tmp, (const char *)(params[i]), 0, 0); physAddrs[i] = tmp; } else if (m_ParamTypes[i] == FP_ARRAY) @@ -105,9 +105,14 @@ cell CForward::execute(cell *params, ForwardPreparedArray *preparedArrays) realParams[i] = params[i]; } } + //Push the parameters in reverse order. Weird, unfriendly part of Small 3.0! + for (i=m_NumParams-1; i>=0; i--) + { + amx_Push(iter->pPlugin->getAMX(), realParams[i]); + } // exec cell retVal; - int err = amx_Execv(iter->pPlugin->getAMX(), &retVal, iter->func, m_NumParams, realParams); + int err = amx_Exec(iter->pPlugin->getAMX(), &retVal, iter->func); // log runtime error, if any if (err != AMX_ERR_NONE) LogError(iter->pPlugin->getAMX(), err, ""); @@ -122,7 +127,7 @@ cell CForward::execute(cell *params, ForwardPreparedArray *preparedArrays) else if (m_ParamTypes[i] == FP_STRINGEX) { // copy back - amx_GetString(reinterpret_cast(params[i]), physAddrs[i], 0); + amx_GetStringOld(reinterpret_cast(params[i]), physAddrs[i], 0); amx_Release(iter->pPlugin->getAMX(), realParams[i]); } else if (m_ParamTypes[i] == FP_ARRAY) @@ -216,7 +221,7 @@ cell CSPForward::execute(cell *params, ForwardPreparedArray *preparedArrays) amx_Allot(m_Amx, (m_ParamTypes[i] == FP_STRING) ? strlen(reinterpret_cast(params[i]))+1 : STRINGEX_MAXLENGTH, &realParams[i], &tmp); - amx_SetString(tmp, (const char *)(params[i]), 0, 0); + amx_SetStringOld(tmp, (const char *)(params[i]), 0, 0); physAddrs[i] = tmp; } else if (m_ParamTypes[i] == FP_ARRAY) @@ -241,10 +246,11 @@ cell CSPForward::execute(cell *params, ForwardPreparedArray *preparedArrays) realParams[i] = params[i]; } } - + for (i=m_NumParams-1; i>=0; i--) + amx_Push(m_Amx, realParams[i]); // exec cell retVal; - int err = amx_Execv(m_Amx, &retVal, m_Func, m_NumParams, realParams); + int err = amx_Exec(m_Amx, &retVal, m_Func); // log runtime error, if any if (err != AMX_ERR_NONE) @@ -260,7 +266,7 @@ cell CSPForward::execute(cell *params, ForwardPreparedArray *preparedArrays) else if (m_ParamTypes[i] == FP_STRINGEX) { // copy back - amx_GetString(reinterpret_cast(params[i]), physAddrs[i], 0); + amx_GetStringOld(reinterpret_cast(params[i]), physAddrs[i], 0); amx_Release(m_Amx, realParams[i]); } else if (m_ParamTypes[i] == FP_ARRAY) diff --git a/amxmodx/CLogEvent.cpp b/amxmodx/CLogEvent.cpp index c6e07692..85d606f7 100755 --- a/amxmodx/CLogEvent.cpp +++ b/amxmodx/CLogEvent.cpp @@ -151,7 +151,6 @@ LogEventsMngr::CLogEvent* LogEventsMngr::registerLogEvent( CPluginMngr::CPlugin* void LogEventsMngr::executeLogEvents() { - int err; bool valid; for(CLogEvent* a = logevents[ logArgc ]; a ; a = a->next) { @@ -171,8 +170,7 @@ void LogEventsMngr::executeLogEvents() if (valid) { - if ((err = amx_Exec(a->plugin->getAMX(), NULL , a->func , 0)) != AMX_ERR_NONE) - LogError(a->plugin->getAMX(), err, ""); + executeForwards(a->func); } } } diff --git a/amxmodx/CMenu.cpp b/amxmodx/CMenu.cpp index 72ccac58..7c346284 100755 --- a/amxmodx/CMenu.cpp +++ b/amxmodx/CMenu.cpp @@ -51,7 +51,7 @@ MenuMngr::~MenuMngr() int MenuMngr::findMenuId(const char* name, AMX* amx) { for( MenuIdEle* b = headid; b ; b = b->next) { - if ( (!b->amx || amx == b->amx) && strstr(name,b->name.c_str()) ) + if ( (!amx || !b->amx || amx == b->amx) && strstr(name,b->name.c_str()) ) return b->id; } return 0; diff --git a/amxmodx/CModule.cpp b/amxmodx/CModule.cpp index e6a471f2..ce551223 100755 --- a/amxmodx/CModule.cpp +++ b/amxmodx/CModule.cpp @@ -35,11 +35,6 @@ #define FAR #endif -// Old -typedef int (FAR *QUERYMOD)(module_info_s**); -typedef int (FAR *ATTACHMOD)(pfnamx_engine_g*,pfnmodule_engine_g*); -typedef int (FAR *DETACHMOD)(void); - // New typedef void* (*PFN_REQ_FNPTR)(const char * /*name*/); typedef int (FAR *QUERYMOD_NEW)(int * /*ifvers*/, amxx_module_info_s * /*modInfo*/); @@ -47,81 +42,6 @@ typedef int (FAR *ATTACHMOD_NEW)(PFN_REQ_FNPTR /*reqFnptrFunc*/); typedef int (FAR *DETACHMOD_NEW)(void); typedef void (FAR *PLUGINSLOADED_NEW)(void); -// Old -// These functions are needed since Small Abstract Machine 2.5.0 -int wamx_FindPublic(AMX *amx, char *name, int *index) -{ return amx_FindPublic(amx, name, index); } - -int wamx_FindPubVar(AMX *amx, char *varname, cell *amx_addr) -{ return amx_FindPubVar(amx, varname, amx_addr); } - -int wamx_GetString(char *dest, cell *source) -{ return amx_GetString(dest, source, 0); } - -AMX_NATIVE_INFO *wamx_NativeInfo(char *name, AMX_NATIVE func) -{ return amx_NativeInfo(name, func); } - -int wamx_SetString(cell *dest, char *source, int pack) -{ return amx_SetString(dest, source, pack, 0); } - -pfnamx_engine_g engAmxFunc = { - amx_Align16, - amx_Align32, - amx_Allot, - amx_Callback, - amx_Clone, - amx_Debug, - amx_Exec, - amx_Execv, - wamx_FindPublic, - wamx_FindPubVar, - amx_FindTagId, - amx_Flags, - amx_GetAddr, - amx_GetPublic, - amx_GetPubVar, - wamx_GetString, - amx_GetTag, - amx_GetUserData, - amx_Init, - amx_InitJIT, - amx_MemInfo, - amx_NameLength, - wamx_NativeInfo, - amx_NumPublics, - amx_NumPubVars, - amx_NumTags, - amx_RaiseError, - amx_Register, - amx_Release, - amx_SetCallback, - amx_SetDebugHook, - wamx_SetString, - amx_SetUserData, - amx_StrLen, -}; - -pfnmodule_engine_g engModuleFunc = { - add_amxnatives, - build_pathname, - copy_amxmemory, - format_amxstring, - get_amxaddr, - get_amxscript, - get_amxscriptname, - get_amxstring, - get_modname, - load_amxscript, - print_srvconsole, - report_error, - set_amxnatives, - set_amxstring, - amxstring_len, - unload_amxscript, - alloc_amxmemory, - free_amxmemory, -}; - // ***************************************************** // class CModule // ***************************************************** @@ -150,8 +70,6 @@ void CModule::clear(bool clearFilename) if (clearFilename) m_Filename.assign("unknown"); - // old - m_InfoOld = NULL; // new m_Amxx = false; m_InfoNew.author = "unknown"; @@ -220,17 +138,11 @@ bool CModule::attachModule() m_Status = MODULE_BADLOAD; return false; } + } else { + m_Status = MODULE_BADLOAD; } - else - { - // old - ATTACHMOD AttachFunc = (ATTACHMOD)DLPROC(m_Handle, "AMX_Attach"); - if (AttachFunc) - (*AttachFunc)(&engAmxFunc,&engModuleFunc); - m_Status = MODULE_LOADED; - return true; - } + return false; } bool CModule::queryModule() @@ -292,44 +204,9 @@ bool CModule::queryModule() } else { - // old interface not 64 bit compatible -#if SMALL_CELL_SIZE == 64 - m_Status = MODULE_NOT64BIT; + m_Status = MODULE_NOQUERY; + m_Amxx = false; return false; -#else - // Try old interface - QUERYMOD queryFunc_Old = (QUERYMOD)DLPROC(m_Handle,"AMX_Query"); // check what version - if (!queryFunc_Old) - { - m_Status = MODULE_NOQUERY; - return false; - } - - (*queryFunc_Old)(&m_InfoOld); - - if (!m_InfoOld) - { - m_Status = MODULE_NOINFO; - return false; - } - - if (m_InfoOld->ivers != AMX_INTERFACE_VERSION) - { - m_Status = MODULE_OLD; - return false; - } - - // Check for attach - if (!DLPROC(m_Handle, "AMX_Attach")) - { - m_Status = MODULE_NOATTACH; - return false; - } - - m_InfoOld->serial = (long int)this; - m_Status = MODULE_QUERY; - return true; -#endif } } @@ -350,12 +227,6 @@ bool CModule::detachModule() g_ModuleCallReason = ModuleCall_NotCalled; } } - else - { - DETACHMOD detachFunc_Old = (DETACHMOD)DLPROC(m_Handle, "AMX_Detach"); - if (detachFunc_Old) - (*detachFunc_Old)(); - } #ifndef FAKEMETA if (IsMetamod()) { diff --git a/amxmodx/CModule.h b/amxmodx/CModule.h index c7b7f915..848455fe 100755 --- a/amxmodx/CModule.h +++ b/amxmodx/CModule.h @@ -66,14 +66,13 @@ struct amxx_module_info_s #define AMXX_PARAM 2 /* Invalid parameter */ #define AMXX_FUNC_NOT_PRESENT 3 /* Function not present */ -#define AMXX_INTERFACE_VERSION 2 +#define AMXX_INTERFACE_VERSION 3 class CModule { String m_Filename; // Filename bool m_Metamod; // Using metamod? bool m_Amxx; // Using new module interface? - module_info_s* m_InfoOld; // module info (old module interface) amxx_module_info_s m_InfoNew; // module info (new module interface) DLHANDLE m_Handle; // handle MODULE_STATUS m_Status; // status @@ -93,14 +92,13 @@ public: #endif const char* getStatus() const; inline const char* getType() const { return m_Amxx ? "amxx" : (m_Metamod ? "amx&mm" : "amx"); } - inline const char* getAuthor() const { return m_Amxx ? (m_InfoNew.author) : (m_InfoOld ? m_InfoOld->author : "unknown"); } - inline const char* getVersion() const { return m_Amxx ? (m_InfoNew.version) : (m_InfoOld ? m_InfoOld->version : "unknown"); } - inline const char* getName() const { return m_Amxx ? (m_InfoNew.name) : (m_InfoOld ? m_InfoOld->name : "unknown"); } - inline module_info_s* getInfo() const { return m_InfoOld; } // old + inline const char* getAuthor() const { return m_InfoNew.author; } + inline const char* getVersion() const { return m_InfoNew.version; } + inline const char* getName() const { return m_InfoNew.name; } inline const amxx_module_info_s* getInfoNew() const { return &m_InfoNew; } // new inline int getStatusValue() { return m_Status; } inline bool operator==( const char* fname ) { return !strcmp( m_Filename.c_str() , fname ); } - inline bool isReloadable() { return m_Amxx ? ((m_Status == MODULE_LOADED) && (m_InfoNew.reload != 0)) : ( (m_Status==MODULE_LOADED) && (m_InfoOld->type==RELOAD_MODULE)); } + inline bool isReloadable() { return ((m_Status == MODULE_LOADED) && (m_InfoNew.reload != 0)); } inline bool isAmxx() const { return m_Amxx; } inline const char *getMissingFunc() const { return m_MissingFunc; } inline const char *getFilename() { return m_Filename.c_str(); } diff --git a/amxmodx/CPlugin.cpp b/amxmodx/CPlugin.cpp index f3c44048..b6c10710 100755 --- a/amxmodx/CPlugin.cpp +++ b/amxmodx/CPlugin.cpp @@ -172,38 +172,12 @@ CPluginMngr::CPlugin::CPlugin(int i, const char* p,const char* n, char* e, int d paused_fun = 0; next = 0; id = i; + m_PauseFwd = registerSPForwardByName(&amx, "plugin_pause"); + m_UnpauseFwd = registerSPForwardByName(&amx, "plugin_unpause"); } CPluginMngr::CPlugin::~CPlugin( ) { - AMX_DBG *pDbg = (AMX_DBG *)amx.userdata[0]; - - if (pDbg) - { - if (pDbg->files) - { - for (int i=0; inumFiles; i++) - { - if (pDbg->files[i]) - { - free(pDbg->files[i]); - pDbg->files[i] = NULL; - } - } - free(pDbg->files); - } - AMX_TRACE *pTrace = pDbg->head; - AMX_TRACE *pNext = NULL; - while (pTrace) - { - pNext = pTrace->next; - free(pTrace); - pTrace = pNext; - } - free(pDbg); - amx.userdata[0] = NULL; - } - unload_amxscript( &amx, &code ); } @@ -232,16 +206,8 @@ void CPluginMngr::CPlugin::pausePlugin() if (isValid()) { // call plugin_pause if provided - int func; - cell retval; - if (amx_FindPublic(&amx, "plugin_pause", &func) == AMX_ERR_NONE) - { - if (isExecutable(func)) - { - - amx_Exec(&amx, &retval, func, 0); - } - } + if (m_PauseFwd != -1) + executeForwards(m_PauseFwd); setStatus(ps_paused); } @@ -256,14 +222,7 @@ void CPluginMngr::CPlugin::unpausePlugin() setStatus(ps_running); // call plugin_unpause if provided - int func; - cell retval; - if (amx_FindPublic(&amx, "plugin_unpause", &func) == AMX_ERR_NONE) - { - if (isExecutable(func)) - { - amx_Exec(&amx, &retval, func, 0); - } - } + if (m_UnpauseFwd != -1) + executeForwards(m_UnpauseFwd); } } diff --git a/amxmodx/CPlugin.h b/amxmodx/CPlugin.h index 252761d4..55efb3e2 100755 --- a/amxmodx/CPlugin.h +++ b/amxmodx/CPlugin.h @@ -64,6 +64,8 @@ public: String title; String author; String errorMsg; + int m_PauseFwd; + int m_UnpauseFwd; int paused_fun; int status; CPlugin* next; @@ -88,8 +90,8 @@ public: inline void setError( const char* n ) { errorMsg.assign(n); } inline bool isValid() const { return ((status != ps_bad_load) && (status != ps_locked)); } inline bool isPaused() const { return ( (status == ps_paused) || (status == ps_stopped)); } - inline bool isFunctionPaused( int id ) const { return (paused_fun & (1< class CVector return false; if (m_Data) { - memcpy(newData, m_Data, m_Size * sizeof(T)); + for (size_t i=0; i class CVector return false; if (m_Data) { - memcpy(newData, m_Data, (m_Size < size) ? (m_Size * sizeof(T)) : (size * sizeof(T))); + size_t end = (m_Size < size) ? (m_Size) : size; + for (size_t i=0; i(const CVector & other) { // copy data - m_Data = new T [other.m_Size]; - m_Size = other.m_Size; + m_Data = new T [other.m_CurrentUsedSize]; + m_Size = other.m_CurrentUsedSize; m_CurrentUsedSize = other.m_CurrentUsedSize; - memcpy(m_Data, other.m_Data, m_CurrentUsedSize * sizeof(T)); + for (size_t i=0; i() diff --git a/amxmodx/JIT/amxexecn.o b/amxmodx/JIT/amxexecn.o new file mode 100755 index 0000000000000000000000000000000000000000..c0c6f00f7c66ff122df935b1a131dce62787e96a GIT binary patch literal 12160 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 literal 0 HcmV?d00001 diff --git a/amxmodx/JIT/amxexecn.obj b/amxmodx/JIT/amxexecn.obj new file mode 100755 index 0000000000000000000000000000000000000000..08d307a4ca67ac46f68bc0db703b5576e6797921 GIT binary patch literal 11735 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 Yy2Z=a>>t2CGbEBdDZKLO$?Wj|ALU7CQvd(} literal 0 HcmV?d00001 diff --git a/amxmodx/JIT/amxjitsn.o b/amxmodx/JIT/amxjitsn.o new file mode 100755 index 0000000000000000000000000000000000000000..541585fb27e1596dd605c630ea9d1cad00b07bcf GIT binary patch literal 26528 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 yNk5bBl7(4weu;r5C} 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 qg5Nu<^Ti0I*AbNFaB-=3 -#include #include #include #include #include /* for wchar_t */ #include -#include +#include #include "osdefs.h" -#if defined LINUX +#if defined LINUX || defined __FreeBSD__ || defined __OpenBSD__ #include #if !defined AMX_NODYNALOAD #include #endif + #if defined JIT + #include + #include + #endif #endif -#if defined __LCC__ || defined __GNUC__ +#if defined __LCC__ #include /* for wcslen() */ #endif -#if (defined _Windows && !defined AMX_NODYNALOAD) || (defined JIT && !defined __linux__) +#include "amx.h" +#if (defined _Windows && !defined AMX_NODYNALOAD) || (defined JIT && __WIN32__) #include #endif -// this file does not include amxmodx.h, so we have to include the memory manager here -#ifdef MEMORY_TEST -#include "mmgr/mmgr.h" -#endif // MEMORY_TEST - -#include "amx.h" - -#ifdef JIT -# ifdef __WIN32__ -# include // DWORD, VirtualProtect, ... -# elif defined __linux__ -# include // mprotect, PROT_* -# include -# else - // :TODO: -# endif -#endif // JIT /* When one or more of the AMX_funcname macris are defined, we want * to compile only those functions. However, when none of these macros @@ -109,11 +95,11 @@ #endif #if !defined AMX_EXPLIT_FUNCTIONS /* no constant set, set them all */ - #define AMX_ALIGN /* amx_Align16() and amx_Align32() */ + #define AMX_ALIGN /* amx_Align16(), amx_Align32() and amx_Align64() */ #define AMX_ALLOT /* amx_Allot() and amx_Release() */ #define AMX_CLEANUP /* amx_Cleanup() */ #define AMX_CLONE /* amx_Clone() */ - #define AMX_EXEC /* amx_Exec() and amx_Execv() */ + #define AMX_EXEC /* amx_Exec() plus amx_Push(), amx_PushArray() and amx_PushString() */ #define AMX_FLAGS /* amx_Flags() */ #define AMX_GETADDR /* amx_GetAddr() */ #define AMX_INIT /* amx_Init() and amx_InitJIT() */ @@ -127,12 +113,15 @@ #define AMX_XXXNATIVES /* amx_NumNatives(), amx_GetNative() and amx_FindNative() */ #define AMX_XXXPUBLICS /* amx_NumPublics(), amx_GetPublic() and amx_FindPublic() */ #define AMX_XXXPUBVARS /* amx_NumPubVars(), amx_GetPubVar() and amx_FindPubVar() */ - #define AMX_XXXSTRING /* amx_StrLength(), amx_GetString() and amx_SetString() */ + #define AMX_XXXSTRING /* amx_StrLen(), amx_GetString() and amx_SetString() */ #define AMX_XXXTAGS /* amx_NumTags(), amx_GetTag() and amx_FindTagId() */ #define AMX_XXXUSERDATA /* amx_GetUserData() and amx_SetUserData() */ #define AMX_UTF8XXX /* amx_UTF8Get(), amx_UTF8Put(), amx_UTF8Check() */ #endif #undef AMX_EXPLIT_FUNCTIONS +#if defined AMX_ANSIONLY + #undef AMX_UTF8XXX /* no UTF-8 support in ANSI/ASCII-only version */ +#endif typedef enum { OP_NONE, /* invalid opcode */ @@ -259,10 +248,10 @@ typedef enum { OP_BOUNDS, OP_SYSREQ_PRI, OP_SYSREQ_C, - OP_FILE, - OP_LINE, - OP_SYMBOL, - OP_SRANGE, + OP_FILE, /* obsolete */ + OP_LINE, /* obsolete */ + OP_SYMBOL, /* obsolete */ + OP_SRANGE, /* obsolete */ OP_JUMP_PRI, OP_SWITCH, OP_CASETBL, @@ -271,135 +260,138 @@ typedef enum { OP_PUSHADDR, OP_NOP, OP_SYSREQ_D, - OP_SYMTAG, + OP_SYMTAG, /* obsolete */ + OP_BREAK, /* ----- */ OP_NUM_OPCODES } OPCODE; -typedef struct tagFUNCSTUBNT { - ucell address PACKED; - ucell nameofs PACKED; -} FUNCSTUBNT PACKED; - #define USENAMETABLE(hdr) \ - ((hdr)->defsize==sizeof(FUNCSTUBNT)) + ((hdr)->defsize==sizeof(AMX_FUNCSTUBNT)) #define NUMENTRIES(hdr,field,nextfield) \ - (int)(((hdr)->nextfield - (hdr)->field) / (hdr)->defsize) + (unsigned)(((hdr)->nextfield - (hdr)->field) / (hdr)->defsize) #define GETENTRY(hdr,table,index) \ - (AMX_FUNCSTUB *)((unsigned char*)(hdr) + (int)(hdr)->table + (int)index*(hdr)->defsize) + (AMX_FUNCSTUB *)((unsigned char*)(hdr) + (unsigned)(hdr)->table + (unsigned)index*(hdr)->defsize) #define GETENTRYNAME(hdr,entry) \ ( USENAMETABLE(hdr) \ - ? (char *)((unsigned char*)(hdr) + ((FUNCSTUBNT*)(entry))->nameofs) \ + ? (char *)((unsigned char*)(hdr) + (unsigned)((AMX_FUNCSTUBNT*)(entry))->nameofs) \ : ((AMX_FUNCSTUB*)(entry))->name ) -static int amx_LittleEndian = -1; /* set to TRUE for Little Endian, and - * to FALSE for Big Endian */ - -static void init_little_endian(void) -{ - if (amx_LittleEndian < 0) { /* initialize this variable only once */ +#if !defined NDEBUG + static int check_endian(void) + { uint16_t val=0x00ff; unsigned char *ptr=(unsigned char *)&val; - /* "ptr" points to the starting address of "val". If that address * holds the byte "0xff", the computer stored the low byte of "val" * at the lower address, and so the memory lay out is Little Endian. */ assert(*ptr==0xff || *ptr==0x00); - amx_LittleEndian= *ptr==0xff; - } /* if */ -} + #if BYTE_ORDER==BIG_ENDIAN + return *ptr==0x00; /* return "true" if big endian */ + #else + return *ptr==0xff; /* return "true" if little endian */ + #endif + } +#endif -static void swap16(uint16_t *v) -{ - unsigned char *s = (unsigned char *)v; - unsigned char t; +#if BYTE_ORDER==BIG_ENDIAN || PAWN_CELL_SIZE==16 + static void swap16(uint16_t *v) + { + unsigned char *s = (unsigned char *)v; + unsigned char t; - assert(sizeof(*v)==2); - /* swap two bytes */ - t=s[0]; - s[0]=s[1]; - s[1]=t; -} + assert(sizeof(*v)==2); + /* swap two bytes */ + t=s[0]; + s[0]=s[1]; + s[1]=t; + } +#endif -static void swap32(uint32_t *v) -{ - unsigned char *s = (unsigned char *)v; - unsigned char t; +#if BYTE_ORDER==BIG_ENDIAN || PAWN_CELL_SIZE==32 + static void swap32(uint32_t *v) + { + unsigned char *s = (unsigned char *)v; + unsigned char t; - assert(sizeof(*v)==4); - /* swap outer two bytes */ - t=s[0]; - s[0]=s[3]; - s[3]=t; - /* swap inner two bytes */ - t=s[1]; - s[1]=s[2]; - s[2]=t; -} + assert(sizeof(*v)==4); + /* swap outer two bytes */ + t=s[0]; + s[0]=s[3]; + s[3]=t; + /* swap inner two bytes */ + t=s[1]; + s[1]=s[2]; + s[2]=t; + } +#endif -#if defined _I64_MAX || defined HAVE_I64 -static void swap64(uint64_t *v) -{ - unsigned char *s = (unsigned char *)v; - unsigned char t; +#if (BYTE_ORDER==BIG_ENDIAN || PAWN_CELL_SIZE==64) && (defined _I64_MAX || defined HAVE_I64) + static void swap64(uint64_t *v) + { + unsigned char *s = (unsigned char *)v; + unsigned char t; - assert(sizeof(*v)==8); + assert(sizeof(*v)==8); - t=s[0]; - s[0]=s[7]; - s[7]=t; + t=s[0]; + s[0]=s[7]; + s[7]=t; - t=s[1]; - s[1]=s[6]; - s[6]=t; + t=s[1]; + s[1]=s[6]; + s[6]=t; - t=s[2]; - s[2]=s[5]; - s[5]=t; + t=s[2]; + s[2]=s[5]; + s[5]=t; - t=s[3]; - s[3]=s[4]; - s[4]=t; -} + t=s[3]; + s[3]=s[4]; + s[4]=t; + } #endif #if defined AMX_ALIGN || defined AMX_INIT uint16_t * AMXAPI amx_Align16(uint16_t *v) { assert(sizeof(*v)==2); - init_little_endian(); - if (!amx_LittleEndian) + assert(check_endian()); + #if BYTE_ORDER==BIG_ENDIAN swap16(v); + #endif return v; } uint32_t * AMXAPI amx_Align32(uint32_t *v) { assert(sizeof(*v)==4); - init_little_endian(); - if (!amx_LittleEndian) + assert(check_endian()); + #if BYTE_ORDER==BIG_ENDIAN swap32(v); + #endif return v; } #if defined _I64_MAX || defined HAVE_I64 uint64_t * AMXAPI amx_Align64(uint64_t *v) { - assert(sizeof(*v)==8); - init_little_endian(); - if (!amx_LittleEndian) - swap64(v); - return v; + assert(sizeof(*v)==8); + assert(check_endian()); + #if BYTE_ORDER==BIG_ENDIAN + swap64(v); + #endif + return v; } #endif /* _I64_MAX || HAVE_I64 */ #endif /* AMX_ALIGN || AMX_INIT */ -#if SMALL_CELL_SIZE==16 +#if PAWN_CELL_SIZE==16 #define swapcell swap16 -#elif SMALL_CELL_SIZE==32 +#elif PAWN_CELL_SIZE==32 #define swapcell swap32 -#elif SMALL_CELL_SIZE==64 && (defined _I64_MAX || defined HAVE_I64) +#elif PAWN_CELL_SIZE==64 && (defined _I64_MAX || defined HAVE_I64) #define swapcell swap64 #else #error Unsupported cell size @@ -423,29 +415,56 @@ int AMXAPI amx_Flags(AMX *amx,uint16_t *flags) } #endif /* AMX_FLAGS */ +void debug(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + FILE *fp = fopen("c:\\dump.txt", "at"); + if (fp) + { + vfprintf(fp, fmt, ap); + fclose(fp); + } + va_end(ap); +} + + #if defined AMX_INIT int AMXAPI amx_Callback(AMX *amx, cell index, cell *result, cell *params) { AMX_HEADER *hdr; AMX_FUNCSTUB *func; AMX_NATIVE f; - int i =0; assert(amx!=NULL); hdr=(AMX_HEADER *)amx->base; assert(hdr!=NULL); assert(hdr->magic==AMX_MAGIC); assert(hdr->natives<=hdr->libraries); - assert(index>=0 && index<(cell)NUMENTRIES(hdr,natives,libraries)); - func=GETENTRY(hdr,natives,index); - f=(AMX_NATIVE)func->address; - amx->userdata[2] = (char *)GETENTRYNAME(hdr, func); +#if defined AMX_NATIVETABLE + if (index=0 && index<(cell)NUMENTRIES(hdr,natives,libraries)); + func=GETENTRY(hdr,natives,index); + f=(AMX_NATIVE)func->address; +#if defined AMX_NATIVETABLE + } /* if */ +#endif assert(f!=NULL); - /* now that we have found the function, patch the program so that any + /* Now that we have found the function, patch the program so that any * subsequent call will call the function directly (bypassing this - * callback) + * callback). + * This trick cannot work in the JIT, because the program would need to + * be re-JIT-compiled after patching a P-code instruction. */ + #if defined JIT && !defined NDEBUG + if ((amx->flags & AMX_FLAG_JITC)!=0) + assert(amx->sysreq_d==0); + #endif if (amx->sysreq_d!=0) { /* at the point of the call, the CIP pseudo-register points directly * behind the SYSREQ instruction and its parameter. @@ -453,7 +472,7 @@ int AMXAPI amx_Callback(AMX *amx, cell index, cell *result, cell *params) unsigned char *code=amx->base+(int)hdr->cod+(int)amx->cip-4; assert(amx->cip >= 4 && amx->cip < (hdr->dat - hdr->cod)); assert(sizeof(f)<=sizeof(cell)); /* function pointer must fit in a cell */ -#if defined __GNUC__ || defined ASM32 || defined JIT +#if defined __GNUC__ || defined ASM32 if (*(cell*)code==index) { #else if (*(cell*)code!=OP_SYSREQ_PRI) { @@ -475,93 +494,28 @@ int AMXAPI amx_Callback(AMX *amx, cell index, cell *result, cell *params) *result = f(amx,params); return amx->error; } +#endif /* defined AMX_INIT */ -#if defined __BORLANDC__ || defined __WATCOMC__ - #pragma argsused -#endif -int AMXAPI amx_Debug(AMX *amx) -{ - return AMX_ERR_DEBUG; -} - -//Here is the actual debugger that AMX Mod X uses -int AMXAPI amx_DebugCall(AMX *amx, int mode) -{ - //right away, check for debugging - AMX_HEADER *hdr; - AMX_DBG *p = 0; - AMX_TRACE *t = 0; - hdr = (AMX_HEADER *)amx->base; - if ( !(amx->flags & AMX_FLAG_DEBUG) || !(amx->flags & AMX_FLAG_LINEOPS)) - return AMX_ERR_NONE; - p = (AMX_DBG *)(amx->userdata[0]); - if ( !p ) - return AMX_ERR_NONE; - if (mode == 2) - { - //mode - push onto the stack - t = (AMX_TRACE *)malloc(sizeof(AMX_TRACE)); - memset(t, 0, sizeof(AMX_TRACE)); - if (!p->head) - { - p->head = t; - t->prev = NULL; - } else { - t->prev = p->tail; - p->tail->next = t; - } - p->tail = t; - t->line = amx->curline; - t->file = amx->curfile; - } else if (mode == 1) { - //mode <0 - pop from the stack - t = p->tail; - if (t) - { - p->tail = t->prev; - free(t); - } - if (p->tail == NULL) - p->head = NULL; - } else if (mode == 0) { - AMX_TRACE *m; - //mode == 0 - clear stack - t = p->head; - while (t) - { - m = t->next; - free(t); - t = m; - } - p->head = 0; - p->tail = 0; - } - - return AMX_ERR_NONE; -} #if defined JIT -#if defined WIN32 || defined __cplusplus extern "C" int AMXAPI getMaxCodeSize(void); extern "C" int AMXAPI asm_runJIT(void *sourceAMXbase, void *jumparray, void *compiledAMXbase); -#else - extern int AMXAPI getMaxCodeSize(void); - extern int AMXAPI asm_runJIT(void *sourceAMXbase, void *jumparray, void *compiledAMXbase); -#endif #endif -#if SMALL_CELL_SIZE==16 - #define JUMPABS(base,ip) ((cell *)(base+*ip)) +#if PAWN_CELL_SIZE==16 + #define JUMPABS(base,ip) ((cell *)((base) + *(ip))) #define RELOC_ABS(base, off) #define RELOC_VALUE(base, v) #else - #define JUMPABS(base, ip) ((cell *)*ip) - #define RELOC_ABS(base, off) *(ucell *)(base+(int)off) += (ucell)base + #define JUMPABS(base, ip) ((cell *)*(ip)) + #define RELOC_ABS(base, off) (*(ucell *)((base)+(int)(off)) += (ucell)(base)) #define RELOC_VALUE(base, v) ((v)+((ucell)(base))) #endif #define DBGPARAM(v) ( (v)=*(cell *)(code+(int)cip), cip+=sizeof(cell) ) +#if defined AMX_INIT + static int amx_BrowseRelocate(AMX *amx) { AMX_HEADER *hdr; @@ -569,7 +523,6 @@ static int amx_BrowseRelocate(AMX *amx) cell cip; long codesize; OPCODE op; - int last_sym_global = 0; #if defined __GNUC__ || defined ASM32 || defined JIT cell *opcode_list; #endif @@ -584,6 +537,7 @@ static int amx_BrowseRelocate(AMX *amx) assert(hdr->magic==AMX_MAGIC); code=amx->base+(int)hdr->cod; codesize=hdr->dat - hdr->cod; + amx->flags=AMX_FLAG_BROWSE; /* sanity checks */ assert(OP_PUSH_PRI==36); @@ -595,38 +549,26 @@ static int amx_BrowseRelocate(AMX *amx) assert(OP_MOVS==117); assert(OP_SYMBOL==126); - amx->flags=AMX_FLAG_BROWSE; - - /* check the debug hook */ - if ((hdr->flags & AMX_FLAG_LINEOPS) && !(hdr->flags & AMX_FLAG_TRACED)) - { - amx->userdata[0] = (AMX_DBG *)malloc(sizeof(AMX_DBG)); - amx->userdata[1] = (void *)amx_DebugCall; - memset(amx->userdata[0], 0, sizeof(AMX_DBG)); - amx->flags |= AMX_FLAG_LINEOPS; - amx->flags |= AMX_FLAG_TRACED; - amx->flags |= AMX_FLAG_DEBUG; - } else { - amx->userdata[0] = 0; - amx->userdata[1] = 0; - amx->userdata[2] = 0; - } - - #if defined __GNUC__ || defined ASM32 || defined JIT && !defined __64BIT__ - amx_Exec(amx, (cell*)&opcode_list, 0, 0); - #if !defined JIT - amx->sysreq_d=(sizeof(AMX_NATIVE)<=sizeof(cell)) ? opcode_list[OP_SYSREQ_D] : 0; - #endif - #else - /* ANSI C - * to use direct system requests, a function pointer must fit in a cell; + amx->sysreq_d=0; /* preset */ + #if (defined __GNUC__ || defined ASM32 || defined JIT) && !defined __64BIT__ + amx_Exec(amx, (cell*)(void*)&opcode_list, 0); + /* to use direct system requests, a function pointer must fit in a cell; * because the native function's address will be stored as the parameter * of SYSREQ.D */ - amx->sysreq_d= (sizeof(AMX_NATIVE)<=sizeof(cell)) ? OP_SYSREQ_D : 0; + if ((amx->flags & AMX_FLAG_JITC)==0 && sizeof(AMX_NATIVE)<=sizeof(cell)) + amx->sysreq_d=opcode_list[OP_SYSREQ_D]; + #else + /* ANSI C + * to use direct system requests, a function pointer must fit in a cell; + * see the comment above + */ + if (sizeof(AMX_NATIVE)<=sizeof(cell)) + amx->sysreq_d=OP_SYSREQ_D; #endif /* start browsing code */ + debug("opcode_list=%p\n", opcode_list); for (cip=0; cip0 && opcurfile); - amx->dbgname=(char *)(code+(int)cip); - cip+=num - sizeof(cell); - if (!(hdr->flags & AMX_FLAG_TRACED) && amx->userdata[0] != NULL) - { - AMX_DBG *pDbg = (AMX_DBG *)(amx->userdata[0]); - if (pDbg->numFiles == 0) - { - pDbg->numFiles++; - pDbg->files = (char **)malloc(sizeof(char *) * 1); - } else { - pDbg->numFiles++; - pDbg->files = (char **)realloc(pDbg->files, pDbg->numFiles * sizeof(char*)); - } - pDbg->files[pDbg->numFiles-1] = (char *)malloc((sizeof(char) * strlen(amx->dbgname)) + 1); - strcpy(pDbg->files[pDbg->numFiles-1], amx->dbgname); - } /* if */ - break; - } /* case */ - case OP_LINE: - DBGPARAM(amx->curline); - DBGPARAM(amx->curfile); - break; + case OP_FILE: case OP_SYMBOL: { cell num; DBGPARAM(num); - DBGPARAM(amx->dbgaddr); - DBGPARAM(amx->dbgparam); - amx->dbgname=(char *)(code+(int)cip); - cip+=num - 2*sizeof(cell); - last_sym_global = (amx->dbgparam >> 8)==0; + cip+=num; break; } /* case */ + case OP_LINE: case OP_SRANGE: - DBGPARAM(amx->dbgaddr); /* dimension level */ - DBGPARAM(amx->dbgparam); /* length */ + cip+=2*sizeof(cell); break; case OP_SYMTAG: - DBGPARAM(amx->dbgparam); /* tag id */ + cip+=sizeof(cell); break; case OP_CASETBL: { cell num; @@ -855,17 +772,17 @@ static int amx_BrowseRelocate(AMX *amx) amx->flags &= ~AMX_FLAG_BROWSE; amx->flags |= AMX_FLAG_RELOC; - amx->flags |= AMX_FLAG_TRACED; return AMX_ERR_NONE; } +#if AMX_COMPACTMARGIN > 2 static void expand(unsigned char *code, long codesize, long memsize) { ucell c; struct { long memloc; ucell c; - } spare[AMX_EXPANDMARGIN]; + } spare[AMX_COMPACTMARGIN]; int sh=0,st=0,sc=0; int shift; @@ -886,15 +803,15 @@ static void expand(unsigned char *code, long codesize, long memsize) } while (codesize>0 && (code[(size_t)codesize-1] & 0x80)!=0); /* sign expand */ if ((code[(size_t)codesize] & 0x40)!=0) { - while (shift < 8*sizeof(cell)) { + while (shift < (int)(8*sizeof(cell))) { c|=(ucell)0xff << shift; shift+=8; } /* while */ } /* if */ /* store */ - while (sc&&(spare[sh].memloc>codesize)) { + while (sc && (spare[sh].memloc>codesize)) { *(ucell *)(code+(int)spare[sh].memloc)=spare[sh].c; - sh=(sh+1)%AMX_EXPANDMARGIN; + sh=(sh+1)%AMX_COMPACTMARGIN; sc--; } /* while */ memsize -= sizeof(cell); @@ -902,26 +819,27 @@ static void expand(unsigned char *code, long codesize, long memsize) if ((memsize>codesize)||((memsize==codesize)&&(memsize==0))) { *(ucell *)(code+(size_t)memsize)=c; } else { - assert(scsize); amx_Align16(&hdr->magic); amx_Align16((uint16_t*)&hdr->flags); @@ -953,13 +871,13 @@ int AMXAPI amx_Init(AMX *amx,void *program) amx_Align32((uint32_t*)&hdr->libraries); amx_Align32((uint32_t*)&hdr->pubvars); amx_Align32((uint32_t*)&hdr->tags); - } /* if */ + #endif if (hdr->magic!=AMX_MAGIC) return AMX_ERR_FORMAT; if (hdr->file_versionamx_version>CUR_FILE_VERSION) return AMX_ERR_VERSION; - if (hdr->defsize!=sizeof(AMX_FUNCSTUB) && hdr->defsize!=sizeof(FUNCSTUBNT)) + if (hdr->defsize!=sizeof(AMX_FUNCSTUB) && hdr->defsize!=sizeof(AMX_FUNCSTUBNT)) return AMX_ERR_FORMAT; if (USENAMETABLE(hdr)) { uint16_t *namelength; @@ -967,19 +885,29 @@ int AMXAPI amx_Init(AMX *amx,void *program) * in that table */ amx_Align32((uint32_t*)&hdr->nametable); - namelength=(uint16_t*)((unsigned char*)program + hdr->nametable); + namelength=(uint16_t*)((unsigned char*)program + (unsigned)hdr->nametable); amx_Align16(namelength); if (*namelength>sNAMEMAX) return AMX_ERR_FORMAT; } /* if */ if (hdr->stp<=0) return AMX_ERR_FORMAT; - if (!amx_LittleEndian && (hdr->flags & AMX_FLAG_COMPACT)==0) - return AMX_ERR_FORMAT; /* On Big Endian machines, use compact encoding */ + #if BYTE_ORDER==BIG_ENDIAN + if ((hdr->flags & AMX_FLAG_COMPACT)==0) { + ucell *code=(ucell *)((unsigned char *)program+(int)hdr->cod); + while (code<(ucell *)((unsigned char *)program+(int)hdr->hea)) + swapcell(code++); + } /* if */ + #endif assert((hdr->flags & AMX_FLAG_COMPACT)!=0 || hdr->hea == hdr->size); - if ((hdr->flags & AMX_FLAG_COMPACT)!=0) - expand((unsigned char *)program+(int)hdr->cod, - hdr->size - hdr->cod, hdr->hea - hdr->cod); + if ((hdr->flags & AMX_FLAG_COMPACT)!=0) { + #if AMX_COMPACTMARGIN > 2 + expand((unsigned char *)program+(int)hdr->cod, + hdr->size - hdr->cod, hdr->hea - hdr->cod); + #else + return AMX_ERR_FORMAT; + #endif + } /* if */ amx->base=(unsigned char *)program; @@ -995,25 +923,33 @@ int AMXAPI amx_Init(AMX *amx,void *program) amx->stk=amx->stp; if (amx->callback==NULL) amx->callback=amx_Callback; - amx->curline=0; - amx->curfile=0; amx->data=NULL; - /* also align all addresses in the public function, public variable and - * public tag tables --offsets into the name table (if present) must also - * be swapped. + /* also align all addresses in the public function, public variable, + * public tag and native function tables --offsets into the name table + * (if present) must also be swapped. */ - if (!amx_LittleEndian) { + #if BYTE_ORDER==BIG_ENDIAN + { /* local */ AMX_FUNCSTUB *fs; int i,num; + fs=GETENTRY(hdr,natives,0); + num=NUMENTRIES(hdr,natives,libraries); + for (i=0; iaddress); /* redundant, because it should be zero */ + if (USENAMETABLE(hdr)) + amx_Align32(&((AMX_FUNCSTUBNT*)fs)->nameofs); + fs=(AMX_FUNCSTUB*)((unsigned char *)fs+hdr->defsize); + } /* for */ + fs=GETENTRY(hdr,publics,0); assert(hdr->publics<=hdr->natives); num=NUMENTRIES(hdr,publics,natives); for (i=0; iaddress); if (USENAMETABLE(hdr)) - amx_AlignCell(&((FUNCSTUBNT*)fs)->nameofs); + amx_Align32(&((AMX_FUNCSTUBNT*)fs)->nameofs); fs=(AMX_FUNCSTUB*)((unsigned char *)fs+hdr->defsize); } /* for */ @@ -1023,7 +959,7 @@ int AMXAPI amx_Init(AMX *amx,void *program) for (i=0; iaddress); if (USENAMETABLE(hdr)) - amx_AlignCell(&((FUNCSTUBNT*)fs)->nameofs); + amx_Align32(&((AMX_FUNCSTUBNT*)fs)->nameofs); fs=(AMX_FUNCSTUB*)((unsigned char *)fs+hdr->defsize); } /* for */ @@ -1038,16 +974,17 @@ int AMXAPI amx_Init(AMX *amx,void *program) for (i=0; iaddress); if (USENAMETABLE(hdr)) - amx_AlignCell(&((FUNCSTUBNT*)fs)->nameofs); + amx_Align32(&((AMX_FUNCSTUBNT*)fs)->nameofs); fs=(AMX_FUNCSTUB*)((unsigned char *)fs+hdr->defsize); } /* for */ - } /* if */ + } /* local */ + #endif - /* relocate call and jump instructions, optionally gather debug information */ + /* relocate call and jump instructions */ amx_BrowseRelocate(amx); /* load any extension modules that the AMX refers to */ - #if (defined _Windows || defined LINUX) && !defined AMX_NODYNALOAD + #if (defined _Windows || defined LINUX || defined __FreeBSD__ || defined __OpenBSD__) && !defined AMX_NODYNALOAD hdr=(AMX_HEADER *)amx->base; numlibraries=NUMENTRIES(hdr,libraries,pubvars); for (i=0; iaddress=(uint32_t)hlib; + lib->address=(ucell)hlib; } /* for */ #endif @@ -1092,109 +1029,101 @@ int AMXAPI amx_Init(AMX *amx,void *program) #if defined JIT + #define CODESIZE_JIT 8192 /* approximate size of the code for the JIT */ + #if defined __WIN32__ /* this also applies to Win32 "console" applications */ - int memoryFullAccess( void* addr, int len ) + #define PROT_READ 0x1 /* page can be read */ + #define PROT_WRITE 0x2 /* page can be written */ + #define PROT_EXEC 0x4 /* page can be executed */ + #define PROT_NONE 0x0 /* page can not be accessed */ + + static int mprotect(void *addr, size_t len, int prot) { - DWORD op; - if ( VirtualProtect( addr, len, PAGE_EXECUTE_READWRITE, &op ) ) - return op; - return 0; + DWORD prev, p = 0; + if ((prot & PROT_WRITE)!=0) + p = PAGE_EXECUTE_READWRITE; + else + p |= PAGE_EXECUTE_READ; + return !VirtualProtect(addr, len, p, &prev); } - int memorySetAccess( void* addr, int len, int access ) - { - DWORD op; - if ( access == 0 ) - return 0; - return VirtualProtect( addr, len, access, &op ); - } + #elif defined LINUX || defined __FreeBSD__ || defined __OpenBSD__ - #else /* #if defined __WIN32 __ */ - // DOS32 has no imposed limits on its segments. - #if defined __BORLANDC__ || defined __WATCOMC__ - #pragma argsused - #endif - int memoryFullAccess( void* addr, int len ) - { - return mprotect(addr, len, PROT_READ|PROT_WRITE|PROT_EXEC); - } + /* Linux already has mprotect() */ - #if defined __BORLANDC__ || defined __WATCOMC__ - #pragma argsused - #endif - int memorySetAccess( void* addr, int len, int access ) - { - return mprotect(addr, len, PROT_READ|PROT_EXEC); - } + #else + + // TODO: Add cases for Linux, Unix, OS/2, ... + + /* DOS32 has no imposed limits on its segments */ + #define mprotect(addr, len, prot) (0) #endif /* #if defined __WIN32 __ */ int AMXAPI amx_InitJIT(AMX *amx, void *reloc_table, void *native_code) { - int mac, res; + int res; AMX_HEADER *hdr; -#ifdef __linux__ - mac = memoryFullAccess( (void *)((int)((void*)asm_runJIT)-(int)((void*)asm_runJIT)%sysconf(_SC_PAGESIZE)), 20000 ); - if ( mac ) -#else - mac = memoryFullAccess((void *)asm_runJIT, 20000); - if ( !mac ) -#endif - return AMX_ERR_INIT_JIT; - - /* copy the prefix */ - memcpy( native_code, amx->base, ((AMX_HEADER *)(amx->base))->cod ); - hdr = (AMX_HEADER*)native_code; - - /* JIT rulz! (TM) */ - /* MP: added check for correct compilation */ - res = asm_runJIT( amx->base, reloc_table, native_code ); - if ( res != 0 ) + if ((amx->flags & AMX_FLAG_JITC)==0) { - memorySetAccess( (void*)asm_runJIT, 20000, mac ); + debug("failing at line %d\n", __LINE__); + return AMX_ERR_INIT_JIT; /* flag not set, this AMX is not prepared for JIT */ + } + + /* Patching SYSREQ opcodes to SYSREQ_D cannot work in the JIT, because the + * program would need to be re-JIT-compiled after patching a P-code + * instruction. If this field is not zero, something went wrong with the + * amx_BrowseRelocate(). + */ + assert(amx->sysreq_d==0); + + if (mprotect(asm_runJIT, CODESIZE_JIT, PROT_READ | PROT_WRITE | PROT_EXEC) != 0) + { + debug("failing at line %d\n", __LINE__); return AMX_ERR_INIT_JIT; } - /* update the required memory size (the previous value was a - * conservative estimate, now we know the exact size) - */ - amx->code_size = (hdr->dat + hdr->stp + 3) & ~3; - /* The compiled code is relocatable, since only relative jumps are - * used for destinations within the generated code and absoulute - * addresses for jumps into the runtime, which is fixed in memory. - */ - amx->base = (unsigned char*) native_code; - amx->cip = hdr->cip; - amx->hea = hdr->hea; - amx->stp = hdr->stp - sizeof(cell); - /* also put a sentinel for strings at the top the stack */ - *(cell *)((char*)native_code + hdr->dat + hdr->stp - sizeof(cell)) = 0; - amx->stk = amx->stp; + /* copy the prefix */ + memcpy(native_code, amx->base, ((AMX_HEADER *)(amx->base))->cod); + hdr = (AMX_HEADER *)native_code; - memorySetAccess( (void*)asm_runJIT, 20000, mac ); - return AMX_ERR_NONE; + /* JIT rulz! (TM) */ + /* MP: added check for correct compilation */ + if ((res = asm_runJIT(amx->base, reloc_table, native_code)) != 0) { + /* update the required memory size (the previous value was a + * conservative estimate, now we know the exact size) + */ + amx->code_size = (hdr->dat + hdr->stp + 3) & ~3; + /* The compiled code is relocatable, since only relative jumps are + * used for destinations within the generated code and absoulute + * addresses for jumps into the runtime, which is fixed in memory. + */ + amx->base = (unsigned char*) native_code; + amx->cip = hdr->cip; + amx->hea = hdr->hea; + amx->stp = hdr->stp - sizeof(cell); + /* also put a sentinel for strings at the top the stack */ + *(cell *)((char*)native_code + hdr->dat + hdr->stp - sizeof(cell)) = 0; + amx->stk = amx->stp; + } /* if */ + + debug("return value is %d\n", res); + + return (res == 0) ? AMX_ERR_NONE : AMX_ERR_INIT_JIT; } #else /* #if defined JIT */ -#if defined _MSC_VER - #pragma warning(push) - #pragma warning(disable: 4100) // unreferenced formal parameter -#endif -#if defined __BORLANDC__ || defined __WATCOMC__ - #pragma argsused -#endif int AMXAPI amx_InitJIT(AMX *amx,void *compiled_program,void *reloc_table) { + (void)amx; + (void)compiled_program; + (void)reloc_table; return AMX_ERR_INIT_JIT; } -#if defined _MSC_VER - #pragma warning(pop) -#endif - #endif /* #if defined JIT */ #endif /* AMX_INIT */ @@ -1202,10 +1131,10 @@ int AMXAPI amx_InitJIT(AMX *amx,void *compiled_program,void *reloc_table) #if defined AMX_CLEANUP int AMXAPI amx_Cleanup(AMX *amx) { - #if (defined _Windows || defined LINUX) && !defined AMX_NODYNALOAD + #if (defined _Windows || defined LINUX || defined __FreeBSD__ || defined __OpenBSD__) && !defined AMX_NODYNALOAD #if defined _Windows typedef int (FAR WINAPI *AMX_ENTRY)(AMX FAR *amx); - #elif defined LINUX + #elif defined LINUX || defined __FreeBSD__ || defined __OpenBSD__ typedef int (*AMX_ENTRY)(AMX *amx); #endif AMX_HEADER *hdr; @@ -1215,7 +1144,7 @@ int AMXAPI amx_Cleanup(AMX *amx) #endif /* unload all extension modules */ - #if (defined _Windows || defined LINUX) && !defined AMX_NODYNALOAD + #if (defined _Windows || defined LINUX || defined __FreeBSD__ || defined __OpenBSD__) && !defined AMX_NODYNALOAD hdr=(AMX_HEADER *)amx->base; assert(hdr->magic==AMX_MAGIC); numlibraries=NUMENTRIES(hdr,libraries,pubvars); @@ -1228,18 +1157,20 @@ int AMXAPI amx_Cleanup(AMX *amx) strcat(funcname,"Cleanup"); #if defined _Windows libcleanup=(AMX_ENTRY)GetProcAddress((HINSTANCE)lib->address,funcname); - #elif defined LINUX + #elif defined LINUX || defined __FreeBSD__ || defined __OpenBSD__ libcleanup=(AMX_ENTRY)dlsym((void*)lib->address,funcname); #endif if (libcleanup!=NULL) libcleanup(amx); #if defined _Windows FreeLibrary((HINSTANCE)lib->address); - #elif defined LINUX + #elif defined LINUX || defined __FreeBSD__ || defined __OpenBSD__ dlclose((void*)lib->address); #endif } /* if */ } /* for */ + #else + (void)amx; #endif return AMX_ERR_NONE; } @@ -1274,8 +1205,6 @@ int AMXAPI amx_Clone(AMX *amxClone, AMX *amxSource, void *data) if (amxClone->debug==NULL) amxClone->debug=amxSource->debug; amxClone->flags=amxSource->flags; - amxClone->curline=0; - amxClone->curfile=0; /* copy the data segment; the stack and the heap can be left uninitialized */ assert(data!=NULL); @@ -1323,11 +1252,11 @@ int AMXAPI amx_NameLength(AMX *amx, int *length) assert(hdr!=NULL); assert(hdr->magic==AMX_MAGIC); if (USENAMETABLE(hdr)) { - uint16_t *namelength=(uint16_t*)(amx->base + hdr->nametable); + uint16_t *namelength=(uint16_t*)(amx->base + (unsigned)hdr->nametable); *length=*namelength; assert(hdr->file_version>=7); /* name table exists only for file version 7+ */ } else { - *length=hdr->defsize - sizeof(cell); + *length=hdr->defsize - sizeof(ucell); } /* if */ return AMX_ERR_NONE; } @@ -1632,7 +1561,7 @@ int AMXAPI amx_SetUserData(AMX *amx, long tag, void *ptr) #endif /* AMX_XXXUSERDATA */ #if defined AMX_REGISTER || defined AMX_EXEC || defined AMX_INIT -static AMX_NATIVE findfunction(const char *name, AMX_NATIVE_INFO *list, int number) +static AMX_NATIVE findfunction(const char *name, const AMX_NATIVE_INFO *list, int number) { int i; @@ -1643,8 +1572,8 @@ static AMX_NATIVE findfunction(const char *name, AMX_NATIVE_INFO *list, int numb return NULL; } -const char *no_function; // PM: Nice hack ;) -int AMXAPI amx_Register(AMX *amx, AMX_NATIVE_INFO *list, int number) +const char *no_function; +int AMXAPI amx_Register(AMX *amx, const AMX_NATIVE_INFO *list, int number) { AMX_FUNCSTUB *func; AMX_HEADER *hdr; @@ -1664,51 +1593,19 @@ int AMXAPI amx_Register(AMX *amx, AMX_NATIVE_INFO *list, int number) /* this function is not yet located */ funcptr=(list!=NULL) ? findfunction(GETENTRYNAME(hdr,func),list,number) : NULL; if (funcptr!=NULL) + { func->address=(ucell)funcptr; - else - { + } else { no_function = GETENTRYNAME(hdr,func); err=AMX_ERR_NOTFOUND; - } + } } /* if */ func=(AMX_FUNCSTUB*)((unsigned char*)func+hdr->defsize); } /* for */ + if (err==AMX_ERR_NONE) + amx->flags|=AMX_FLAG_NTVREG; return err; } - -static cell AMX_NATIVE_CALL null_native(AMX *amx, cell *params) -{ - return 0; -} - -void amx_NullNativeTable(AMX *amx) -{ - AMX_FUNCSTUB *func; - AMX_HEADER *hdr; - int i, numnatives; - - hdr=(AMX_HEADER *)amx->base; - if (hdr == NULL) - return; - if (hdr->magic!=AMX_MAGIC) - return; - - numnatives = NUMENTRIES(hdr, natives, libraries); - - func=GETENTRY(hdr, natives, 0); - - for (i=0; iaddress = NULL; - } else { - func->address = (ucell)null_native; - } - func=(AMX_FUNCSTUB*)((unsigned char*)func+hdr->defsize); - } -} - #endif /* AMX_REGISTER || AMX_EXEC || AMX_INIT */ #if defined AMX_NATIVEINFO @@ -1723,26 +1620,88 @@ AMX_NATIVE_INFO * AMXAPI amx_NativeInfo(const char *name, AMX_NATIVE func) #if defined AMX_EXEC || defined AMX_INIT +#define STKMARGIN ((cell)(16*sizeof(cell))) + +int AMXAPI amx_Push(AMX *amx, cell value) +{ + AMX_HEADER *hdr; + unsigned char *data; + + if (amx->hea+STKMARGIN>amx->stk) + return AMX_ERR_STACKERR; + hdr=(AMX_HEADER *)amx->base; + data=(amx->data!=NULL) ? amx->data : amx->base+(int)hdr->dat; + amx->stk-=sizeof(cell); + amx->paramcount+=1; + *(cell *)(data+(int)amx->stk)=value; + return AMX_ERR_NONE; +} + +int AMXAPI amx_PushArray(AMX *amx, cell *amx_addr, cell **phys_addr, const cell array[], int numcells) +{ + cell *paddr; + int err; + + assert(amx!=NULL); + assert(amx_addr!=NULL); + assert(array!=NULL); + + err=amx_Allot(amx,numcells,amx_addr,&paddr); + if (err==AMX_ERR_NONE) { + if (phys_addr!=NULL) + *phys_addr=paddr; + memcpy(paddr,array,numcells*sizeof(cell)); + err=amx_Push(amx,*amx_addr); + } /* if */ + return err; +} + +int AMXAPI amx_PushString(AMX *amx, cell *amx_addr, cell **phys_addr, const char *string, int pack, int use_wchar) +{ + cell *paddr; + int numcells,err; + + assert(amx!=NULL); + assert(amx_addr!=NULL); + assert(string!=NULL); + + #if defined AMX_ANSIONLY + numcells=strlen(string) + 1; + #else + numcells= (use_wchar ? wcslen((const wchar_t*)string) : strlen(string)) + 1; + #endif + if (pack) + numcells=(numcells+sizeof(cell)-1)/sizeof(cell); + err=amx_Allot(amx,numcells,amx_addr,&paddr); + if (err==AMX_ERR_NONE) { + if (phys_addr!=NULL) + *phys_addr=paddr; + amx_SetString(paddr,string,pack,use_wchar,UNLIMITED); + err=amx_Push(amx,*amx_addr); + } /* if */ + return err; +} + #define GETPARAM(v) ( v=*(cell *)cip++ ) +#define SKIPPARAM(n) ( cip=(cell *)cip+(n) ) #define PUSH(v) ( stk-=sizeof(cell), *(cell *)(data+(int)stk)=v ) #define POP(v) ( v=*(cell *)(data+(int)stk), stk+=sizeof(cell) ) #define ABORT(amx,v) { (amx)->stk=reset_stk; (amx)->hea=reset_hea; return v; } -#define STKMARGIN ((cell)(16*sizeof(cell))) #define CHKMARGIN() if (hea+STKMARGIN>stk) return AMX_ERR_STACKERR #define CHKSTACK() if (stk>amx->stp) return AMX_ERR_STACKLOW #define CHKHEAP() if (heahlw) return AMX_ERR_HEAPLOW -#if defined __GNUC__ && !defined ASM32 && !defined JIT +#if defined __GNUC__ && !(defined ASM32 || defined JIT) /* GNU C version uses the "labels as values" extension to create * fast "indirect threaded" interpreter. */ #define NEXT(cip) goto **cip++ -int AMXAPI amx_Exec(AMX *amx, cell *retval, int index, int numparams, ...) +int AMXAPI amx_Exec(AMX *amx, cell *retval, int index) { -static void *amx_opcodelist[] = { +static const void * const amx_opcodelist[] = { &&op_none, &&op_load_pri, &&op_load_alt, &&op_load_s_pri, &&op_load_s_alt,&&op_lref_pri, &&op_lref_alt, &&op_lref_s_pri, &&op_lref_s_alt,&&op_load_i, &&op_lodb_i, &&op_const_pri, @@ -1777,43 +1736,7 @@ static void *amx_opcodelist[] = { &&op_file, &&op_line, &&op_symbol, &&op_srange, &&op_jump_pri, &&op_switch, &&op_casetbl, &&op_swap_pri, &&op_swap_alt, &&op_pushaddr, &&op_nop, &&op_sysreq_d, - &&op_symtag }; -static void *amx_opcodelist_nodebug[] = { - &&op_none, &&op_load_pri, &&op_load_alt, &&op_load_s_pri, - &&op_load_s_alt,&&op_lref_pri, &&op_lref_alt, &&op_lref_s_pri, - &&op_lref_s_alt,&&op_load_i, &&op_lodb_i, &&op_const_pri, - &&op_const_alt, &&op_addr_pri, &&op_addr_alt, &&op_stor_pri, - &&op_stor_alt, &&op_stor_s_pri,&&op_stor_s_alt,&&op_sref_pri, - &&op_sref_alt, &&op_sref_s_pri,&&op_sref_s_alt,&&op_stor_i, - &&op_strb_i, &&op_lidx, &&op_lidx_b, &&op_idxaddr, - &&op_idxaddr_b, &&op_align_pri, &&op_align_alt, &&op_lctrl, - &&op_sctrl, &&op_move_pri, &&op_move_alt, &&op_xchg, - &&op_push_pri, &&op_push_alt, &&op_push_r, &&op_push_c, - &&op_push, &&op_push_s, &&op_pop_pri, &&op_pop_alt, - &&op_stack_nodebug, &&op_heap, &&op_proc, &&op_ret_nodebug, - &&op_retn_nodebug, &&op_call_nodebug, &&op_call_pri_nodebug, &&op_jump, - &&op_jrel, &&op_jzer, &&op_jnz, &&op_jeq, - &&op_jneq, &&op_jless, &&op_jleq, &&op_jgrtr, - &&op_jgeq, &&op_jsless, &&op_jsleq, &&op_jsgrtr, - &&op_jsgeq, &&op_shl, &&op_shr, &&op_sshr, - &&op_shl_c_pri, &&op_shl_c_alt, &&op_shr_c_pri, &&op_shr_c_alt, - &&op_smul, &&op_sdiv, &&op_sdiv_alt, &&op_umul, - &&op_udiv, &&op_udiv_alt, &&op_add, &&op_sub, - &&op_sub_alt, &&op_and, &&op_or, &&op_xor, - &&op_not, &&op_neg, &&op_invert, &&op_add_c, - &&op_smul_c, &&op_zero_pri, &&op_zero_alt, &&op_zero, - &&op_zero_s, &&op_sign_pri, &&op_sign_alt, &&op_eq, - &&op_neq, &&op_less, &&op_leq, &&op_grtr, - &&op_geq, &&op_sless, &&op_sleq, &&op_sgrtr, - &&op_sgeq, &&op_eq_c_pri, &&op_eq_c_alt, &&op_inc_pri, - &&op_inc_alt, &&op_inc, &&op_inc_s, &&op_inc_i, - &&op_dec_pri, &&op_dec_alt, &&op_dec, &&op_dec_s, - &&op_dec_i, &&op_movs, &&op_cmps, &&op_fill, - &&op_halt, &&op_bounds, &&op_sysreq_pri,&&op_sysreq_c, - &&op_file, &&op_line_nodebug, &&op_symbol_nodebug, &&op_srange_nodebug, - &&op_jump_pri, &&op_switch, &&op_casetbl, &&op_swap_pri, - &&op_swap_alt, &&op_pushaddr, &&op_nop, &&op_sysreq_d, - &&op_symtag_nodebug }; + &&op_symtag, &&op_break }; AMX_HEADER *hdr; AMX_FUNCSTUB *func; unsigned char *code, *data; @@ -1822,31 +1745,22 @@ static void *amx_opcodelist_nodebug[] = { cell offs; ucell codesize; int num,i; - va_list ap; - AMX_DEBUGCALL tracer = 0; - AMX_DBG *pdbg = 0; /* HACK: return label table (for amx_BrowseRelocate) if amx structure * has the AMX_FLAG_BROWSE flag set. */ + assert(amx!=NULL); if ((amx->flags & AMX_FLAG_BROWSE)==AMX_FLAG_BROWSE) { assert(sizeof(cell)==sizeof(void *)); assert(retval!=NULL); - if (amx->flags & AMX_FLAG_DEBUG) - { - *retval=(cell)(amx_opcodelist); - } else { - *retval=(cell)(amx_opcodelist_nodebug); - } + *retval=(cell)amx_opcodelist; return 0; } /* if */ if (amx->callback==NULL) return AMX_ERR_CALLBACK; - i=amx_Register(amx,NULL,0); /* verify that all natives are registered */ - if (i!=AMX_ERR_NONE) - return i; - + 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); @@ -1861,7 +1775,8 @@ static void *amx_opcodelist_nodebug[] = { stk=amx->stk; reset_stk=stk; reset_hea=hea; - frm=0; /* just to avoid compiler warnings */ + alt=frm=0; /* just to avoid compiler warnings */ + num=0; /* just to avoid compiler warnings */ /* get the start address */ if (index==AMX_EXEC_MAIN) { @@ -1881,7 +1796,7 @@ static void *amx_opcodelist_nodebug[] = { } else if (index<0) { return AMX_ERR_INDEX; } else { - if (index>=NUMENTRIES(hdr,publics,natives)) + if (index>=(int)NUMENTRIES(hdr,publics,natives)) return AMX_ERR_INDEX; func=GETENTRY(hdr,publics,index); cip=(cell *)(code + (int)func->address); @@ -1889,7 +1804,7 @@ static void *amx_opcodelist_nodebug[] = { /* check values just copied */ CHKSTACK(); CHKHEAP(); - init_little_endian(); + assert(check_endian()); /* sanity checks */ assert(OP_PUSH_PRI==36); @@ -1900,53 +1815,25 @@ static void *amx_opcodelist_nodebug[] = { assert(OP_INC_PRI==107); assert(OP_MOVS==117); assert(OP_SYMBOL==126); - #if SMALL_CELL_SIZE==16 + #if PAWN_CELL_SIZE==16 assert(sizeof(cell)==2); - #elif SMALL_CELL_SIZE==32 + #elif PAWN_CELL_SIZE==32 assert(sizeof(cell)==4); - #elif SMALL_CELL_SIZE==64 + #elif PAWN_CELL_SIZE==64 assert(sizeof(cell)==8); #else #error Unsupported cell size #endif if (index!=AMX_EXEC_CONT) { - /* push the parameters to the stack (in reverse order) */ - if (numparams & 0xFFFF0000) { - cell *params; - stk-=(numparams>>=16)*sizeof(cell); - va_start(ap,numparams); - params = va_arg(ap,cell*); - va_end(ap); - for (i=0; iparamcount*sizeof(cell); + PUSH(amx->paramcount*sizeof(cell)); + amx->paramcount=0; /* push the parameter count to the stack & reset */ PUSH(0); /* zero return address */ } /* if */ /* check stack/heap before starting to run */ CHKMARGIN(); - if ((amx->flags & AMX_FLAG_DEBUG) && (amx->flags & AMX_FLAG_LINEOPS)) - { - if (amx->userdata[0]) - { - tracer = (AMX_DEBUGCALL)amx->userdata[1]; - pdbg = (AMX_DBG *)(amx->userdata[0]); - if (tracer) - { - //as a precaution, clear the call stack - (tracer)(amx, 0); - } - } - } - /* start running */ NEXT(cip); @@ -1990,14 +1877,14 @@ static void *amx_opcodelist_nodebug[] = { NEXT(cip); op_load_i: /* verify address */ - if ((pri>=hea && pri=(ucell)amx->stp) + if (pri>=hea && pri=(ucell)amx->stp) ABORT(amx,AMX_ERR_MEMACCESS); pri= * (cell *)(data+(int)pri); NEXT(cip); op_lodb_i: GETPARAM(offs); /* verify address */ - if ((pri>=hea && pri=(ucell)amx->stp) + if (pri>=hea && pri=(ucell)amx->stp) ABORT(amx,AMX_ERR_MEMACCESS); switch (offs) { case 1: @@ -2063,14 +1950,14 @@ static void *amx_opcodelist_nodebug[] = { NEXT(cip); op_stor_i: /* verify address */ - if ((alt>=hea && alt=(ucell)amx->stp) + if (alt>=hea && alt=(ucell)amx->stp) ABORT(amx,AMX_ERR_MEMACCESS); *(cell *)(data+(int)alt)=pri; NEXT(cip); op_strb_i: GETPARAM(offs); /* verify address */ - if ((alt>=hea && alt=(ucell)amx->stp) + if (alt>=hea && alt=(ucell)amx->stp) ABORT(amx,AMX_ERR_MEMACCESS); switch (offs) { case 1: @@ -2087,7 +1974,7 @@ static void *amx_opcodelist_nodebug[] = { op_lidx: offs=pri*sizeof(cell)+alt; /* verify address */ - if ((offs>=hea && offs=(ucell)amx->stp) + if (offs>=hea && offs=(ucell)amx->stp) ABORT(amx,AMX_ERR_MEMACCESS); pri= * (cell *)(data+(int)offs); NEXT(cip); @@ -2095,7 +1982,7 @@ static void *amx_opcodelist_nodebug[] = { GETPARAM(offs); offs=(pri << (int)offs)+alt; /* verify address */ - if ((offs>=hea && offs=(ucell)amx->stp) + if (offs>=hea && offs=(ucell)amx->stp) ABORT(amx,AMX_ERR_MEMACCESS); pri= * (cell *)(data+(int)offs); NEXT(cip); @@ -2108,13 +1995,17 @@ static void *amx_opcodelist_nodebug[] = { NEXT(cip); op_align_pri: GETPARAM(offs); - if (amx_LittleEndian && offs=codesize) - ABORT(amx,AMX_ERR_MEMACCESS); - cip=(cell *)(code+(int)offs); - NEXT(cip); - op_ret_nodebug: POP(frm); POP(offs); /* verify the return address */ @@ -2251,19 +2123,6 @@ static void *amx_opcodelist_nodebug[] = { cip=(cell *)(code+(int)offs); NEXT(cip); op_retn: - if (tracer) - { - (tracer)(amx, 1); - } - POP(frm); - POP(offs); - /* verify the return address */ - if ((ucell)offs>=codesize) - ABORT(amx,AMX_ERR_MEMACCESS); - cip=(cell *)(code+(int)offs); - stk+= *(cell *)(data+(int)stk) + sizeof(cell); /* remove parameters from the stack */ - NEXT(cip); - op_retn_nodebug: POP(frm); POP(offs); /* verify the return address */ @@ -2273,26 +2132,10 @@ static void *amx_opcodelist_nodebug[] = { stk+= *(cell *)(data+(int)stk) + sizeof(cell); /* remove parameters from the stack */ NEXT(cip); op_call: - if (tracer) - { - (tracer)(amx, 2); - } - PUSH(((unsigned char *)cip-code)+sizeof(cell));/* push address behind instruction */ - cip=JUMPABS(code, cip); /* jump to the address */ - NEXT(cip); - op_call_nodebug: PUSH(((unsigned char *)cip-code)+sizeof(cell));/* push address behind instruction */ cip=JUMPABS(code, cip); /* jump to the address */ NEXT(cip); op_call_pri: - if (tracer) - { - (tracer)(amx, 2); - } - PUSH((unsigned char *)cip-code); - cip=(cell *)(code+(int)pri); - NEXT(cip); - op_call_pri_nodebug: PUSH((unsigned char *)cip-code); cip=(cell *)(code+(int)pri); NEXT(cip); @@ -2576,13 +2419,13 @@ static void *amx_opcodelist_nodebug[] = { /* verify top & bottom memory addresses, for both source and destination * addresses */ - if ((pri>=hea && pri=(ucell)amx->stp) + if (pri>=hea && pri=(ucell)amx->stp) ABORT(amx,AMX_ERR_MEMACCESS); - if (((pri+offs)>hea && (pri+offs)(ucell)amx->stp) + if ((pri+offs)>hea && (pri+offs)(ucell)amx->stp) ABORT(amx,AMX_ERR_MEMACCESS); - if ((alt>=hea && alt=(ucell)amx->stp) + if (alt>=hea && alt=(ucell)amx->stp) ABORT(amx,AMX_ERR_MEMACCESS); - if (((alt+offs)>hea && (alt+offs)(ucell)amx->stp) + if ((alt+offs)>hea && (alt+offs)(ucell)amx->stp) ABORT(amx,AMX_ERR_MEMACCESS); memcpy(data+(int)alt, data+(int)pri, (int)offs); NEXT(cip); @@ -2591,34 +2434,32 @@ static void *amx_opcodelist_nodebug[] = { /* verify top & bottom memory addresses, for both source and destination * addresses */ - if ((pri>=hea && pri=(ucell)amx->stp) + if (pri>=hea && pri=(ucell)amx->stp) ABORT(amx,AMX_ERR_MEMACCESS); - if (((pri+offs)>hea && (pri+offs)(ucell)amx->stp) + if ((pri+offs)>hea && (pri+offs)(ucell)amx->stp) ABORT(amx,AMX_ERR_MEMACCESS); - if ((alt>=hea && alt=(ucell)amx->stp) + if (alt>=hea && alt=(ucell)amx->stp) ABORT(amx,AMX_ERR_MEMACCESS); - if (((alt+offs)>hea && (alt+offs)(ucell)amx->stp) + if ((alt+offs)>hea && (alt+offs)(ucell)amx->stp) ABORT(amx,AMX_ERR_MEMACCESS); pri=memcmp(data+(int)alt, data+(int)pri, (int)offs); NEXT(cip); op_fill: GETPARAM(offs); /* verify top & bottom memory addresses */ - if ((alt>=hea && alt=(ucell)amx->stp) + if (alt>=hea && alt=(ucell)amx->stp) ABORT(amx,AMX_ERR_MEMACCESS); - if (((alt+offs)>hea && (alt+offs)(ucell)amx->stp) + if ((alt+offs)>hea && (alt+offs)(ucell)amx->stp) ABORT(amx,AMX_ERR_MEMACCESS); - for (i=(int)alt; offs>=sizeof(cell); i+=sizeof(cell), offs-=sizeof(cell)) + for (i=(int)alt; offs>=(int)sizeof(cell); i+=sizeof(cell), offs-=sizeof(cell)) *(cell *)(data+i) = pri; NEXT(cip); op_halt: GETPARAM(offs); if (retval!=NULL) *retval=pri; - /* store complete status */ + /* store complete status (stk and hea are already set in the ABORT macro) */ amx->frm=frm; - amx->stk=stk; - amx->hea=hea; amx->pri=pri; amx->alt=alt; amx->cip=(cell)((unsigned char*)cip-code); @@ -2695,61 +2536,30 @@ static void *amx_opcodelist_nodebug[] = { assert(0); /* this code should not occur during execution */ NEXT(cip); op_line: - assert((amx->flags & AMX_FLAG_BROWSE)==0); - GETPARAM(amx->curline); - GETPARAM(amx->curfile); - NEXT(cip); - op_line_nodebug: - assert((amx->flags & AMX_FLAG_BROWSE)==0); - GETPARAM(amx->curline); - GETPARAM(amx->curfile); + SKIPPARAM(2); NEXT(cip); op_symbol: - assert((amx->flags & AMX_FLAG_BROWSE)==0); - GETPARAM(offs); - GETPARAM(amx->dbgaddr); - GETPARAM(amx->dbgparam); - amx->dbgname=(char *)cip; - cip=(cell *)((unsigned char *)cip + (int)offs - 2*sizeof(cell)); - amx->dbgcode=DBG_SYMBOL; - assert((amx->dbgparam >> 8)>0); /* local symbols only */ - NEXT(cip); - op_symbol_nodebug: - assert((amx->flags & AMX_FLAG_BROWSE)==0); GETPARAM(offs); cip=(cell *)((unsigned char *)cip + (int)offs); NEXT(cip); op_srange: - assert((amx->flags & AMX_FLAG_BROWSE)==0); - GETPARAM(amx->dbgaddr); /* dimension level */ - GETPARAM(amx->dbgparam); /* length */ - amx->dbgcode=DBG_SRANGE; - NEXT(cip); - op_srange_nodebug: - assert((amx->flags & AMX_FLAG_BROWSE)==0); - cip+=2; + SKIPPARAM(2); NEXT(cip); op_symtag: - assert((amx->flags & AMX_FLAG_BROWSE)==0); - GETPARAM(amx->dbgparam); /* tag id */ - amx->dbgcode=DBG_SYMTAG; - NEXT(cip); - op_symtag_nodebug: - assert((amx->flags & AMX_FLAG_BROWSE)==0); - cip+=1; + SKIPPARAM(1); NEXT(cip); op_jump_pri: cip=(cell *)(code+(int)pri); NEXT(cip); op_switch: { cell *cptr; - cptr=(cell *)*cip + 1; /* +1, to skip the "casetbl" opcode */ - cip=(cell *)*(cptr+1); /* preset to "none-matched" case */ + cptr=JUMPABS(code,cip)+1; /* +1, to skip the "casetbl" opcode */ + cip=JUMPABS(code,cptr+1); /* preset to "none-matched" case */ num=(int)*cptr; /* number of records in the case table */ for (cptr+=2; num>0 && *cptr!=pri; num--,cptr+=2) /* nothing */; if (num>0) - cip=(cell *)*(cptr+1); /* case found */ + cip=JUMPABS(code,cptr+1); /* case found */ NEXT(cip); } op_casetbl: @@ -2771,6 +2581,26 @@ static void *amx_opcodelist_nodebug[] = { NEXT(cip); op_nop: NEXT(cip); + op_break: + if (amx->debug!=NULL) { + /* store status */ + amx->frm=frm; + amx->stk=stk; + amx->hea=hea; + amx->cip=(cell)((unsigned char*)cip-code); + num=amx->debug(amx); + if (num!=AMX_ERR_NONE) { + if (num==AMX_ERR_SLEEP) { + amx->pri=pri; + amx->alt=alt; + amx->reset_stk=reset_stk; + amx->reset_hea=reset_hea; + return num; + } /* if */ + ABORT(amx,num); + } /* if */ + } /* if */ + NEXT(cip); } #else @@ -2781,7 +2611,8 @@ static void *amx_opcodelist_nodebug[] = { * Microsoft C/C++ (and most other C compilers) use "cdecl". * The important point is that you assemble AMXEXEC.ASM with the matching * calling convention, or the right JIT, respectively. - * jitr.asm is for Watcom's register calling convention, jits.asm for "cdecl". + * AMXJITR.ASM is for Watcom's register calling convention, AMXJITS.ASM and + * AMXJITSN.ASM are for "cdecl". */ #if defined __WATCOMC__ #if !defined STACKARGS /* for AMX32.DLL */ @@ -2789,33 +2620,37 @@ static void *amx_opcodelist_nodebug[] = { /* The following pragma tells the compiler into which registers * the parameters have to go. */ #pragma aux amx_exec_asm parm [eax] [edx] [ebx] [ecx]; + extern cell amx_exec_jit(cell *regs,cell *retval,cell stp,cell hea); + #pragma aux amx_exec_jit parm [eax] [edx] [ebx] [ecx]; #else extern cell __cdecl amx_exec_asm(cell *regs,cell *retval,cell stp,cell hea); + extern cell __cdecl amx_exec_jit(cell *regs,cell *retval,cell stp,cell hea); #endif #elif defined __GNUC__ /* force "cdecl" by adding an "attribute" to the declaration */ - #if defined __cplusplus extern "C" cell amx_exec_asm(cell *regs,cell *retval,cell stp,cell hea) __attribute__((cdecl)); - #else - extern cell amx_exec_asm(cell *regs,cell *retval,cell stp,cell hea) __attribute__((cdecl)); - #endif + extern "C" cell amx_exec_jit(cell *regs,cell *retval,cell stp,cell hea) __attribute__((cdecl)); #else /* force "cdecl" by specifying it as a "function class" with the "__cdecl" keyword */ extern "C" cell __cdecl amx_exec_asm(cell *regs,cell *retval,cell stp,cell hea); + extern "C" cell __cdecl amx_exec_jit(cell *regs,cell *retval,cell stp,cell hea); #endif #endif -#if defined ASM32 || defined JIT -#if defined WIN32 || defined __cplusplus - extern "C" void *amx_opcodelist[]; - extern "C" void *amx_opcodelist_nodebug[]; -#else - extern void *amx_opcodelist[]; - extern void *amx_opcodelist_nodebug[]; +#if defined ASM32 + extern "C" void *amx_opcodelist[]; + #ifdef __WATCOMC__ + #pragma aux amx_opcodelist "_*" + #endif #endif +#if defined JIT + extern "C" void const *amx_opcodelist_jit[]; + #ifdef __WATCOMC__ + #pragma aux amx_opcodelist_jit "_*" + #endif #endif -int AMXAPI amx_Exec(AMX *amx, cell *retval, int index, int numparams, ...) +int AMXAPI amx_Exec(AMX *amx, cell *retval, int index) { AMX_HEADER *hdr; AMX_FUNCSTUB *func; @@ -2824,21 +2659,14 @@ int AMXAPI amx_Exec(AMX *amx, cell *retval, int index, int numparams, ...) cell reset_stk, reset_hea, *cip; ucell codesize; int i; - va_list ap; #if defined ASM32 || defined JIT - #ifdef __WATCOMC__ - #pragma aux amx_opcodelist "_*" - #pragma aux amx_opcodelist_nodebug "_*" - #endif cell parms[9]; /* registers and parameters for assembler AMX */ #else OPCODE op; cell offs; int num; #endif - AMX_DEBUGCALL tracer = 0; - AMX_DBG *pdbg = 0; - + assert(amx!=NULL); #if defined ASM32 || defined JIT /* HACK: return label table (for amx_BrowseRelocate) if amx structure * is not passed. @@ -2846,43 +2674,28 @@ int AMXAPI amx_Exec(AMX *amx, cell *retval, int index, int numparams, ...) if ((amx->flags & AMX_FLAG_BROWSE)==AMX_FLAG_BROWSE) { assert(sizeof(cell)==sizeof(void *)); assert(retval!=NULL); - #if defined JIT - /* The JIT does not support a "debug" opcode list; however, its single - * opcode list is called "amx_opcodelist", although it should be called - * amx_opcodelist_nodebug - */ + #if defined ASM32 && defined JIT + if ((amx->flags & AMX_FLAG_JITC)!=0) + *retval=(cell)amx_opcodelist_jit; + else + *retval=(cell)amx_opcodelist; + #elif defined ASM32 *retval=(cell)amx_opcodelist; #else - if (amx->flags & AMX_FLAG_DEBUG) - { - *retval=(cell)(amx_opcodelist); - } else { - *retval=(cell)(amx_opcodelist_nodebug); - } + *retval=(cell)amx_opcodelist_jit; #endif return 0; } /* if */ #endif - - if ((amx->flags & AMX_FLAG_DEBUG) && (amx->flags & AMX_FLAG_LINEOPS)) - { - if (amx->userdata[0]) - { - tracer = (AMX_DEBUGCALL)amx->userdata[1]; - pdbg = (AMX_DBG *)(amx->userdata[0]); - } - } - if (amx->callback==NULL) return AMX_ERR_CALLBACK; - i=amx_Register(amx,NULL,0); /* verify that all natives are registered */ - if (i!=AMX_ERR_NONE) - return i; - + 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); + /* set up the registers */ hdr=(AMX_HEADER *)amx->base; assert(hdr->magic==AMX_MAGIC); @@ -2917,11 +2730,12 @@ int AMXAPI amx_Exec(AMX *amx, cell *retval, int index, int numparams, ...) return AMX_ERR_INDEX; func=GETENTRY(hdr,publics,index); cip=(cell *)(code + (int)func->address); + debug("CIP: %p. CIP op: %p. opcode_list: %p", cip, *cip, amx_opcodelist); } /* if */ /* check values just copied */ CHKSTACK(); CHKHEAP(); - init_little_endian(); + assert(check_endian()); /* sanity checks */ assert(OP_PUSH_PRI==36); @@ -2932,34 +2746,21 @@ int AMXAPI amx_Exec(AMX *amx, cell *retval, int index, int numparams, ...) assert(OP_INC_PRI==107); assert(OP_MOVS==117); assert(OP_SYMBOL==126); - #if SMALL_CELL_SIZE==16 + #if PAWN_CELL_SIZE==16 assert(sizeof(cell)==2); - #elif SMALL_CELL_SIZE==32 + #elif PAWN_CELL_SIZE==32 assert(sizeof(cell)==4); - #elif SMALL_CELL_SIZE==64 + #elif PAWN_CELL_SIZE==64 assert(sizeof(cell)==8); #else #error Unsupported cell size #endif - if (index!=AMX_EXEC_CONT) { - /* push the parameters to the stack (in reverse order) */ - if (numparams & 0xFFFF0000L) { - cell *params; - stk-=(numparams>>=16)*sizeof(cell); - va_start(ap,numparams); - params = va_arg(ap,cell*); - va_end(ap); - for (i=0; iparamcount*sizeof(cell); + PUSH(amx->paramcount*sizeof(cell)); + amx->paramcount=0; /* push the parameter count to the stack & reset */ #if defined ASM32 || defined JIT PUSH(RELOC_VALUE(code,0));/* relocated zero return address */ #else @@ -2983,7 +2784,16 @@ int AMXAPI amx_Exec(AMX *amx, cell *retval, int index, int numparams, ...) parms[7] = (cell)code; parms[8] = (cell)codesize; - i = amx_exec_asm(parms,retval,amx->stp,hea); + #if defined ASM32 && defined JIT + if ((amx->flags & AMX_FLAG_JITC)!=0) + i = amx_exec_jit(parms,retval,amx->stp,hea); + else + i = amx_exec_asm(parms,retval,amx->stp,hea); + #elif defined ASM32 + i = amx_exec_asm(parms,retval,amx->stp,hea); + #else + i = amx_exec_jit(parms,retval,amx->stp,hea); + #endif if (i == AMX_ERR_SLEEP) { amx->reset_stk=reset_stk; amx->reset_hea=reset_hea; @@ -3158,13 +2968,17 @@ int AMXAPI amx_Exec(AMX *amx, cell *retval, int index, int numparams, ...) break; case OP_ALIGN_PRI: GETPARAM(offs); - if (amx_LittleEndian && (size_t)offsstk=stk; - if (tracer) - { - (tracer)(amx, 1); - } break; case OP_CALL: PUSH(((unsigned char *)cip-code)+sizeof(cell));/* skip address */ cip=JUMPABS(code, cip); /* jump to the address */ - if (tracer) - { - (tracer)(amx, 2); - } break; case OP_CALL_PRI: PUSH((unsigned char *)cip-code); @@ -3420,6 +3226,7 @@ int AMXAPI amx_Exec(AMX *amx, cell *retval, int index, int numparams, ...) if (alt==0) ABORT(amx,AMX_ERR_DIVIDE); /* divide must always round down; this is a bit + * involved to do in a machine-independent way. */ offs=(pri % alt + alt) % alt; /* true modulus */ pri=(pri - offs) / alt; /* division result */ @@ -3625,10 +3432,8 @@ int AMXAPI amx_Exec(AMX *amx, cell *retval, int index, int numparams, ...) GETPARAM(offs); if (retval!=NULL) *retval=pri; - /* store complete status */ + /* store complete status (stk and hea are already set in the ABORT macro) */ amx->frm=frm; - amx->stk=stk; - amx->hea=hea; amx->pri=pri; amx->alt=alt; amx->cip=(cell)((unsigned char*)cip-code); @@ -3699,33 +3504,18 @@ int AMXAPI amx_Exec(AMX *amx, cell *retval, int index, int numparams, ...) ABORT(amx,amx->error); } /* if */ break; - case OP_FILE: - GETPARAM(offs); - cip=(cell *)((unsigned char *)cip+(int)offs); - assert(0); /* this code should not occur during execution */ - break; case OP_LINE: - assert((amx->flags & AMX_FLAG_BROWSE)==0); - GETPARAM(amx->curline); - GETPARAM(amx->curfile); + SKIPPARAM(2); break; case OP_SYMBOL: - assert((amx->flags & AMX_FLAG_BROWSE)==0); GETPARAM(offs); - GETPARAM(amx->dbgaddr); - GETPARAM(amx->dbgparam); - amx->dbgname=(char *)cip; - cip=(cell *)((unsigned char *)cip + (int)offs - 2*sizeof(cell)); - assert((amx->dbgparam >> 8)>0); /* local symbols only */ + cip=(cell *)((unsigned char *)cip + (int)offs); break; case OP_SRANGE: - assert((amx->flags & AMX_FLAG_BROWSE)==0); - GETPARAM(amx->dbgaddr); /* dimension level */ - GETPARAM(amx->dbgparam); /* length */ + SKIPPARAM(2); break; case OP_SYMTAG: - assert((amx->flags & AMX_FLAG_BROWSE)==0); - GETPARAM(amx->dbgparam); /* tag id */ + SKIPPARAM(1); break; case OP_JUMP_PRI: cip=(cell *)(code+(int)pri); @@ -3733,13 +3523,13 @@ int AMXAPI amx_Exec(AMX *amx, cell *retval, int index, int numparams, ...) case OP_SWITCH: { cell *cptr; - cptr=(cell *)*cip + 1; /* +1, to skip the "casetbl" opcode */ - cip=(cell *)*(cptr+1); /* preset to "none-matched" case */ + cptr=JUMPABS(code,cip)+1; /* +1, to skip the "casetbl" opcode */ + cip=JUMPABS(code,cptr+1); /* preset to "none-matched" case */ num=(int)*cptr; /* number of records in the case table */ for (cptr+=2; num>0 && *cptr!=pri; num--,cptr+=2) /* nothing */; if (num>0) - cip=(cell *)*(cptr+1); /* case found */ + cip=JUMPABS(code,cptr+1); /* case found */ break; } /* case */ case OP_SWAP_PRI: @@ -3758,10 +3548,32 @@ int AMXAPI amx_Exec(AMX *amx, cell *retval, int index, int numparams, ...) break; case OP_NOP: break; - case OP_CASETBL: - assert(0); /* should not occur during execution */ - /* drop through to "invalid instruction" */ + case OP_BREAK: + assert((amx->flags & AMX_FLAG_BROWSE)==0); + if (amx->debug!=NULL) { + /* store status */ + amx->frm=frm; + amx->stk=stk; + amx->hea=hea; + amx->cip=(cell)((unsigned char*)cip-code); + num=amx->debug(amx); + if (num!=AMX_ERR_NONE) { + if (num==AMX_ERR_SLEEP) { + amx->pri=pri; + amx->alt=alt; + amx->reset_stk=reset_stk; + amx->reset_hea=reset_hea; + return num; + } /* if */ + ABORT(amx,num); + } /* if */ + } /* if */ + break; default: + /* case OP_FILE: should not occur during execution + * case OP_CASETBL: should not occur during execution + */ + assert(0); ABORT(amx,AMX_ERR_INVINSTR); } /* switch */ } /* for */ @@ -3770,14 +3582,6 @@ int AMXAPI amx_Exec(AMX *amx, cell *retval, int index, int numparams, ...) #endif /* __GNUC__ */ -/* For interfacing applications not written in C/C++, amx_Execv() works like - * amx_Exec(), but has all parameters passed via an array. - */ -int AMXAPI amx_Execv(AMX *amx, cell *retval, int index, int numparams, cell params[]) -{ - return amx_Exec(amx, retval, index, numparams<<16, params); -} - #endif /* AMX_EXEC || AMX_INIT */ #if defined AMX_SETCALLBACK @@ -3794,7 +3598,6 @@ int AMXAPI amx_SetCallback(AMX *amx,AMX_CALLBACK callback) int AMXAPI amx_SetDebugHook(AMX *amx,AMX_DEBUG debug) { assert(amx!=NULL); - assert(debug!=NULL); amx->debug=debug; return AMX_ERR_NONE; } @@ -3822,7 +3625,7 @@ int AMXAPI amx_GetAddr(AMX *amx,cell amx_addr,cell **phys_addr) data=(amx->data!=NULL) ? amx->data : amx->base+(int)hdr->dat; assert(phys_addr!=NULL); - if ((amx_addr>=amx->hea && amx_addrstk) || amx_addr<0 || amx_addr>=amx->stp) { + if (amx_addr>=amx->hea && amx_addrstk || amx_addr<0 || amx_addr>=amx->stp) { *phys_addr=NULL; return AMX_ERR_MEMACCESS; } /* if */ @@ -3832,7 +3635,7 @@ int AMXAPI amx_GetAddr(AMX *amx,cell amx_addr,cell **phys_addr) } #endif /* AMX_GETADDR */ -#if defined AMX_ALLOT +#if defined AMX_ALLOT || defined AMX_EXEC int AMXAPI amx_Allot(AMX *amx,int cells,cell *amx_addr,cell **phys_addr) { AMX_HEADER *hdr; @@ -3862,22 +3665,25 @@ int AMXAPI amx_Release(AMX *amx,cell amx_addr) } #endif /* AMX_ALLOT */ -#if defined AMX_XXXSTRING +#if defined AMX_XXXSTRING || defined AMX_UTF8XXX #define CHARBITS (8*sizeof(char)) -#if SMALL_CELL_SIZE==16 +#if PAWN_CELL_SIZE==16 #define CHARMASK (0xffffu << 8*(2-sizeof(char))) -#elif SMALL_CELL_SIZE==32 +#elif PAWN_CELL_SIZE==32 #define CHARMASK (0xffffffffuL << 8*(4-sizeof(char))) -#elif SMALL_CELL_SIZE==64 +#elif PAWN_CELL_SIZE==64 #define CHARMASK (0xffffffffffffffffuLL << 8*(8-sizeof(char))) #else #error Unsupported cell size #endif -int AMXAPI amx_StrLen(cell *cstr, int *length) +int AMXAPI amx_StrLen(const cell *cstr, int *length) { int len; + #if BYTE_ORDER==LITTLE_ENDIAN + cell c; + #endif assert(length!=NULL); if (cstr==NULL) { @@ -3889,16 +3695,16 @@ int AMXAPI amx_StrLen(cell *cstr, int *length) /* packed string */ assert(sizeof(char)==1); len=strlen((char *)cstr); /* find '\0' */ - init_little_endian(); - if (amx_LittleEndian) { + assert(check_endian()); + #if BYTE_ORDER==LITTLE_ENDIAN /* on Little Endian machines, toggle the last bytes */ - cell c=cstr[len/sizeof(cell)]; /* get last cell */ + c=cstr[len/sizeof(cell)]; /* get last cell */ len=len - len % sizeof(cell); /* len = multiple of "cell" bytes */ while ((c & CHARMASK)!=0) { len++; c <<= 8*sizeof(char); } /* if */ - } /* if */ + #endif } else { for (len=0; cstr[len]!=0; len++) /* nothing */; @@ -3906,72 +3712,112 @@ int AMXAPI amx_StrLen(cell *cstr, int *length) *length = len; return AMX_ERR_NONE; } +#endif -int AMXAPI amx_SetString(cell *dest,const char *source,int pack,int use_wchar) +#if defined AMX_XXXSTRING || defined AMX_EXEC +int AMXAPI amx_SetString(cell *dest,const char *source,int pack,int use_wchar,size_t size) { /* the memory blocks should not overlap */ - int len= use_wchar ? wcslen((const wchar_t*)source) : strlen(source); - int i; + int len, i; + + assert(UNLIMITED>0); + #if defined AMX_ANSIONLY + (void)use_wchar; + len=strlen(source); + #else + len= use_wchar ? wcslen((const wchar_t*)source) : strlen(source); + #endif if (pack) { /* create a packed string */ + if (size=size*sizeof(cell)) + len=size*sizeof(cell)-1; dest[len/sizeof(cell)]=0; /* clear last bytes of last (semi-filled) cell*/ - if (use_wchar) { - for (i=0; i=0) swapcell((ucell *)&dest[len--]); - } /* if */ + #endif + } else { /* create an unpacked string */ - if (use_wchar) { - for (i=0; i=size) + len=size-1; + #if defined AMX_ANSIONLY for (i=0; iUNPACKEDMAX) { /* source string is packed */ cell c = 0; /* to avoid a compiler warning */ int i=sizeof(cell)-1; - for ( ;; ) { + while ((size_t)len> i*CHARBITS); - else + #if defined AMX_ANSIONLY dest[len++]=(char)(c >> i*CHARBITS); + #else + if (use_wchar) + ((wchar_t*)dest)[len++]=(char)(c >> i*CHARBITS); + else + dest[len++]=(char)(c >> i*CHARBITS); + #endif if (dest[len-1]=='\0') break; /* terminating zero character found */ i=(i+sizeof(cell)-1) % sizeof(cell); } /* for */ } else { /* source string is unpacked */ - if (use_wchar) { - while (*source!=0) - ((wchar_t*)dest)[len++]=(wchar_t)*source++; - } else { - while (*source!=0) + #if defined AMX_ANSIONLY + while (*source!=0 && (size_t)len=size) + len=size-1; + if (len>=0) + dest[len]='\0'; /* store terminator */ return AMX_ERR_NONE; } #endif /* AMX_XXXSTRING */ @@ -3989,8 +3835,8 @@ int AMXAPI amx_GetString(char *dest,const cell *source,int use_wchar) */ int AMXAPI amx_UTF8Get(const char *string, const char **endptr, cell *value) { -static char utf8_count[16]={ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 4 }; -static long utf8_lowmark[5] = { 0x80, 0x800, 0x10000, 0x200000, 0x4000000 }; +static const char utf8_count[16]={ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 4 }; +static const long utf8_lowmark[5] = { 0x80, 0x800, 0x10000L, 0x200000L, 0x4000000L }; unsigned char c; cell result; int followup; @@ -4028,19 +3874,19 @@ static long utf8_lowmark[5] = { 0x80, 0x800, 0x10000, 0x200000, 0x4000000 }; switch (followup) { case 4: if (((c=*string++) & 0xc0) != 0x80) goto error; - result = (result << 6) | (c & 0x3f); + result = (result << 6) | c & 0x3f; case 3: if (((c=*string++) & 0xc0) != 0x80) goto error; - result = (result << 6) | (c & 0x3f); + result = (result << 6) | c & 0x3f; case 2: if (((c=*string++) & 0xc0) != 0x80) goto error; - result = (result << 6) | (c & 0x3f); + result = (result << 6) | c & 0x3f; case 1: if (((c=*string++) & 0xc0) != 0x80) goto error; - result = (result << 6) | (c & 0x3f); + result = (result << 6) | c & 0x3f; case 0: if (((c=*string++) & 0xc0) != 0x80) goto error; - result = (result << 6) | (c & 0x3f); + result = (result << 6) | c & 0x3f; } /* switch */ /* Do additional checks: shortest encoding & reserved positions. The * lowmark limits also depends on the code length; it can be read from @@ -4048,7 +3894,7 @@ static long utf8_lowmark[5] = { 0x80, 0x800, 0x10000, 0x200000, 0x4000000 }; */ if (result=0xd800 && result<=0xdfff) || result==0xfffe || result==0xffff) + if (result>=0xd800 && result<=0xdfff || result==0xfffe || result==0xffff) goto error; } /* if */ @@ -4064,9 +3910,9 @@ error: } /* amx_UTF8Put() - * Encode a single character into a character string. The character may be - * up to 6 bytes long. The function returns an error code if "maxchars" is - * lower than the requried number of characters; in this case nothing is + * Encode a single character into a byte string. The character may result in + * a string of up to 6 bytes. The function returns an error code if "maxchars" + * is lower than the required number of characters; in this case nothing is * stored. * The function does not zero-terminate the string. */ @@ -4083,40 +3929,40 @@ int AMXAPI amx_UTF8Put(char *string, char **endptr, int maxchars, cell value) } else if (value<0x800) { /* 110xxxxx 10xxxxxx */ if (maxchars < 2) goto error; - *string++ = (char)(((value>>6) & 0x1f) | 0xc0); - *string++ = (char)((value & 0x3f) | 0x80); + *string++ = (char)((value>>6) & 0x1f | 0xc0); + *string++ = (char)(value & 0x3f | 0x80); } else if (value<0x10000) { /* 1110xxxx 10xxxxxx 10xxxxxx (16 bits, BMP plane) */ if (maxchars < 3) goto error; - if ((value>=0xd800 && value<=0xdfff) || value==0xfffe || value==0xffff) + if (value>=0xd800 && value<=0xdfff || value==0xfffe || value==0xffff) goto error; /* surrogate pairs and invalid characters */ - *string++ = (char)(((value>>12) & 0x0f) | 0xe0); - *string++ = (char)(((value>>6) & 0x3f) | 0x80); - *string++ = (char)((value & 0x3f) | 0x80); + *string++ = (char)((value>>12) & 0x0f | 0xe0); + *string++ = (char)((value>>6) & 0x3f | 0x80); + *string++ = (char)(value & 0x3f | 0x80); } else if (value<0x200000) { /* 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */ if (maxchars < 4) goto error; - *string++ = (char)(((value>>18) & 0x07) | 0xf0); - *string++ = (char)(((value>>12) & 0x3f) | 0x80); - *string++ = (char)(((value>>6) & 0x3f) | 0x80); - *string++ = (char)((value & 0x3f) | 0x80); + *string++ = (char)((value>>18) & 0x07 | 0xf0); + *string++ = (char)((value>>12) & 0x3f | 0x80); + *string++ = (char)((value>>6) & 0x3f | 0x80); + *string++ = (char)(value & 0x3f | 0x80); } else if (value<0x4000000) { /* 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx */ if (maxchars < 5) goto error; - *string++ = (char)(((value>>24) & 0x03) | 0xf8); - *string++ = (char)(((value>>18) & 0x3f) | 0x80); - *string++ = (char)(((value>>12) & 0x3f) | 0x80); - *string++ = (char)(((value>>6) & 0x3f) | 0x80); - *string++ = (char)((value & 0x3f) | 0x80); + *string++ = (char)((value>>24) & 0x03 | 0xf8); + *string++ = (char)((value>>18) & 0x3f | 0x80); + *string++ = (char)((value>>12) & 0x3f | 0x80); + *string++ = (char)((value>>6) & 0x3f | 0x80); + *string++ = (char)(value & 0x3f | 0x80); } else { /* 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx (31 bits) */ if (maxchars < 6) goto error; - *string++ = (char)(((value>>30) & 0x01) | 0xfc); - *string++ = (char)(((value>>24) & 0x3f) | 0x80); - *string++ = (char)(((value>>18) & 0x3f) | 0x80); - *string++ = (char)(((value>>12) & 0x3f) | 0x80); - *string++ = (char)(((value>>6) & 0x3f) | 0x80); - *string++ = (char)((value & 0x3f) | 0x80); + *string++ = (char)((value>>30) & 0x01 | 0xfc); + *string++ = (char)((value>>24) & 0x3f | 0x80); + *string++ = (char)((value>>18) & 0x3f | 0x80); + *string++ = (char)((value>>12) & 0x3f | 0x80); + *string++ = (char)((value>>6) & 0x3f | 0x80); + *string++ = (char)(value & 0x3f | 0x80); } /* if */ if (endptr!=NULL) @@ -4132,11 +3978,40 @@ error: * encoding. The function returns an error code, it is AMX_ERR_NONE if the * string is valid UTF-8 (or valid ASCII for that matter). */ -int AMXAPI amx_UTF8Check(const char *string) +int AMXAPI amx_UTF8Check(const char *string, int *length) { int err=AMX_ERR_NONE; - while (err==AMX_ERR_NONE && *string!='\0') + int len=0; + while (err==AMX_ERR_NONE && *string!='\0') { err=amx_UTF8Get(string,&string,NULL); + len++; + } /* while */ + if (length!=NULL) + *length=len; + return err; +} + +/* amx_UTF8Len() + * Run through a wide string and return how many 8-bit characters are needed to + * store the string in UTF-8 format. The returned cound excludes the terminating + * zero byte. The function returns an error code. + */ +int AMXAPI amx_UTF8Len(const cell *cstr, int *length) +{ + int err; + + assert(length!=NULL); + err=amx_StrLen(cstr, length); + if (err==AMX_ERR_NONE && (ucell)*cstr<=UNPACKEDMAX) { + char buffer[10]; /* maximum UTF-8 code is 6 characters */ + char *endptr; + int len=*length, count=0; + while (len-->0) { + amx_UTF8Put(buffer, &endptr, sizeof buffer, *cstr++); + count+=(int)(endptr-buffer); + } /* while */ + *length=count; + } /* while */ return err; } #endif /* AMX_UTF8XXX */ @@ -4163,3 +4038,74 @@ const char *AMXAPI amx_GetLibrary(AMX *amx, int index, char *buffer, int len) return buffer; } + +int AMXAPI amx_SetStringOld(cell *dest,const char *source,int pack,int use_wchar) +{ /* the memory blocks should not overlap */ + int len= use_wchar ? wcslen((const wchar_t*)source) : strlen(source); + int i; + if (pack) { + //FOR AMX MOD X WE DON'T CARE ABOUT PACKING +#if 0 + /* create a packed string */ + dest[len/sizeof(cell)]=0; /* clear last bytes of last (semi-filled) cell*/ + if (use_wchar) { + for (i=0; i=0) + swapcell((ucell *)&dest[len--]); + } /* if */ +#endif + } else { + /* create an unpacked string */ + if (use_wchar) { + for (i=0; iUNPACKEDMAX) { + /* source string is packed */ + cell c = 0; /* to avoid a compiler warning */ + int i=sizeof(cell)-1; + for ( ;; ) { + if (i==sizeof(cell)-1) + c=*source++; + if (use_wchar) + ((wchar_t*)dest)[len++]=(char)(c >> i*CHARBITS); + else + dest[len++]=(char)(c >> i*CHARBITS); + if (dest[len-1]=='\0') + break; /* terminating zero character found */ + i=(i+sizeof(cell)-1) % sizeof(cell); + } /* for */ + } else { + /* source string is unpacked */ + if (use_wchar) { + while (*source!=0) + ((wchar_t*)dest)[len++]=(wchar_t)*source++; + } else { + while (*source!=0) + dest[len++]=(char)*source++; + } /* if */ + } /* if */ + dest[len]='\0'; /* store terminator */ + return AMX_ERR_NONE; +} diff --git a/amxmodx/amx.h b/amxmodx/amx.h index 1ec389b5..480e75bf 100755 --- a/amxmodx/amx.h +++ b/amxmodx/amx.h @@ -1,6 +1,6 @@ -/* Abstract Machine for the Small compiler +/* Pawn Abstract Machine (for the Pawn language) * - * Copyright (c) ITB CompuPhase, 1997-2004 + * Copyright (c) ITB CompuPhase, 1997-2005 * * This software is provided "as-is", without any express or implied warranty. * In no event will the authors be held liable for any damages arising from @@ -21,54 +21,98 @@ * Version: $Id$ */ -#if defined __linux__ +#if defined FREEBSD && !defined __FreeBSD__ + #define __FreeBSD__ +#endif +#if defined LINUX || defined __FreeBSD__ || defined __OpenBSD__ #include #endif #ifndef AMX_H_INCLUDED #define AMX_H_INCLUDED -#if defined __LCC__ || defined __DMC__ || defined __linux__ +#if defined HAVE_STDINT_H #include -#elif !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L - /* The ISO C99 defines the int16_t and int_32t types. If the compiler got - * here, these types are probably undefined. - */ - #if defined __FreeBSD__ - #include - #else - typedef short int int16_t; - typedef unsigned short int uint16_t; - #if defined SN_TARGET_PS2 - typedef int int32_t; - typedef unsigned int uint32_t; +#else + #if defined __LCC__ || defined __DMC__ || defined LINUX + #if defined HAVE_INTTYPES_H + #include #else - typedef long int int32_t; - typedef unsigned long int uint32_t; + #include #endif - // evilspy's fix for mingw - #if defined __GNUC__ - typedef long long int64_t; - typedef unsigned long long uint64_t; - #define HAVE_I64 - #elif defined __WIN32__ || defined _WIN32 || defined WIN32 - typedef __int64 int64_t; - typedef unsigned __int64 uint64_t; - #define HAVE_I64 + #elif !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L + /* The ISO C99 defines the int16_t and int_32t types. If the compiler got + * here, these types are probably undefined. + */ + #if defined __MACH__ + #include + typedef unsigned short int uint16_t; + typedef unsigned long int uint32_t; + #elif defined __FreeBSD__ + #include + #else + typedef short int int16_t; + typedef unsigned short int uint16_t; + #if defined SN_TARGET_PS2 + typedef int int32_t; + typedef unsigned int uint32_t; + #else + typedef long int int32_t; + typedef unsigned long int uint32_t; + #endif + #if defined __WIN32__ || defined _WIN32 || defined WIN32 + typedef __int64 int64_t; + typedef unsigned __int64 uint64_t; + #define HAVE_I64 + #elif defined __GNUC__ + typedef long long int64_t; + typedef unsigned long long uint64_t; + #define HAVE_I64 + #endif #endif #endif + #define HAVE_STDINT_H +#endif +#if defined _LP64 || defined WIN64 || defined _WIN64 + #if !defined __64BIT__ + #define __64BIT__ + #endif #endif +#if HAVE_ALLOCA_H + #include +#endif #if defined __WIN32__ || defined _WIN32 || defined WIN32 /* || defined __MSDOS__ */ #if !defined alloca #define alloca(n) _alloca(n) #endif #endif +#if !defined arraysize + #define arraysize(array) (sizeof(array) / sizeof((array)[0])) +#endif + #ifdef __cplusplus extern "C" { #endif +#if PAWN_CELL_SIZE==32 + #define REAL float +#elif PAWN_CELL_SIZE==64 + #define REAL double +#else + #error Unsupported cell size +#endif + +#if defined PAWN_DLL + #if !defined AMX_NATIVE_CALL + #define AMX_NATIVE_CALL __stdcall + #endif + #if !defined AMXAPI + #define AMXAPI __stdcall + #endif +#endif + /* calling convention for native functions */ #if !defined AMX_NATIVE_CALL #define AMX_NATIVE_CALL @@ -79,6 +123,8 @@ extern "C" { #define AMXAPI __stdcall #elif defined CDECL #define AMXAPI __cdecl + #elif defined GCC_HASCLASSVISIBILITY + #define AMXAPI __attribute__ ((visibility("default"))) #else #define AMXAPI #endif @@ -96,46 +142,36 @@ extern "C" { * 5 (tagnames table) 4 * 6 (reformatted header) 6 * 7 (name table, opcodes SYMTAG & SYSREQ.D) 7 + * 8 (opcode STMT, renewed debug interface) 8 */ -#define CUR_FILE_VERSION 7 /* current file version; also the current AMX version */ +#define CUR_FILE_VERSION 8 /* current file version; also the current AMX version */ #define MIN_FILE_VERSION 6 /* lowest supported file format version for the current AMX version */ -#define MIN_AMX_VERSION 7 /* minimum AMX version needed to support the current file format */ +#define MIN_AMX_VERSION 8 /* minimum AMX version needed to support the current file format */ -#if defined BIT16 - #define SMALL_CELL_SIZE 16 /* for backward compatibility */ +#if !defined PAWN_CELL_SIZE + #define PAWN_CELL_SIZE 32 /* by default, use 32-bit cells */ #endif -#if !defined SMALL_CELL_SIZE - #define SMALL_CELL_SIZE 32 /* by default, use 32-bit cells */ -#endif -#if SMALL_CELL_SIZE==16 +#if PAWN_CELL_SIZE==16 typedef uint16_t ucell; typedef int16_t cell; -#elif SMALL_CELL_SIZE==32 +#elif PAWN_CELL_SIZE==32 typedef uint32_t ucell; typedef int32_t cell; -#elif SMALL_CELL_SIZE==64 +#elif PAWN_CELL_SIZE==64 typedef uint64_t ucell; typedef int64_t cell; #else - #error Unsupported cell size (SMALL_CELL_SIZE) + #error Unsupported cell size (PAWN_CELL_SIZE) #endif -#if SMALL_CELL_SIZE==32 - #define REAL float -#elif SMALL_CELL_SIZE==64 - #define REAL double -#else - #error Unsupported cell size -#endif - -#define UNPACKEDMAX ((1 << (sizeof(cell)-1)*8) - 1) +#define UNPACKEDMAX ((1L << (sizeof(cell)-1)*8) - 1) +#define UNLIMITED (~1u >> 1) struct tagAMX; typedef cell (AMX_NATIVE_CALL *AMX_NATIVE)(struct tagAMX *amx, cell *params); typedef int (AMXAPI *AMX_CALLBACK)(struct tagAMX *amx, cell index, cell *result, cell *params); typedef int (AMXAPI *AMX_DEBUG)(struct tagAMX *amx); -typedef int (AMXAPI *AMX_DEBUGCALL)(struct tagAMX *amx, int mode); #if !defined _FAR #define _FAR #endif @@ -149,7 +185,7 @@ typedef int (AMXAPI *AMX_DEBUGCALL)(struct tagAMX *amx, int mode); /* Some compilers do not support the #pragma align, which should be fine. Some * compilers give a warning on unknown #pragmas, which is not so fine... */ -#if defined SN_TARGET_PS2 || defined __GNUC__ +#if (defined SN_TARGET_PS2 || defined __GNUC__) && !defined AMX_NO_ALIGN #define AMX_NO_ALIGN #endif @@ -160,8 +196,10 @@ typedef int (AMXAPI *AMX_DEBUGCALL)(struct tagAMX *amx, int mode); #endif #if !defined AMX_NO_ALIGN - #if defined __linux__ + #if defined LINUX || defined __FreeBSD__ #pragma pack(1) /* structures must be packed (byte-aligned) */ + #elif defined MACOS && defined __MWERKS__ + #pragma options align=mac68k #else #pragma pack(push) #pragma pack(1) /* structures must be packed (byte-aligned) */ @@ -171,25 +209,30 @@ typedef int (AMXAPI *AMX_DEBUGCALL)(struct tagAMX *amx, int mode); #endif #endif -typedef struct { +typedef struct tagAMX_NATIVE_INFO { const char _FAR *name PACKED; AMX_NATIVE func PACKED; -} AMX_NATIVE_INFO; +} PACKED AMX_NATIVE_INFO; #define AMX_USERNUM 4 #define sEXPMAX 19 /* maximum name length for file version <= 6 */ #define sNAMEMAX 31 /* maximum name length of symbol name */ typedef struct tagAMX_FUNCSTUB { - ucell address PACKED; - const char name[sEXPMAX+1] PACKED; -} AMX_FUNCSTUB; + ucell address PACKED; + char name[sEXPMAX+1] PACKED; +} PACKED AMX_FUNCSTUB; + +typedef struct tagFUNCSTUBNT { + ucell address PACKED; + ucell nameofs PACKED; //we need this for amxx to be backwards comaptible +} PACKED AMX_FUNCSTUBNT; /* The AMX structure is the internal structure for many functions. Not all * fields are valid at all times; many fields are cached in local variables. */ typedef struct tagAMX { - unsigned char _FAR *base PACKED; /* points to the AMX header ("amxhdr") plus the code, optionally also the data */ + unsigned char _FAR *base PACKED; /* points to the AMX header plus the code, optionally also the data */ unsigned char _FAR *data PACKED; /* points to separate data+stack+heap, may be NULL */ AMX_CALLBACK callback PACKED; AMX_DEBUG debug PACKED; /* debug callback */ @@ -201,28 +244,23 @@ typedef struct tagAMX { cell stk PACKED; /* stack pointer: relative to base + amxhdr->dat */ cell stp PACKED; /* top of the stack: relative to base + amxhdr->dat */ int flags PACKED; /* current status, see amx_Flags() */ - /* for assertions and debug hook */ - cell curline PACKED; - cell curfile PACKED; - int dbgcode PACKED; - cell dbgaddr PACKED; - cell dbgparam PACKED; - char _FAR *dbgname PACKED; /* user data */ long usertags[AMX_USERNUM] PACKED; void _FAR *userdata[AMX_USERNUM] PACKED; /* native functions can raise an error */ int error PACKED; + /* passing parameters requires a "count" field */ + int paramcount; /* the sleep opcode needs to store the full AMX status */ cell pri PACKED; cell alt PACKED; cell reset_stk PACKED; cell reset_hea PACKED; cell sysreq_d PACKED; /* relocated address/value for the SYSREQ.D opcode */ - /* support variables for the JIT */ + /* support variables for the JIT */ int reloc_size PACKED; /* required temporary buffer for relocations */ long code_size PACKED; /* estimated memory footprint of the native code */ -} AMX; +} PACKED AMX; /* The AMX_HEADER structure is both the memory format as the file format. The * structure is used internaly. @@ -244,26 +282,11 @@ typedef struct tagAMX_HEADER { int32_t libraries PACKED; /* offset to the table of libraries */ int32_t pubvars PACKED; /* the "public variables" table */ int32_t tags PACKED; /* the "public tagnames" table */ - int32_t nametable PACKED; /* name table, file version 7 only */ -} AMX_HEADER PACKED; -#define AMX_MAGIC 0xf1e0 + int32_t nametable PACKED; /* name table */ +} PACKED AMX_HEADER; -//double linked list for stack -typedef struct tagAMX_TRACE -{ - cell line PACKED; - cell file PACKED; - struct tagAMX_TRACE *next PACKED; - struct tagAMX_TRACE *prev PACKED; -} AMX_TRACE PACKED; - -typedef struct tagAMX_DBG -{ - int32_t numFiles PACKED; /* number of chars in array */ - char **files PACKED; /* array of files */ - AMX_TRACE *head PACKED; /* begin of link list */ - AMX_TRACE *tail PACKED; /* end of link list */ -} AMX_DBG PACKED; +//This is always the same for us +#define AMX_MAGIC 0xf1e0 enum { AMX_ERR_NONE, @@ -280,6 +303,7 @@ enum { AMX_ERR_NATIVE, /* native function failed */ AMX_ERR_DIVIDE, /* divide by zero */ AMX_ERR_SLEEP, /* go into sleepmode - code can be restarted */ + AMX_ERR_INVSTATE, /* invalid state for this access */ AMX_ERR_MEMORY = 16, /* out of memory */ AMX_ERR_FORMAT, /* invalid file format */ @@ -292,29 +316,17 @@ enum { AMX_ERR_INIT_JIT, /* cannot initialize the JIT */ AMX_ERR_PARAMS, /* parameter error */ AMX_ERR_DOMAIN, /* domain error, expression result does not fit in range */ -}; - -enum { - DBG_INIT, /* query/initialize */ - DBG_FILE, /* file number in curfile, filename in name */ - DBG_LINE, /* line number in curline, file number in curfile */ - DBG_SYMBOL, /* address in dbgaddr, class/type in dbgparam */ - DBG_CLRSYM, /* stack address below which locals should be removed. stack address in stk */ - DBG_CALL, /* function call, address jumped to in dbgaddr */ - DBG_RETURN, /* function returns */ - DBG_TERMINATE, /* program ends, code address in dbgaddr, reason in dbgparam */ - DBG_SRANGE, /* symbol size and dimensions (arrays); level in dbgaddr (!); length in dbgparam */ - DBG_SYMTAG, /* tag of the most recent symbol (if non-zero), tag in dbgparam */ + AMX_ERR_GENERAL, /* general error (unknown or unspecific error) */ }; /* AMX_FLAG_CHAR16 0x01 no longer used */ #define AMX_FLAG_DEBUG 0x02 /* symbolic info. available */ #define AMX_FLAG_COMPACT 0x04 /* compact encoding */ -#define AMX_FLAG_BIGENDIAN 0x08 /* big endian encoding */ -#define AMX_FLAG_NOCHECKS 0x10 /* no array bounds checking */ -#define AMX_FLAG_LINEOPS 0x20 /* line ops are parsed by the JIT [loadtime only flag] */ -#define AMX_FLAG_TRACED 0x40 /* the file has already been traced */ -#define AMX_FLAG_BROWSE 0x4000 /* browsing/relocating or executing */ +#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_NTVREG 0x1000 /* all native functions are registered */ +#define AMX_FLAG_JITC 0x2000 /* abstract machine is JIT compiled */ +#define AMX_FLAG_BROWSE 0x4000 /* busy browsing */ #define AMX_FLAG_RELOC 0x8000 /* jump/call addresses relocated */ #define AMX_EXEC_MAIN -1 /* start at program entry point */ @@ -322,16 +334,18 @@ enum { #define AMX_USERTAG(a,b,c,d) ((a) | ((b)<<8) | ((long)(c)<<16) | ((long)(d)<<24)) -#define AMX_EXPANDMARGIN 64 +#if !defined AMX_COMPACTMARGIN + #define AMX_COMPACTMARGIN 64 +#endif /* for native functions that use floating point parameters, the following * two macros are convenient for casting a "cell" into a "float" type _without_ * changing the bit pattern */ -#if SMALL_CELL_SIZE==32 +#if PAWN_CELL_SIZE==32 #define amx_ftoc(f) ( * ((cell*)&f) ) /* float to cell */ #define amx_ctof(c) ( * ((float*)&c) ) /* cell to float */ -#elif SMALL_CELL_SIZE==64 +#elif PAWN_CELL_SIZE==64 #define amx_ftoc(f) ( * ((cell*)&f) ) /* float to cell */ #define amx_ctof(c) ( * ((double*)&c) ) /* cell to float */ #else @@ -345,7 +359,7 @@ enum { amx_StrLen(amx_cstr_, &amx_length_); \ if (amx_length_ > 0 && \ ((result) = (void*)alloca((amx_length_ + 1) * sizeof(*(result)))) != NULL) \ - amx_GetString((char*)(result), amx_cstr_, sizeof(*(result))>1); \ + amx_GetString((char*)(result), amx_cstr_, sizeof(*(result))>1, amx_length_); \ else (result) = NULL; \ } while (0) @@ -354,23 +368,11 @@ uint32_t * AMXAPI amx_Align32(uint32_t *v); #if defined _I64_MAX || defined HAVE_I64 uint64_t * AMXAPI amx_Align64(uint64_t *v); #endif - -#if SMALL_CELL_SIZE==32 -#define amx_AlignCell amx_Align32 -#elif SMALL_CELL_SIZE==64 -#define amx_AlignCell amx_Align64 -#else -#error Unsupported cell size -#endif - int AMXAPI amx_Allot(AMX *amx, int cells, cell *amx_addr, cell **phys_addr); int AMXAPI amx_Callback(AMX *amx, cell index, cell *result, cell *params); int AMXAPI amx_Cleanup(AMX *amx); int AMXAPI amx_Clone(AMX *amxClone, AMX *amxSource, void *data); -int AMXAPI amx_Debug(AMX *amx); /* default debug procedure, does nothing */ -int AMXAPI amx_DebugCall(AMX *amx, int mode); -int AMXAPI amx_Exec(AMX *amx, cell *retval, int index, int numparams, ...); -int AMXAPI amx_Execv(AMX *amx, cell *retval, int index, int numparams, cell params[]); +int AMXAPI amx_Exec(AMX *amx, cell *retval, int index); int AMXAPI amx_FindNative(AMX *amx, const char *name, int *index); int AMXAPI amx_FindPublic(AMX *amx, const char *funcname, int *index); int AMXAPI amx_FindPubVar(AMX *amx, const char *varname, cell *amx_addr); @@ -380,37 +382,56 @@ int AMXAPI amx_GetAddr(AMX *amx,cell amx_addr,cell **phys_addr); int AMXAPI amx_GetNative(AMX *amx, int index, char *funcname); int AMXAPI amx_GetPublic(AMX *amx, int index, char *funcname); int AMXAPI amx_GetPubVar(AMX *amx, int index, char *varname, cell *amx_addr); -int AMXAPI amx_GetString(char *dest,const cell *source, int use_wchar); +int AMXAPI amx_GetString(char *dest,const cell *source, int use_wchar, size_t size); int AMXAPI amx_GetTag(AMX *amx, int index, char *tagname, cell *tag_id); int AMXAPI amx_GetUserData(AMX *amx, long tag, void **ptr); int AMXAPI amx_Init(AMX *amx, void *program); int AMXAPI amx_InitJIT(AMX *amx, void *reloc_table, void *native_code); int AMXAPI amx_MemInfo(AMX *amx, long *codesize, long *datasize, long *stackheap); int AMXAPI amx_NameLength(AMX *amx, int *length); -AMX_NATIVE_INFO * AMXAPI amx_NativeInfo(const char *name,AMX_NATIVE func); +AMX_NATIVE_INFO * AMXAPI amx_NativeInfo(const char *name, AMX_NATIVE func); int AMXAPI amx_NumNatives(AMX *amx, int *number); int AMXAPI amx_NumPublics(AMX *amx, int *number); int AMXAPI amx_NumPubVars(AMX *amx, int *number); int AMXAPI amx_NumTags(AMX *amx, int *number); +int AMXAPI amx_Push(AMX *amx, cell value); +int AMXAPI amx_PushArray(AMX *amx, cell *amx_addr, cell **phys_addr, const cell array[], int numcells); +int AMXAPI amx_PushString(AMX *amx, cell *amx_addr, cell **phys_addr, const char *string, int pack, int use_wchar); int AMXAPI amx_RaiseError(AMX *amx, int error); -int AMXAPI amx_Register(AMX *amx, AMX_NATIVE_INFO *nativelist, int number); +int AMXAPI amx_Register(AMX *amx, const AMX_NATIVE_INFO *nativelist, int number); int AMXAPI amx_Release(AMX *amx, cell amx_addr); int AMXAPI amx_SetCallback(AMX *amx, AMX_CALLBACK callback); int AMXAPI amx_SetDebugHook(AMX *amx, AMX_DEBUG debug); -int AMXAPI amx_SetString(cell *dest, const char *source, int pack, int use_wchar); +int AMXAPI amx_SetString(cell *dest, const char *source, int pack, int use_wchar, size_t size); int AMXAPI amx_SetUserData(AMX *amx, long tag, void *ptr); -int AMXAPI amx_StrLen(cell *cstring, int *length); +int AMXAPI amx_StrLen(const cell *cstring, int *length); +int AMXAPI amx_UTF8Check(const char *string, int *length); int AMXAPI amx_UTF8Get(const char *string, const char **endptr, cell *value); +int AMXAPI amx_UTF8Len(const cell *cstr, int *length); int AMXAPI amx_UTF8Put(char *string, char **endptr, int maxchars, cell value); -int AMXAPI amx_UTF8Check(const char *string); int AMXAPI amx_GetLibraries(AMX *amx); const char *AMXAPI amx_GetLibrary(AMX *amx, int index, char *buffer, int len); +int AMXAPI amx_SetStringOld(cell *dest,const char *source,int pack,int use_wchar); +int AMXAPI amx_GetStringOld(char *dest,const cell *source,int use_wchar); -//no longer used! void amx_NullNativeTable(AMX *amx); +#if PAWN_CELL_SIZE==16 + #define amx_AlignCell(v) amx_Align16(v) +#elif PAWN_CELL_SIZE==32 + #define amx_AlignCell(v) amx_Align32(v) +#elif PAWN_CELL_SIZE==64 && (defined _I64_MAX || defined HAVE_I64) + #define amx_AlignCell(v) amx_Align64(v) +#else + #error Unsupported cell size +#endif + +#define amx_RegisterFunc(amx, name, func) \ + amx_Register((amx), amx_NativeInfo((name),(func)), 1); #if !defined AMX_NO_ALIGN - #if defined __linux__ + #if defined LINUX || defined __FreeBSD__ #pragma pack() /* reset default packing */ + #elif defined MACOS && defined __MWERKS__ + #pragma options align=reset #else #pragma pack(pop) /* reset previous packing */ #endif diff --git a/amxmodx/amxcore.cpp b/amxmodx/amxcore.cpp index fbbf2cad..a708bfff 100755 --- a/amxmodx/amxcore.cpp +++ b/amxmodx/amxcore.cpp @@ -1,6 +1,6 @@ -/* Core module for the Small AMX +/* Core module for the Pawn AMX * - * Copyright (c) ITB CompuPhase, 1997-2004 + * Copyright (c) ITB CompuPhase, 1997-2005 * * This software is provided "as-is", without any express or implied warranty. * In no event will the authors be held liable for any damages arising from @@ -34,14 +34,7 @@ #include #include #include - -// this file does not include amxmodx.h, so we have to include the memory manager here -#ifdef MEMORY_TEST -#include "mmgr/mmgr.h" -#endif // MEMORY_TEST - #include "amx.h" - #if defined __WIN32__ || defined _WIN32 || defined WIN32 || defined _Windows #include #endif @@ -60,14 +53,13 @@ # define _tcscpy strcpy # define _tcsdup strdup # define _tcslen strlen -# define _stprintf sprintf #endif #define CHARBITS (8*sizeof(char)) typedef unsigned char uchar; -#if !defined NOPROPLIST +#if !defined AMX_NOPROPLIST typedef struct _property_list { struct _property_list *next; cell id; @@ -76,7 +68,7 @@ typedef struct _property_list { //??? safe AMX (owner of the property) } proplist; -static proplist proproot = { NULL }; +static proplist proproot = { NULL, 0, NULL, 0 }; static proplist *list_additem(proplist *root) { @@ -142,15 +134,13 @@ static proplist *list_finditem(proplist *root,cell id,char *name,cell value, } #endif -#if defined __BORLANDC__ || defined __WATCOMC__ - #pragma argsused -#endif static cell AMX_NATIVE_CALL numargs(AMX *amx, cell *params) { AMX_HEADER *hdr; uchar *data; cell bytes; + (void)params; hdr=(AMX_HEADER *)amx->base; data=amx->data ? amx->data : amx->base+(int)hdr->dat; /* the number of bytes is on the stack, at "frm + 2*cell" */ @@ -190,18 +180,16 @@ static cell AMX_NATIVE_CALL setarg(AMX *amx, cell *params) /* adjust the address in "value" in case of an array access */ value+=params[2]*sizeof(cell); /* verify the address */ - if (value<0 || (value>=amx->hea && valuestk)) + if (value<0 || value>=amx->hea && valuestk) return 0; /* set the value indirectly */ * (cell *)(data+(int)value) = params[3]; return 1; } -#if defined __BORLANDC__ || defined __WATCOMC__ - #pragma argsused -#endif static cell AMX_NATIVE_CALL heapspace(AMX *amx,cell *params) { + (void)params; return amx->stk - amx->hea; } @@ -220,142 +208,22 @@ static cell AMX_NATIVE_CALL funcidx(AMX *amx,cell *params) return 0; } /* if */ - amx_GetString(name,cstr,0); + amx_GetString(name,cstr,0,UNLIMITED); err=amx_FindPublic(amx,name,&index); if (err!=AMX_ERR_NONE) index=-1; /* this is not considered a fatal error */ return index; } -int amx_StrPack(cell *dest,cell *source) -{ - int len; - - amx_StrLen(source,&len); - if ((ucell)*source>UNPACKEDMAX) { - /* source string is already packed */ - while (len >= 0) { - *dest++ = *source++; - len-=sizeof(cell); - } /* while */ - } else { - /* pack string, from bottom up */ - cell c; - int i; - for (c=0,i=0; iUNPACKEDMAX) { - /* unpack string, from top down (so string can be unpacked in place) */ - cell c; - int i,len; - amx_StrLen(source,&len); - dest[len]=0; - for (i=len-1; i>=0; i--) { - c=source[i/sizeof(cell)] >> (sizeof(cell)-i%sizeof(cell)-1)*CHARBITS; - dest[i]=c & UCHAR_MAX; - } /* for */ - } else { - /* source string is already unpacked */ - while ((*dest++ = *source++) != 0) - /* nothing */; - } /* if */ - return AMX_ERR_NONE; -} - -static int verify_addr(AMX *amx,cell addr) -{ - int err; - cell *cdest; - - err=amx_GetAddr(amx,addr,&cdest); - if (err!=AMX_ERR_NONE) - amx_RaiseError(amx,err); - return err; -} - -static cell AMX_NATIVE_CALL core_strlen(AMX *amx,cell *params) -{ - cell *cptr; - int len = 0; - - if (amx_GetAddr(amx,params[1],&cptr)==AMX_ERR_NONE) - amx_StrLen(cptr,&len); - return len; -} - -static cell AMX_NATIVE_CALL strpack(AMX *amx,cell *params) -{ - cell *cdest,*csrc; - int len,needed,err; - size_t lastaddr; - - /* calculate number of cells needed for (packed) destination */ - amx_GetAddr(amx,params[2],&csrc); - amx_StrLen(csrc,&len); - needed=(len+sizeof(cell))/sizeof(cell); /* # of cells needed */ - assert(needed>0); - lastaddr=(size_t)(params[1]+sizeof(cell)*needed-1); - if (verify_addr(amx,(cell)lastaddr)!=AMX_ERR_NONE) - return 0; - - amx_GetAddr(amx,params[1],&cdest); - err=amx_StrPack(cdest,csrc); - if (err!=AMX_ERR_NONE) - return amx_RaiseError(amx,err); - - return len; -} - -static cell AMX_NATIVE_CALL strunpack(AMX *amx,cell *params) -{ - cell *cdest,*csrc; - int len,err; - size_t lastaddr; - - /* calculate number of cells needed for (packed) destination */ - amx_GetAddr(amx,params[2],&csrc); - amx_StrLen(csrc,&len); - assert(len>=0); - lastaddr=(size_t)(params[1]+sizeof(cell)*(len+1)-1); - if (verify_addr(amx,(cell)lastaddr)!=AMX_ERR_NONE) - return 0; - - amx_GetAddr(amx,params[1],&cdest); - err=amx_StrUnpack(cdest,csrc); - if (err!=AMX_ERR_NONE) - return amx_RaiseError(amx,err); - - return len; -} - -#if defined __BORLANDC__ || defined __WATCOMC__ - #pragma argsused -#endif static cell AMX_NATIVE_CALL swapchars(AMX *amx,cell *params) { union { cell c; - #if SMALL_CELL_SIZE==16 + #if PAWN_CELL_SIZE==16 uchar b[2]; - #elif SMALL_CELL_SIZE==32 + #elif PAWN_CELL_SIZE==32 uchar b[4]; - #elif SMALL_CELL_SIZE==64 + #elif PAWN_CELL_SIZE==64 uchar b[8]; #else #error Unsupported cell size @@ -363,20 +231,21 @@ static cell AMX_NATIVE_CALL swapchars(AMX *amx,cell *params) } value; uchar t; + (void)amx; assert((size_t)params[0]==sizeof(cell)); value.c = params[1]; - #if SMALL_CELL_SIZE==16 + #if PAWN_CELL_SIZE==16 t = value.b[0]; value.b[0] = value.b[1]; value.b[1] = t; - #elif SMALL_CELL_SIZE==32 + #elif PAWN_CELL_SIZE==32 t = value.b[0]; value.b[0] = value.b[3]; value.b[3] = t; t = value.b[1]; value.b[1] = value.b[2]; value.b[2] = t; - #elif SMALL_CELL_SIZE==64 + #elif PAWN_CELL_SIZE==64 t = value.b[0]; value.b[0] = value.b[7]; value.b[7] = t; @@ -395,11 +264,9 @@ static cell AMX_NATIVE_CALL swapchars(AMX *amx,cell *params) return value.c; } -#if defined __BORLANDC__ || defined __WATCOMC__ - #pragma argsused -#endif static cell AMX_NATIVE_CALL core_tolower(AMX *amx,cell *params) { + (void)amx; #if defined __WIN32__ || defined _WIN32 || defined WIN32 return (cell)CharLower((LPTSTR)params[1]); #elif defined _Windows @@ -409,11 +276,9 @@ static cell AMX_NATIVE_CALL core_tolower(AMX *amx,cell *params) #endif } -#if defined __BORLANDC__ || defined __WATCOMC__ - #pragma argsused -#endif static cell AMX_NATIVE_CALL core_toupper(AMX *amx,cell *params) { + (void)amx; #if defined __WIN32__ || defined _WIN32 || defined WIN32 return (cell)CharUpper((LPTSTR)params[1]); #elif defined _Windows @@ -423,19 +288,15 @@ static cell AMX_NATIVE_CALL core_toupper(AMX *amx,cell *params) #endif } -#if defined __BORLANDC__ || defined __WATCOMC__ - #pragma argsused -#endif static cell AMX_NATIVE_CALL core_min(AMX *amx,cell *params) { + (void)amx; return params[1] <= params[2] ? params[1] : params[2]; } -#if defined __BORLANDC__ || defined __WATCOMC__ - #pragma argsused -#endif static cell AMX_NATIVE_CALL core_max(AMX *amx,cell *params) { + (void)amx; return params[1] >= params[2] ? params[1] : params[2]; } @@ -451,7 +312,7 @@ static cell AMX_NATIVE_CALL core_clamp(AMX *amx,cell *params) return value; } -#if !defined NOPROPLIST +#if !defined AMX_NOPROPLIST static char *MakePackedString(cell *cptr) { int len; @@ -459,10 +320,21 @@ static char *MakePackedString(cell *cptr) amx_StrLen(cptr,&len); dest=(char *)malloc(len+sizeof(cell)); - amx_GetString(dest,cptr,0); + amx_GetString(dest,cptr,0,UNLIMITED); return dest; } +static int verify_addr(AMX *amx,cell addr) +{ + int err; + cell *cdest; + + err=amx_GetAddr(amx,addr,&cdest); + if (err!=AMX_ERR_NONE) + amx_RaiseError(amx,err); + return err; +} + static cell AMX_NATIVE_CALL getproperty(AMX *amx,cell *params) { cell *cstr; @@ -480,7 +352,7 @@ static cell AMX_NATIVE_CALL getproperty(AMX *amx,cell *params) return 0; } /* if */ amx_GetAddr(amx,params[4],&cstr); - amx_SetString(cstr,item->name,1,0); + amx_SetString(cstr,item->name,1,0,UNLIMITED); } /* if */ free(name); return (item!=NULL) ? item->value : 0; @@ -545,12 +417,14 @@ static cell AMX_NATIVE_CALL existproperty(AMX *amx,cell *params) } #endif +#if !defined AMX_NORANDOM /* This routine comes from the book "Inner Loops" by Rick Booth, Addison-Wesley * (ISBN 0-201-47960-5). This is a "multiplicative congruential random number * generator" that has been extended to 31-bits (the standard C version returns * only 15-bits). */ -static unsigned long IL_StandardRandom_seed = 0L; +#define INITIAL_SEED 0xcaa938dbL +static unsigned long IL_StandardRandom_seed = INITIAL_SEED; /* always use a non-zero seed */ #define IL_RMULT 1103515245L #if defined __BORLANDC__ || defined __WATCOMC__ #pragma argsused @@ -562,7 +436,7 @@ static cell AMX_NATIVE_CALL core_random(AMX *amx,cell *params) /* one-time initialization (or, mostly one-time) */ #if !defined SN_TARGET_PS2 && !defined _WIN32_WCE - if (IL_StandardRandom_seed == 0L) + if (IL_StandardRandom_seed == INITIAL_SEED) IL_StandardRandom_seed=(unsigned long)time(NULL); #endif @@ -579,6 +453,7 @@ static cell AMX_NATIVE_CALL core_random(AMX *amx,cell *params) result %= params[1]; return (cell)result; } +#endif AMX_NATIVE_INFO core_Natives[] = { @@ -587,22 +462,13 @@ AMX_NATIVE_INFO core_Natives[] = { { "setarg", setarg }, { "heapspace", heapspace }, { "funcidx", funcidx }, - { "strlen", core_strlen }, - { "strpack", strpack }, - { "strunpack", strunpack }, { "swapchars", swapchars }, { "tolower", core_tolower }, { "toupper", core_toupper }, - { "random", core_random }, { "min", core_min }, { "max", core_max }, { "clamp", core_clamp }, -#if !defined NOPROPLIST - { "getproperty", getproperty }, - { "setproperty", setproperty }, - { "deleteproperty",delproperty }, - { "existproperty", existproperty }, -#endif + { "random", core_random }, { NULL, NULL } /* terminator */ }; @@ -611,12 +477,10 @@ int AMXEXPORT amx_CoreInit(AMX *amx) return amx_Register(amx, core_Natives, -1); } -#if defined __BORLANDC__ || defined __WATCOMC__ - #pragma argsused -#endif int AMXEXPORT amx_CoreCleanup(AMX *amx) { - #if !defined NOPROPLIST + (void)amx; + #if !defined AMX_NOPROPLIST //??? delete only the properties owned by the AMX while (proproot.next!=NULL) list_delete(&proproot,proproot.next); diff --git a/amxmodx/amxdefn.asm b/amxmodx/amxdefn.asm new file mode 100755 index 00000000..450f6a03 --- /dev/null +++ b/amxmodx/amxdefn.asm @@ -0,0 +1,86 @@ +; Definition of the AMX structure for assembler syntax (NASM) + + struc amx_s +_base: resd 1 +_dataseg: resd 1 +_callback: resd 1 +_debug: resd 1 +_cip: resd 1 +_frm: resd 1 +_hea: resd 1 +_hlw: resd 1 +_stk: resd 1 +_stp: resd 1 +_flags: resd 1 +_usertags: resd 4 ; 4 = AMX_USERNUM (#define'd in amx.h) +_userdata: resd 4 ; 4 = AMX_USERNUM (#define'd in amx.h) +_error: resd 1 +_paramcount: resd 1 +_pri: resd 1 +_alt: resd 1 +_reset_stk: resd 1 +_reset_hea: resd 1 +_syscall_d: resd 1 +%ifdef JIT + ; the two fields below are for the JIT; they do not exist in + ; the non-JIT version of the abstract machine +_reloc_size: resd 1 ; memory block for relocations +_code_size: resd 1 ; memory size of the native code +%endif + endstruc + + struc amxhead_s +_size: resd 1 ; size of the "file" +_magic: resw 1 ; signature +_file_version: resb 1; file format version +_amx_version: resb 1 ; required version of the AMX +_h_flags: resw 1 +_defsize: resw 1 ; size of one public/native function entry +_cod: resd 1 ; initial value of COD - code block +_dat: resd 1 ; initial value of DAT - data block +_h_hea: resd 1 ; initial value of HEA - start of the heap +_h_stp: resd 1 ; initial value of STP - stack top +_h_cip: resd 1 ; initial value of CIP - the instruction pointer +_publics: resd 1 ; offset to the "public functions" table +_natives: resd 1 ; offset to the "native functions" table +_libraries: resd 1 ; offset to the "library" table +_pubvars: resd 1 ; offset to the "public variables" table +_tags: resd 1 ; offset to the "public tagnames" table +_nametable: resd 1 ; offset to the name table, file version 7 only + endstruc + + +AMX_ERR_NONE EQU 0 +AMX_ERR_EXIT EQU 1 +AMX_ERR_ASSERT EQU 2 +AMX_ERR_STACKERR EQU 3 +AMX_ERR_BOUNDS EQU 4 +AMX_ERR_MEMACCESS EQU 5 +AMX_ERR_INVINSTR EQU 6 +AMX_ERR_STACKLOW EQU 7 +AMX_ERR_HEAPLOW EQU 8 +AMX_ERR_CALLBACK EQU 9 +AMX_ERR_NATIVE EQU 10 +AMX_ERR_DIVIDE EQU 11 ; for catching divide errors +AMX_ERR_SLEEP EQU 12 + +AMX_ERR_MEMORY EQU 16 +AMX_ERR_FORMAT EQU 17 +AMX_ERR_VERSION EQU 18 +AMX_ERR_NOTFOUND EQU 19 +AMX_ERR_INDEX EQU 20 +AMX_ERR_DEBUG EQU 21 +AMX_ERR_INIT EQU 22 +AMX_ERR_USERDATA EQU 23 +AMX_ERR_INIT_JIT EQU 24 +AMX_ERR_PARAMS EQU 25 +AMX_ERR_DOMAIN EQU 26 +AMX_ERR_GENERAL EQU 27 + +AMX_FLAG_DEBUG EQU 0002h ; symbolic info. available +AMX_FLAG_COMPACT EQU 0004h +AMX_FLAG_BYTEOPC EQU 0008h +AMX_FLAG_NOCHECKS EQU 0010h +AMX_FLAG_BROWSE EQU 4000h +AMX_FLAG_RELOC EQU 8000h ; jump/call addresses relocated + diff --git a/amxmodx/amxexecn.asm b/amxmodx/amxexecn.asm index 2a14e9e1..a5a6cf78 100755 --- a/amxmodx/amxexecn.asm +++ b/amxmodx/amxexecn.asm @@ -1,4 +1,4 @@ -; AMXEXECN.ASM Abstract Machine for the "Small" language +; AMXEXECN.ASM Abstract Machine for the "Pawn" language ; ;Some notes: @@ -25,7 +25,7 @@ ; ;Copyright and license of use, please read ;----------------------------------------- -;The assembler implementation of the abstract machine for the Small language, +;The assembler implementation of the abstract machine for the Pawn language, ;specifically the file AMXEXEC.ASM, is copyright (c) 1998-2000 by Marc Peter. ; ;Permission is hereby granted, without written agreement and without paid @@ -56,6 +56,8 @@ ; ;History (list of changes) ;------------------------- +; 17 february 2005 by Thiadmer Riemersms +; Addition of the BREAK opcode, removal of the older debugging opcode table. ; 6 march 2004 by Thiadmer Riemersma ; Corrected a bug in OP_FILL, where a cell preceding the array would ; be overwritten (zero'ed out). This bug was brought to my attention @@ -95,92 +97,7 @@ %endif %endmacro - -; I could not get NASM's structure definition to work (it appears to confuse -; ENDSTRUC with "end segment"). So the definition below uses constants for -; the field offsets. -;amx_s STRUC - _base EQU 00h ;DD ? - _dataseg EQU 04h ;DD ? - _callback EQU 08h ;DD ? - _debug EQU 0ch ;DD ? - _cip EQU 10h ;DD ? - _frm EQU 14h ;DD ? - _hea EQU 18h ;DD ? - _hlw EQU 1ch ;DD ? - _stk EQU 20h ;DD ? - _stp EQU 24h ;DD ? - _flags EQU 28h ;DD ? - _curline EQU 2ch ;DD ? - _curfile EQU 30h ;DD ? - _dbgcode EQU 34h ;DD ? - _dbgaddr EQU 38h ;DD ? - _dbgparam EQU 3ch ;DD ? - _dbgname EQU 40h ;DD ? - _usertags1 EQU 44h ;DD 4 DUP (?) ; 4 = AMX_USERNUM (#define'd in amx.h) - _usertags2 EQU 44h ;DD 4 DUP (?) ; 4 = AMX_USERNUM (#define'd in amx.h) - _usertags3 EQU 44h ;DD 4 DUP (?) ; 4 = AMX_USERNUM (#define'd in amx.h) - _usertags4 EQU 44h ;DD 4 DUP (?) ; 4 = AMX_USERNUM (#define'd in amx.h) - _userdata1 EQU 54h ;DD 4 DUP (?) ; 4 = AMX_USERNUM (#define'd in amx.h) - _userdata2 EQU 54h ;DD 4 DUP (?) ; 4 = AMX_USERNUM (#define'd in amx.h) - _userdata3 EQU 54h ;DD 4 DUP (?) ; 4 = AMX_USERNUM (#define'd in amx.h) - _userdata4 EQU 54h ;DD 4 DUP (?) ; 4 = AMX_USERNUM (#define'd in amx.h) - _error EQU 64h ;DD ? - _pri EQU 68h ;DD ? - _alt EQU 6ch ;DD ? - _reset_stk EQU 70h ;DD ? - _reset_hea EQU 74h ;DD ? - _syscall_d EQU 78h ;DD ? - ; the two fields below are for the JIT; they do not exist in - ; the non-JIT version of the abstract machine -; _reloc_size EQU 7ch ;DD ? ; memory block for relocations -; _code_size EQU 80h ;DD ? ; memory size of the native code -;amx_s ENDS - - - AMX_ERR_NONE EQU 0 - AMX_ERR_EXIT EQU 1 - AMX_ERR_ASSERT EQU 2 - AMX_ERR_STACKERR EQU 3 - AMX_ERR_BOUNDS EQU 4 - AMX_ERR_MEMACCESS EQU 5 - AMX_ERR_INVINSTR EQU 6 - AMX_ERR_STACKLOW EQU 7 - AMX_ERR_HEAPLOW EQU 8 - AMX_ERR_CALLBACK EQU 9 - AMX_ERR_NATIVE EQU 10 - AMX_ERR_DIVIDE EQU 11 ; MP: added for catching divide errors - AMX_ERR_SLEEP EQU 12 ; (TR) - - AMX_ERR_MEMORY EQU 16 - AMX_ERR_FORMAT EQU 17 - AMX_ERR_VERSION EQU 18 - AMX_ERR_NOTFOUND EQU 19 - AMX_ERR_INDEX EQU 20 - AMX_ERR_DEBUG EQU 21 - AMX_ERR_INIT EQU 22 - AMX_ERR_USERDATA EQU 23 - AMX_ERR_INIT_JIT EQU 24 - AMX_ERR_PARAMS EQU 25 - AMX_ERR_DOMAIN EQU 26 - - DBG_INIT EQU 0 - DBG_FILE EQU 1 - DBG_LINE EQU 2 - DBG_SYMBOL EQU 3 - DBG_CLRSYM EQU 4 - DBG_CALL EQU 5 - DBG_RETURN EQU 6 - DBG_TERMINATE EQU 7 - DBG_SRANGE EQU 8 ; (TR) - DBG_SYMTAG EQU 9 ; (TR) - - AMX_FLAG_CHAR16 EQU 0001h ; characters are 16-bit - AMX_FLAG_DEBUG EQU 0002h ; symbolic info. available - AMX_FLAG_LINEOPS EQU 0020h ; line op information - AMX_FLAG_TRACED EQU 0040h ; - AMX_FLAG_BROWSE EQU 4000h - AMX_FLAG_RELOC EQU 8000h ; jump/call addresses relocated +%include "amxdefn.asm" ;#define PUSH(v) ( stk-=sizeof(cell), *(cell *)(data+(int)stk)=v ) %macro _PUSH 1 @@ -659,29 +576,6 @@ OP_POP_ALT: ;good OP_STACK: - mov edx,ecx - add ecx,[esi+4] - _CHKMARGIN - _CHKSTACK - mov ebp,amx - test DWORD [ebp+_flags],AMX_FLAG_DEBUG - jz short op_stk_goon - ; update several structure fields and call the debug hook - mov DWORD [ebp+_dbgcode],DBG_CLRSYM - mov [ebp+_stk],ecx - push eax - mov eax,ebp ; 1st parm: amx - _SAVEREGS - push eax ; pass parameter via the stack - call [ebp+_debug] ; call debug function - _DROPARGS 4 ; remove arguments from stack - _RESTOREREGS - pop eax - op_stk_goon: - add esi,8 - GO_ON - -OP_STACK_nodebug: mov edx,ecx add ecx,[esi+4] _CHKMARGIN @@ -711,35 +605,6 @@ OP_PROC: GO_ON OP_RET: - _POP ebx - _POP esi - cmp esi,code ; verify ESI>=code - jb err_memaccess - cmp esi,codesiz ; verify ESI=code @@ -760,107 +625,17 @@ OP_RETN: jae err_memaccess mov frm,ebx add ebx,edi - mov ebp,amx - test DWORD [ebp+_flags], AMX_FLAG_DEBUG - jz short op_retn_goon - ; update several structure fields and call the debug hook - mov DWORD [ebp+_dbgcode],DBG_RETURN - mov [ebp+_dbgparam],eax - push eax - mov [ebp+_stk],ecx ; store STK - mov eax,hea - mov [ebp+_hea],eax ; store HEA - mov eax,ebp ; parm: amx - _SAVEREGS - push eax - call [ebp+_debug] ; call debug function - _DROPARGS 4 ; remove arguments from stack - _RESTOREREGS - ; also send the DBG_CLRSYM code - mov eax,[edi+ecx] - lea ecx,[ecx+eax+4] - mov DWORD [ebp+_dbgcode],DBG_CLRSYM - mov [ebp+_stk],ecx - mov eax,ebp ; parm: amx - _SAVEREGS - push eax - call [ebp+_debug] ; call debug function - _DROPARGS 4 ; remove arguments from stack - _RESTOREREGS - pop eax - ; ECX already adjusted - GO_ON - op_retn_goon: mov ebp,[edi+ecx] lea ecx,[ecx+ebp+4] GO_ON -OP_RETN_nodebug: - _POP ebx - _POP esi - cmp esi,code ; verify ESI>=code - jb err_memaccess - cmp esi,codesiz ; verify ESI155 million instr./sec on my AMD K6-2/366 with the Hanoi "bench" @@ -20,42 +21,78 @@ ; step. ; NOTE 3: -; During execution of the compiled code with amx_exec_asm() the x86 processor's +; During execution of the compiled code with amx_exec_jit() the x86 processor's ; stack is switched into the data section of the abstract machine. This means ; that there should always be enough memory left between HEA and STK to provide ; stack space for occurring interrupts! (see the STACKRESERVE variable) ; NOTE 4: -; Although the Small compiler doesn't generate the LCTRL, SCTRL and CALL.I +; Although the Pawn compiler doesn't generate the LCTRL, SCTRL and CALL.I ; instructions, I have to tell that they don't work as expected in a JIT ; compiled program, because there is no easy way of transforming AMX code ; addresses and JIT translated ones. This might be fixed in a future version. + +; NX ("No eXecute") and XD (eXecution Denied) bits +; (by Thiadmer Riemersma) +; +; AMD defined a bit "No eXecute" for the page table entries (for its 64-bit +; processors) and Intel came with the same design, but calling it differently. +; The purpose is to make "buffer overrun" security holes impossible, or at least +; very, very difficult, by marking the stack and the heap as memory regions +; such that an attempt to execute processor instructions will cause a processor +; exception (of course, a buffer overrun that is not explictly handled will then +; crash the application --instead of executing the rogue code). +; +; For JIT compilers, this has the impact that you are not allowed to execute the +; code that the JIT has generated. To do that, you must adjust the attributes +; for the memory page. For Microsoft Windows, you can use VirtualAlloc() to +; allocate a memory block with the appropriate fags; on Linux (with a recent +; kernel), you would use vmalloc_exec(). Microsoft Windows also offers the +; function VirtualProtect() to change the page attributes of an existing memory +; block, but there are caveats in its use: if the block spans multiple pages, +; these pages must be consecutive, and if there are blocks of memory in a page +; unrelated to the JIT, their page attributes will change too. +; +; The JIT compiler itself requires only read-write access (this is the default +; for a memory block that you allocate). The execution of the JIT-compiled code +; requires full access to the memory block: read, write and execute. It needs +; write access, because the SYSREQ.C opcode is patched to SYSREQ.D after the +; first lookup (this is an optimization, look up the address of the native +; function only once). For processors that do not support the NX/XD bit, +; execution of code is implicitly supported if read access is supported. +; +; During compilation, the JIT compiler requires write-access to its own code +; segment: the JIT-compiler patches P-code parameters into its own code segment +; during compilation. This is handled in the support code for amx_InitJIT. +; +; +; CALLING CONVENTIONS +; (by Thiadmer Riemersma) ; -; CALLING CONVENTIONS (by Thiadmer Riemersma) ; This version is the JIT that uses the "stack calling convention". In the ; original implementation, this meant __cdecl; both for the calling convention ; for the _asm_runJIT routine itself as for the callback functions. ; The current release supports __stdcall for the callback functions; to -; use it, you need to assemble the file with STDECL defined (Since STDCALL is +; use it, you need to assemble the file with STDECL defined (Since STDCALL is ; a reserved word on the assembler, I had to choose a different name for the ; macro, hence STDECL.) ; Revision History -;------------------ -; 16 September 2004 by David "BAILOPAN" Anderson -; Implemented a compile time toggleable debug hook on OP_CALL and OP_RET. -; NOTE: JIT has not had debug hooks since 1999. -; 8 September 2004 by David "BAILOPAN" Anderson -; Changed OP_LINE call to be compile-time toggle-able between compiling -; line ops or not. +; ---------------- +; 17 february 2005 by Thiadmer Riemersms +; Addition of the BREAK opcode, removal of the older debugging opcode +; table. There should now be some debug support (if enabled during the +; build of the JIT compiler), but not enough to run a debugger: the JIT +; compiler does not keep a list that relates the code addresses of the +; P-code versus the native code. ; 29 June 2004 by G.W.M. Vissers -; Translated the thing into NASM. The actual generation of the code is -; put into the data section because the code modifies itself whereas the -; text section is usually read-only in the Unix ELF format. +; Translated the thing into NASM. The actual generation of the code is +; put into the data section because the code modifies itself whereas the +; text section is usually read-only in the Unix ELF format. ; 6 march 2004 by Thiadmer Riemersma ; Corrected a bug in OP_FILL, where a cell preceding the array would ; be overwritten (zero'ed out). This bug was brought to my attention -; by Robert Daniels. +; by Robert Daniels. ; 22 december 2003 by Thiadmer Riemersma (TR) ; Added the SYMTAG and SYSCALL.D opcodes (these are not really supported; ; SYMTAG is a no-op). @@ -94,8 +131,8 @@ ; hanoi bench. ; 1999/08/05 MP ; * fixed OP_LINE in the case of NODBGCALLS==1, where no compiled address -; was stored for the LINE byte code (I.e. SWITCH would jump to totally -; wrong addresses.) The same fix was applied to OP_FILL, OP_FILE and +; was stored for the LINE byte code (i.e. SWITCH would jump to totally +; wrong addresses). The same fix was applied to OP_FILL, OP_FILE and ; OP_SCTRL (for the no-op case). ; 1999/08/04 MP ; * updated with 4 new opcodes (SRANGE does nothing at the moment; 2dim. @@ -107,6 +144,16 @@ ; to compute the destination address: It searches backwards now. ; 1999/07/08 MP - initial revision + +; +; Support for the BREAK opcode (callback to the debugger): 0 = no, all other +; values = yes. Beware that the compiled code runs slower when this is enabled, +; and that debug support is still fairly minimal. +; +; GWMV: to generate LINE opcode, %define DEBUGSUPPORT +; +%undef DEBUGSUPPORT + ; ; If this is set to 1 the JIT generates relocatable code for case tables, too. ; If set to 0, a faster variant for switch (using absolute addresses) is @@ -128,119 +175,17 @@ ; ; This variable controls the generation of memory range checks at run-time. ; You should set this to 0, only when you are sure that there are no range -; violations in your Small programs and you really need those 5% speed gain. +; violations in your Pawn programs and you really need those 5% speed gain. ; ; GWMV: To disable runtime checks, %undef it, instread of setting it to zero ; %define DORUNTIMECHECKS - - struc amx_s -_base: resd 1 -_dataseg: resd 1 -_callback: resd 1 -_debug: resd 1 -_cip: resd 1 -_frm: resd 1 -_hea: resd 1 -_hlw: resd 1 -_stk: resd 1 -_stp: resd 1 -_flags: resd 1 -_curline: resd 1 -_curfile: resd 1 -_dbgcode: resd 1 -_dbgaddr: resd 1 -_dbgparam: resd 1 -_dbgname: resd 1 -;usertags and userdata are 16 bytes on AMX Mod X -_usertags1: resd 1 ; 4 = AMX_USERNUM (#define'd in amx.h) -_usertags2: resd 1 ; 4 = AMX_USERNUM (#define'd in amx.h) -_usertags3: resd 1 ; 4 = AMX_USERNUM (#define'd in amx.h) -_usertags4: resd 1 ; 4 = AMX_USERNUM (#define'd in amx.h) -_userdata1: resd 1 ; 4 = AMX_USERNUM (#define'd in amx.h) -_userdata2: resd 1 ; 4 = AMX_USERNUM (#define'd in amx.h) -_userdata3: resd 1 ; 4 = AMX_USERNUM (#define'd in amx.h) -_userdata4: resd 1 ; 4 = AMX_USERNUM (#define'd in amx.h) -_error: resd 1 -_pri: resd 1 -_alt: resd 1 -_reset_stk: resd 1 -_reset_hea: resd 1 -_syscall_d: resd 1 -; the two fields below are for the JIT -; they are included in the non-JIT version for AMX Mod X -; this is to make sure that the structs match universally! -_reloc_size: resd 1 ; memory block for relocations -_code_size: resd 1 ; memory size of the native code - endstruc - - - struc amxhead_s -_size: resd 1 ; size of the "file" -_magic: resw 1 ; signature -_file_version: resb 1 ;file format version -_amx_version: resb 1 ; required version of the AMX -_h_flags: resw 1 -_defsize: resw 1 ; size of one public/native function entry -_cod: resd 1 ; initial value of COD - code block -_dat: resd 1 ; initial value of DAT - data block -_h_hea: resd 1 ; initial value of HEA - start of the heap -_h_stp: resd 1 ; initial value of STP - stack top -_h_cip: resd 1 ; initial value of CIP - the instruction pointer -_publics: resd 1 ; offset to the "public functions" table -_natives: resd 1 ; offset to the "native functions" table -_libraries: resd 1 ; offset to the "library" table -_pubvars: resd 1 ; offset to the "public variables" table -_tags: resd 1 ; offset to the "public tagnames" table - endstruc - - -AMX_ERR_NONE equ 0 -AMX_ERR_EXIT equ 1 -AMX_ERR_ASSERT equ 2 -AMX_ERR_STACKERR equ 3 -AMX_ERR_BOUNDS equ 4 -AMX_ERR_MEMACCESS equ 5 -AMX_ERR_INVINSTR equ 6 -AMX_ERR_STACKLOW equ 7 -AMX_ERR_HEAPLOW equ 8 -AMX_ERR_CALLBACK equ 9 -AMX_ERR_NATIVE equ 10 -AMX_ERR_DIVIDE equ 11 ; MP: added for catching divide errors -AMX_ERR_SLEEP equ 12 ; (TR) go into sleep mode - -AMX_ERR_MEMORY equ 16 -AMX_ERR_FORMAT equ 17 -AMX_ERR_VERSION equ 18 -AMX_ERR_NOTFOUND equ 19 -AMX_ERR_INDEX equ 20 -AMX_ERR_DEBUG equ 21 -AMX_ERR_INIT equ 22 -AMX_ERR_USERDATA equ 23 -AMX_ERR_INIT_JIT equ 24 -AMX_ERR_PARAMS equ 25 -AMX_ERR_DOMAIN equ 26 - -DBG_INIT equ 0 -DBG_FILE equ 1 -DBG_LINE equ 2 -DBG_SYMBOL equ 3 -DBG_CLRSYM equ 4 -DBG_CALL equ 5 -DBG_RETURN equ 6 -DBG_TERMINATE equ 7 -DBG_SRANGE equ 8 -DBG_SYMTAG equ 9 - -AMX_FLAG_CHAR16 equ 0001h ; characters are 16-bit -AMX_FLAG_DEBUG equ 0002h ; symbolic info. available -AMX_FLAG_LINEOPS equ 0020h ; line ops should be parsed [load time only flag] - ~dvander -AMX_FLAG_BROWSE equ 4000h -AMX_FLAG_RELOC equ 8000h ; jump/call addresses relocated +%define JIT 1 +%include "amxdefn.asm" ; GWMV: -; Nasm can't do the next as equivalence statements, since the value of +; Nasm can't do the next as equivalence statements, since the value of ; esi is not determined at compile time %define stk [esi+32] ; define some aliases to registers that will %define alt [esi+28] ; be stored on the stack when the code is @@ -269,7 +214,7 @@ AMX_FLAG_RELOC equ 8000h ; jump/call addresses relocated ; -; For determining the biggest native code section generated for ONE Small +; For determining the biggest native code section generated for ONE Pawn ; opcode. (See the following macro and the PUBLIC function getMaxCodeSize().) ; ; GWMV: Do NOT see the following macro. See CHECKCODESIZE instead. @@ -278,20 +223,12 @@ AMX_FLAG_RELOC equ 8000h ; jump/call addresses relocated ; ; This is the work horse of the whole JIT: It actually copies the code. -; Notes from ~dvander (with help of dJeyL) -; This takes a source and ending address pointer in the assembled JIT code. -; Then it subtracts them and copies the code in between. -; The last parameter is the number of bytes the opcode is so it can jump -; to the next one. -; Also note that the "in between" code is NEVER executed during the compile -; phase of the JIT. It's only assembled in memory, and copied into the -; final output bytecode by this function. %macro GO_ON 2-3 4 mov esi, %1 ;get source address of JIT code mov ecx,%2-%1 ;get number of bytes to copy mov [ebx],edi ;store address for jump-correction - add ebx,%3 - rep movsb + add ebx,%3 + rep movsb cmp ebx,[end_code] jae code_gen_done jmp dword [ebx] ;go on with the next opcode @@ -300,9 +237,7 @@ AMX_FLAG_RELOC equ 8000h ; jump/call addresses relocated ; GWMV: ; Nasm can't handle the determination of the maximum code size as was done ; in the Masm implementation, since it only does two passes. This macro is -; called *after* the code for each Small instruction. -; Notes by ~dvander: This just substracts a label's ip from the current ip. -; Therefore you get an instant size check - see RELOC +; called *after* the code for each Pawn instruction. %macro CHECKCODESIZE 1 %if MAXCODESIZE < $-%1 %assign MAXCODESIZE $-%1 @@ -310,14 +245,9 @@ AMX_FLAG_RELOC equ 8000h ; jump/call addresses relocated %endmacro ; -; Modify the argument of an x86 instruction with the Small opcode's parameter +; Modify the argument of an x86 instruction with the Pawn opcode's parameter ; before copying the code. ; -; Notes by ~dvander (thanks to dJeyL) - this will take an address and modify -; the dword at it. Since the JIT copies already assembled code, you see -; things like "call 12345678h". This is an arbitrary value as putval -; will modify it in memory and then GO_ON will add it to the program. -; It is important to get the putval address right - it's in bytes. %macro putval 1 mov eax,[ebx+4] mov dword [%1],eax @@ -326,17 +256,12 @@ AMX_FLAG_RELOC equ 8000h ; jump/call addresses relocated ; ; Add an entry to the table of addresses which have to be relocated after the ; code compilation is done. -; Notes by ~dvander: This is sort of what amx_BrowseRelocate() does, although -; relocation is actually done after code generation (this just adds to a -; table). Like putval, this takes in an address and marks it to be -; rewritten. It is a good idea to just use labels to find relocation -; offsets (see OP_CALL and OP_RETN). After code generation, this table -; is browsed and the correct threaded jumps are placed. +; %macro RELOC 1-2 ; adr, dest mov ebp,[reloc_num] %if %0 < 2 mov eax,[ebx+4] - %else + %else lea eax,[%2] %endif mov [edx+ebp],eax ; write absolute destination @@ -356,7 +281,7 @@ section .text global asm_runJIT, _asm_runJIT -global amx_exec_asm, _amx_exec_asm +global amx_exec_jit, _amx_exec_jit global getMaxCodeSize, _getMaxCodeSize @@ -381,7 +306,7 @@ _asm_runJIT: mov eax,[esp+20] ; get amxh mov edx,[esp+24] ; get jumps array mov ebx,[esp+28] ; get destination - + mov [amxhead],eax ; save pointer to AMX_HEADER struct mov ecx,[eax+_cod] ; get offset of start of code mov eax,[eax+_dat] ; offset of start of data = end of code @@ -481,9 +406,9 @@ reloc_done: ret ; GWMV: -; The code below modifies itself to store the arguments to the Small opcodes +; The code below modifies itself to store the arguments to the Pawn opcodes ; in the compiled code. This is fine, but the .text section in an ELF executable -; is usually marked read-only, that's why this code is in the .data section. +; is usually marked read-only, that's why this code is in the .data section. section .data exec @@ -817,7 +742,7 @@ OP_ALIGN_PRI: CHECKCODESIZE j_align_pri OP_ALIGN_ALT: -;nop +;nop; mov eax,4 sub eax,[ebx+4] mov dword [j_align_alt+1],eax @@ -1045,7 +970,7 @@ OP_HEAP: call [chk_marginheap] %endif CHECKCODESIZE j_heap - + ;good OP_PROC: ;nop; @@ -1073,119 +998,22 @@ OP_RET: ;good OP_RETN: ;nop; - ;save registers - push eax - push ebp - ;get .amx flags - mov ebp,[amxhead] - mov eax,[ebp+_h_flags] - ;check to see if the flag has line ops - and eax,AMX_FLAG_DEBUG - cmp eax,AMX_FLAG_DEBUG - ;restore registers - pop ebp - pop eax - ;if so, skip down to debug compiler - jmp _go_jit_retn_debug + GO_ON j_retn, OP_CALL -_go_jit_retn_nodebug: - GO_ON j_retn_nodebug, _go_jit_retn_go - j_retn_nodebug: + j_retn: jmp [jit_retn] - CHECKCODESIZE j_retn_nodebug -_go_jit_retn_go: - jmp _go_jit_retn_end - -_go_jit_retn_debug: - GO_ON j_retn, OP_CALL - j_retn: - push ebp - push eax - push edx - ;get AMX - mov ebp,amx - ;get debug call ptr - mov eax,[ebp+_userdata2] - ;check validity - mov edx, dword 0 - cmp eax, edx - je _go_jit_skip_debug - xchg esp,esi ;switch stack - push 1 ;param 2 mode 1 = pop - push ebp ;param 1 - amx - call eax ;indirect debug call - add esp, 8 ;restore stack - xchg esp,esi ;return to AMX stack - mov ebp,amx ;restore AMX [necessary?] - _go_jit_skip_debug: - pop edx - pop eax - pop ebp - jmp [jit_retn] - CHECKCODESIZE j_retn -_go_jit_retn_end: + CHECKCODESIZE j_retn ;good OP_CALL: ;nop; - ;save registers - push eax - push ebp - ;get .amx flags - mov ebp,[amxhead] - mov eax,[ebp+_h_flags] - ;check to see if the flag has line ops - and eax,AMX_FLAG_DEBUG - cmp eax,AMX_FLAG_DEBUG - ;restore registers - pop ebp - pop eax - ;if so, skip down to debug compiler - jmp _go_jit_debug + RELOC 1 + GO_ON j_call, OP_CALL_I, 8 -_go_jit_nodebug: - RELOC 1 - GO_ON j_call_nodebug, _j_call_go_on, 8 - j_call_nodebug: - db 0e8h, 0, 0, 0, 0 - CHECKCODESIZE j_call_nodebug - -_j_call_go_on: - jmp _opcall_end - -_go_jit_debug: - ;thanks to Julien "dJeyL" Laurent for code relocation explanation - RELOC _go_jit_reloc-j_call+1 - GO_ON j_call, OP_CALL_I, 8 - j_call: - ; save some registers - push ebp - push eax - push edx - ; get AMX - mov ebp,amx - ; get debug call pointer - mov eax,[ebp+_userdata2] - ; check to see if it's valid - mov edx, dword 0 - cmp eax,edx - je _go_jit_skip_call - xchg esp,esi ;switch to caller stack - push 2 ;param mode=2, push - push ebp ;param amx - call eax ;indirect call - add esp, 8 ;restore stack - xchg esp,esi ;return to AMX stack - mov ebp,amx ;restore AMX [necessary?] - _go_jit_skip_call: - ;restore original registers - pop edx - pop eax - pop ebp - _go_jit_reloc: - db 0e8h, 0, 0, 0, 0 - CHECKCODESIZE j_call -_opcall_end: + j_call: + ;call 12345678h ; tasm chokes on this out of a sudden + db 0e8h, 0, 0, 0, 0 + CHECKCODESIZE j_call OP_CALL_I: ;nop; @@ -1857,39 +1685,12 @@ OP_FILE: ;opcode is simply ignored OP_LINE: ;nop; -;~dvander - opline is now variable on compile time :] - ;save registers - push eax - push ebp - ;get .amx flags - mov ebp,[amxhead] - mov eax,[ebp+_h_flags] - ;check to see if the flag has line ops - and eax,AMX_FLAG_LINEOPS - cmp eax,AMX_FLAG_LINEOPS - ;restore registers - pop ebp - pop eax - ;if so, skip down to debug compiler - je _go_debug - mov [ebx],edi ; no line number support: ignore opcode add ebx,12 ; move on to next opcode cmp ebx,[end_code] jae code_gen_done jmp dword [ebx] ; go on with the next opcode -_go_debug: - putval j_line+6 - mov eax,[ebx+8] - mov [j_line_sm],eax - GO_ON j_line, OP_SYMBOL, 12 - j_line: - call [jit_line] - DD 0 ; space for curline -j_line_sm DD 0 ; space for curfile - CHECKCODESIZE j_line - OP_SYMBOL: ;ignored mov [ebx],edi mov eax,[ebx+4] ; get size @@ -2019,6 +1820,23 @@ OP_SYMTAG: ;ignored (TR) jmp dword [ebx] ; go on with the next opcode +OP_BREAK: +%ifndef DEBUGSUPPORT + mov [ebx],edi ; no line number support: ignore opcode + add ebx,4 ; move on to next opcode + cmp ebx,[end_code] + jae code_gen_done + jmp DWORD [ebx] ; go on with the next opcode +%else + GO_ON j_break, OP_INVALID + j_break: + mov ebp,amx + cmp DWORD [ebp+_debug], 0 + je $+4 ; jump around the "call" statement + call [jit_break] + CHECKCODESIZE j_break +%endif + OP_INVALID: ; break from the compiler with an error code mov eax,AMX_ERR_INVINSTR pop esi @@ -2032,12 +1850,12 @@ section .text ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; -;cell asm_exec( cell *regs, cell *retval, cell stp, cell hea ); +;cell amx_exec( cell *regs, cell *retval, cell stp, cell hea ); ; eax edx ebx ecx ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -amx_exec_asm: -_amx_exec_asm: +amx_exec_jit: +_amx_exec_jit: push edi push esi push ebp @@ -2338,20 +2156,39 @@ JIT_OP_SYSREQ_D: ; (TR) ret -JIT_OP_LINE: - pop ecx ; get return address - mov ebp,amx - push eax - push edx - mov eax,[ecx] ; get curline - mov edx,[ecx+4] ; get curfile - add ecx,8 ; skip curline & curfile - mov [ebp+_curline],eax ; store curline - mov [ebp+_curfile],edx ; store curfile +JIT_OP_BREAK: +%ifdef DEBUGSUPPORT + mov ecx,esp ; get STK into ECX + mov ebp,amx ; get amx into EBP + + sub ecx,edi ; correct STK + + mov [ebp+_pri],eax ; store values in AMX structure: PRI, + mov [ebp+_alt],edx ; ALT, + mov [ebp+_stk],ecx ; STK, + mov ecx,hea ; HEA, + mov ebx,frm ; and FRM + mov [ebp+_hea],ecx + mov [ebp+_frm],ebx ; EBX & ECX are invalid by now + ;??? storing CIP is not very useful, because the code changed (during JIT compile) + + xchg esp,esi ; switch to caller stack + push ebp ; 1st param: amx + call [ebp+_debug] + _DROPARGS 4 ; remove args from stack + xchg esp,esi ; switch back to AMX stack + cmp eax,AMX_ERR_NONE + jne _return_popstack; return error code, if any + + mov ebp,amx ; get amx into EBP + mov eax,[ebp+_pri] ; restore values + mov edx,[ebp+_alt] ; ALT, + mov edx,alt ; restore ALT + mov ebx,frm ; restore FRM + add ebx,edi ; relocate frame +%endif + ret - pop edx - pop eax - jmp ecx ; jump back JIT_OP_SWITCH: pop ebp ; pop return address = table address @@ -2370,9 +2207,10 @@ JIT_OP_SWITCH: jmp ebp %endif + ; The caller of asm_runJIT() can determine the maximum size of the compiled ; code by multiplying the result of this function by the number of opcodes in -; Small module. +; Pawn module. ; ; unsigned long getMaxCodeSize_(); ; @@ -2414,17 +2252,17 @@ jit_fill DD JIT_OP_FILL jit_bounds DD JIT_OP_BOUNDS jit_sysreq DD JIT_OP_SYSREQ jit_sysreq_d DD JIT_OP_SYSREQ_D -jit_line DD JIT_OP_LINE +jit_break DD JIT_OP_BREAK jit_switch DD JIT_OP_SWITCH ; ; The table for the browser/relocator function. ; -global amx_opcodelist, _amx_opcodelist +global amx_opcodelist_jit, _amx_opcodelist_jit -amx_opcodelist: -_amx_opcodelist: +amx_opcodelist_jit: +_amx_opcodelist_jit: DD OP_INVALID DD OP_LOAD_PRI DD OP_LOAD_ALT @@ -2562,3 +2400,6 @@ _amx_opcodelist: DD OP_NOP ; TR DD OP_SYSREQ_D ; TR DD OP_SYMTAG ; TR + DD OP_BREAK ; TR + +END diff --git a/amxmodx/amxmodx.cpp b/amxmodx/amxmodx.cpp index 6bc346e4..33faf851 100755 --- a/amxmodx/amxmodx.cpp +++ b/amxmodx/amxmodx.cpp @@ -353,7 +353,7 @@ static cell AMX_NATIVE_CALL is_linux_server(AMX *amx, cell *params) static cell AMX_NATIVE_CALL is_amd64_server(AMX *amx, cell *params) { -#if SMALL_CELL_SIZE==64 +#if PAWN_CELL_SIZE==64 return 1; #else return 0; @@ -794,10 +794,11 @@ static cell AMX_NATIVE_CALL register_menucmd(AMX *amx, cell *params) /* 3 param int ilen, idx; char* sptemp = get_amxstring(amx,params[3],0,ilen); - if(amx_FindPublic(amx, sptemp ,&idx)!=AMX_ERR_NONE) { - AMXXLOG_Log("[AMXX] Function is not present (function \"%s\") (plugin \"%s\")",sptemp,plugin->getName() ); - amx_RaiseError(amx,AMX_ERR_NATIVE); - return 0; + idx = registerSPForwardByName(amx, sptemp, FP_CELL, FP_CELL, FP_DONE); + if (idx == -1) + { + LogError(amx, AMX_ERR_NOTFOUND, "Function \"%s\" was not found", sptemp); + return 0; } g_menucmds.registerMenuCmd( plugin , params[1] , params[2] , idx ); @@ -870,9 +871,10 @@ static cell AMX_NATIVE_CALL register_concmd(AMX *amx, cell *params) /* 4 param * CPluginMngr::CPlugin* plugin = g_plugins.findPluginFast( amx ); int i, idx = 0; char* temp = get_amxstring(amx,params[2],0, i ); - if(amx_FindPublic(amx, temp ,&idx)!=AMX_ERR_NONE) { - AMXXLOG_Log("[AMXX] Function is not present (function \"%s\") (plugin \"%s\")",temp,plugin->getName() ); - amx_RaiseError(amx,AMX_ERR_NATIVE); + idx = registerSPForwardByName(amx, temp, FP_CELL, FP_CELL, FP_CELL, FP_DONE); + if (idx == -1) + { + LogError(amx, AMX_ERR_NOTFOUND, "Function \"%s\" was not found", temp); return 0; } temp = get_amxstring(amx,params[1],0, i ); @@ -897,9 +899,10 @@ static cell AMX_NATIVE_CALL register_clcmd(AMX *amx, cell *params) /* 4 param */ CPluginMngr::CPlugin* plugin = g_plugins.findPluginFast( amx ); int i, idx = 0; char* temp = get_amxstring(amx,params[2],0, i ); - if(amx_FindPublic(amx, temp ,&idx)!=AMX_ERR_NONE) { - AMXXLOG_Log("[AMXX] Function is not present (function \"%s\") (plugin \"%s\")",temp,plugin->getName() ); - amx_RaiseError(amx,AMX_ERR_NATIVE); + idx = registerSPForwardByName(amx, temp, FP_CELL, FP_CELL, FP_CELL, FP_DONE); + if(idx==-1) + { + LogError(amx, AMX_ERR_NOTFOUND, "Function \"%s\" was not found", temp); return 0; } temp = get_amxstring(amx,params[1],0, i ); @@ -922,9 +925,10 @@ static cell AMX_NATIVE_CALL register_srvcmd(AMX *amx, cell *params) /* 2 param * CPluginMngr::CPlugin* plugin = g_plugins.findPluginFast( amx ); int i, idx = 0; char* temp = get_amxstring(amx,params[2],0, i ); - if(amx_FindPublic(amx, temp ,&idx)!=AMX_ERR_NONE) { - AMXXLOG_Log("[AMXX] Function is not present (function \"%s\") (plugin \"%s\")",temp,plugin->getName() ); - amx_RaiseError(amx,AMX_ERR_NATIVE); + idx = registerSPForwardByName(amx, temp, FP_CELL, FP_CELL, FP_CELL, FP_DONE); + if (idx==-1) + { + LogError(amx, AMX_ERR_NOTFOUND, "Function \"%s\" was not found", temp); return 0; } temp = get_amxstring(amx,params[1],0, i ); @@ -1023,10 +1027,10 @@ static cell AMX_NATIVE_CALL register_event(AMX *amx, cell *params) /* 2 param */ } sTemp = get_amxstring(amx,params[2],0,len); - - if ( amx_FindPublic(amx, sTemp , &iFunction) != AMX_ERR_NONE){ - AMXXLOG_Log("[AMXX] Function is not present (function \"%s\") (plugin \"%s\")",sTemp,plugin->getName() ); - amx_RaiseError(amx,AMX_ERR_NATIVE); + iFunction = registerSPForwardByName(amx, sTemp, FP_CELL, FP_DONE); + if (iFunction==-1) + { + LogError(amx, AMX_ERR_NOTFOUND, "Function \"%s\" was not found", sTemp); return 0; } @@ -1874,20 +1878,9 @@ static cell AMX_NATIVE_CALL pause(AMX *amx, cell *params) /* 3 param */ CPluginMngr::CPlugin *plugin = 0; - if ( flags & 2 ) { // pause function - if (flags&4){ //look out side the plugin - temp = get_amxstring(amx,params[3],0,ilen); - plugin = g_plugins.findPlugin(temp); - } - else plugin = g_plugins.findPluginFast(amx); - if ( !plugin ) return 0; // plugin not found - temp = get_amxstring(amx,params[2],0,ilen); - int err, index; - if ((err = amx_FindPublic( plugin->getAMX(), temp , &index) )!= AMX_ERR_NONE){ - AMXXLOG_Log("[AMXX] Function is not present (function \"%s\") (plugin \"%s\")", temp,plugin->getName() ); - return 0; - } - plugin->pauseFunction( index ); + if ( flags & 2 ) + { // pause function + AMXXLOG_Log("[AMXX] This usage of the native pause() has been deprecated!"); return 1; } else if (flags&4){ @@ -1915,24 +1908,11 @@ static cell AMX_NATIVE_CALL unpause(AMX *amx, cell *params) /* 3 param */ char* sptemp = get_amxstring(amx,params[1],0,ilen); int flags = UTIL_ReadFlags(sptemp); CPluginMngr::CPlugin *plugin = 0; - if (flags&2) { - if (flags&4){ - sptemp = get_amxstring(amx,params[3],0,ilen); - plugin = g_plugins.findPlugin(sptemp); - } - else - plugin = g_plugins.findPluginFast(amx); - if ( !plugin ) return 0; - sptemp = get_amxstring(amx,params[2],0,ilen); - int err, index; - if ((err = amx_FindPublic(plugin->getAMX(), sptemp , &index) )!= AMX_ERR_NONE){ - AMXXLOG_Log("[AMXX] Function is not present (function \"%s\") (plugin \"%s\")", sptemp,plugin->getName() ); - return 0; - } - plugin->unpauseFunction( index ); + if (flags&2) + { + AMXXLOG_Log("[AMXX] This usage of the native pause() has been deprecated!"); return 1; - } - else if (flags&4){ + } else if (flags&4) { sptemp = get_amxstring(amx,params[2],0,ilen); plugin = g_plugins.findPlugin(sptemp); } @@ -2298,10 +2278,10 @@ static cell AMX_NATIVE_CALL register_logevent(AMX *amx, cell *params) char* temp = get_amxstring(amx,params[1],0, a ); - if (amx_FindPublic(amx, temp , &iFunc) != AMX_ERR_NONE){ - AMXXLOG_Log("[AMXX] Function is not present (function \"%s\") (plugin \"%s\")", - temp,plugin->getName() ); - amx_RaiseError(amx,AMX_ERR_NATIVE); + iFunc = registerSPForwardByName(amx, temp, FP_DONE); + if (iFunc == -1) + { + LogError(amx, AMX_ERR_NOTFOUND, "Function \"%s\" was not found", temp); return 0; } @@ -2457,31 +2437,22 @@ static cell AMX_NATIVE_CALL get_module(AMX *amx, cell *params) set_amxstring(amx, params[2], info && info->name ? info->name : "unk", params[3]); set_amxstring(amx, params[4], info && info->author ? info->author : "unk", params[5]); set_amxstring(amx, params[6], info && info->version ? info->version : "unk", params[7]); - } - else - { - module_info_s *info = (*moduleIter).getInfo(); - set_amxstring(amx, params[2], info && info->name ? info->name : "unk", params[3]); - set_amxstring(amx, params[4], info && info->author ? info->author : "unk", params[5]); - set_amxstring(amx, params[6], info && info->version ? info->version : "unk", params[7]); } // compatibility problem possible int numParams = params[0] / sizeof(cell); if (numParams < 8) { - CPluginMngr::CPlugin *curPlugin = g_plugins.findPluginFast(amx); - AMXXLOG_Log("[AMXX] get_module: call to a previous version (plugin \"%s\", line %d)", curPlugin->getName(), amx->curline); - amx_RaiseError(amx, AMX_ERR_NATIVE); + LogError(amx, AMX_ERR_NATIVE, "Call to incompatible version"); + return 0; } // set status cell *addr; if (amx_GetAddr(amx, params[8], &addr) != AMX_ERR_NONE) { - CPluginMngr::CPlugin *curPlugin = g_plugins.findPluginFast(amx); - AMXXLOG_Log("[AMXX] get_module: invalid reference (plugin \"%s\", line %d)", curPlugin->getName(), amx->curline); - amx_RaiseError(amx, AMX_ERR_NATIVE); + LogError(amx, AMX_ERR_NATIVE, "Invalid reference plugin"); + return 0; } *addr = (cell)(*moduleIter).getStatusValue(); @@ -2526,8 +2497,7 @@ static cell AMX_NATIVE_CALL callfunc_begin(AMX *amx, cell *params) if (g_CallFunc_Plugin) { // scripter's fault - AMXXLOG_Log("[AMXX] callfunc_begin called without callfunc_end (plugin \"%s\", line %d)", curPlugin->getName(), amx->curline); - amx_RaiseError(amx, AMX_ERR_NATIVE); + LogError(amx, AMX_ERR_NATIVE, "callfunc_begin called without callfunc_end"); return 0; } @@ -2608,8 +2578,7 @@ static cell AMX_NATIVE_CALL callfunc_end(AMX *amx, cell *params) if (!g_CallFunc_Plugin) { // scripter's fault - AMXXLOG_Log("[AMXX] callfunc_end called without callfunc_begin (plugin \"%s\", line %d)", curPlugin->getName(), amx->curline); - amx_RaiseError(amx, AMX_ERR_NATIVE); + LogError(amx, AMX_ERR_NATIVE, "callfunc_end called without callfunc_begin"); return 0; } @@ -2633,9 +2602,13 @@ static cell AMX_NATIVE_CALL callfunc_end(AMX *amx, cell *params) g_CallFunc_CurParam = 0; // actual call - if ((err = amx_Execv(plugin->getAMX(), &retVal, func, curParam, gparams)) != AMX_ERR_NONE) + // Pawn - push parameters in reverse order + for (int i=curParam-1; i>=0; i--) + { + amx_Push(amx, gparams[i]); + } + if ((err = amx_Exec(plugin->getAMX(), &retVal, func) != AMX_ERR_NONE)) { - LogError(amx, err, ""); return 0; } @@ -2672,8 +2645,7 @@ static cell AMX_NATIVE_CALL callfunc_push_byval(AMX *amx, cell *params) if (!g_CallFunc_Plugin) { // scripter's fault - AMXXLOG_Log("[AMXX] callfunc_push_xxx called without callfunc_begin (plugin \"%s\", line %d)", curPlugin->getName(), amx->curline); - amx_RaiseError(amx, AMX_ERR_NATIVE); + LogError(amx, AMX_ERR_NATIVE, "callfunc_push_xxx called without callfunc_begin"); return 0; } @@ -2698,15 +2670,13 @@ static cell AMX_NATIVE_CALL callfunc_push_byref(AMX *amx, cell *params) if (!g_CallFunc_Plugin) { // scripter's fault - AMXXLOG_Log("[AMXX] callfunc_push_xxx called without callfunc_begin (plugin \"%s\", line %d)", curPlugin->getName(), amx->curline); - amx_RaiseError(amx, AMX_ERR_NATIVE); + LogError(amx, AMX_ERR_NATIVE, "callfunc_push_xxx called without callfunc_begin"); return 0; } if (g_CallFunc_CurParam == CALLFUNC_MAXPARAMS) { - AMXXLOG_Log("[AMXX] callfunc_push_xxx: maximal parameters num: %d", CALLFUNC_MAXPARAMS); - amx_RaiseError(amx, AMX_ERR_NATIVE); + LogError(amx, AMX_ERR_NATIVE, "callfunc_push_xxx: maximal parameters num: %d", CALLFUNC_MAXPARAMS); return 0; } @@ -2756,15 +2726,13 @@ static cell AMX_NATIVE_CALL callfunc_push_str(AMX *amx, cell *params) if (!g_CallFunc_Plugin) { // scripter's fault - AMXXLOG_Log("[AMXX] callfunc_push_xxx called without callfunc_begin (plugin \"%s\", line %d)", curPlugin->getName(), amx->curline); - amx_RaiseError(amx, AMX_ERR_NATIVE); + LogError(amx, AMX_ERR_NATIVE, "callfunc_push_xxx called without callfunc_begin"); return 0; } if (g_CallFunc_CurParam == CALLFUNC_MAXPARAMS) { - AMXXLOG_Log("[AMXX] callfunc_push_xxx: maximal parameters num: %d", CALLFUNC_MAXPARAMS); - amx_RaiseError(amx, AMX_ERR_NATIVE); + LogError(amx, AMX_ERR_NATIVE, "callfunc_push_xxx: maximal parameters num: %d", CALLFUNC_MAXPARAMS); return 0; } @@ -2799,7 +2767,7 @@ static cell AMX_NATIVE_CALL callfunc_push_str(AMX *amx, cell *params) // copy it to the allocated memory // we assume it's unpacked // :NOTE: 4th parameter use_wchar since Small Abstract Machine 2.5.0 - amx_SetString(phys_addr, str, 0, 0); + amx_SetString(phys_addr, str, 0, 0, 0); // push the address and set the reference flag so that memory is released after function call. g_CallFunc_ParamInfo[g_CallFunc_CurParam].flags = CALLFUNC_FLAG_BYREF; diff --git a/amxmodx/amxmodx.h b/amxmodx/amxmodx.h index 0bca46a3..c854d8a8 100755 --- a/amxmodx/amxmodx.h +++ b/amxmodx/amxmodx.h @@ -68,7 +68,7 @@ #include "amxxlog.h" #define AMXXLOG_Log g_log.Log -#define AMX_VERSION "1.10-RC1" +#define AMX_VERSION "1.50-RC1" extern AMX_NATIVE_INFO core_Natives[]; extern AMX_NATIVE_INFO time_Natives[]; @@ -244,7 +244,6 @@ enum CountModulesMode int countModules(CountModulesMode mode); void modules_callPluginsLoaded(); -int add_amxnatives(module_info_s* info,AMX_NATIVE_INFO*natives); cell* get_amxaddr(AMX *amx,cell amx_addr); char* build_pathname(char *fmt, ... ); char* build_pathname_r(char *buffer, size_t maxlen, char *fmt, ...); @@ -280,6 +279,7 @@ extern ModuleCallReason g_ModuleCallReason; // modules.cpp extern CModule *g_CurrentlyCalledModule; // modules.cpp extern const char *g_LastRequestedFunc; // modules.cpp void Module_CacheFunctions(); +void Module_UncacheFunctions(); void *Module_ReqFnptr(const char *funcName); // modules.cpp @@ -297,6 +297,7 @@ extern int FF_PluginLog; extern int FF_PluginEnd; extern int FF_InconsistentFile; extern int FF_ClientAuthorized; +extern bool g_coloredmenus; #ifdef FAKEMETA extern CFakeMeta g_FakeMeta; diff --git a/amxmodx/file.cpp b/amxmodx/file.cpp index d2be53e3..562a97ef 100755 --- a/amxmodx/file.cpp +++ b/amxmodx/file.cpp @@ -364,19 +364,6 @@ static cell AMX_NATIVE_CALL amx_fclose(AMX *amx, cell *params) } } -static cell AMX_NATIVE_CALL amx_fgetc(AMX *amx, cell *params) -{ - unsigned int id = params[1] - 1; - if (id >= FileList.size() || FileList.at(id) == NULL) - return 0; - FILE *fp = FileList.at(id); - if (fp) { - return fgetc(fp); - } else { - return -1; - } -} - static cell AMX_NATIVE_CALL amx_fread(AMX *amx, cell *params) { unsigned int id = params[1] - 1; @@ -394,6 +381,20 @@ static cell AMX_NATIVE_CALL amx_fread(AMX *amx, cell *params) return -1; } +#ifdef UNUSED +static cell AMX_NATIVE_CALL amx_fgetc(AMX *amx, cell *params) +{ + unsigned int id = params[1] - 1; + if (id >= FileList.size() || FileList.at(id) == NULL) + return 0; + FILE *fp = FileList.at(id); + if (fp) { + return fgetc(fp); + } else { + return -1; + } +} + static cell AMX_NATIVE_CALL amx_fwrite(AMX *amx, cell *params) { unsigned int id = params[1] - 1; @@ -506,6 +507,7 @@ static cell AMX_NATIVE_CALL amx_ftell(AMX *amx, cell *params) } return -1; } +#endif //UNUSED static cell AMX_NATIVE_CALL amx_filesize(AMX *amx, cell *params) { @@ -521,6 +523,7 @@ static cell AMX_NATIVE_CALL amx_filesize(AMX *amx, cell *params) return -1; } +#ifdef UNUSED static cell AMX_NATIVE_CALL amx_fgetl(AMX *amx, cell *params) { unsigned int id = params[1] - 1; @@ -636,6 +639,7 @@ static cell AMX_NATIVE_CALL amx_fputf(AMX *amx, cell *params) } return -1; } +#endif //UNUSED static cell AMX_NATIVE_CALL amx_build_pathname(AMX *amx, cell *params) { @@ -723,8 +727,10 @@ AMX_NATIVE_INFO file_Natives[] = { //Sanji's File Natives { "fopen", amx_fopen }, { "fclose", amx_fclose }, - { "fgetc", amx_fgetc }, { "fread", amx_fread }, + { "filesize", amx_filesize }, +#ifdef UNUSED + { "fgetc", amx_fgetc }, { "fwrite", amx_fwrite }, { "feof", amx_feof }, { "fseek", amx_fseek }, @@ -733,16 +739,16 @@ AMX_NATIVE_INFO file_Natives[] = { { "fflush", amx_fflush }, { "fscanf", amx_fscanf }, { "ftell", amx_ftell }, - { "filesize", amx_filesize }, { "fgetl", amx_fgetl }, { "fgeti", amx_fgeti }, { "fgets", amx_fgets }, { "fputs", amx_fputs }, { "fputl", amx_fputl }, { "fputi", amx_fputi }, - { "unlink", delete_file }, { "fgetf", amx_fgetf }, { "fputf", amx_fputf }, +#endif + { "unlink", delete_file }, { "build_pathname", amx_build_pathname}, { "dir_exists", dir_exists }, { "open_dir", amx_open_dir }, diff --git a/amxmodx/float.cpp b/amxmodx/float.cpp index 5350e7a3..90776f74 100755 --- a/amxmodx/float.cpp +++ b/amxmodx/float.cpp @@ -96,7 +96,7 @@ static cell AMX_NATIVE_CALL n_floatstr(AMX *amx,cell *params) return 0; /* Now convert the Small String into a C type null terminated string */ - amx_GetString(szSource, pString, 0); + amx_GetStringOld(szSource, pString, 0); /* Now convert this to a float. */ fNum = (REAL)atof(szSource); diff --git a/amxmodx/meta_api.cpp b/amxmodx/meta_api.cpp index f3053caf..e81f7491 100755 --- a/amxmodx/meta_api.cpp +++ b/amxmodx/meta_api.cpp @@ -90,6 +90,7 @@ float g_auth_time; bool g_initialized = false; bool g_IsNewMM = false; bool g_NeedsP = false; +bool g_coloredmenus; #ifdef MEMORY_TEST float g_next_memreport_time; @@ -605,7 +606,6 @@ void C_ClientCommand( edict_t *pEntity ) { CPlayer *pPlayer = GET_PLAYER_POINTER(pEntity); META_RES result = MRES_IGNORED; cell ret = 0; - int err; const char* cmd = CMD_ARGV(0); const char* arg = CMD_ARGV(1); @@ -665,10 +665,7 @@ void C_ClientCommand( edict_t *pEntity ) { if ( (*aa).matchCommandLine( cmd , arg ) && (*aa).getPlugin()->isExecutable( (*aa).getFunction() ) ) { - - if ((err =amx_Exec((*aa).getPlugin()->getAMX(), &ret , (*aa).getFunction() , 3, pPlayer->index, (*aa).getFlags(),(*aa).getId() )) != AMX_ERR_NONE) - LogError((*aa).getPlugin()->getAMX(), err, ""); - + ret = executeForwards((*aa).getFunction(), pPlayer->index, (*aa).getFlags(), (*aa).getId()); if ( ret & 2 ) result = MRES_SUPERCEDE; if ( ret & 1 ) RETURN_META(MRES_SUPERCEDE); } @@ -695,33 +692,19 @@ void C_ClientCommand( edict_t *pEntity ) { int menuid = pPlayer->menu; pPlayer->menu = 0; -#ifdef ENABLEEXEPTIONS - try{ -#endif MenuMngr::iterator a = g_menucmds.begin(); while( a ) { if ( (*a).matchCommand( menuid , bit_key ) && (*a).getPlugin()->isExecutable( (*a).getFunction() ) ) { - - if ( ( err = amx_Exec((*a).getPlugin()->getAMX(), &ret ,(*a).getFunction() , 2, pPlayer->index,pressed_key)) != AMX_ERR_NONE) - LogError((*a).getPlugin()->getAMX(), err, ""); - + ret = executeForwards((*a).getFunction(), pPlayer->index, pressed_key); if ( ret & 2 ) result = MRES_SUPERCEDE; if ( ret & 1 ) RETURN_META(MRES_SUPERCEDE); } ++a; } - -#ifdef ENABLEEXEPTIONS - } - catch( ... ) - { - AMXXLOG_Log( "[AMXX] Fatal error at menu commmand execution"); - } -#endif } } /* check for PLUGIN_HANDLED_MAIN and block hl call if needed */ @@ -898,35 +881,6 @@ void C_WriteEntity_Post(int iValue) { } void C_MessageEnd_Post(void) { g_events.executeEvents(); - -#if 0 // ######### this is done by call above - EventsMngr::iterator a = g_events.begin(); - int err; -#ifdef ENABLEEXEPTIONS - try - { -#endif - - while ( a ) - { - - if ((err = amx_Exec((*a).getPlugin()->getAMX(), NULL , (*a).getFunction() , 1, mPlayerIndex /*g_events.getArgInteger(0)*/ )) != AMX_ERR_NONE) - LogError((*a).getPlugin()->getAMX(), err, ""); - - - ++a; - - } - -#ifdef ENABLEEXEPTIONS - } - catch( ... ) - { - AMXXLOG_Log( "[AMXX] Fatal error at event execution"); - } -#endif -#endif - if (endfunction) (*endfunction)(NULL); RETURN_META(MRES_IGNORED); } @@ -1134,6 +1088,13 @@ C_DLLEXPORT int Meta_Attach(PLUG_LOADTIME now, META_FUNCTIONS *pFunctionTable, m a = &gameDir[i]; g_mod_name.assign(a); + if (g_mod_name.compare("cstrike")==0 || + g_mod_name.compare("czero")==0 || + g_mod_name.compare("dod")==0) + g_coloredmenus = true; + else + g_coloredmenus = false; + // ###### Print short GPL print_srvconsole( "\n AMX Mod X version %s Copyright (c) 2004-2005 AMX Mod X Development Team \n" " AMX Mod X comes with ABSOLUTELY NO WARRANTY; for details type `amxx gpl'.\n", AMX_VERSION); @@ -1194,6 +1155,8 @@ C_DLLEXPORT int Meta_Detach(PLUG_LOADTIME now, PL_UNLOAD_REASON reason) { g_log.CloseFile(); + Module_UncacheFunctions(); + return(TRUE); } diff --git a/amxmodx/modules.cpp b/amxmodx/modules.cpp index d4cee11d..9c3291bf 100755 --- a/amxmodx/modules.cpp +++ b/amxmodx/modules.cpp @@ -95,7 +95,7 @@ void free_amxmemory(void **ptr) int load_amxscript(AMX *amx, void **program, const char *filename, char error[64], int debug) { *error = 0; - CAmxxReader reader(filename, SMALL_CELL_SIZE / 8); + CAmxxReader reader(filename, PAWN_CELL_SIZE / 8); if (reader.GetStatus() == CAmxxReader::Err_None) { size_t bufSize = reader.GetBufferSize(); @@ -153,59 +153,72 @@ int load_amxscript(AMX *amx, void **program, const char *filename, char error[64 return (amx->error = AMX_ERR_FORMAT); } - if ( (int)CVAR_GET_FLOAT("amx_debug") >= 2 || debug) - { - //automatic debug mode - hdr->flags |= AMX_FLAG_LINEOPS; - hdr->flags |= AMX_FLAG_DEBUG; - } - int err; memset(amx, 0, sizeof(*amx)); + + if ((int)CVAR_GET_FLOAT("amx_debug") >= 2 || debug) + { + if ((amx->flags & AMX_FLAG_DEBUG) != 0) + { + //:TODO: debug support + } + } else { +#ifdef JIT + //if (hdr->file_version == CUR_FILE_VERSION) + amx->flags |= AMX_FLAG_JITC; +#endif + } + if ((err = amx_Init( amx, *program )) != AMX_ERR_NONE) { sprintf(error,"Load error %d (invalid file format or version)", err); return (amx->error = AMX_ERR_INIT); } -#ifdef JIT - void *np = new char[ amx->code_size ]; - void *rt = new char[ amx->reloc_size ]; - if ( !np || (!rt && amx->reloc_size > 0) ) - { - delete[] np; - delete[] rt; - strcpy(error,"Failed to initialize plugin"); - return (amx->error = AMX_ERR_INIT); - } + LOG_MESSAGE(PLID, "AMX: %p FLAGS: %d\n", amx, amx->flags); - if ( (err = amx_InitJIT(amx, rt, np)) == AMX_ERR_NONE ) +#ifdef JIT + if (amx->flags & AMX_FLAG_JITC) { - //amx->base = (unsigned char FAR *)realloc( np, amx->code_size ); -#ifndef __linux__ - amx->base = new unsigned char[ amx->code_size ]; -#else - //posix_memalign((void **)&(amx->base), sysconf(_SC_PAGESIZE), amx->code_size); - amx->base = (unsigned char *)memalign(sysconf(_SC_PAGESIZE), amx->code_size); - mprotect((void *)amx->base, amx->code_size, PROT_READ|PROT_WRITE|PROT_EXEC); -#endif - if ( amx->base ) - memcpy( amx->base , np , amx->code_size ); - delete[] np; - delete[] rt; - delete[] *program; - (*program) = amx->base; - if ( *program == 0 ){ - strcpy(error,"Failed to allocate memory"); - return (amx->error = AMX_ERR_MEMORY); + char *np = new char[ amx->code_size ]; + char *rt = new char[ amx->reloc_size ]; + if ( !np || (!rt && amx->reloc_size > 0) ) + { + delete[] np; + delete[] rt; + strcpy(error,"Failed to initialize plugin"); + return (amx->error = AMX_ERR_INIT); + } + + if ( (err = amx_InitJIT(amx, (void *)rt, (void *)np)) == AMX_ERR_NONE ) + { + //amx->base = (unsigned char FAR *)realloc( np, amx->code_size ); +#ifndef __linux__ + amx->base = new unsigned char[ amx->code_size ]; +#else + //posix_memalign((void **)&(amx->base), sysconf(_SC_PAGESIZE), amx->code_size); + amx->base = (unsigned char *)memalign(sysconf(_SC_PAGESIZE), amx->code_size); + mprotect((void *)amx->base, amx->code_size, PROT_READ|PROT_WRITE|PROT_EXEC); +#endif + if ( amx->base ) + memcpy( amx->base , np , amx->code_size ); + delete[] np; + delete[] rt; + char *prg = (char *)(*program); + delete[] *prg; + (*program) = amx->base; + if ( *program == 0 ){ + strcpy(error,"Failed to allocate memory"); + return (amx->error = AMX_ERR_MEMORY); + } + } + else + { + delete[] np; + delete[] rt; + sprintf(error, "Failed to initialize plugin (%d)", err); + return (amx->error = AMX_ERR_INIT_JIT); } - } - else - { - delete[] np; - delete[] rt; - sprintf(error, "Failed to initialize plugin (%d)", err); - return (amx->error = AMX_ERR_INIT_JIT); } #endif @@ -219,7 +232,6 @@ int load_amxscript(AMX *amx, void **program, const char *filename, char error[64 } g_loadedscripts.put( aa ); - amx->sysreq_d = 0; return set_amxnatives(amx,error); } @@ -345,7 +357,8 @@ int unload_amxscript(AMX* amx, void** program) { CList::iterator a = g_loadedscripts.find( amx ); if ( a ) a.remove(); - delete[] *program; + char *prg = (char *)*program; + delete[] *prg; *program = 0; return AMX_ERR_NONE; } @@ -469,27 +482,6 @@ char* build_pathname_addons(char *fmt, ... ) return string; } -int add_amxnatives(module_info_s* info,AMX_NATIVE_INFO*natives) -{ - CList::iterator a = g_modules.begin(); - - while ( a ) - { - if ( (*a).getInfo() == info ) - { - AMX_NATIVE_INFO** aa = new AMX_NATIVE_INFO*(natives); - if ( aa == 0 ) return AMX_ERR_NATIVE; - (*a).m_Natives.put( aa ); - return AMX_ERR_NONE; - } - - ++a; - } - - return AMX_ERR_NATIVE; -} - - bool validFile(const char* file) { const char* a = 0; @@ -505,7 +497,7 @@ bool validFile(const char* file) void ConvertModuleName(const char *pathString, String &path) { -#if SMALL_CELL_SIZE==64 +#if PAWN_CELL_SIZE==64 char *ptr = strstr(pathString, "i386"); if (ptr) { @@ -600,7 +592,7 @@ void ConvertModuleName(const char *pathString, String &path) } } #endif //__linux__ -#endif //SMALL_CELL_SIZE==64 +#endif //PAWN_CELL_SIZE==64 } int loadModules(const char* filename, PLUG_LOADTIME now) @@ -930,10 +922,14 @@ int MNF_AddNatives(AMX_NATIVE_INFO* natives) const char *MNF_GetModname(void) { - // :TODO: Do we have to do this?? + // :TODO: Do we have to do this?? + // I dunno who wrote the above comment but no +#if 0 static char buffer[64]; strcpy(buffer, g_mod_name.c_str()); return buffer; +#endif + return g_mod_name.c_str(); } AMX *MNF_GetAmxScript(int id) @@ -1169,13 +1165,17 @@ REAL MNF_CellToReal(cell x) return *(REAL*)&x; } +#ifdef __linux__ +#define _vsnprintf vsnprintf +#endif + void MNF_Log(const char *fmt, ...) { - // :TODO: Overflow possible here char msg[3072]; va_list arglst; va_start(arglst, fmt); - vsprintf(msg, fmt, arglst); + _vsnprintf(msg, sizeof(msg)-1, fmt, arglst); + //vsprintf(msg, fmt, arglst); va_end(arglst); AMXXLOG_Log("%s", msg); } @@ -1220,7 +1220,7 @@ void GenericError(AMX *amx, int err, int line, char buf[], const char *file) geterr = NULL; else geterr = amx_errs[err]; - if (!(amx->flags & AMX_FLAG_LINEOPS)) + if (!(amx->flags & AMX_FLAG_DEBUG)) { if (geterr == NULL) { @@ -1250,7 +1250,7 @@ void LogError(AMX *amx, int err, const char *fmt, ...) { //does this plugin have debug info? va_list arg; - AMX_DBG *dbg = (AMX_DBG *)(amx->userdata[0]); + //AMX_DBG *dbg = (AMX_DBG *)(amx->userdata[0]); static char buf[1024]; static char vbuf[1024]; *buf = 0; @@ -1259,7 +1259,7 @@ void LogError(AMX *amx, int err, const char *fmt, ...) va_start(arg, fmt); vsprintf(vbuf, fmt, arg); va_end(arg); - +#if 0 if (!dbg || !(dbg->tail)) { if (dbg && amx->curfile < dbg->numFiles && amx->curfile >= 0) @@ -1313,6 +1313,8 @@ void LogError(AMX *amx, int err, const char *fmt, ...) t = dbg->tail; } } +#endif + amx_RaiseError(amx, err); } void MNF_MergeDefinitionFile(const char *file) @@ -1386,7 +1388,7 @@ const char *g_LastRequestedFunc = NULL; #define REGISTER_FUNC(name, func) \ { \ pFunc = new func_s; \ - pFunc->pfn = func; \ + pFunc->pfn = (void *)func; \ pFunc->desc = name; \ g_functions.put(pFunc); \ } @@ -1398,6 +1400,16 @@ void MNF_RegisterFunction(void *pfn, const char *description) REGISTER_FUNC(description, pfn); } +void Module_UncacheFunctions() +{ + g_functions.clear(); +} + +int amx_Execv() +{ + return AMX_ERR_NOTFOUND; +} + void Module_CacheFunctions() { func_s *pFunc; @@ -1430,7 +1442,7 @@ void Module_CacheFunctions() // other amx stuff REGISTER_FUNC("amx_Exec", amx_Exec) - REGISTER_FUNC("amx_Execv", amx_Execv) + REGISTER_FUNC("amx_Execv", amx_Execv) //I HOPE NO ONE USES THIS!!!! REGISTER_FUNC("amx_Allot", amx_Allot) REGISTER_FUNC("amx_FindPublic", amx_FindPublic) REGISTER_FUNC("amx_FindNative", amx_FindNative) diff --git a/amxmodx/modules.h b/amxmodx/modules.h index 296200fc..727f8010 100755 --- a/amxmodx/modules.h +++ b/amxmodx/modules.h @@ -45,135 +45,8 @@ #undef C_DLLEXPORT #define C_DLLEXPORT extern "C" DLLEXPORT -#define AMX_INTERFACE_VERSION 6 - #define RELOAD_MODULE 0 #define STATIC_MODULE 1 -struct module_info_s { - const char* name; - const char* author; - const char* version; - int ivers; - int type; - long int serial; -}; - -// Small scripting language -struct pfnamx_engine_g { - uint16_t* (*pfnamx_Align16)(uint16_t *); // value - uint32_t* (*pfnamx_Align32)(uint32_t *); // value - int (*pfnamx_Allot)(AMX*, int, cell*, cell**); // amx, length, amx_addr, phys_addr - int (*pfnamx_Callback)(AMX*, cell , cell*, cell*); // amx, index,result,params - int (*pfnamx_Clone)(AMX*, AMX*, void*); // amxClone, amxSrc, data - int (*pfnamx_Debug)(AMX*); // default debug procedure, does nothing // amx - int (*pfnamx_Exec)(AMX*, cell*, int , int , ...); // amx, return val, index, num_params, ... - int (*pfnamx_Execv)(AMX*, cell*, int , int, cell[]); // amx, return val, index, num_params, param[] - int (*pfnamx_FindPublic)(AMX*, char*, int*); // amx, func name, index - int (*pfnamx_FindPubVar)(AMX*, char*, cell*); // anx, var name, amx_addr - int (*pfnamx_FindTagId)(AMX*, cell , char*); // amx. tag_id, tagname - int (*pfnamx_Flags)(AMX*,uint16_t *); // amx, flags - int (*pfnamx_GetAddr)(AMX*,cell ,cell**); // amx, amx_addr, phys_addr - int (*pfnamx_GetPublic)(AMX*, int , char*); // amx, index, funcname - int (*pfnamx_GetPubVar)(AMX*, int , char*, cell*); // amx, index, varname, amx_addr - int (*pfnamx_GetString)(char*dest,cell*); // dest, source - int (*pfnamx_GetTag)(AMX*, int , char*, cell*); // amx, index, tagname, tag_id - int (*pfnamx_GetUserData)(AMX*, long , void **); // amx, tag, ptr - int (*pfnamx_Init)(AMX*, void *); // amx, program - int (*pfnamx_InitJIT)(AMX*, void *, void *); // amx, reloc_table, native_code - int (*pfnamx_MemInfo)(AMX*, long*, long*, long*); // amx, codesize, datasize, stackheap - int (*pfnamx_NameLength)(AMX*, int*); // amx, length - AMX_NATIVE_INFO * (*pfnamx_NativeInfo)(char*,AMX_NATIVE ); // name, func - int (*pfnamx_NumPublics)(AMX*, int*); // amx, number - int (*pfnamx_NumPubVars)(AMX*, int*); // amx, number - int (*pfnamx_NumTags)(AMX*, int*); // amx, number - int (*pfnamx_RaiseError)(AMX*, int ); // amx, error - int (*pfnamx_Register)(AMX*, AMX_NATIVE_INFO*, int ); // amx, nativelist, number - int (*pfnamx_Release)(AMX*, cell ); // amx, amx_addr - int (*pfnamx_SetCallback)(AMX*, AMX_CALLBACK ); // amx, callback - int (*pfnamx_SetDebugHook)(AMX*, AMX_DEBUG ); // amx, debug - int (*pfnamx_SetString)(cell*, char*, int ); // dest, source, pack - int (*pfnamx_SetUserData)(AMX*, long , void*); // amx, tag, prt - int (*pfnamx_StrLen)(cell*, int*); // amx, cstring, length -}; -extern pfnamx_engine_g* g_engAmxFunc; - -#define AMX_ALIGN16 (*g_engAmxFunc->pfnamx_Align16) -#define AMX_ALIGN32 (*g_engAmxFunc->pfnamx_Align32) -#define AMX_ALLOT (*g_engAmxFunc->pfnamx_Allot) -#define AMX_CALLBACK (*g_engAmxFunc->pfnamx_Callback) -#define AMX_CLONE (*g_engAmxFunc->pfnamx_Clone) -#define AMX_DEBUG (*g_engAmxFunc->pfnamx_Debug) -#define AMX_EXEC (*g_engAmxFunc->pfnamx_Exec) -#define AMX_EXECV (*g_engAmxFunc->pfnamx_Execv) -#define AMX_FINDPUBLIC (*g_engAmxFunc->pfnamx_FindPublic) -#define AMX_FINDPUBVAR (*g_engAmxFunc->pfnamx_FindPubVar) -#define AMX_FINDTAGID (*g_engAmxFunc->pfnamx_FindTagId) -#define AMX_FLAGS (*g_engAmxFunc->pfnamx_Flags) -#define AMX_GETADDR (*g_engAmxFunc->pfnamx_GetAddr) -#define AMX_GETPUBLIC (*g_engAmxFunc->pfnamx_GetPublic) -#define AMX_GETPUBVAR (*g_engAmxFunc->pfnamx_GetPubVar) -#define AMX_GETSTRING (*g_engAmxFunc->pfnamx_GetString) -#define AMX_GETTAG (*g_engAmxFunc->pfnamx_GetTag) -#define AMX_GETUSERDATA (*g_engAmxFunc->pfnamx_GetUserData) -#define AMX_INIT (*g_engAmxFunc->pfnamx_Init) -#define AMX_INITJIT (*g_engAmxFunc->pfnamx_InitJIT) -#define AMX_MEMINFO (*g_engAmxFunc->pfnamx_MemInfo) -#define AMX_NAMELENGTH (*g_engAmxFunc->pfnamx_NameLength) -#define AMX_NATIVEINFO (*g_engAmxFunc->pfnamx_NativeInfo) -#define AMX_NUMPUBLICS (*g_engAmxFunc->pfnamx_NumPublics) -#define AMX_NUMPUBVARS (*g_engAmxFunc->pfnamx_NumPubVars) -#define AMX_NUMTAGS (*g_engAmxFunc->pfnamx_NumTags) -#define AMX_RAISEERROR (*g_engAmxFunc->pfnamx_RaiseError) -#define AMX_REGISTER (*g_engAmxFunc->pfnamx_Register) -#define AMX_RELEASE (*g_engAmxFunc->pfnamx_Release) -#define AMX_SETCALLBACK (*g_engAmxFunc->pfnamx_SetCallback) -#define AMX_SETDEBUGHOOK (*g_engAmxFunc->pfnamx_SetDebugHook) -#define AMX_SETSTRING (*g_engAmxFunc->pfnamx_SetString) -#define AMX_SETUSERDATA (*g_engAmxFunc->pfnamx_SetUserData) -#define AMX_STRLEN (*g_engAmxFunc->pfnamx_StrLen) - -// Modules API -struct pfnmodule_engine_g { - int (*pfnadd_amxnatives)(module_info_s*,AMX_NATIVE_INFO*); // list - char* (*pfnbuild_pathname)(char*, ...); // format, .... - void (*pfncopy_amxmemory)(cell*,cell*,int); // dest, src, len - char* (*pfnformat_amxstring)(AMX*, cell*, int ,int& ); // amx, format, start pos, len - cell* (*pfnget_amxaddr)(AMX*,cell ); // amx, cell - AMX* (*pfnget_amxscript)(int, void**,const char**); // id, code, name - const char* (*pfnget_amxscriptname)(AMX* amx); // amx - char* (*pfnget_amxstring)(AMX*,cell,int, int&); // amx, src, buffer (0-3), len - void (*pfnget_modname)(char*); // modname - int (*pfnload_amxscript)(AMX*, void**, const char*, char[64], int); // amx, code, path, error info - void (*pfnprint_console)(char*, ...); // format, .... - void (*pfnreport_error)(int code, char*, ... ); - int (*pfnset_amxnatives)(AMX*,char[64]); // amx, error info - int (*pfnset_amxstring)(AMX*,cell ,const char*,int); // amx, dest, string, maxlen - int (*pfnamxstring_length)(cell*); // src - int (*pfnunload_amxscript)(AMX* amx,void**); // amx, code - void* (*pfnalloc_amxmemory)(void**,int size); - void (*pfnfree_amxmemory)(void**); -}; -extern pfnmodule_engine_g* g_engModuleFunc; - -#define ADD_AMXNATIVES (*g_engModuleFunc->pfnadd_amxnatives) -#define AMXSTRING_LENGTH (*g_engModuleFunc->pfnamxstring_length) -#define BUILD_PATHNAME (*g_engModuleFunc->pfnbuild_pathname) -#define COPY_AMXMEMORY (*g_engModuleFunc->pfncopy_amxmemory) -#define FORMAT_AMXSTRING (*g_engModuleFunc->pfnformat_amxstring) -#define GET_AMXADDR (*g_engModuleFunc->pfnget_amxaddr) -#define GET_AMXSCRIPT (*g_engModuleFunc->pfnget_amxscript) -#define GET_AMXSCRIPTNAME (*g_engModuleFunc->pfnget_amxscriptname) -#define GET_AMXSTRING (*g_engModuleFunc->pfnget_amxstring) -#define GET_MODNAME (*g_engModuleFunc->pfnget_modname) -#define LOAD_AMXSCRIPT (*g_engModuleFunc->pfnload_amxscript) -#define PRINT_CONSOLE (*g_engModuleFunc->pfnprint_console) -#define REPORT_ERROR (*g_engModuleFunc->pfnreport_error) -#define SET_AMXNATIVES (*g_engModuleFunc->pfnset_amxnatives) -#define SET_AMXSTRING (*g_engModuleFunc->pfnset_amxstring) -#define UNLOAD_AMXSCRIPT (*g_engModuleFunc->pfnunload_amxscript) -#define ALLOC_AMXMEMORY (*g_engModuleFunc->pfnalloc_amxmemory) -#define FREE_AMXMEMORY (*g_engModuleFunc->pfnfree_amxmemory) - #endif // __MODULES_H__ diff --git a/amxmodx/msvc/amxmodx_mm.vcproj b/amxmodx/msvc/amxmodx_mm.vcproj index d3cd5f44..e7a85095 100755 --- a/amxmodx/msvc/amxmodx_mm.vcproj +++ b/amxmodx/msvc/amxmodx_mm.vcproj @@ -300,7 +300,7 @@ Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories=""C:\Hry\Half-Life\SDK\Multiplayer Source\pm_shared";"C:\Hry\Half-Life\SDK\Multiplayer Source\dlls";"C:\Hry\Half-Life\SDK\Multiplayer Source\engine";"C:\Hry\Half-Life\SDK\Multiplayer Source\common";C:\Files\Programming\metamod\metamod" - PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;amxmodx_EXPORTS;JIT" + PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;amxmodx_EXPORTS;PAWN_CELL_SIZE=32;ASM32;JIT" BasicRuntimeChecks="3" RuntimeLibrary="5" StructMemberAlignment="3" @@ -319,7 +319,7 @@ + + @@ -780,6 +784,9 @@ + + diff --git a/amxmodx/srvcmd.cpp b/amxmodx/srvcmd.cpp index e6220b73..79707c84 100755 --- a/amxmodx/srvcmd.cpp +++ b/amxmodx/srvcmd.cpp @@ -150,14 +150,14 @@ void amx_command(){ print_srvconsole( "%s %s\n", Plugin_info.name, Plugin_info.version); print_srvconsole( "Authors: %s (%s)\n", "Felix \"SniperBeamer\" Geyer, David \"BAILOPAN\" Anderson, Pavol \"PM OnoTo\" Marko, Jonny \"Got His Gun\" Bergstrom, and Lukasz \"SidLuke\" Wlasinski.", Plugin_info.url); print_srvconsole( "Compiled: %s\n", __DATE__ ", " __TIME__); -#ifdef JIT - print_srvconsole( "Core mode: JIT\n"); +#if defined JIT && !defined ASM32 + print_srvconsole( "Core mode: JIT Only\n"); +#elif !defined JIT && defined ASM32 + print_srvconsole( "Core mode: ASM32 Only\n"); +#elif defined JIT && defined ASM32 + print_srvconsole( "Core mode: JIT+ASM32\n"); #else -#ifdef ASM32 - print_srvconsole( "Core mode: ASM\n"); -#else - print_srvconsole( "Core mode: Normal\n"); -#endif + print_srvconsole( "Core mode: Normal\n"); #endif } else if (!strcmp(cmd,"modules")) @@ -264,39 +264,19 @@ void amx_command(){ void plugin_srvcmd() { - - cell ret = 0; - int err; - const char* cmd = CMD_ARGV(0); - -#ifdef ENABLEEXEPTIONS - try{ -#endif + cell ret = 0; + const char* cmd = CMD_ARGV(0); - CmdMngr::iterator a = g_commands.srvcmdbegin(); - - while ( a ) - { - if ( (*a).matchCommand( cmd ) && - (*a).getPlugin()->isExecutable( (*a).getFunction() ) ) - { - - if ((err = amx_Exec( (*a).getPlugin()->getAMX(), &ret , (*a).getFunction() - , 3 , g_srvindex , (*a).getFlags() , (*a).getId() )) != AMX_ERR_NONE) - { - LogError((*a).getPlugin()->getAMX(), err, ""); - } - if ( ret ) break; - } - - ++a; - } - -#ifdef ENABLEEXEPTIONS - }catch( ... ) + CmdMngr::iterator a = g_commands.srvcmdbegin(); + + while ( a ) + { + if ( (*a).matchCommand( cmd ) && + (*a).getPlugin()->isExecutable( (*a).getFunction() ) ) { - AMXXLOG_Log( "[AMXX] fatal error at forward function execution"); + cell ret = executeForwards((*a).getFunction(), g_srvindex, (*a).getFlags(), (*a).getId()); + if ( ret ) break; } -#endif - + ++a; + } } diff --git a/amxmodx/string.cpp b/amxmodx/string.cpp index 0da9ab63..b2b669e0 100755 --- a/amxmodx/string.cpp +++ b/amxmodx/string.cpp @@ -471,7 +471,7 @@ static cell AMX_NATIVE_CALL amx_strtok(AMX *amx, cell *params) char token = params[6]; //trim int trim = params[7]; - for (i=0; i