diff --git a/amxmodx/amx.c b/amxmodx/amx.c index eb6f4b19..e94ab820 100755 --- a/amxmodx/amx.c +++ b/amxmodx/amx.c @@ -1,28 +1,89 @@ /* Abstract Machine for the Small compiler * - * Copyright (c) ITB CompuPhase, 1997-2002 - * This file may be freely used. No warranties of any kind. + * Copyright (c) ITB CompuPhase, 1997-2003 * - * Version: $Id$ + * This software is provided "as-is", without any express or implied warranty. + * In no event will the authors be held liable for any damages arising from + * the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * PM: Whole file changed + * Fixed FAR / _FAR problems */ +#define AMX_NODYNALOAD // PM: Already implemented #define WIN32_LEAN_AND_MEAN #include #include #include #include -#if defined __linux__ +#include "osdefs.h" +#if defined LINUX #include + #if !defined AMX_NODYNALOAD + #include + #endif #endif -#if defined JIT +#include "amx.h" +#if (defined _Windows && !defined AMX_NODYNALOAD) || defined JIT #include #endif -#include "osdefs.h" -#include "amx.h" - -//#if !defined __linux__ /* Linux GCC already has these types */ -typedef unsigned char u_char; -//#endif - +/* When one or more of the AMX_funcname macris are defined, we want + * to compile only those functions. However, when none of these macros + * is present, we want to compile everything. + */ +#if defined AMX_ALIGN || defined AMX_ALLOT || defined AMX_CLEANUP + #define AMX_EXPLIT_FUNCTIONS +#endif +#if defined AMX_CLONE || defined AMX_EXEC || defined AMX_FLAGS + #define AMX_EXPLIT_FUNCTIONS +#endif +#if defined AMX_GETADDR || defined AMX_INIT || defined AMX_MEMINFO + #define AMX_EXPLIT_FUNCTIONS +#endif +#if defined AMX_NAMELENGTH || defined AMX_NATIVEINFO || defined AMX_RAISEERROR + #define AMX_EXPLIT_FUNCTIONS +#endif +#if defined AMX_REGISTER || defined AMX_SETCALLBACK || defined AMX_SETDEBUGHOOK + #define AMX_EXPLIT_FUNCTIONS +#endif +#if defined AMX_STRERROR || defined AMX_XXXNATIVES || defined AMX_XXXPUBLICS + #define AMX_EXPLIT_FUNCTIONS +#endif +#if defined AMX_XXXPUBVARS || defined AMX_XXXSTRING || defined AMX_XXXTAGS + #define AMX_EXPLIT_FUNCTIONS +#endif +#if defined AMX_XXXUSERDATA + #define AMX_EXPLIT_FUNCTIONS +#endif +#if !defined AMX_EXPLIT_FUNCTIONS + /* no constant set, set them all */ + #define AMX_ALIGN /* amx_Align16() and amx_Align32() */ + #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_FLAGS /* amx_Flags() */ + #define AMX_GETADDR /* amx_GetAddr() */ + #define AMX_INIT /* amx_Init() and amx_InitJIT() */ + #define AMX_MEMINFO /* amx_MemInfo() */ + #define AMX_NAMELENGTH /* amx_NameLength() */ + #define AMX_NATIVEINFO /* amx_NativeInfo() */ + #define AMX_RAISEERROR /* amx_RaiseError() */ + #define AMX_REGISTER /* amx_Register() */ + #define AMX_SETCALLBACK /* amx_SetCallback() */ + #define AMX_SETDEBUGHOOK /* amx_SetDebugHook() */ + #define AMX_STRERROR /* amx_StrError() */ + #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_XXXTAGS /* amx_NumTags(), amx_GetTag() and amx_FindTagId() */ + #define AMX_XXXUSERDATA /* amx_GetUserData() and amx_SetUserData() */ +#endif +#undef AMX_EXPLIT_FUNCTIONS typedef enum { OP_NONE, /* invalid opcode */ OP_LOAD_PRI, @@ -158,23 +219,27 @@ typedef enum { OP_SWAP_PRI, OP_SWAP_ALT, OP_PUSHADDR, -//OP_CALLN, OP_NOP, + OP_SYSREQ_D, + OP_SYMTAG, /* ----- */ OP_NUM_OPCODES } OPCODE; - -#define NUMENTRIES(hdr,field,nextfield) (int)(((hdr).nextfield - (hdr).field)/sizeof(AMX_FUNCSTUB)) - +#define NUMENTRIES(hdr,field,nextfield) \ + (int)(((hdr)->nextfield - (hdr)->field) / (hdr)->defsize) +#define GETENTRY(hdr,table,index) \ + (AMX_FUNCSTUB *)((unsigned char*)(hdr) + (int)(hdr)->table + index*(hdr)->defsize) +#define GETENTRYNAME(hdr,entry) \ + (((hdr)->defsize==2*sizeof(uint32_t)) \ + ? (char *)((unsigned char*)(hdr) + *((uint32_t *)(entry)+1)) \ + : (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 */ uint16_t val=0x00ff; - u_char *ptr=(u_char *)&val; - + 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. @@ -183,24 +248,20 @@ static void init_little_endian(void) amx_LittleEndian= *ptr==0xff; } /* if */ } - 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; } - 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]; @@ -211,7 +272,7 @@ static void swap32(uint32_t *v) s[1]=s[2]; s[2]=t; } - +#if defined AMX_ALIGN || defined AMX_INIT uint16_t *amx_Align16(uint16_t *v) { assert(sizeof(*v)==2); @@ -220,7 +281,6 @@ uint16_t *amx_Align16(uint16_t *v) swap16(v); return v; } - uint32_t *amx_Align32(uint32_t *v) { assert(sizeof(cell)==4); @@ -229,17 +289,16 @@ uint32_t *amx_Align32(uint32_t *v) swap32(v); return v; } - +#endif /* AMX_ALIGN || AMX_INIT */ #if defined BIT16 #define swapcell swap16 #else #define swapcell swap32 #endif - +#if defined AMX_FLAGS int AMXAPI amx_Flags(AMX *amx,uint16_t *flags) { AMX_HEADER *hdr; - *flags=0; if (amx==NULL) return AMX_ERR_FORMAT; @@ -251,27 +310,30 @@ int AMXAPI amx_Flags(AMX *amx,uint16_t *flags) *flags=hdr->flags; return AMX_ERR_NONE; } - +#endif /* AMX_FLAGS */ +#if defined AMX_INIT int AMXAPI amx_Callback(AMX *amx, cell index, cell *result, cell *params) { - AMX_HEADER *hdr=(AMX_HEADER *)amx->base; - AMX_FUNCSTUB *func=(AMX_FUNCSTUB *)(amx->base+(int)hdr->natives+(int)index*sizeof(AMX_FUNCSTUB)); - AMX_NATIVE f=(AMX_NATIVE)func->address; - assert(f!=NULL); + AMX_HEADER *hdr; + AMX_FUNCSTUB *func; + AMX_NATIVE f; + assert(amx!=NULL); + hdr=(AMX_HEADER *)amx->base; + assert(hdr!=NULL); assert(hdr->natives<=hdr->libraries); - assert(index<(cell)NUMENTRIES(*hdr,natives,libraries)); - + assert(index>=0 && index<(cell)NUMENTRIES(hdr,natives,libraries)); + func=GETENTRY(hdr,natives,index); + f=(AMX_NATIVE)func->address; + assert(f!=NULL); /* Note: - * params[0] == number of parameters passed to the native function + * params[0] == number of bytes for the additional parameters passed to the native function * params[1] == first argument * etc. */ - amx->error=AMX_ERR_NONE; *result = f(amx,params); return amx->error; } - #if defined __BORLANDC__ || defined __WATCOMC__ #pragma argsused #endif @@ -279,12 +341,10 @@ int AMXAPI amx_Debug(AMX *amx) { return AMX_ERR_DEBUG; } - #if defined JIT extern int AMXAPI getMaxCodeSize(void); extern int AMXAPI asm_runJIT(void *sourceAMXbase, void *jumparray, void *compiledAMXbase); #endif - #if defined BIT16 #define JUMPABS(base,ip) ((cell *)(base+*ip)) #define RELOC_ABS(base, off) @@ -294,13 +354,11 @@ int AMXAPI amx_Debug(AMX *amx) #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) ) - static int amx_BrowseRelocate(AMX *amx) { AMX_HEADER *hdr; - u_char *code; + unsigned char *code; cell cip; long codesize; OPCODE op; @@ -313,12 +371,9 @@ static int amx_BrowseRelocate(AMX *amx) int opcode_count = 0; int reloc_count = 0; #endif - - hdr=(AMX_HEADER *)amx->base; code=amx->base+(int)hdr->cod; codesize=hdr->dat - hdr->cod; - /* sanity checks */ assert(OP_PUSH_PRI==36); assert(OP_PROC==46); @@ -328,25 +383,24 @@ static int amx_BrowseRelocate(AMX *amx) assert(OP_INC_PRI==107); assert(OP_MOVS==117); assert(OP_SYMBOL==126); - /* check the debug hook */ amx->dbgcode=DBG_INIT; assert(amx->flags==0); amx->flags=AMX_FLAG_BROWSE; debug= amx->debug(amx)==AMX_ERR_NONE; if (debug) - amx->flags=AMX_FLAG_DEBUG | AMX_FLAG_BROWSE; - + amx->flags|=AMX_FLAG_DEBUG; #if defined __GNUC__ || defined ASM32 || defined JIT - amx_Exec(NULL, (cell *)&opcode_list, 0, 0); + amx_Exec(amx, (cell *)&opcode_list, 0, 0); #endif - /* start browsing code */ for (cip=0; cip0 && op=256) + if ((int)op>=256) { + amx->flags &= ~AMX_FLAG_BROWSE; return AMX_ERR_INVINSTR; + } /* if */ #if defined __GNUC__ || defined ASM32 || defined JIT /* relocate symbol */ *(ucell **)(code+(int)cip) = opcode_list[op]; @@ -412,9 +466,9 @@ static int amx_BrowseRelocate(AMX *amx) case OP_BOUNDS: case OP_SYSREQ_C: case OP_PUSHADDR: + case OP_SYSREQ_D: cip+=sizeof(cell); break; - case OP_LOAD_I: /* instructions without parameters */ case OP_STOR_I: case OP_LIDX: @@ -474,7 +528,6 @@ static int amx_BrowseRelocate(AMX *amx) case OP_SWAP_ALT: case OP_NOP: break; - case OP_CALL: /* opcodes that need relocation */ case OP_JUMP: case OP_JZER: @@ -496,15 +549,6 @@ static int amx_BrowseRelocate(AMX *amx) RELOC_ABS(code, cip); cip+=sizeof(cell); break; - -// case OP_CALLN: -// #if defined JIT -// reloc_count++; -// #endif -// RELOC_ABS(code, cip); -// cip+=2*sizeof(cell); -// break; - case OP_FILE: { cell num; DBGPARAM(num); @@ -551,6 +595,14 @@ static int amx_BrowseRelocate(AMX *amx) amx->debug(amx); } /* if */ break; + case OP_SYMTAG: + DBGPARAM(amx->dbgparam); /* tag id */ + if (debug && last_sym_global) { /* do global symbols only */ + assert(amx->flags==(AMX_FLAG_DEBUG | AMX_FLAG_BROWSE)); + amx->dbgcode=DBG_SYMTAG; + amx->debug(amx); + } /* if */ + break; case OP_CASETBL: { cell num; int i; @@ -565,31 +617,28 @@ static int amx_BrowseRelocate(AMX *amx) break; } /* case */ default: + amx->flags &= ~AMX_FLAG_BROWSE; return AMX_ERR_INVINSTR; } /* switch */ } /* for */ - #if defined JIT amx->code_size = getMaxCodeSize()*opcode_count + hdr->cod + (hdr->stp - hdr->dat); amx->reloc_size = 2*sizeof(cell)*reloc_count; #endif - + amx->flags &= ~AMX_FLAG_BROWSE; amx->flags |= AMX_FLAG_RELOC; return AMX_ERR_NONE; } - static void expand(unsigned char *code, long codesize, long memsize) { -#define SPARESIZE 32 ucell c; struct { long memloc; ucell c; - } spare[SPARESIZE]; + } spare[AMX_EXPANDMARGIN]; int sh=0,st=0,sc=0; int shift; - /* for in-place expansion, move from the end backward */ assert(memsize % sizeof(cell) == 0); while (codesize>0) { @@ -615,7 +664,7 @@ static void expand(unsigned char *code, long codesize, long memsize) /* store */ while (sc&&(spare[sh].memloc>codesize)) { *(ucell *)(code+(int)spare[sh].memloc)=spare[sh].c; - sh=(sh+1)%SPARESIZE; + sh=(sh+1)%AMX_EXPANDMARGIN; sc--; } /* while */ memsize -= sizeof(cell); @@ -623,21 +672,34 @@ 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(scflags & AMX_FLAG_RELOC)!=0) + return AMX_ERR_INIT; /* already initialized (may not do so twice) */ hdr=(AMX_HEADER *)program; /* the header is in Little Endian, on a Big Endian machine, swap all * multi-byte words @@ -659,11 +721,20 @@ int AMXAPI amx_Init(AMX *amx, void *program) amx_Align32((uint32_t*)&hdr->pubvars); amx_Align32((uint32_t*)&hdr->tags); } /* if */ - - if (hdr->magic!=AMX_MAGIC || hdr->defsize!=sizeof(AMX_FUNCSTUB)) + if (hdr->magic!=AMX_MAGIC) return AMX_ERR_FORMAT; - if (hdr->file_version>CUR_FILE_VERSION || hdr->amx_versionfile_versionamx_version>CUR_FILE_VERSION) return AMX_ERR_VERSION; + if (hdr->defsize!=sizeof(AMX_FUNCSTUB) && hdr->defsize!=2*sizeof(uint32_t)) + return AMX_ERR_FORMAT; + if (hdr->defsize==2*sizeof(uint32_t)) { + /* when there is a separate name table, check the maximum name length + * in that table + */ + uint16_t *namelength=(uint16_t*)((unsigned char*)program + hdr->nametable); + if (*namelength>sNAMEMAX) + return AMX_ERR_FORMAT; + } /* if */ if (hdr->stp<=0) return AMX_ERR_FORMAT; if ((hdr->flags & AMX_FLAG_CHAR16)!=0) @@ -674,14 +745,11 @@ int AMXAPI amx_Init(AMX *amx, void *program) if ((hdr->flags & AMX_FLAG_COMPACT)!=0) expand((unsigned char *)program+(int)hdr->cod, hdr->size - hdr->cod, hdr->hea - hdr->cod); - amx->base=(unsigned char *)program; - /* Set a zero cell at the top of the stack, which functions * as a sentinel for strings. */ * (cell *)(amx->base+(int)hdr->stp-sizeof(cell)) = 0; - /* set initial values */ amx->hlw=hdr->hea - hdr->dat; /* stack and heap relative to data segment */ amx->stp=hdr->stp - hdr->dat - sizeof(cell); @@ -694,161 +762,120 @@ int AMXAPI amx_Init(AMX *amx, void *program) amx->curline=0; amx->curfile=0; amx->data=NULL; - /* also align all addresses in the public function, public variable and * public tag tables */ if (!amx_LittleEndian) { AMX_FUNCSTUB *fs; int i,num; - - fs=(AMX_FUNCSTUB *)(amx->base + (int)hdr->publics); + fs=GETENTRY(hdr,publics,0); assert(hdr->publics<=hdr->natives); - num=NUMENTRIES(*hdr,publics,natives); + num=NUMENTRIES(hdr,publics,natives); for (i=0; iaddress); - fs++; + fs=(AMX_FUNCSTUB*)((unsigned char *)fs+hdr->defsize); } /* for */ - - fs=(AMX_FUNCSTUB *)(amx->base + (int)hdr->pubvars); + fs=GETENTRY(hdr,pubvars,0); assert(hdr->pubvars<=hdr->tags); - num=NUMENTRIES(*hdr,pubvars,tags); + num=NUMENTRIES(hdr,pubvars,tags); for (i=0; iaddress); - fs++; + fs=(AMX_FUNCSTUB*)((unsigned char *)fs+hdr->defsize); } /* for */ - - fs=(AMX_FUNCSTUB *)(amx->base + (int)hdr->tags); - assert(hdr->tags<=hdr->cod); - num=NUMENTRIES(*hdr,tags,cod); + fs=GETENTRY(hdr,tags,0); + if (hdr->file_version<7) { + assert(hdr->tags<=hdr->cod); + num=NUMENTRIES(hdr,tags,cod); + } else { + assert(hdr->tags<=hdr->nametable); + num=NUMENTRIES(hdr,tags,nametable); + } /* if */ for (i=0; iaddress); - fs++; + fs=(AMX_FUNCSTUB*)((unsigned char *)fs+hdr->defsize); } /* for */ } /* if */ - /* relocate call and jump instructions, optionally gather debug information */ amx_BrowseRelocate(amx); - + /* load any extension modules that the AMX refers to */ + #if (defined _Windows || defined LINUX) && !defined AMX_NODYNALOAD + hdr=(AMX_HEADER *)amx->base; + numlibraries=NUMENTRIES(hdr,libraries,tags); + for (i=0; iaddress=(uint32_t)hlib; + } /* for */ + #endif return AMX_ERR_NONE; } - -int AMXAPI amx_Clone(AMX *amxClone, AMX *amxSource, void *data) -{ - AMX_HEADER *hdr; - u_char FAR *dataSource; - - if (amxSource==NULL) - return AMX_ERR_FORMAT; - if (amxClone==NULL) - return AMX_ERR_PARAMS; - hdr=(AMX_HEADER *)amxSource->base; - if (hdr->magic!=AMX_MAGIC) - return AMX_ERR_FORMAT; - if (hdr->file_version>CUR_FILE_VERSION || hdr->amx_versionbase=amxSource->base; - amxClone->hlw=hdr->hea - hdr->dat; /* stack and heap relative to data segment */ - amxClone->stp=hdr->stp - hdr->dat - sizeof(cell); - amxClone->hea=amxClone->hlw; - amxClone->stk=amxClone->stp; - if (amxClone->callback==NULL) - amxClone->callback=amxSource->callback; - if (amxClone->debug==NULL) - amxClone->debug=amxSource->debug; - amxClone->curline=0; - amxClone->curfile=0; - - /* copy the data segment; the stack and the heap can be left uninitialized */ - assert(data!=NULL); - amxClone->data=(u_char FAR *)data; - dataSource=(amxSource->data!=NULL) ? amxSource->data : amxSource->base+(int)hdr->dat; - memcpy(amxClone->data,dataSource,(size_t)(hdr->hea-hdr->dat)); - - /* Set a zero cell at the top of the stack, which functions - * as a sentinel for strings. - */ - * (cell *)(amxClone->data+(int)amxClone->stp) = 0; - - return AMX_ERR_NONE; -} - -int AMXAPI amx_MemInfo(AMX *amx, long *codesize, long *datasize, long *stackheap) -{ - AMX_HEADER *hdr; - - if (amx==NULL) - return AMX_ERR_FORMAT; - hdr=(AMX_HEADER *)amx->base; - if (hdr->magic!=AMX_MAGIC) - return AMX_ERR_FORMAT; - if (hdr->file_version>CUR_FILE_VERSION || hdr->amx_versiondat-hdr->cod; - if (datasize!=NULL) - *datasize=hdr->hea-hdr->dat; - if (stackheap!=NULL) - *stackheap=hdr->stp-hdr->hea; - - return AMX_ERR_NONE; -} - #if defined JIT - -#if defined __WIN32__ /* this also applies to Win32 "console" applications */ - -int memoryFullAccess( void* addr, int len ) -{ - DWORD op; - - if ( VirtualProtect( addr, len, PAGE_EXECUTE_READWRITE, &op ) ) - return op; - return 0; -} - -int memorySetAccess( void* addr, int len, int access ) -{ - DWORD op; - - if ( access == 0 ) - return 0; - return VirtualProtect( addr, len, access, &op ); -} - -#else /* #if defined __WIN32 __ */ - -// TODO: Add cases for Linux, Unix, OS/2, ... - -// DOS32 has no imposed limits on its segments. -#if defined __BORLANDC__ || defined __WATCOMC__ - #pragma argsused -#endif -int memoryFullAccess( void* addr, int len ) { return 1; } - -#if defined __BORLANDC__ || defined __WATCOMC__ - #pragma argsused -#endif -int memorySetAccess( void* addr, int len, int access ) { return 1; } - -#endif /* #if defined __WIN32 __ */ - + #if defined __WIN32__ /* this also applies to Win32 "console" applications */ + int memoryFullAccess( void* addr, int len ) + { + DWORD op; + if ( VirtualProtect( addr, len, PAGE_EXECUTE_READWRITE, &op ) ) + return op; + return 0; + } + int memorySetAccess( void* addr, int len, int access ) + { + DWORD op; + if ( access == 0 ) + return 0; + return VirtualProtect( addr, len, access, &op ); + } + #else /* #if defined __WIN32 __ */ + // TODO: Add cases for Linux, Unix, OS/2, ... + // DOS32 has no imposed limits on its segments. + #if defined __BORLANDC__ || defined __WATCOMC__ + #pragma argsused + #endif + int memoryFullAccess( void* addr, int len ) { return 1; } + #if defined __BORLANDC__ || defined __WATCOMC__ + #pragma argsused + #endif + int memorySetAccess( void* addr, int len, int access ) { return 1; } + #endif /* #if defined __WIN32 __ */ int AMXAPI amx_InitJIT(AMX *amx, void *reloc_table, void *native_code) { int mac, res; AMX_HEADER *hdr; - mac = memoryFullAccess( asm_runJIT, 20000 ); if ( ! mac ) return AMX_ERR_INIT_JIT; - /* copy the prefix */ memcpy( native_code, amx->base, ((AMX_HEADER *)(amx->base))->cod ); - hdr = (AMX_HEADER*)native_code; - + hdr = native_code; /* JIT rulz! (TM) */ /* MP: added check for correct compilation */ res = asm_runJIT( amx->base, reloc_table, native_code ); @@ -857,7 +884,6 @@ int AMXAPI amx_InitJIT(AMX *amx, void *reloc_table, void *native_code) memorySetAccess( asm_runJIT, 20000, mac ); return AMX_ERR_INIT_JIT; } - /* update the required memory size (the previous value was a * conservative estimate, now we know the exact size) */ @@ -873,13 +899,14 @@ int AMXAPI amx_InitJIT(AMX *amx, void *reloc_table, void *native_code) /* 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; - memorySetAccess( asm_runJIT, 20000, mac ); return AMX_ERR_NONE; } - #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 @@ -887,47 +914,204 @@ int AMXAPI amx_InitJIT(AMX *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 */ +#if defined AMX_CLEANUP +int AMXAPI amx_Cleanup(AMX *amx) +{ + #if (defined _Windows || defined LINUX) && !defined AMX_NODYNALOAD + #if defined _Windows + typedef int (_FAR WINAPI *AMX_ENTRY)(AMX _FAR *amx); + #elif defined LINUX + typedef int (*AMX_ENTRY)(AMX *amx); + #endif + AMX_HEADER *hdr; + int numlibraries,i; + AMX_FUNCSTUB *lib; + AMX_ENTRY libcleanup; + #endif + /* unload all extension modules */ + #if (defined _Windows || defined LINUX) && !defined AMX_NODYNALOAD + hdr=(AMX_HEADER *)amx->base; + numlibraries=NUMENTRIES(hdr,libraries,tags); + for (i=0; iaddress!=0) { + char funcname[sNAMEMAX+12]; /* +1 for '\0', +4 for 'amx_', +7 for 'Cleanup' */ + strcpy(funcname,"amx_"); + strcat(funcname,GETENTRYNAME(hdr,lib)); + strcat(funcname,"Cleanup"); + //funcname[4]=toupper(funcname[4]); + #if defined _Windows + libcleanup=(AMX_ENTRY)GetProcAddress((HINSTANCE)lib->address,funcname); + #elif defined LINUX + libcleanup=(AMX_ENTRY)dlsym((void*)lib->address,funcname); + #endif + if (libcleanup!=NULL) + libcleanup(amx); + #if defined _Windows + FreeLibrary((HINSTANCE)lib->address); + #elif defined LINUX + dlclose((void*)lib->address); + #endif + } /* if */ + } /* for */ + #endif + return AMX_ERR_NONE; +} +#endif /* AMX_CLEANUP */ +#if defined AMX_CLONE +int AMXAPI amx_Clone(AMX *amxClone, AMX *amxSource, void *data) +{ + AMX_HEADER *hdr; + unsigned char _FAR *dataSource; + if (amxSource==NULL) + return AMX_ERR_FORMAT; + if (amxClone==NULL) + return AMX_ERR_PARAMS; + if ((amxSource->flags & AMX_FLAG_RELOC)==0) + return AMX_ERR_INIT; + hdr=(AMX_HEADER *)amxSource->base; + if (hdr->magic!=AMX_MAGIC) + return AMX_ERR_FORMAT; + if (hdr->file_version>CUR_FILE_VERSION || hdr->amx_versionbase=amxSource->base; + amxClone->hlw=hdr->hea - hdr->dat; /* stack and heap relative to data segment */ + amxClone->stp=hdr->stp - hdr->dat - sizeof(cell); + amxClone->hea=amxClone->hlw; + amxClone->stk=amxClone->stp; + if (amxClone->callback==NULL) + amxClone->callback=amxSource->callback; + 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); + amxClone->data=(unsigned char _FAR *)data; + dataSource=(amxSource->data!=NULL) ? amxSource->data : amxSource->base+(int)hdr->dat; + memcpy(amxClone->data,dataSource,(size_t)(hdr->hea-hdr->dat)); + /* Set a zero cell at the top of the stack, which functions + * as a sentinel for strings. + */ + * (cell *)(amxClone->data+(int)amxClone->stp) = 0; + return AMX_ERR_NONE; +} +#endif /* AMX_CLONE */ +#if defined AMX_MEMINFO +int AMXAPI amx_MemInfo(AMX *amx, long *codesize, long *datasize, long *stackheap) +{ + AMX_HEADER *hdr; + if (amx==NULL) + return AMX_ERR_FORMAT; + hdr=(AMX_HEADER *)amx->base; + if (hdr->magic!=AMX_MAGIC) + return AMX_ERR_FORMAT; + if (hdr->file_version>CUR_FILE_VERSION || hdr->amx_versiondat - hdr->cod; + if (datasize!=NULL) + *datasize=hdr->hea - hdr->dat; + if (stackheap!=NULL) + *stackheap=hdr->stp - hdr->hea; + return AMX_ERR_NONE; +} +#endif /* AMX_MEMINFO */ +#if defined AMX_NAMELENGTH int AMXAPI amx_NameLength(AMX *amx, int *length) { AMX_HEADER *hdr=(AMX_HEADER *)amx->base; assert(hdr!=NULL); *length=hdr->defsize - sizeof(uint32_t); + if (*length==sizeof(uint32_t)) { + uint16_t *namelength=(uint16_t*)(amx->base + hdr->nametable); + *length=*namelength; + assert(hdr->file_version>=7); /* name table exists only for file version 7+ */ + } /* if */ return AMX_ERR_NONE; } - +#endif /* AMX_NAMELENGTH */ +#if defined AMX_XXXNATIVES +int AMXAPI amx_NumNatives(AMX *amx, int *number) +{ + AMX_HEADER *hdr=(AMX_HEADER *)amx->base; + assert(hdr!=NULL); + assert(hdr->natives<=hdr->libraries); + *number=NUMENTRIES(hdr,natives,libraries); + return AMX_ERR_NONE; +} +int AMXAPI amx_GetNative(AMX *amx, int index, char *funcname) +{ + AMX_HEADER *hdr; + AMX_FUNCSTUB *func; + hdr=(AMX_HEADER *)amx->base; + assert(hdr!=NULL); + assert(hdr->natives<=hdr->libraries); + if (index>=(cell)NUMENTRIES(hdr,natives,libraries)) + return AMX_ERR_INDEX; + func=GETENTRY(hdr,natives,index); + strcpy(funcname,GETENTRYNAME(hdr,func)); + return AMX_ERR_NONE; +} +int AMXAPI amx_FindNative(AMX *amx, char *name, int *index) +{ + int first,last,mid,result; + char pname[sNAMEMAX+1]; + amx_NumNatives(amx, &last); + last--; /* last valid index is 1 less than the number of functions */ + first=0; + /* binary search */ + while (first<=last) { + mid=(first+last)/2; + amx_GetNative(amx, mid, pname); + result=strcmp(pname,name); + if (result>0) { + last=mid-1; + } else if (result<0) { + first=mid+1; + } else { + *index=mid; + return AMX_ERR_NONE; + } /* if */ + } /* while */ + /* not found, set to an invalid index, so amx_Exec() will fail */ + *index=INT_MAX; + return AMX_ERR_NOTFOUND; +} +#endif /* AMX_XXXNATIVES */ +#if defined AMX_XXXPUBLICS int AMXAPI amx_NumPublics(AMX *amx, int *number) { AMX_HEADER *hdr=(AMX_HEADER *)amx->base; assert(hdr!=NULL); assert(hdr->publics<=hdr->natives); - *number=NUMENTRIES(*hdr,publics,natives); + *number=NUMENTRIES(hdr,publics,natives); return AMX_ERR_NONE; } - int AMXAPI amx_GetPublic(AMX *amx, int index, char *funcname) { AMX_HEADER *hdr; AMX_FUNCSTUB *func; - hdr=(AMX_HEADER *)amx->base; assert(hdr!=NULL); assert(hdr->publics<=hdr->natives); - if (index>=(cell)NUMENTRIES(*hdr,publics,natives)) + if (index>=(cell)NUMENTRIES(hdr,publics,natives)) return AMX_ERR_INDEX; - - func=(AMX_FUNCSTUB *)(amx->base+(int)hdr->publics+index*sizeof(AMX_FUNCSTUB)); - strcpy(funcname,func->name); + func=GETENTRY(hdr,publics,index); + strcpy(funcname,GETENTRYNAME(hdr,func)); return AMX_ERR_NONE; } - int AMXAPI amx_FindPublic(AMX *amx, char *name, int *index) { int first,last,mid,result; - char pname[sEXPMAX+1]; - + char pname[sNAMEMAX+1]; amx_NumPublics(amx, &last); last--; /* last valid index is 1 less than the number of functions */ first=0; @@ -949,39 +1133,35 @@ int AMXAPI amx_FindPublic(AMX *amx, char *name, int *index) *index=INT_MAX; return AMX_ERR_NOTFOUND; } - +#endif /* AMX_XXXPUBLICS */ +#if defined AMX_XXXPUBVARS int AMXAPI amx_NumPubVars(AMX *amx, int *number) { AMX_HEADER *hdr=(AMX_HEADER *)amx->base; assert(hdr!=NULL); assert(hdr->pubvars<=hdr->tags); - *number=NUMENTRIES(*hdr,pubvars,tags); + *number=NUMENTRIES(hdr,pubvars,tags); return AMX_ERR_NONE; } - int AMXAPI amx_GetPubVar(AMX *amx, int index, char *varname, cell *amx_addr) { AMX_HEADER *hdr; AMX_FUNCSTUB *var; - hdr=(AMX_HEADER *)amx->base; assert(hdr!=NULL); assert(hdr->pubvars<=hdr->tags); - if (index>=(cell)NUMENTRIES(*hdr,pubvars,tags)) + if (index>=(cell)NUMENTRIES(hdr,pubvars,tags)) return AMX_ERR_INDEX; - - var=(AMX_FUNCSTUB *)(amx->base+(int)hdr->pubvars+index*sizeof(AMX_FUNCSTUB)); - strcpy(varname,var->name); + var=GETENTRY(hdr,pubvars,index); + strcpy(varname,GETENTRYNAME(hdr,var)); *amx_addr=var->address; return AMX_ERR_NONE; } - int AMXAPI amx_FindPubVar(AMX *amx, char *varname, cell *amx_addr) { int first,last,mid,result; - char pname[sEXPMAX+1]; + char pname[sNAMEMAX+1]; cell paddr; - amx_NumPubVars(amx, &last); last--; /* last valid index is 1 less than the number of functions */ first=0; @@ -1003,7 +1183,8 @@ int AMXAPI amx_FindPubVar(AMX *amx, char *varname, cell *amx_addr) *amx_addr=0; return AMX_ERR_NOTFOUND; } - +#endif /* AMX_XXXPUBVARS */ +#if defined AMX_XXXTAGS int AMXAPI amx_NumTags(AMX *amx, int *number) { AMX_HEADER *hdr=(AMX_HEADER *)amx->base; @@ -1012,16 +1193,19 @@ int AMXAPI amx_NumTags(AMX *amx, int *number) *number=0; return AMX_ERR_VERSION; } /* if */ - assert(hdr->tags<=hdr->cod); - *number=NUMENTRIES(*hdr,tags,cod); + if (hdr->file_version<7) { + assert(hdr->tags<=hdr->cod); + *number=NUMENTRIES(hdr,tags,cod); + } else { + assert(hdr->tags<=hdr->nametable); + *number=NUMENTRIES(hdr,tags,nametable); + } /* if */ return AMX_ERR_NONE; } - int AMXAPI amx_GetTag(AMX *amx, int index, char *tagname, cell *tag_id) { AMX_HEADER *hdr; AMX_FUNCSTUB *tag; - hdr=(AMX_HEADER *)amx->base; assert(hdr!=NULL); if (hdr->file_version<5) { /* the tagname table appeared in file format 5 */ @@ -1029,22 +1213,24 @@ int AMXAPI amx_GetTag(AMX *amx, int index, char *tagname, cell *tag_id) *tag_id=0; return AMX_ERR_VERSION; } /* if */ - - assert(hdr->tags<=hdr->cod); - if (index>=(cell)NUMENTRIES(*hdr,tags,cod)) - return AMX_ERR_INDEX; - - tag=(AMX_FUNCSTUB *)(amx->base+(int)hdr->tags+index*sizeof(AMX_FUNCSTUB)); - strcpy(tagname,tag->name); + if (hdr->file_version<7) { + assert(hdr->tags<=hdr->cod); + if (index>=(cell)NUMENTRIES(hdr,tags,cod)) + return AMX_ERR_INDEX; + } else { + assert(hdr->tags<=hdr->nametable); + if (index>=(cell)NUMENTRIES(hdr,tags,nametable)) + return AMX_ERR_INDEX; + } /* if */ + tag=GETENTRY(hdr,tags,index); + strcpy(tagname,GETENTRYNAME(hdr,tag)); *tag_id=tag->address; return AMX_ERR_NONE; } - int AMXAPI amx_FindTagId(AMX *amx, cell tag_id, char *tagname) { int first,last,mid; cell mid_id; - #if !defined NDEBUG /* verify that the tagname table is sorted on the tag_id */ amx_NumTags(amx, &last); @@ -1058,7 +1244,6 @@ int AMXAPI amx_FindTagId(AMX *amx, cell tag_id, char *tagname) } /* for */ } /* if */ #endif - amx_NumTags(amx, &last); last--; /* last valid index is 1 less than the number of functions */ first=0; @@ -1077,11 +1262,11 @@ int AMXAPI amx_FindTagId(AMX *amx, cell tag_id, char *tagname) *tagname='\0'; return AMX_ERR_NOTFOUND; } - +#endif /* AMX_XXXTAGS */ +#if defined AMX_XXXUSERDATA int AMXAPI amx_GetUserData(AMX *amx, long tag, void **ptr) { int index; - assert(amx!=NULL); assert(tag!=0); for (index=0; indexusertags[index]!=tag; index++) @@ -1091,11 +1276,9 @@ int AMXAPI amx_GetUserData(AMX *amx, long tag, void **ptr) *ptr=amx->userdata[index]; return AMX_ERR_NONE; } - int AMXAPI amx_SetUserData(AMX *amx, long tag, void *ptr) { int index; - assert(amx!=NULL); assert(tag!=0); /* try to find existing tag */ @@ -1113,51 +1296,48 @@ int AMXAPI amx_SetUserData(AMX *amx, long tag, void *ptr) amx->userdata[index]=ptr; return AMX_ERR_NONE; } - +#endif /* AMX_XXXUSERDATA */ +#if defined AMX_REGISTER || defined AMX_EXEC || defined AMX_INIT static AMX_NATIVE findfunction(char *name, AMX_NATIVE_INFO *list, int number) { int i; - assert(list!=NULL); for (i=0; list[i].name!=NULL && (ibase; assert(hdr!=NULL); assert(hdr->natives<=hdr->libraries); - numnatives=NUMENTRIES(*hdr,natives,libraries); - + numnatives=NUMENTRIES(hdr,natives,libraries); err=AMX_ERR_NONE; - func=(AMX_FUNCSTUB *)(amx->base+(int)hdr->natives); + func=GETENTRY(hdr,natives,0); for (i=0; iaddress==0) { /* this function is not yet located */ - funcptr=(list!=NULL) ? findfunction(func->name,list,number) : NULL; + funcptr=(list!=NULL) ? findfunction(GETENTRYNAME(hdr,func),list,number) : NULL; if (funcptr!=NULL) func->address=(uint32_t)funcptr; else - { + { err=AMX_ERR_NOTFOUND; - no_function = func->name; - } + no_function = func->name; + } } /* if */ - func++; + func=(AMX_FUNCSTUB*)((unsigned char*)func+hdr->defsize); } /* for */ return err; } - +#endif /* AMX_REGISTER || AMX_EXEC || AMX_INIT */ +#if defined AMX_NATIVEINFO AMX_NATIVE_INFO * AMXAPI amx_NativeInfo(char *name,AMX_NATIVE func) { static AMX_NATIVE_INFO n; @@ -1165,27 +1345,24 @@ AMX_NATIVE_INFO * AMXAPI amx_NativeInfo(char *name,AMX_NATIVE func) n.func=func; return &n; } - +#endif /* AMX_NATIVEINFO */ +#if defined AMX_EXEC || defined AMX_INIT #define GETPARAM(v) ( v=*(cell *)cip++ ) #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__ +#if defined __GNUC__ && !defined ASM32 /* 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, ...) { -static void *labels[] = { +static void *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, @@ -1219,40 +1396,75 @@ static void *labels[] = { &&op_halt, &&op_bounds, &&op_sysreq_pri,&&op_sysreq_c, &&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_calln*/ }; + &&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 }; AMX_HEADER *hdr; AMX_FUNCSTUB *func; - u_char *code, *data; + unsigned char *code, *data; cell pri,alt,stk,frm,hea; cell reset_stk, reset_hea, *cip; cell offs; + ucell codesize; int num,i; va_list ap; - //int debug; - + int debug; /* HACK: return label table (for amx_BrowseRelocate) if amx structure - * is not passed. + * has the AMX_FLAG_BROWSE flag set. */ - if (amx==NULL) { + if ((amx->flags & AMX_FLAG_BROWSE)==AMX_FLAG_BROWSE) { assert(sizeof(cell)==sizeof(void *)); assert(retval!=NULL); - *retval=(cell)labels; + *retval=(cell)((amx->flags & AMX_FLAG_DEBUG)==0 ? amx_opcodelist_nodebug : 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 + i=amx_Register(amx,NULL,0); /* verify that all natives are registered */ if (i!=AMX_ERR_NONE) - return i;*/ - - amx->flags &= ~AMX_FLAG_BROWSE; - //if ((amx->flags & AMX_FLAG_RELOC)==0) - // return AMX_ERR_INIT; - //debug= (amx->flags & AMX_FLAG_DEBUG)!=0; - + return i; + if ((amx->flags & AMX_FLAG_RELOC)==0) + return AMX_ERR_INIT; + assert((amx->flags & AMX_FLAG_BROWSE)==0); + debug= (amx->flags & AMX_FLAG_DEBUG)!=0; /* set up the registers */ hdr=(AMX_HEADER *)amx->base; + codesize=(ucell)(hdr->dat-hdr->cod); code=amx->base+(int)hdr->cod; data=(amx->data!=NULL) ? amx->data : amx->base+(int)hdr->dat; hea=amx->hea; @@ -1260,14 +1472,13 @@ static void *labels[] = { reset_stk=stk; reset_hea=hea; frm=0; /* just to avoid compiler warnings */ - /* get the start address */ - /*if (index==AMX_EXEC_MAIN) { + if (index==AMX_EXEC_MAIN) { if (hdr->cip<0) return AMX_ERR_INDEX; cip=(cell *)(code + (int)hdr->cip); } else if (index==AMX_EXEC_CONT) { - // all registers: pri, alt, frm, cip, hea, stk, reset_stk, reset_hea + /* all registers: pri, alt, frm, cip, hea, stk, reset_stk, reset_hea */ frm=amx->frm; stk=amx->stk; hea=amx->hea; @@ -1279,26 +1490,25 @@ static void *labels[] = { } else if (index<0) { return AMX_ERR_INDEX; } else { - if (index>=NUMENTRIES(*hdr,publics,natives)) - return AMX_ERR_INDEX;*/ - func=(AMX_FUNCSTUB *)(amx->base + (int)hdr->publics + index*sizeof(AMX_FUNCSTUB)); + if (index>=NUMENTRIES(hdr,publics,natives)) + return AMX_ERR_INDEX; + func=GETENTRY(hdr,publics,index); cip=(cell *)(code + (int)func->address); - //} /* if */ + } /* if */ /* check values just copied */ CHKSTACK(); CHKHEAP(); - - //if (debug && index!=AMX_EXEC_CONT) { + init_little_endian(); + if (debug && index!=AMX_EXEC_CONT) { /* set the entry point in the debugger by marking a "call" to the * exported function */ - // amx->dbgcode=DBG_CALL; - // amx->dbgaddr=(ucell)((u_char*)cip-code); - // amx->debug(amx); - //} /* if */ - + amx->dbgcode=DBG_CALL; + amx->dbgaddr=(ucell)((unsigned char*)cip-code); + amx->debug(amx); + } /* if */ /* sanity checks */ - /*assert(OP_PUSH_PRI==36); + assert(OP_PUSH_PRI==36); assert(OP_PROC==46); assert(OP_SHL==65); assert(OP_SMUL==72); @@ -1306,9 +1516,8 @@ static void *labels[] = { assert(OP_INC_PRI==107); assert(OP_MOVS==117); assert(OP_SYMBOL==126); - assert(sizeof(cell)==4);*/ - - //if (index!=AMX_EXEC_CONT) { + assert(sizeof(cell)==4); + if (index!=AMX_EXEC_CONT) { /* push the parameters to the stack (in reverse order) */ if (numparams & 0xFFFF0000) { cell *params; @@ -1327,13 +1536,11 @@ static void *labels[] = { } /* if */ PUSH(numparams*sizeof(cell)); PUSH(0); /* zero return address */ - //} /* if */ + } /* if */ /* check stack/heap before starting to run */ CHKMARGIN(); - /* start running */ NEXT(cip); - op_none: ABORT(amx,AMX_ERR_INVINSTR); op_load_pri: @@ -1374,14 +1581,14 @@ static void *labels[] = { NEXT(cip); op_load_i: /* verify address */ - if (pri>=hea && pri=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=amx->stp) + if (pri>=hea && pri=(ucell)amx->stp) ABORT(amx,AMX_ERR_MEMACCESS); switch (offs) { case 1: @@ -1447,18 +1654,18 @@ static void *labels[] = { NEXT(cip); op_stor_i: /* verify address */ - if (alt>=hea && alt=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=amx->stp) + if (alt>=hea && alt=(ucell)amx->stp) ABORT(amx,AMX_ERR_MEMACCESS); switch (offs) { case 1: - *(data+(int)alt)=(u_char)pri; + *(data+(int)alt)=(unsigned char)pri; break; case 2: *(uint16_t *)(data+(int)alt)=(uint16_t)pri; @@ -1471,7 +1678,7 @@ static void *labels[] = { op_lidx: offs=pri*sizeof(cell)+alt; /* verify address */ - if (offs>=hea && offs=amx->stp) + if (offs>=hea && offs=(ucell)amx->stp) ABORT(amx,AMX_ERR_MEMACCESS); pri= * (cell *)(data+(int)offs); NEXT(cip); @@ -1479,7 +1686,7 @@ static void *labels[] = { GETPARAM(offs); offs=(pri << (int)offs)+alt; /* verify address */ - if (offs>=hea && offs=amx->stp) + if (offs>=hea && offs=(ucell)amx->stp) ABORT(amx,AMX_ERR_MEMACCESS); pri= * (cell *)(data+(int)offs); NEXT(cip); @@ -1522,7 +1729,7 @@ static void *labels[] = { pri=frm; break; case 6: - pri=(cell)((u_char *)cip - code); + pri=(cell)((unsigned char *)cip - code); break; } /* switch */ NEXT(cip); @@ -1594,12 +1801,19 @@ static void *labels[] = { stk+=offs; CHKMARGIN(); CHKSTACK(); - /* if (debug && offs>0) { + if (debug && offs>0) { amx->dbgcode=DBG_CLRSYM; amx->stk=stk; amx->hea=hea; amx->debug(amx); - }*/ /* if */ + } /* if */ + NEXT(cip); + op_stack_nodebug: + GETPARAM(offs); + alt=stk; + stk+=offs; + CHKMARGIN(); + CHKSTACK(); NEXT(cip); op_heap: GETPARAM(offs); @@ -1616,57 +1830,79 @@ static void *labels[] = { op_ret: POP(frm); POP(offs); + /* verify the return address */ + if ((ucell)offs>=codesize) + ABORT(amx,AMX_ERR_MEMACCESS); + cip=(cell *)(code+(int)offs); + if (debug) { + amx->stk=stk; + amx->hea=hea; + amx->dbgcode=DBG_RETURN; + amx->dbgparam=pri; /* store "return value" */ + amx->debug(amx); + } /* if */ + NEXT(cip); + op_ret_nodebug: + POP(frm); + POP(offs); + /* verify the return address */ + if ((ucell)offs>=codesize) + ABORT(amx,AMX_ERR_MEMACCESS); cip=(cell *)(code+(int)offs); - //if (debug) { - // amx->dbgcode=DBG_RETURN; - // amx->dbgparam=pri; /* store "return value" */ - // amx->debug(amx); - //} /* if */ NEXT(cip); op_retn: 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 */ - /*if (debug) { + if (debug) { amx->stk=stk; amx->hea=hea; amx->dbgcode=DBG_RETURN; - amx->dbgparam=pri; //store "return value" + amx->dbgparam=pri; /* store "return value" */ amx->debug(amx); amx->dbgcode=DBG_CLRSYM; amx->debug(amx); - }*/ /* if */ + } /* if */ + NEXT(cip); + op_retn_nodebug: + 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_call: - PUSH(((u_char *)cip-code)+sizeof(cell)); /* push address behind instruction */ + PUSH(((unsigned char *)cip-code)+sizeof(cell));/* push address behind instruction */ + cip=JUMPABS(code, cip); /* jump to the address */ + if (debug) { + amx->dbgcode=DBG_CALL; + amx->dbgaddr=(ucell)((unsigned char*)cip-code); + amx->debug(amx); + } /* if */ + NEXT(cip); + op_call_nodebug: + PUSH(((unsigned char *)cip-code)+sizeof(cell));/* push address behind instruction */ cip=JUMPABS(code, cip); /* jump to the address */ - //if (debug) { - // amx->dbgcode=DBG_CALL; - // amx->dbgaddr=(ucell)((u_char*)cip-code); - // amx->debug(amx); - //} /* if */ NEXT(cip); op_call_pri: - PUSH((u_char *)cip-code); + PUSH((unsigned char *)cip-code); + cip=(cell *)(code+(int)pri); + if (debug) { + amx->dbgcode=DBG_CALL; + amx->dbgaddr=pri; + amx->debug(amx); + } /* if */ + NEXT(cip); + op_call_pri_nodebug: + PUSH((unsigned char *)cip-code); cip=(cell *)(code+(int)pri); - //if (debug) { - // amx->dbgcode=DBG_CALL; - // amx->dbgaddr=pri; - // amx->debug(amx); - //} /* if */ NEXT(cip); -//op_calln: -// GETPARAM(offs); -// PUSH(offs); -// PUSH(((u_char *)cip-code)+sizeof(cell)); /* skip address */ -// cip=JUMPABS(code, cip); /* jump to the address */ -// if (debug) { -// amx->dbgcode=DBG_CALL; -// amx->dbgaddr=(ucell)((u_char *)cip-code); -// amx->debug(amx); -// } /* if */ -// NEXT(cip); op_jump: /* since the GETPARAM() macro modifies cip, you cannot * do GETPARAM(cip) directly */ @@ -1674,79 +1910,79 @@ static void *labels[] = { NEXT(cip); op_jrel: offs=*cip; - cip=(cell *)((u_char *)cip + (int)offs + sizeof(cell)); + cip=(cell *)((unsigned char *)cip + (int)offs + sizeof(cell)); NEXT(cip); op_jzer: if (pri==0) cip=JUMPABS(code, cip); else - cip=(cell *)((u_char *)cip+sizeof(cell)); + cip=(cell *)((unsigned char *)cip+sizeof(cell)); NEXT(cip); op_jnz: if (pri!=0) cip=JUMPABS(code, cip); else - cip=(cell *)((u_char *)cip+sizeof(cell)); + cip=(cell *)((unsigned char *)cip+sizeof(cell)); NEXT(cip); op_jeq: if (pri==alt) cip=JUMPABS(code, cip); else - cip=(cell *)((u_char *)cip+sizeof(cell)); + cip=(cell *)((unsigned char *)cip+sizeof(cell)); NEXT(cip); op_jneq: if (pri!=alt) cip=JUMPABS(code, cip); else - cip=(cell *)((u_char *)cip+sizeof(cell)); + cip=(cell *)((unsigned char *)cip+sizeof(cell)); NEXT(cip); op_jless: if ((ucell)pri < (ucell)alt) cip=JUMPABS(code, cip); else - cip=(cell *)((u_char *)cip+sizeof(cell)); + cip=(cell *)((unsigned char *)cip+sizeof(cell)); NEXT(cip); op_jleq: if ((ucell)pri <= (ucell)alt) cip=JUMPABS(code, cip); else - cip=(cell *)((u_char *)cip+sizeof(cell)); + cip=(cell *)((unsigned char *)cip+sizeof(cell)); NEXT(cip); op_jgrtr: if ((ucell)pri > (ucell)alt) cip=JUMPABS(code, cip); else - cip=(cell *)((u_char *)cip+sizeof(cell)); + cip=(cell *)((unsigned char *)cip+sizeof(cell)); NEXT(cip); op_jgeq: if ((ucell)pri >= (ucell)alt) cip=JUMPABS(code, cip); else - cip=(cell *)((u_char *)cip+sizeof(cell)); + cip=(cell *)((unsigned char *)cip+sizeof(cell)); NEXT(cip); op_jsless: if (prialt) cip=JUMPABS(code, cip); else - cip=(cell *)((u_char *)cip+sizeof(cell)); + cip=(cell *)((unsigned char *)cip+sizeof(cell)); NEXT(cip); op_jsgeq: if (pri>=alt) cip=JUMPABS(code, cip); else - cip=(cell *)((u_char *)cip+sizeof(cell)); + cip=(cell *)((unsigned char *)cip+sizeof(cell)); NEXT(cip); op_shl: pri<<=alt; @@ -1944,14 +2180,41 @@ static void *labels[] = { NEXT(cip); op_movs: GETPARAM(offs); + /* verify top & bottom memory addresses, for both source and destination + * addresses + */ + if (pri>=hea && pri=(ucell)amx->stp) + ABORT(amx,AMX_ERR_MEMACCESS); + if ((pri+offs)>hea && (pri+offs)(ucell)amx->stp) + ABORT(amx,AMX_ERR_MEMACCESS); + if (alt>=hea && alt=(ucell)amx->stp) + ABORT(amx,AMX_ERR_MEMACCESS); + 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); op_cmps: GETPARAM(offs); + /* verify top & bottom memory addresses, for both source and destination + * addresses + */ + if (pri>=hea && pri=(ucell)amx->stp) + ABORT(amx,AMX_ERR_MEMACCESS); + if ((pri+offs)>hea && (pri+offs)(ucell)amx->stp) + ABORT(amx,AMX_ERR_MEMACCESS); + if (alt>=hea && alt=(ucell)amx->stp) + ABORT(amx,AMX_ERR_MEMACCESS); + 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) + ABORT(amx,AMX_ERR_MEMACCESS); + 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)) *(cell *)(data+i) = pri; NEXT(cip); @@ -1965,36 +2228,38 @@ static void *labels[] = { amx->hea=hea; amx->pri=pri; amx->alt=alt; - amx->cip=(cell)((u_char*)cip-code); - //if (debug) { - // amx->dbgcode=DBG_TERMINATE; - // amx->dbgaddr=(cell)((u_char *)cip-code); - // amx->dbgparam=offs; - // amx->debug(amx); - // } /* if */ - //if (offs==AMX_ERR_SLEEP) { - // amx->reset_stk=reset_stk; - // amx->reset_hea=reset_hea; - // return (int)offs; - //} /* if */ + amx->cip=(cell)((unsigned char*)cip-code); + if (debug) { + amx->dbgcode=DBG_TERMINATE; + amx->dbgaddr=(cell)((unsigned char *)cip-code); + amx->dbgparam=offs; + amx->debug(amx); + } /* if */ + if (offs==AMX_ERR_SLEEP) { + amx->reset_stk=reset_stk; + amx->reset_hea=reset_hea; + return (int)offs; + } /* if */ ABORT(amx,(int)offs); op_bounds: GETPARAM(offs); - if (pri>=offs || pri<0) + if ((ucell)pri>(ucell)offs) ABORT(amx,AMX_ERR_BOUNDS); NEXT(cip); op_sysreq_pri: /* save a few registers */ - amx->cip=(cell)((u_char *)cip-code); + amx->cip=(cell)((unsigned char *)cip-code); amx->hea=hea; amx->frm=frm; amx->stk=stk; num=amx->callback(amx,pri,&pri,(cell *)(data+(int)stk)); 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 (int)offs; + return num; } /* if */ ABORT(amx,num); } /* if */ @@ -2002,38 +2267,64 @@ static void *labels[] = { op_sysreq_c: GETPARAM(offs); /* save a few registers */ - amx->cip=(cell)((u_char *)cip-code); + amx->cip=(cell)((unsigned char *)cip-code); amx->hea=hea; amx->frm=frm; amx->stk=stk; num=amx->callback(amx,offs,&pri,(cell *)(data+(int)stk)); 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 (int)offs; + return num; } /* if */ ABORT(amx,num); } /* if */ NEXT(cip); + op_sysreq_d: + GETPARAM(offs); + /* save a few registers */ + amx->cip=(cell)((unsigned char *)cip-code); + amx->hea=hea; + amx->frm=frm; + amx->stk=stk; + pri=((AMX_NATIVE)offs)(amx,(cell *)(data+(int)stk)); + if (amx->error!=AMX_ERR_NONE) { + if (amx->error==AMX_ERR_SLEEP) { + amx->pri=pri; + amx->alt=alt; + amx->reset_stk=reset_stk; + amx->reset_hea=reset_hea; + return num; + } /* if */ + ABORT(amx,amx->error); + } /* if */ + NEXT(cip); op_file: GETPARAM(offs); - cip=(cell *)((u_char *)cip + (int)offs); + cip=(cell *)((unsigned char *)cip + (int)offs); 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); - //if (debug) { - // amx->frm=frm; - // amx->stk=stk; - // amx->hea=hea; - // amx->dbgcode=DBG_LINE; - // num=amx->debug(amx); - // if (num!=AMX_ERR_NONE) - // ABORT(amx,num); - // } /* if */ + if (debug) { + amx->frm=frm; + amx->stk=stk; + amx->hea=hea; + amx->dbgcode=DBG_LINE; + num=amx->debug(amx); + if (num!=AMX_ERR_NONE) + ABORT(amx,num); + } /* if */ + NEXT(cip); + op_line_nodebug: + assert((amx->flags & AMX_FLAG_BROWSE)==0); + GETPARAM(amx->curline); + GETPARAM(amx->curfile); NEXT(cip); op_symbol: assert((amx->flags & AMX_FLAG_BROWSE)==0); @@ -2041,30 +2332,51 @@ static void *labels[] = { GETPARAM(amx->dbgaddr); GETPARAM(amx->dbgparam); amx->dbgname=(char *)cip; - cip=(cell *)((u_char *)cip + (int)offs - 2*sizeof(cell)); + cip=(cell *)((unsigned char *)cip + (int)offs - 2*sizeof(cell)); amx->dbgcode=DBG_SYMBOL; assert((amx->dbgparam >> 8)>0); /* local symbols only */ - // if (debug) { - // amx->frm=frm; /* debugger needs this to relocate the symbols */ - // amx->debug(amx); - // } /* if */ + if (debug) { + amx->frm=frm; /* debugger needs this to relocate the symbols */ + amx->debug(amx); + } /* if */ + 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; - // if (debug) { - // amx->frm=frm; /* debugger needs this to relocate the symbols */ - // amx->debug(amx); - // } /* if */ + if (debug) { + amx->frm=frm; /* debugger needs this to relocate the symbols */ + amx->debug(amx); + } /* if */ + NEXT(cip); + op_srange_nodebug: + assert((amx->flags & AMX_FLAG_BROWSE)==0); + cip+=2; + NEXT(cip); + op_symtag: + assert((amx->flags & AMX_FLAG_BROWSE)==0); + GETPARAM(amx->dbgparam); /* tag id */ + amx->dbgcode=DBG_SYMTAG; + if (debug) { + amx->frm=frm; /* debugger needs this to relocate the symbols */ + amx->debug(amx); + } /* if */ + NEXT(cip); + op_symtag_nodebug: + assert((amx->flags & AMX_FLAG_BROWSE)==0); + cip+=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 */ num=(int)*cptr; /* number of records in the case table */ @@ -2094,47 +2406,49 @@ static void *labels[] = { op_nop: NEXT(cip); } - #else /* ANSI C & assembler versions */ - #if defined ASM32 || defined JIT /* For Watcom C/C++ use register calling convention (faster); for - * Microsoft C/C++ (and possibly others) use __cdecl. + * 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. + * calling convention, or the right JIT, respectively. + * jitr.asm is for Watcom's register calling convention, jits.asm for "cdecl". */ #if defined __WATCOMC__ - #if defined amx_Init && !defined STACKARGS /* for AMX32.DLL */ + #if !defined STACKARGS /* for AMX32.DLL */ extern cell amx_exec_asm(cell *regs,cell *retval,cell stp,cell hea); /* The following pragma tells the compiler into which registers * the parameters have to go. */ #pragma aux amx_exec_asm parm [eax] [edx] [ebx] [ecx]; #else - extern cell AMXAPI amx_exec_asm(cell *regs,cell *retval,cell stp,cell hea); + extern cell __cdecl amx_exec_asm(cell *regs,cell *retval,cell stp,cell hea); #endif + #elif defined __GNUC__ + /* force "cdecl" by adding an "attribute" to the declaration */ + extern cell amx_exec_asm(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 cell __cdecl amx_exec_asm(cell *regs,cell *retval,cell stp,cell hea); #endif #endif - -//#include - int AMXAPI amx_Exec(AMX *amx, cell *retval, int index, int numparams, ...) { AMX_HEADER *hdr; AMX_FUNCSTUB *func; - u_char *code, *data; + unsigned char *code, *data; cell pri,alt,stk,frm,hea; cell reset_stk, reset_hea, *cip; + ucell codesize; int i; va_list ap; - //int debug; + int debug; #if defined ASM32 || defined JIT extern void *amx_opcodelist[]; + extern void *amx_opcodelist_nodebug[]; #ifdef __WATCOMC__ #pragma aux amx_opcodelist "_*" + #pragma aux amx_opcodelist_nodebug "_*" #endif cell parms[9]; /* MP: registers for assembler AMX */ #else @@ -2142,34 +2456,37 @@ int AMXAPI amx_Exec(AMX *amx, cell *retval, int index, int numparams, ...) cell offs; int num; #endif - #if defined ASM32 || defined JIT /* HACK: return label table (for amx_BrowseRelocate) if amx structure * is not passed. */ - if (amx==NULL) { + if ((amx->flags & AMX_FLAG_BROWSE)==AMX_FLAG_BROWSE) { assert(sizeof(cell)==sizeof(void *)); assert(retval!=NULL); - *retval=(cell)amx_opcodelist; + #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 + */ + *retval=(cell)amx_opcodelist; + #else + *retval=(cell)((amx->flags & AMX_FLAG_DEBUG)==0 ? amx_opcodelist_nodebug : amx_opcodelist); + #endif return 0; } /* if */ #endif - 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; - - amx->flags &= ~AMX_FLAG_BROWSE; + i=amx_Register(amx,NULL,0); /* verify that all natives are registered */ + if (i!=AMX_ERR_NONE) + return i; if ((amx->flags & AMX_FLAG_RELOC)==0) return AMX_ERR_INIT; - //debug= (amx->flags & AMX_FLAG_DEBUG)!=0; - + assert((amx->flags & AMX_FLAG_BROWSE)==0); + debug= (amx->flags & AMX_FLAG_DEBUG)!=0; /* set up the registers */ hdr=(AMX_HEADER *)amx->base; + codesize=(ucell)(hdr->dat-hdr->cod); code=amx->base+(int)hdr->cod; data=(amx->data!=NULL) ? amx->data : amx->base+(int)hdr->dat; hea=amx->hea; @@ -2177,60 +2494,56 @@ int AMXAPI amx_Exec(AMX *amx, cell *retval, int index, int numparams, ...) reset_stk=stk; reset_hea=hea; frm=alt=pri=0; /* silence up compiler */ - /* get the start address */ - //if (index==AMX_EXEC_MAIN) { - // if (hdr->cip<0) - // return AMX_ERR_INDEX; - // cip=(cell *)(code + (int)hdr->cip); - //} else if (index==AMX_EXEC_CONT) { - /* all registers: pri, alt, frm, cip, hea, stk, reset_stk, reset_hea */ - // frm=amx->frm; - // stk=amx->stk; - // hea=amx->hea; - // pri=amx->pri; - // alt=amx->alt; - // reset_stk=amx->reset_stk; - // reset_hea=amx->reset_hea; - // cip=(cell *)(code + (int)amx->cip); - //} else if (index<0) { - // return AMX_ERR_INDEX; - //} else { - if (index>=(cell)NUMENTRIES(*hdr,publics,natives)) + if (index==AMX_EXEC_MAIN) { + if (hdr->cip<0) return AMX_ERR_INDEX; - func=(AMX_FUNCSTUB *)(amx->base + (int)hdr->publics + index*sizeof(AMX_FUNCSTUB)); + cip=(cell *)(code + (int)hdr->cip); + } else if (index==AMX_EXEC_CONT) { + /* all registers: pri, alt, frm, cip, hea, stk, reset_stk, reset_hea */ + frm=amx->frm; + stk=amx->stk; + hea=amx->hea; + pri=amx->pri; + alt=amx->alt; + reset_stk=amx->reset_stk; + reset_hea=amx->reset_hea; + cip=(cell *)(code + (int)amx->cip); + } else if (index<0) { + return AMX_ERR_INDEX; + } else { + if (index>=(cell)NUMENTRIES(hdr,publics,natives)) + return AMX_ERR_INDEX; + func=GETENTRY(hdr,publics,index); cip=(cell *)(code + (int)func->address); - //} /* if */ + } /* if */ /* check values just copied */ CHKSTACK(); CHKHEAP(); - - - //if (debug && index!=AMX_EXEC_CONT) { + init_little_endian(); + if (debug && index!=AMX_EXEC_CONT) { /* set the entry point in the debugger by marking a "call" to the * exported function */ - // amx->dbgcode=DBG_CALL; - // amx->dbgaddr=(ucell)((u_char *)cip-code); - // amx->debug(amx); - //} /* if */ - + amx->dbgcode=DBG_CALL; + amx->dbgaddr=(ucell)((unsigned char *)cip-code); + amx->debug(amx); + } /* if */ /* sanity checks */ - //assert(OP_PUSH_PRI==36); - //assert(OP_PROC==46); - //assert(OP_SHL==65); - //assert(OP_SMUL==72); - // assert(OP_EQ==95); - // assert(OP_INC_PRI==107); - //assert(OP_MOVS==117); - //assert(OP_SYMBOL==126); - //#if defined(BIT16) - // assert(sizeof(cell)==2); - //#else - // assert(sizeof(cell)==4); - //#endif - - //if (index!=AMX_EXEC_CONT) { + assert(OP_PUSH_PRI==36); + assert(OP_PROC==46); + assert(OP_SHL==65); + assert(OP_SMUL==72); + assert(OP_EQ==95); + assert(OP_INC_PRI==107); + assert(OP_MOVS==117); + assert(OP_SYMBOL==126); + #if defined(BIT16) + assert(sizeof(cell)==2); + #else + assert(sizeof(cell)==4); + #endif + if (index!=AMX_EXEC_CONT) { /* push the parameters to the stack (in reverse order) */ if (numparams & 0xFFFF0000L) { cell *params; @@ -2248,19 +2561,17 @@ int AMXAPI amx_Exec(AMX *amx, cell *retval, int index, int numparams, ...) va_end(ap); } /* if */ PUSH(numparams*sizeof(cell)); - //#if defined ASM32 || defined JIT - // PUSH(RELOC_VALUE(code,0));/* relocated zero return address */ - //#else + #if defined ASM32 || defined JIT + PUSH(RELOC_VALUE(code,0));/* relocated zero return address */ + #else PUSH(0); /* zero return address */ - //#endif - //} /* if */ + #endif + } /* if */ /* check stack/heap before starting to run */ CHKMARGIN(); - /* start running */ #if defined ASM32 || defined JIT /* either the assembler abstract machine or the JIT; both by Marc Peter */ - parms[0] = pri; parms[1] = alt; parms[2] = (cell)cip; @@ -2269,8 +2580,7 @@ int AMXAPI amx_Exec(AMX *amx, cell *retval, int index, int numparams, ...) parms[5] = frm; parms[6] = (cell)amx; parms[7] = (cell)code; -// parms[8] = (cell)debug; - + parms[8] = (cell)debug; i = amx_exec_asm(parms,retval,amx->stp,hea); if (i == AMX_ERR_SLEEP) { amx->reset_stk=reset_stk; @@ -2284,9 +2594,7 @@ int AMXAPI amx_Exec(AMX *amx, cell *retval, int index, int numparams, ...) amx->hea=reset_hea; } /* if */ return i; - #else - for ( ;; ) { op=(OPCODE) *cip++; switch (op) { @@ -2328,14 +2636,14 @@ int AMXAPI amx_Exec(AMX *amx, cell *retval, int index, int numparams, ...) break; case OP_LOAD_I: /* verify address */ - if (pri>=hea && pri=amx->stp) + if (pri>=hea && pri=(ucell)amx->stp) ABORT(amx,AMX_ERR_MEMACCESS); pri= * (cell *)(data+(int)pri); break; case OP_LODB_I: GETPARAM(offs); /* verify address */ - if (pri>=hea && pri=amx->stp) + if (pri>=hea && pri=(ucell)amx->stp) ABORT(amx,AMX_ERR_MEMACCESS); switch (offs) { case 1: @@ -2401,18 +2709,18 @@ int AMXAPI amx_Exec(AMX *amx, cell *retval, int index, int numparams, ...) break; case OP_STOR_I: /* verify address */ - if (alt>=hea && alt=amx->stp) + if (alt>=hea && alt=(ucell)amx->stp) ABORT(amx,AMX_ERR_MEMACCESS); *(cell *)(data+(int)alt)=pri; break; case OP_STRB_I: GETPARAM(offs); /* verify address */ - if (alt>=hea && alt=amx->stp) + if (alt>=hea && alt=(ucell)amx->stp) ABORT(amx,AMX_ERR_MEMACCESS); switch (offs) { case 1: - *(data+(int)alt)=(u_char)pri; + *(data+(int)alt)=(unsigned char)pri; break; case 2: *(uint16_t *)(data+(int)alt)=(uint16_t)pri; @@ -2425,7 +2733,7 @@ int AMXAPI amx_Exec(AMX *amx, cell *retval, int index, int numparams, ...) case OP_LIDX: offs=pri*sizeof(cell)+alt; /* verify address */ - if (offs>=hea && offs=amx->stp) + if (offs>=hea && offs=(ucell)amx->stp) ABORT(amx,AMX_ERR_MEMACCESS); pri= * (cell *)(data+(int)offs); break; @@ -2433,7 +2741,7 @@ int AMXAPI amx_Exec(AMX *amx, cell *retval, int index, int numparams, ...) GETPARAM(offs); offs=(pri << (int)offs)+alt; /* verify address */ - if (offs>=hea && offs=amx->stp) + if (offs>=hea && offs=(ucell)amx->stp) ABORT(amx,AMX_ERR_MEMACCESS); pri= * (cell *)(data+(int)offs); break; @@ -2476,7 +2784,7 @@ int AMXAPI amx_Exec(AMX *amx, cell *retval, int index, int numparams, ...) pri=frm; break; case 6: - pri=(cell)((u_char *)cip - code); + pri=(cell)((unsigned char *)cip - code); break; } /* switch */ break; @@ -2548,12 +2856,12 @@ int AMXAPI amx_Exec(AMX *amx, cell *retval, int index, int numparams, ...) stk+=offs; CHKMARGIN(); CHKSTACK(); - /*if (debug && offs>0) { + if (debug && offs>0) { amx->dbgcode=DBG_CLRSYM; amx->hea=hea; amx->stk=stk; amx->debug(amx); - } *//* if */ + } /* if */ break; case OP_HEAP: GETPARAM(offs); @@ -2570,58 +2878,55 @@ int AMXAPI amx_Exec(AMX *amx, cell *retval, int index, int numparams, ...) case OP_RET: POP(frm); POP(offs); + /* verify the return address */ + if ((ucell)offs>=codesize) + ABORT(amx,AMX_ERR_MEMACCESS); cip=(cell *)(code+(int)offs); - //if (debug) { - // amx->dbgcode=DBG_RETURN; - // amx->dbgparam=pri; /* store "return value" */ - // amx->debug(amx); - //} /* if */ + if (debug) { + amx->stk=stk; + amx->hea=hea; + amx->dbgcode=DBG_RETURN; + amx->dbgparam=pri; /* store "return value" */ + amx->debug(amx); + } /* if */ break; case OP_RETN: 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 */ amx->stk=stk; - //if (debug) { - // amx->stk=stk; - // amx->hea=hea; - // amx->dbgcode=DBG_RETURN; - // amx->dbgparam=pri; /* store "return value" */ - // amx->debug(amx); - // amx->dbgcode=DBG_CLRSYM; - // amx->debug(amx); - //} /* if */ + if (debug) { + amx->stk=stk; + amx->hea=hea; + amx->dbgcode=DBG_RETURN; + amx->dbgparam=pri; /* store "return value" */ + amx->debug(amx); + amx->dbgcode=DBG_CLRSYM; + amx->debug(amx); + } /* if */ break; case OP_CALL: - PUSH(((u_char *)cip-code)+sizeof(cell)); /* skip address */ + PUSH(((unsigned char *)cip-code)+sizeof(cell));/* skip address */ cip=JUMPABS(code, cip); /* jump to the address */ - //if (debug) { - // amx->dbgcode=DBG_CALL; - // amx->dbgaddr=(ucell)((u_char *)cip-code); - // amx->debug(amx); - // } /* if */ + if (debug) { + amx->dbgcode=DBG_CALL; + amx->dbgaddr=(ucell)((unsigned char *)cip-code); + amx->debug(amx); + } /* if */ break; case OP_CALL_PRI: - PUSH((u_char *)cip-code); + PUSH((unsigned char *)cip-code); cip=(cell *)(code+(int)pri); - //if (debug) { - // amx->dbgcode=DBG_CALL; - // amx->dbgaddr=pri; - // amx->debug(amx); - //} /* if */ + if (debug) { + amx->dbgcode=DBG_CALL; + amx->dbgaddr=pri; + amx->debug(amx); + } /* if */ break; -// case OP_CALLN: -// GETPARAM(offs); -// PUSH(offs); -// PUSH(((u_char *)cip-code)+sizeof(cell)); /* skip address */ -// cip=JUMPABS(code, cip); /* jump to the address */ -// if (debug) { -// amx->dbgcode=DBG_CALL; -// amx->dbgaddr=(ucell)((u_char *)cip-code); -// amx->debug(amx); -// } /* if */ -// break; case OP_JUMP: /* since the GETPARAM() macro modifies cip, you cannot * do GETPARAM(cip) directly */ @@ -2629,79 +2934,79 @@ int AMXAPI amx_Exec(AMX *amx, cell *retval, int index, int numparams, ...) break; case OP_JREL: offs=*cip; - cip=(cell *)((u_char *)cip + (int)offs + sizeof(cell)); + cip=(cell *)((unsigned char *)cip + (int)offs + sizeof(cell)); break; case OP_JZER: if (pri==0) cip=JUMPABS(code, cip); else - cip=(cell *)((u_char *)cip+sizeof(cell)); + cip=(cell *)((unsigned char *)cip+sizeof(cell)); break; case OP_JNZ: if (pri!=0) cip=JUMPABS(code, cip); else - cip=(cell *)((u_char *)cip+sizeof(cell)); + cip=(cell *)((unsigned char *)cip+sizeof(cell)); break; case OP_JEQ: if (pri==alt) cip=JUMPABS(code, cip); else - cip=(cell *)((u_char *)cip+sizeof(cell)); + cip=(cell *)((unsigned char *)cip+sizeof(cell)); break; case OP_JNEQ: if (pri!=alt) cip=JUMPABS(code, cip); else - cip=(cell *)((u_char *)cip+sizeof(cell)); + cip=(cell *)((unsigned char *)cip+sizeof(cell)); break; case OP_JLESS: if ((ucell)pri < (ucell)alt) cip=JUMPABS(code, cip); else - cip=(cell *)((u_char *)cip+sizeof(cell)); + cip=(cell *)((unsigned char *)cip+sizeof(cell)); break; case OP_JLEQ: if ((ucell)pri <= (ucell)alt) cip=JUMPABS(code, cip); else - cip=(cell *)((u_char *)cip+sizeof(cell)); + cip=(cell *)((unsigned char *)cip+sizeof(cell)); break; case OP_JGRTR: if ((ucell)pri > (ucell)alt) cip=JUMPABS(code, cip); else - cip=(cell *)((u_char *)cip+sizeof(cell)); + cip=(cell *)((unsigned char *)cip+sizeof(cell)); break; case OP_JGEQ: if ((ucell)pri >= (ucell)alt) cip=JUMPABS(code, cip); else - cip=(cell *)((u_char *)cip+sizeof(cell)); + cip=(cell *)((unsigned char *)cip+sizeof(cell)); break; case OP_JSLESS: if (prialt) cip=JUMPABS(code, cip); else - cip=(cell *)((u_char *)cip+sizeof(cell)); + cip=(cell *)((unsigned char *)cip+sizeof(cell)); break; case OP_JSGEQ: if (pri>=alt) cip=JUMPABS(code, cip); else - cip=(cell *)((u_char *)cip+sizeof(cell)); + cip=(cell *)((unsigned char *)cip+sizeof(cell)); break; case OP_SHL: pri<<=alt; @@ -2899,14 +3204,41 @@ int AMXAPI amx_Exec(AMX *amx, cell *retval, int index, int numparams, ...) break; case OP_MOVS: GETPARAM(offs); + /* verify top & bottom memory addresses, for both source and destination + * addresses + */ + if (pri>=hea && pri=(ucell)amx->stp) + ABORT(amx,AMX_ERR_MEMACCESS); + if ((pri+offs)>hea && (pri+offs)(ucell)amx->stp) + ABORT(amx,AMX_ERR_MEMACCESS); + if (alt>=hea && alt=(ucell)amx->stp) + ABORT(amx,AMX_ERR_MEMACCESS); + if ((alt+offs)>hea && (alt+offs)(ucell)amx->stp) + ABORT(amx,AMX_ERR_MEMACCESS); memcpy(data+(int)alt, data+(int)pri, (int)offs); break; case OP_CMPS: GETPARAM(offs); + /* verify top & bottom memory addresses, for both source and destination + * addresses + */ + if (pri>=hea && pri=(ucell)amx->stp) + ABORT(amx,AMX_ERR_MEMACCESS); + if ((pri+offs)>hea && (pri+offs)(ucell)amx->stp) + ABORT(amx,AMX_ERR_MEMACCESS); + if (alt>=hea && alt=(ucell)amx->stp) + ABORT(amx,AMX_ERR_MEMACCESS); + if ((alt+offs)>hea && (alt+offs)(ucell)amx->stp) + ABORT(amx,AMX_ERR_MEMACCESS); pri=memcmp(data+(int)alt, data+(int)pri, (int)offs); break; case OP_FILL: GETPARAM(offs); + /* verify top & bottom memory addresses (destination only) */ + if (alt>=hea && alt=(ucell)amx->stp) + ABORT(amx,AMX_ERR_MEMACCESS); + if ((alt+offs)>hea && (alt+offs)(ucell)amx->stp) + ABORT(amx,AMX_ERR_MEMACCESS); for (i=(int)alt; (size_t)offs>=sizeof(cell); i+=sizeof(cell), offs-=sizeof(cell)) *(cell *)(data+i) = pri; break; @@ -2920,13 +3252,13 @@ int AMXAPI amx_Exec(AMX *amx, cell *retval, int index, int numparams, ...) amx->hea=hea; amx->pri=pri; amx->alt=alt; - amx->cip=(cell)((u_char*)cip-code); - //if (debug) { - // amx->dbgcode=DBG_TERMINATE; - // amx->dbgaddr=(cell)((u_char *)cip-code); - // amx->dbgparam=offs; - // amx->debug(amx); - //} /* if */ + amx->cip=(cell)((unsigned char*)cip-code); + if (debug) { + amx->dbgcode=DBG_TERMINATE; + amx->dbgaddr=(cell)((unsigned char *)cip-code); + amx->dbgparam=offs; + amx->debug(amx); + } /* if */ if (offs==AMX_ERR_SLEEP) { amx->reset_stk=reset_stk; amx->reset_hea=reset_hea; @@ -2935,21 +3267,23 @@ int AMXAPI amx_Exec(AMX *amx, cell *retval, int index, int numparams, ...) ABORT(amx,(int)offs); case OP_BOUNDS: GETPARAM(offs); - if (pri>=offs || pri<0) + if ((ucell)pri>(ucell)offs) ABORT(amx,AMX_ERR_BOUNDS); break; case OP_SYSREQ_PRI: /* save a few registers */ - amx->cip=(cell)((u_char *)cip-code); + amx->cip=(cell)((unsigned char *)cip-code); amx->hea=hea; amx->frm=frm; amx->stk=stk; num=amx->callback(amx,pri,&pri,(cell *)(data+(int)stk)); 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 (int)offs; + return num; } /* if */ ABORT(amx,num); } /* if */ @@ -2957,30 +3291,51 @@ int AMXAPI amx_Exec(AMX *amx, cell *retval, int index, int numparams, ...) case OP_SYSREQ_C: GETPARAM(offs); /* save a few registers */ - amx->cip=(cell)((u_char *)cip-code); + amx->cip=(cell)((unsigned char *)cip-code); amx->hea=hea; amx->frm=frm; amx->stk=stk; num=amx->callback(amx,offs,&pri,(cell *)(data+(int)stk)); 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 (int)offs; + return num; } /* if */ ABORT(amx,num); } /* if */ break; + case OP_SYSREQ_D: + GETPARAM(offs); + /* save a few registers */ + amx->cip=(cell)((unsigned char *)cip-code); + amx->hea=hea; + amx->frm=frm; + amx->stk=stk; + pri=((AMX_NATIVE)offs)(amx,(cell *)(data+(int)stk)); + if (amx->error!=AMX_ERR_NONE) { + if (amx->error==AMX_ERR_SLEEP) { + amx->pri=pri; + amx->alt=alt; + amx->reset_stk=reset_stk; + amx->reset_hea=reset_hea; + return num; + } /* if */ + ABORT(amx,amx->error); + } /* if */ + break; case OP_FILE: GETPARAM(offs); - cip=(cell *)((u_char *)cip+(int)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); - /*if (debug) { + if (debug) { amx->frm=frm; amx->stk=stk; amx->hea=hea; @@ -2988,7 +3343,7 @@ int AMXAPI amx_Exec(AMX *amx, cell *retval, int index, int numparams, ...) num=amx->debug(amx); if (num!=AMX_ERR_NONE) ABORT(amx,num); - } *//* if */ + } /* if */ break; case OP_SYMBOL: assert((amx->flags & AMX_FLAG_BROWSE)==0); @@ -2996,30 +3351,38 @@ int AMXAPI amx_Exec(AMX *amx, cell *retval, int index, int numparams, ...) GETPARAM(amx->dbgaddr); GETPARAM(amx->dbgparam); amx->dbgname=(char *)cip; - cip=(cell *)((u_char *)cip + (int)offs - 2*sizeof(cell)); + cip=(cell *)((unsigned char *)cip + (int)offs - 2*sizeof(cell)); assert((amx->dbgparam >> 8)>0); /* local symbols only */ - //if (debug) { - // amx->frm=frm; /* debugger needs this to relocate the symbols */ - // amx->dbgcode=DBG_SYMBOL; - // amx->debug(amx); - //} /* if */ + if (debug) { + amx->frm=frm; /* debugger needs this to relocate the symbols */ + amx->dbgcode=DBG_SYMBOL; + amx->debug(amx); + } /* if */ break; case OP_SRANGE: assert((amx->flags & AMX_FLAG_BROWSE)==0); GETPARAM(amx->dbgaddr); /* dimension level */ GETPARAM(amx->dbgparam); /* length */ - //if (debug) { - // amx->frm=frm; /* debugger needs this to relocate the symbols */ - // amx->dbgcode=DBG_SRANGE; - // amx->debug(amx); - //} /* if */ + if (debug) { + amx->frm=frm; /* debugger needs this to relocate the symbols */ + amx->dbgcode=DBG_SRANGE; + amx->debug(amx); + } /* if */ + break; + case OP_SYMTAG: + assert((amx->flags & AMX_FLAG_BROWSE)==0); + GETPARAM(amx->dbgparam); /* tag id */ + if (debug) { + amx->frm=frm; /* debugger needs this to relocate the symbols */ + amx->dbgcode=DBG_SYMTAG; + amx->debug(amx); + } /* if */ break; case OP_JUMP_PRI: cip=(cell *)(code+(int)pri); break; case OP_SWITCH: { cell *cptr; - cptr=(cell *)*cip + 1; /* +1, to skip the "casetbl" opcode */ cip=(cell *)*(cptr+1); /* preset to "none-matched" case */ num=(int)*cptr; /* number of records in the case table */ @@ -3054,9 +3417,7 @@ int AMXAPI amx_Exec(AMX *amx, cell *retval, int index, int numparams, ...) } /* for */ #endif } - #endif /* __GNUC__ */ - /* For interfacing applications not written in C/C++, amx_Execv() works like * amx_Exec(), but has all parameters passed via an array. */ @@ -3064,7 +3425,8 @@ int AMXAPI amx_Execv(AMX *amx, cell *retval, int index, int numparams, cell para { return amx_Exec(amx, retval, index, numparams<<16, params); } - +#endif /* AMX_EXEC || AMX_INIT */ +#if defined AMX_SETCALLBACK int AMXAPI amx_SetCallback(AMX *amx,AMX_CALLBACK callback) { assert(amx!=NULL); @@ -3072,7 +3434,8 @@ int AMXAPI amx_SetCallback(AMX *amx,AMX_CALLBACK callback) amx->callback=callback; return AMX_ERR_NONE; } - +#endif /* AMX_SETCALLBACK */ +#if defined AMX_SETDEBUGHOOK int AMXAPI amx_SetDebugHook(AMX *amx,AMX_DEBUG debug) { assert(amx!=NULL); @@ -3080,40 +3443,42 @@ int AMXAPI amx_SetDebugHook(AMX *amx,AMX_DEBUG debug) amx->debug=debug; return AMX_ERR_NONE; } - +#endif /* AMX_SETDEBUGHOOK */ +#if defined AMX_RAISEERROR int AMXAPI amx_RaiseError(AMX *amx, int error) { assert(error>0); amx->error=error; return AMX_ERR_NONE; } - +#endif /* AMX_RAISEERROR */ +#if defined AMX_GETADDR int AMXAPI amx_GetAddr(AMX *amx,cell amx_addr,cell **phys_addr) { AMX_HEADER *hdr; - u_char *data; - + unsigned char *data; assert(amx!=NULL); hdr=(AMX_HEADER *)amx->base; assert(hdr!=NULL); data=(amx->data!=NULL) ? amx->data : amx->base+(int)hdr->dat; - - if (amx_addr>=amx->hea && amx_addrstk || amx_addr<0 || amx_addr>=amx->stp) + assert(phys_addr!=NULL); + if (amx_addr>=amx->hea && amx_addrstk || amx_addr<0 || amx_addr>=amx->stp) { + *phys_addr=NULL; return AMX_ERR_MEMACCESS; + } /* if */ *phys_addr=(cell *)(data + (int)amx_addr); return AMX_ERR_NONE; } - +#endif /* AMX_GETADDR */ +#if defined AMX_ALLOT int AMXAPI amx_Allot(AMX *amx,int cells,cell *amx_addr,cell **phys_addr) { AMX_HEADER *hdr; - u_char *data; - + unsigned char *data; assert(amx!=NULL); hdr=(AMX_HEADER *)amx->base; assert(hdr!=NULL); data=(amx->data!=NULL) ? amx->data : amx->base+(int)hdr->dat; - if (amx->stk - amx->hea - cells*sizeof(cell) < STKMARGIN) return AMX_ERR_MEMORY; assert(amx_addr!=NULL); @@ -3123,28 +3488,33 @@ int AMXAPI amx_Allot(AMX *amx,int cells,cell *amx_addr,cell **phys_addr) amx->hea += cells*sizeof(cell); return AMX_ERR_NONE; } - int AMXAPI amx_Release(AMX *amx,cell amx_addr) { if (amx->hea > amx_addr) amx->hea=amx_addr; return AMX_ERR_NONE; } - +#endif /* AMX_ALLOT */ +#if defined AMX_XXXSTRING #define CHARBITS (8*sizeof(char)) #if defined BIT16 #define CHARMASK (0xffffu << 8*(2-sizeof(char))) #else #define CHARMASK (0xffffffffuL << 8*(4-sizeof(char))) #endif - int AMXAPI amx_StrLen(cell *cstr, int *length) { - register int len = 0; + int len; + assert(length!=NULL); + if (cstr==NULL) { + *length=0; + return AMX_ERR_PARAMS; + } /* if */ if ((ucell)*cstr>UCHAR_MAX) { /* packed string */ assert(sizeof(char)==1); /* Unicode needs different functions */ len=strlen((char *)cstr); /* find '\0' */ + init_little_endian(); if (amx_LittleEndian) { /* on Little Endian machines, toggle the last bytes */ cell c=cstr[len/sizeof(cell)]; /* get last cell */ @@ -3155,54 +3525,94 @@ int AMXAPI amx_StrLen(cell *cstr, int *length) } /* if */ } /* if */ } else { - while( cstr[ len ] ) - ++len; - /* nothing */ + for (len=0; cstr[len]!=0; len++) + /* nothing */; } /* if */ *length = len; return AMX_ERR_NONE; } - int AMXAPI amx_SetString(cell *dest,char *source,int pack) { /* the memory blocks should not overlap */ - if (pack) { int len=strlen(source); + if (pack) { /* create a packed string */ dest[len/sizeof(cell)]=0; /* clear last bytes of last (semi-filled) cell*/ memcpy(dest,source,len); /* On Big Endian machines, the characters are well aligned in the * cells; on Little Endian machines, we must swap all cells. */ + init_little_endian(); if (amx_LittleEndian) { len /= sizeof(cell); while (len>=0) swapcell((ucell *)&dest[len--]); } /* if */ } else { - /* create an unpacked string */ - while (*dest++=(cell)*source++) - ; + /* create an unpacked string */ + int i; + for (i=0; iUCHAR_MAX) { /* source string is packed */ cell c = 0; /* to avoid a compiler warning */ int i=sizeof(cell)-1; - do { + for ( ;; ) { if (i==sizeof(cell)-1) c=*source++; - *dest=(char)(c >> i*CHARBITS); + dest[len++]=(char)(c >> i*CHARBITS); + if (dest[len-1]=='\0') + break; /* terminating zero character found */ i=(i+sizeof(cell)-1) % sizeof(cell); - } while (*dest++!='\0'); + } /* for */ } else { /* source string is unpacked */ - while (*dest++=(char)*source++) - ; + while (*source!=0) + dest[len++]=(char)*source++; } /* if */ + dest[len]='\0'; /* store terminator */ return AMX_ERR_NONE; } - +#endif /* AMX_XXXSTRING */ +#if defined AMX_STRERROR +char * AMXAPI amx_StrError(int errnum) +{ +static char *messages[] = { + /* AMX_ERR_NONE */ "(none)", + /* AMX_ERR_EXIT */ "Forced exit", + /* AMX_ERR_ASSERT */ "Assertion failed", + /* AMX_ERR_STACKERR */ "Stack/heap collision (insufficient stack size)", + /* AMX_ERR_BOUNDS */ "Array index out of bounds", + /* AMX_ERR_MEMACCESS */ "Invalid memory access", + /* AMX_ERR_INVINSTR */ "Invalid instruction", + /* AMX_ERR_STACKLOW */ "Stack underflow", + /* AMX_ERR_HEAPLOW */ "Heap underflow", + /* AMX_ERR_CALLBACK */ "No (valid) native function callback", + /* AMX_ERR_NATIVE */ "Native function failed", + /* AMX_ERR_DIVIDE */ "Divide by zero", + /* AMX_ERR_SLEEP */ "(sleep mode)", + /* 13 */ "(reserved)", + /* 14 */ "(reserved)", + /* 15 */ "(reserved)", + /* AMX_ERR_MEMORY */ "Out of memory", + /* AMX_ERR_FORMAT */ "Invalid/unsupported P-code file format", + /* AMX_ERR_VERSION */ "File is for a newer version of the AMX", + /* AMX_ERR_NOTFOUND */ "Native/Public function is not found", + /* AMX_ERR_INDEX */ "Invalid index parameter (bad entry point)", + /* AMX_ERR_DEBUG */ "Debugger cannot run", + /* AMX_ERR_INIT */ "AMX not initialized (or doubly initialized)", + /* AMX_ERR_USERDATA */ "Unable to set user data field (table full)", + /* AMX_ERR_INIT_JIT */ "Cannot initialize the JIT", + /* AMX_ERR_PARAMS */ "Parameter error", + }; + if (errnum < 0 || errnum >= sizeof messages / sizeof messages[0]) + return "(unknown)"; + return messages[errnum]; +} +#endif /* AMX_STRERROR */ diff --git a/amxmodx/amx.h b/amxmodx/amx.h index feb13178..d9671d44 100755 --- a/amxmodx/amx.h +++ b/amxmodx/amx.h @@ -1,23 +1,27 @@ /* Abstract Machine for the Small compiler * - * Copyright (c) ITB CompuPhase, 1997-2002 - * This file may be freely used. No warranties of any kind. + * Copyright (c) ITB CompuPhase, 1997-2003 * - * Version: $Id$ + * This software is provided "as-is", without any express or implied warranty. + * In no event will the authors be held liable for any damages arising from + * the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * PM: Whole file changed */ - -#if defined __linux__ +#if defined LINUX #include #endif - #ifndef __AMX_H #define __AMX_H - #if !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 __LCC__ || defined __linux__ + #if defined __LCC__ || defined LINUX #include #else typedef short int int16_t; @@ -31,27 +35,31 @@ #endif #endif #endif - -/* 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 - #define AMX_NO_ALIGN +#if defined __WIN32__ || defined _WIN32 || defined WIN32 || defined __MSDOS__ + #if !defined alloca + #define alloca(n) _alloca(n) + #endif #endif - #ifdef __cplusplus extern "C" { #endif - /* calling convention for native functions */ #if !defined AMX_NATIVE_CALL #define AMX_NATIVE_CALL #endif /* calling convention for all interface functions and callback functions */ #if !defined AMXAPI - #define AMXAPI + #if defined STDECL + #define AMXAPI __stdcall + #elif defined CDECL + #define AMXAPI __cdecl + #else + #define AMXAPI + #endif +#endif +#if !defined AMXEXPORT + #define AMXEXPORT #endif - /* File format version Required AMX version * 0 (original version) 0 * 1 (opcodes JUMP.pri, SWITCH and CASETBL) 1 @@ -60,10 +68,11 @@ extern "C" { * 4 (opcodes SWAP.pri/alt and PUSHADDR) 4 * 5 (tagnames table) 4 * 6 (reformatted header) 6 + * 7 (name table, opcodes SYMTAG & SYSREQ.D) 7 */ -#define MIN_FILE_VERSION 6 /* lowest file format version */ -#define CUR_FILE_VERSION 6 /* current AMX version (parallel with file version) */ - +#define CUR_FILE_VERSION 7 /* 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 */ #if !defined CELL_TYPE #define CELL_TYPE #if defined(BIT16) @@ -74,23 +83,32 @@ extern "C" { typedef int32_t cell; #endif #endif - -struct __amx; -typedef cell (AMX_NATIVE_CALL *AMX_NATIVE)(struct __amx *amx, cell *params); -typedef int (AMXAPI *AMX_CALLBACK)(struct __amx *amx, cell index, +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 __amx *amx); -#if !defined FAR - #define FAR +typedef int (AMXAPI *AMX_DEBUG)(struct tagAMX *amx); +#if !defined _FAR + #define _FAR #endif - #if defined _MSC_VER #pragma warning(disable:4103) /* disable warning message 4103 that complains * about pragma pack in a header file */ + #pragma warning(disable:4100) /* "'%$S' : unreferenced formal parameter" */ +#endif +/* 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__ + #define AMX_NO_ALIGN +#endif +#if defined __GNUC__ + #define PACKED __attribute__((packed)) +#else + #define PACKED #endif - #if !defined AMX_NO_ALIGN - #if defined __linux__ + #if defined LINUX #pragma pack(1) /* structures must be packed (byte-aligned) */ #else #pragma pack(push) @@ -100,74 +118,80 @@ typedef int (AMXAPI *AMX_DEBUG)(struct __amx *amx); #endif #endif #endif - typedef struct { - char FAR *name; - AMX_NATIVE func; -} AMX_NATIVE_INFO; - + char _FAR *name PACKED; + AMX_NATIVE func PACKED; +} AMX_NATIVE_INFO PACKED; #define AMX_USERNUM 4 -#define sEXPMAX 19 -typedef struct { - uint32_t address; - char name[sEXPMAX+1]; -} AMX_FUNCSTUB; - +#define sEXPMAX 19 /* maximum name length for file version <= 6 */ +#define sNAMEMAX 31 /* maximum name length of symbol name */ +typedef struct tagAMX_FUNCSTUB { + uint32_t address PACKED; + char name[sEXPMAX+1] PACKED; +} AMX_FUNCSTUB PACKED; /* 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 __amx { - unsigned char FAR *base; /* points to the AMX header ("amxhdr") plus the code, optionally also the data */ - unsigned char FAR *data; /* points to separate data+stack+heap, may be NULL */ - AMX_CALLBACK callback; - AMX_DEBUG debug; +typedef struct tagAMX { + unsigned char _FAR *base PACKED; /* points to the AMX header ("amxhdr") 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 */ /* for external functions a few registers must be accessible from the outside */ - cell cip; /* relative to base + amxhdr->cod */ - cell frm; /* relative to base + amxhdr->dat */ - cell hea, hlw, stk, stp; /* all four are relative to base + amxhdr->dat */ - int flags; /* current status, see amx_Flags() */ + cell cip PACKED; /* instruction pointer: relative to base + amxhdr->cod */ + cell frm PACKED; /* stack frame base: relative to base + amxhdr->dat */ + cell hea PACKED; /* top of the heap: relative to base + amxhdr->dat */ + cell hlw PACKED; /* bottom of the heap: relative to base + amxhdr->dat */ + 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, curfile; - int dbgcode; - cell dbgaddr, dbgparam; - char FAR *dbgname; + 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]; - void FAR *userdata[AMX_USERNUM]; + long usertags[AMX_USERNUM] PACKED; + void _FAR *userdata[AMX_USERNUM] PACKED; /* native functions can raise an error */ - int error; + int error PACKED; /* the sleep opcode needs to store the full AMX status */ - cell pri, alt, reset_stk, reset_hea; + cell pri PACKED; + cell alt PACKED; + cell reset_stk PACKED; + cell reset_hea PACKED; + cell _FAR *syscall_d PACKED; /* relocated value/address for the SYSCALL.D opcode */ #if defined JIT /* support variables for the JIT */ - int reloc_size; /* required temporary buffer for relocations */ - long code_size; /* estimated memory footprint of the native code */ + int reloc_size PACKED; /* required temporary buffer for relocations */ + long code_size PACKED; /* estimated memory footprint of the native code */ #endif -} AMX; - +} AMX PACKED; /* The AMX_HEADER structure is both the memory format as the file format. The * structure is used internaly. */ -typedef struct __amx_header { - int32_t size; /* size of the "file" */ - uint16_t magic; /* signature */ - char file_version; /* file format version */ - char amx_version; /* required version of the AMX */ - int16_t flags; - int16_t defsize; - int32_t cod; /* initial value of COD - code block */ - int32_t dat; /* initial value of DAT - data block */ - int32_t hea; /* initial value of HEA - start of the heap */ - int32_t stp; /* initial value of STP - stack top */ - int32_t cip; /* initial value of CIP - the instruction pointer */ - int32_t publics; /* offset to the "public functions" table */ - int32_t natives; /* offset to the "native functions" table */ - int32_t libraries; /* offset to the table of libraries */ - int32_t pubvars; /* the "public variables" table */ - int32_t tags; /* the "public tagnames" table */ -} AMX_HEADER; +typedef struct tagAMX_HEADER { + int32_t size PACKED; /* size of the "file" */ + uint16_t magic PACKED; /* signature */ + char file_version PACKED; /* file format version */ + char amx_version PACKED; /* required version of the AMX */ + int16_t flags PACKED; + int16_t defsize PACKED; /* size of a definition record */ + int32_t cod PACKED; /* initial value of COD - code block */ + int32_t dat PACKED; /* initial value of DAT - data block */ + int32_t hea PACKED; /* initial value of HEA - start of the heap */ + int32_t stp PACKED; /* initial value of STP - stack top */ + int32_t cip PACKED; /* initial value of CIP - the instruction pointer */ + int32_t publics PACKED; /* offset to the "public functions" table */ + int32_t natives PACKED; /* offset to the "native functions" table */ + 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 - enum { AMX_ERR_NONE, /* reserve the first 15 error codes for exit codes of the abstract machine */ @@ -183,7 +207,6 @@ 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_MEMORY = 16, /* out of memory */ AMX_ERR_FORMAT, /* invalid file format */ AMX_ERR_VERSION, /* file is for a newer version of the AMX */ @@ -194,8 +217,8 @@ enum { AMX_ERR_USERDATA, /* unable to set user data field (table full) */ 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 */ @@ -206,33 +229,50 @@ enum { 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 */ }; - #define AMX_FLAG_CHAR16 0x01 /* characters are 16-bit */ #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_BROWSE 0x4000 +#define AMX_FLAG_NOCHECKS 0x10 /* no array bounds checking */ +#define AMX_FLAG_BROWSE 0x4000 /* browsing/relocating or executing */ #define AMX_FLAG_RELOC 0x8000 /* jump/call addresses relocated */ - #define AMX_EXEC_MAIN -1 /* start at program entry point */ #define AMX_EXEC_CONT -2 /* continue from last address */ - #define AMX_USERTAG(a,b,c,d) ((a) | ((b)<<8) | ((long)(c)<<16) | ((long)(d)<<24)) - +#define AMX_EXPANDMARGIN 64 +/* 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 + */ +#define amx_ftoc(f) ( * ((cell*)&f) ) /* float to cell */ +#define amx_ctof(c) ( * ((float*)&c) ) /* cell to float */ +#define amx_StrParam(amx,param,result) { \ + cell *amx_cstr_; int amx_length_; \ + amx_GetAddr((amx), (param), &amx_cstr_); \ + amx_StrLen(amx_cstr_, &amx_length_); \ + if (amx_length_ > 0 && \ + ((result) = (char*)alloca(amx_length_ + 1)) != NULL) \ + amx_GetString((result), amx_cstr_); \ + else (result) = NULL; \ +} uint16_t * AMXAPI amx_Align16(uint16_t *v); uint32_t * AMXAPI amx_Align32(uint32_t *v); 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_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_FindNative(AMX *amx, char *name, int *index); int AMXAPI amx_FindPublic(AMX *amx, char *funcname, int *index); int AMXAPI amx_FindPubVar(AMX *amx, char *varname, cell *amx_addr); int AMXAPI amx_FindTagId(AMX *amx, cell tag_id, char *tagname); int AMXAPI amx_Flags(AMX *amx,uint16_t *flags); 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,cell *source); @@ -243,6 +283,7 @@ 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(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); @@ -253,19 +294,16 @@ int AMXAPI amx_SetCallback(AMX *amx, AMX_CALLBACK callback); int AMXAPI amx_SetDebugHook(AMX *amx, AMX_DEBUG debug); int AMXAPI amx_SetString(cell *dest, char *source, int pack); int AMXAPI amx_SetUserData(AMX *amx, long tag, void *ptr); +char * AMXAPI amx_StrError(int errnum); int AMXAPI amx_StrLen(cell *cstring, int *length); - #if !defined AMX_NO_ALIGN - #if defined __linux__ + #if defined LINUX #pragma pack() /* reset default packing */ #else #pragma pack(pop) /* reset previous packing */ #endif #endif - #ifdef __cplusplus } #endif - #endif /* __AMX_H */ -