1 #ifdef PAWN
2 
3 /*  Pawn Abstract Machine (for the Pawn language)
4  *
5  *  Copyright (c) ITB CompuPhase, 1997-2006
6  *
7  *  This software is provided "as-is", without any express or implied warranty.
8  *  In no event will the authors be held liable for any damages arising from
9  *  the use of this software.
10  *
11  *  Permission is granted to anyone to use this software for any purpose,
12  *  including commercial applications, and to alter it and redistribute it
13  *  freely, subject to the following restrictions:
14  *
15  *  1.  The origin of this software must not be misrepresented; you must not
16  *      claim that you wrote the original software. If you use this software in
17  *      a product, an acknowledgment in the product documentation would be
18  *      appreciated but is not required.
19  *  2.  Altered source versions must be plainly marked as such, and must not be
20  *      misrepresented as being the original software.
21  *  3.  This notice may not be removed or altered from any source distribution.
22  *
23  *  Version: $Id: amx.c,v 1.3 2007/07/10 14:54:51 grum Exp $
24  */
25 
26 #if BUILD_PLATFORM == WINDOWS && BUILD_TYPE == RELEASE && BUILD_COMPILER == MSVC && PAWN_CELL_SIZE == 64
27   /* bad bad workaround but we have to prevent a compiler crash :/ */
28   #pragma optimize("g",off)
29 #endif
30 
31 #define WIN32_LEAN_AND_MEAN
32 #if defined _UNICODE || defined __UNICODE__ || defined UNICODE
33 # if !defined UNICODE   /* for Windows API */
34 #   define UNICODE
35 # endif
36 # if !defined _UNICODE  /* for C library */
37 #   define _UNICODE
38 # endif
39 #endif
40 
41 #include <assert.h>
42 #include <stdarg.h>
43 #include <stddef.h>     /* for wchar_t */
44 #include <stdlib.h>     /* for getenv() */
45 #include <string.h>
46 #include "osdefs.h"
47 #if defined LINUX || defined __FreeBSD__ || defined __OpenBSD__
48   #if !defined AMX_NODYNALOAD
49     #include <dlfcn.h>
50   #endif
51   #if defined JIT
52     #include <sys/types.h>
53     #include <sys/mman.h>
54   #endif
55 #endif
56 #if defined __LCC__ || defined LINUX
57   #include <wchar.h>    /* for wcslen() */
58 #endif
59 #include "amx.h"
60 #if (defined _Windows && !defined AMX_NODYNALOAD) || (defined JIT && __WIN32__)
61   #include <windows.h>
62 #endif
63 
64 
65 /* When one or more of the AMX_funcname macris are defined, we want
66  * to compile only those functions. However, when none of these macros
67  * is present, we want to compile everything.
68  */
69 #if defined AMX_ALIGN       || defined AMX_ALLOT        || defined AMX_CLEANUP
70   #define AMX_EXPLIT_FUNCTIONS
71 #endif
72 #if defined AMX_CLONE        || defined AMX_DEFCALLBACK || defined AMX_EXEC
73   #define AMX_EXPLIT_FUNCTIONS
74 #endif
75 #if defined AMX_FLAGS       || defined AMX_GETADDR      || defined AMX_INIT
76   #define AMX_EXPLIT_FUNCTIONS
77 #endif
78 #if defined AMX_MEMINFO     || defined AMX_NAMELENGTH   || defined AMX_NATIVEINFO
79   #define AMX_EXPLIT_FUNCTIONS
80 #endif
81 #if defined AMX_PUSHXXX     || defined AMX_RAISEERROR   || defined AMX_REGISTER
82   #define AMX_EXPLIT_FUNCTIONS
83 #endif
84 #if defined AMX_SETCALLBACK || defined AMX_SETDEBUGHOOK || defined AMX_XXXNATIVES
85   #define AMX_EXPLIT_FUNCTIONS
86 #endif
87 #if defined AMX_XXXPUBLICS  || defined AMX_XXXPUBVARS   || defined AMX_XXXSTRING
88   #define AMX_EXPLIT_FUNCTIONS
89 #endif
90 #if defined AMX_XXXTAGS     || defined AMX_XXXUSERDATA  || defined AMX_UTF8XXX
91   #define AMX_EXPLIT_FUNCTIONS
92 #endif
93 #if !defined AMX_EXPLIT_FUNCTIONS
94   /* no constant set, set them all */
95   #define AMX_ALIGN             /* amx_Align16(), amx_Align32() and amx_Align64() */
96   #define AMX_ALLOT             /* amx_Allot() and amx_Release() */
97   #define AMX_DEFCALLBACK       /* amx_Callback() */
98   #define AMX_CLEANUP           /* amx_Cleanup() */
99   #define AMX_CLONE             /* amx_Clone() */
100   #define AMX_EXEC              /* amx_Exec() */
101   #define AMX_FLAGS             /* amx_Flags() */
102   #define AMX_GETADDR           /* amx_GetAddr() */
103   #define AMX_INIT              /* amx_Init() and amx_InitJIT() */
104   #define AMX_MEMINFO           /* amx_MemInfo() */
105   #define AMX_NAMELENGTH        /* amx_NameLength() */
106   #define AMX_NATIVEINFO        /* amx_NativeInfo() */
107   #define AMX_PUSHXXX           /* amx_Push(), amx_PushArray() and amx_PushString() */
108   #define AMX_RAISEERROR        /* amx_RaiseError() */
109   #define AMX_REGISTER          /* amx_Register() */
110   #define AMX_SETCALLBACK       /* amx_SetCallback() */
111   #define AMX_SETDEBUGHOOK      /* amx_SetDebugHook() */
112   #define AMX_XXXNATIVES        /* amx_NumNatives(), amx_GetNative() and amx_FindNative() */
113   #define AMX_XXXPUBLICS        /* amx_NumPublics(), amx_GetPublic() and amx_FindPublic() */
114   #define AMX_XXXPUBVARS        /* amx_NumPubVars(), amx_GetPubVar() and amx_FindPubVar() */
115   #define AMX_XXXSTRING         /* amx_StrLen(), amx_GetString() and amx_SetString() */
116   #define AMX_XXXTAGS           /* amx_NumTags(), amx_GetTag() and amx_FindTagId() */
117   #define AMX_XXXUSERDATA       /* amx_GetUserData() and amx_SetUserData() */
118   #define AMX_UTF8XXX           /* amx_UTF8Get(), amx_UTF8Put(), amx_UTF8Check() */
119 #endif
120 #undef AMX_EXPLIT_FUNCTIONS
121 #if defined AMX_ANSIONLY
122   #undef AMX_UTF8XXX            /* no UTF-8 support in ANSI/ASCII-only version */
123 #endif
124 #if defined AMX_NO_NATIVEINFO
125   #undef AMX_NATIVEINFO
126 #endif
127 #if AMX_USERNUM <= 0
128   #undef AMX_XXXUSERDATA
129 #endif
130 #if defined JIT
131   #define AMX_NO_MACRO_INSTR    /* JIT is incompatible with macro instructions */
132 #endif
133 
134 typedef enum {
135   OP_NONE,              /* invalid opcode */
136   OP_LOAD_PRI,
137   OP_LOAD_ALT,
138   OP_LOAD_S_PRI,
139   OP_LOAD_S_ALT,
140   OP_LREF_PRI,
141   OP_LREF_ALT,
142   OP_LREF_S_PRI,
143   OP_LREF_S_ALT,
144   OP_LOAD_I,
145   OP_LODB_I,
146   OP_CONST_PRI,
147   OP_CONST_ALT,
148   OP_ADDR_PRI,
149   OP_ADDR_ALT,
150   OP_STOR_PRI,
151   OP_STOR_ALT,
152   OP_STOR_S_PRI,
153   OP_STOR_S_ALT,
154   OP_SREF_PRI,
155   OP_SREF_ALT,
156   OP_SREF_S_PRI,
157   OP_SREF_S_ALT,
158   OP_STOR_I,
159   OP_STRB_I,
160   OP_LIDX,
161   OP_LIDX_B,
162   OP_IDXADDR,
163   OP_IDXADDR_B,
164   OP_ALIGN_PRI,
165   OP_ALIGN_ALT,
166   OP_LCTRL,
167   OP_SCTRL,
168   OP_MOVE_PRI,
169   OP_MOVE_ALT,
170   OP_XCHG,
171   OP_PUSH_PRI,
172   OP_PUSH_ALT,
173   OP_PUSH_R,
174   OP_PUSH_C,
175   OP_PUSH,
176   OP_PUSH_S,
177   OP_POP_PRI,
178   OP_POP_ALT,
179   OP_STACK,
180   OP_HEAP,
181   OP_PROC,
182   OP_RET,
183   OP_RETN,
184   OP_CALL,
185   OP_CALL_PRI,
186   OP_JUMP,
187   OP_JREL,
188   OP_JZER,
189   OP_JNZ,
190   OP_JEQ,
191   OP_JNEQ,
192   OP_JLESS,
193   OP_JLEQ,
194   OP_JGRTR,
195   OP_JGEQ,
196   OP_JSLESS,
197   OP_JSLEQ,
198   OP_JSGRTR,
199   OP_JSGEQ,
200   OP_SHL,
201   OP_SHR,
202   OP_SSHR,
203   OP_SHL_C_PRI,
204   OP_SHL_C_ALT,
205   OP_SHR_C_PRI,
206   OP_SHR_C_ALT,
207   OP_SMUL,
208   OP_SDIV,
209   OP_SDIV_ALT,
210   OP_UMUL,
211   OP_UDIV,
212   OP_UDIV_ALT,
213   OP_ADD,
214   OP_SUB,
215   OP_SUB_ALT,
216   OP_AND,
217   OP_OR,
218   OP_XOR,
219   OP_NOT,
220   OP_NEG,
221   OP_INVERT,
222   OP_ADD_C,
223   OP_SMUL_C,
224   OP_ZERO_PRI,
225   OP_ZERO_ALT,
226   OP_ZERO,
227   OP_ZERO_S,
228   OP_SIGN_PRI,
229   OP_SIGN_ALT,
230   OP_EQ,
231   OP_NEQ,
232   OP_LESS,
233   OP_LEQ,
234   OP_GRTR,
235   OP_GEQ,
236   OP_SLESS,
237   OP_SLEQ,
238   OP_SGRTR,
239   OP_SGEQ,
240   OP_EQ_C_PRI,
241   OP_EQ_C_ALT,
242   OP_INC_PRI,
243   OP_INC_ALT,
244   OP_INC,
245   OP_INC_S,
246   OP_INC_I,
247   OP_DEC_PRI,
248   OP_DEC_ALT,
249   OP_DEC,
250   OP_DEC_S,
251   OP_DEC_I,
252   OP_MOVS,
253   OP_CMPS,
254   OP_FILL,
255   OP_HALT,
256   OP_BOUNDS,
257   OP_SYSREQ_PRI,
258   OP_SYSREQ_C,
259   OP_FILE,    /* obsolete */
260   OP_LINE,    /* obsolete */
261   OP_SYMBOL,  /* obsolete */
262   OP_SRANGE,  /* obsolete */
263   OP_JUMP_PRI,
264   OP_SWITCH,
265   OP_CASETBL,
266   OP_SWAP_PRI,
267   OP_SWAP_ALT,
268   OP_PUSH_ADR,
269   OP_NOP,
270   OP_SYSREQ_N,
271   OP_SYMTAG,  /* obsolete */
272   OP_BREAK,
273   OP_PUSH2_C,
274   OP_PUSH2,
275   OP_PUSH2_S,
276   OP_PUSH2_ADR,
277   OP_PUSH3_C,
278   OP_PUSH3,
279   OP_PUSH3_S,
280   OP_PUSH3_ADR,
281   OP_PUSH4_C,
282   OP_PUSH4,
283   OP_PUSH4_S,
284   OP_PUSH4_ADR,
285   OP_PUSH5_C,
286   OP_PUSH5,
287   OP_PUSH5_S,
288   OP_PUSH5_ADR,
289   OP_LOAD_BOTH,
290   OP_LOAD_S_BOTH,
291   OP_CONST,
292   OP_CONST_S,
293   /* ----- */
294   OP_SYSREQ_D,
295   OP_SYSREQ_ND,
296   /* ----- */
297   OP_NUM_OPCODES
298 } OPCODE;
299 
300 #define USENAMETABLE(hdr) \
301                         ((hdr)->defsize==sizeof(AMX_FUNCSTUBNT))
302 #define NUMENTRIES(hdr,field,nextfield) \
303                         (unsigned)(((hdr)->nextfield - (hdr)->field) / (hdr)->defsize)
304 #define GETENTRY(hdr,table,index) \
305                         (AMX_FUNCSTUB *)((unsigned char*)(hdr) + (unsigned)(hdr)->table + (unsigned)index*(hdr)->defsize)
306 #define GETENTRYNAME(hdr,entry) \
307                         ( USENAMETABLE(hdr) \
308                            ? (char *)((unsigned char*)(hdr) + (unsigned)((AMX_FUNCSTUBNT*)(entry))->nameofs) \
309                            : ((AMX_FUNCSTUB*)(entry))->name )
310 
311 #if !defined NDEBUG
check_endian(void)312   static int check_endian(void)
313   {
314     uint16_t val=0x00ff;
315     unsigned char *ptr=(unsigned char *)&val;
316     /* "ptr" points to the starting address of "val". If that address
317      * holds the byte "0xff", the computer stored the low byte of "val"
318      * at the lower address, and so the memory lay out is Little Endian.
319      */
320     assert(*ptr==0xff || *ptr==0x00);
321     #if BYTE_ORDER==BIG_ENDIAN
322       return *ptr==0x00;  /* return "true" if big endian */
323     #else
324       return *ptr==0xff;  /* return "true" if little endian */
325     #endif
326   }
327 #endif
328 
329 #if BYTE_ORDER==BIG_ENDIAN || PAWN_CELL_SIZE==16
swap16(uint16_t * v)330   static void swap16(uint16_t *v)
331   {
332     unsigned char *s = (unsigned char *)v;
333     unsigned char t;
334 
335     assert(sizeof(*v)==2);
336     /* swap two bytes */
337     t=s[0];
338     s[0]=s[1];
339     s[1]=t;
340   }
341 #endif
342 
343 #if BYTE_ORDER==BIG_ENDIAN || PAWN_CELL_SIZE==32
swap32(uint32_t * v)344   static void swap32(uint32_t *v)
345   {
346     unsigned char *s = (unsigned char *)v;
347     unsigned char t;
348 
349     assert_static(sizeof(*v)==4);
350     /* swap outer two bytes */
351     t=s[0];
352     s[0]=s[3];
353     s[3]=t;
354     /* swap inner two bytes */
355     t=s[1];
356     s[1]=s[2];
357     s[2]=t;
358   }
359 #endif
360 
361 #if (BYTE_ORDER==BIG_ENDIAN || PAWN_CELL_SIZE==64) && (defined _I64_MAX || defined INT64_MAX || defined HAVE_I64)
swap64(uint64_t * v)362   static void swap64(uint64_t *v)
363   {
364     unsigned char *s = (unsigned char *)v;
365     unsigned char t;
366 
367     assert(sizeof(*v)==8);
368 
369     t=s[0];
370     s[0]=s[7];
371     s[7]=t;
372 
373     t=s[1];
374     s[1]=s[6];
375     s[6]=t;
376 
377     t=s[2];
378     s[2]=s[5];
379     s[5]=t;
380 
381     t=s[3];
382     s[3]=s[4];
383     s[4]=t;
384   }
385 #endif
386 
387 #if defined AMX_ALIGN || defined AMX_INIT
amx_Align16(uint16_t * v)388 uint16_t * AMXAPI amx_Align16(uint16_t *v)
389 {
390   assert_static(sizeof(*v)==2);
391   assert(check_endian());
392   #if BYTE_ORDER==BIG_ENDIAN
393     swap16(v);
394   #endif
395   return v;
396 }
397 
amx_Align32(uint32_t * v)398 uint32_t * AMXAPI amx_Align32(uint32_t *v)
399 {
400   assert_static(sizeof(*v)==4);
401   assert(check_endian());
402   #if BYTE_ORDER==BIG_ENDIAN
403     swap32(v);
404   #endif
405   return v;
406 }
407 
408 #if defined _I64_MAX || defined INT64_MAX || defined HAVE_I64
amx_Align64(uint64_t * v)409 uint64_t * AMXAPI amx_Align64(uint64_t *v)
410 {
411   assert(sizeof(*v)==8);
412   assert(check_endian());
413   #if BYTE_ORDER==BIG_ENDIAN
414     swap64(v);
415   #endif
416   return v;
417 }
418 #endif  /* _I64_MAX || HAVE_I64 */
419 #endif  /* AMX_ALIGN || AMX_INIT */
420 
421 #if PAWN_CELL_SIZE==16
422   #define swapcell  swap16
423 #elif PAWN_CELL_SIZE==32
424   #define swapcell  swap32
425 #elif PAWN_CELL_SIZE==64 && (defined _I64_MAX || defined INT64_MAX || defined HAVE_I64)
426   #define swapcell  swap64
427 #else
428   #error Unsupported cell size
429 #endif
430 
431 #if defined AMX_FLAGS
amx_Flags(AMX * amx,uint16_t * flags)432 int AMXAPI amx_Flags(AMX *amx,uint16_t *flags)
433 {
434   AMX_HEADER *hdr;
435 
436   *flags=0;
437   if (amx==NULL)
438     return AMX_ERR_FORMAT;
439   hdr=(AMX_HEADER *)amx->base;
440   if (hdr->magic!=AMX_MAGIC)
441     return AMX_ERR_FORMAT;
442   if (hdr->file_version>CUR_FILE_VERSION || hdr->amx_version<MIN_FILE_VERSION)
443     return AMX_ERR_VERSION;
444   *flags=hdr->flags;
445   return AMX_ERR_NONE;
446 }
447 #endif /* AMX_FLAGS */
448 
449 #if defined AMX_DEFCALLBACK
amx_Callback(AMX * amx,cell index,cell * result,const cell * params)450 int AMXAPI amx_Callback(AMX *amx, cell index, cell *result, const cell *params)
451 {
452 #if defined AMX_NATIVETABLE
453   extern AMX_NATIVE const AMX_NATIVETABLE[];
454 #endif
455   AMX_HEADER *hdr;
456   AMX_FUNCSTUB *func;
457   AMX_NATIVE f;
458 
459   assert(amx!=NULL);
460   hdr=(AMX_HEADER *)amx->base;
461   assert(hdr!=NULL);
462   assert(hdr->magic==AMX_MAGIC);
463   assert(hdr->natives<=hdr->libraries);
464 #if defined AMX_NATIVETABLE
465   if (index<0) {
466     /* size of AMX_NATIVETABLE is unknown here, so we cannot verify index */
467     f=(AMX_NATIVETABLE)[-(index+1)];
468   } else {
469 #endif
470     assert(index>=0 && index<(cell)NUMENTRIES(hdr,natives,libraries));
471     func=GETENTRY(hdr,natives,index);
472     f=(AMX_NATIVE)func->address;
473 #if defined AMX_NATIVETABLE
474   } /* if */
475 #endif
476   assert(f!=NULL);
477 
478   /* Now that we have found the function, patch the program so that any
479    * subsequent call will call the function directly (bypassing this
480    * callback).
481    * This trick cannot work in the JIT, because the program would need to
482    * be re-JIT-compiled after patching a P-code instruction.
483    */
484   #if defined JIT && !defined NDEBUG
485     if ((amx->flags & AMX_FLAG_JITC)!=0)
486       assert(amx->sysreq_d==0);
487   #endif
488   if (amx->sysreq_d!=0) {
489     /* at the point of the call, the CIP pseudo-register points directly
490      * behind the SYSREQ instruction and its parameter(s)
491      */
492     unsigned char *code=amx->base+(int)hdr->cod+(int)amx->cip-sizeof(cell);
493     assert(amx->cip >= 4 && amx->cip < (hdr->dat - hdr->cod));
494     assert_static(sizeof(f)<=sizeof(cell)); /* function pointer must fit in a cell */
495     if (amx->flags & AMX_FLAG_SYSREQN)		/* SYSREQ.N has 2 parameters */
496       code-=sizeof(cell);
497 #if defined __GNUC__ || defined __ICC || defined ASM32
498     if (*(cell*)code==index) {
499 #else
500     if (*(cell*)code!=OP_SYSREQ_PRI) {
501       assert(*(cell*)(code-sizeof(cell))==OP_SYSREQ_C || *(cell*)(code-sizeof(cell))==OP_SYSREQ_N);
502       assert(*(cell*)code==index);
503 #endif
504       *(cell*)(code-sizeof(cell))=amx->sysreq_d;
505       *(cell*)code=(cell)f;
506     } /* if */
507   } /* if */
508 
509   /* Note:
510    *   params[0] == number of bytes for the additional parameters passed to the native function
511    *   params[1] == first argument
512    *   etc.
513    */
514 
515   amx->error=AMX_ERR_NONE;
516   *result = f(amx,params);
517   return amx->error;
518 }
519 #endif /* defined AMX_DEFCALLBACK */
520 
521 
522 #if defined JIT
523   extern int AMXAPI getMaxCodeSize(void);
524   extern int AMXAPI asm_runJIT(void *sourceAMXbase, void *jumparray, void *compiledAMXbase);
525 #endif
526 
527 #if PAWN_CELL_SIZE==16 || defined AMX_DONT_RELOCATE
528   #define JUMPABS(base,ip)      ((cell *)((base) + *(ip)))
529   #define RELOC_ABS(base, off)
530   #define RELOC_VALUE(base, v)
531 #else
532   #define JUMPABS(base, ip)     ((cell *)*(ip))
533   #define RELOC_ABS(base, off)  (*(ucell *)((base)+(int)(off)) += (ucell)(base))
534   #define RELOC_VALUE(base, v)  ((v)+((ucell)(base)))
535 #endif
536 
537 #define DBGPARAM(v)     ( (v)=*(cell *)(code+(int)cip), cip+=sizeof(cell) )
538 
539 #if defined AMX_INIT
540 
541 static int amx_BrowseRelocate(AMX *amx)
542 {
543   AMX_HEADER *hdr;
544   unsigned char *code;
545   cell cip;
546   long codesize;
547   OPCODE op;
548   int sysreq_flg;
549   #if defined __GNUC__ || defined __ICC || defined ASM32 || defined JIT
550     cell *opcode_list;
551   #endif
552   #if defined JIT
553     int opcode_count = 0;
554     int reloc_count = 0;
555   #endif
556 
557   assert(amx!=NULL);
558   hdr=(AMX_HEADER *)amx->base;
559   assert(hdr!=NULL);
560   assert(hdr->magic==AMX_MAGIC);
561   code=amx->base+(int)hdr->cod;
562   codesize=hdr->dat - hdr->cod;
563   amx->flags|=AMX_FLAG_BROWSE;
564 
565   /* sanity checks */
566   assert_static(OP_PUSH_PRI==36);
567   assert_static(OP_PROC==46);
568   assert_static(OP_SHL==65);
569   assert_static(OP_SMUL==72);
570   assert_static(OP_EQ==95);
571   assert_static(OP_INC_PRI==107);
572   assert_static(OP_MOVS==117);
573   assert_static(OP_SYMBOL==126);
574   assert_static(OP_LOAD_BOTH==154);
575 
576   amx->sysreq_d=0;      /* preset */
577   sysreq_flg=0;
578   #if defined __GNUC__ || defined __ICC || defined ASM32 || defined JIT
579     amx_Exec(amx, (cell*)(void*)&opcode_list, 0);
580   #endif
581 
582   /* start browsing code */
583   for (cip=0; cip<codesize; ) {
584     op=(OPCODE) *(ucell *)(code+(int)cip);
585     if ((unsigned)op>=OP_NUM_OPCODES) {
586       amx->flags &= ~AMX_FLAG_BROWSE;
587       return AMX_ERR_INVINSTR;
588     } /* if */
589     #if defined __GNUC__ || defined __ICC || defined ASM32 || defined JIT
590       /* relocate opcode (only works if the size of an opcode is at least
591        * as big as the size of a pointer (jump address); so basically we
592        * rely on the opcode and a pointer being 32-bit
593        */
594       *(cell *)(code+(int)cip) = opcode_list[op];
595     #endif
596     #if defined JIT
597       opcode_count++;
598     #endif
599     cip+=sizeof(cell);
600     switch (op) {
601 #if !defined AMX_NO_MACRO_INSTR
602     case OP_PUSH5_C:    /* instructions with 5 parameters */
603     case OP_PUSH5:
604     case OP_PUSH5_S:
605     case OP_PUSH5_ADR:
606       cip+=sizeof(cell)*5;
607       break;
608 
609     case OP_PUSH4_C:    /* instructions with 4 parameters */
610     case OP_PUSH4:
611     case OP_PUSH4_S:
612     case OP_PUSH4_ADR:
613       #if defined AMX_NO_MACRO_INSTR
614         amx->flags &= ~AMX_FLAG_BROWSE;
615         return AMX_ERR_INVINSTR;
616       #endif
617       cip+=sizeof(cell)*4;
618       break;
619 
620     case OP_PUSH3_C:    /* instructions with 3 parameters */
621     case OP_PUSH3:
622     case OP_PUSH3_S:
623     case OP_PUSH3_ADR:
624       #if defined AMX_NO_MACRO_INSTR
625         amx->flags &= ~AMX_FLAG_BROWSE;
626         return AMX_ERR_INVINSTR;
627       #endif
628       cip+=sizeof(cell)*3;
629       break;
630 
631     case OP_PUSH2_C:    /* instructions with 2 parameters */
632     case OP_PUSH2:
633     case OP_PUSH2_S:
634     case OP_PUSH2_ADR:
635     case OP_LOAD_BOTH:
636     case OP_LOAD_S_BOTH:
637     case OP_CONST:
638     case OP_CONST_S:
639       #if defined AMX_NO_MACRO_INSTR
640         amx->flags &= ~AMX_FLAG_BROWSE;
641         return AMX_ERR_INVINSTR;
642       #endif
643       cip+=sizeof(cell)*2;
644       break;
645 #endif /* !defined AMX_NO_MACRO_INSTR */
646 
647     case OP_LOAD_PRI:   /* instructions with 1 parameter */
648     case OP_LOAD_ALT:
649     case OP_LOAD_S_PRI:
650     case OP_LOAD_S_ALT:
651     case OP_LREF_PRI:
652     case OP_LREF_ALT:
653     case OP_LREF_S_PRI:
654     case OP_LREF_S_ALT:
655     case OP_LODB_I:
656     case OP_CONST_PRI:
657     case OP_CONST_ALT:
658     case OP_ADDR_PRI:
659     case OP_ADDR_ALT:
660     case OP_STOR_PRI:
661     case OP_STOR_ALT:
662     case OP_STOR_S_PRI:
663     case OP_STOR_S_ALT:
664     case OP_SREF_PRI:
665     case OP_SREF_ALT:
666     case OP_SREF_S_PRI:
667     case OP_SREF_S_ALT:
668     case OP_STRB_I:
669     case OP_LIDX_B:
670     case OP_IDXADDR_B:
671     case OP_ALIGN_PRI:
672     case OP_ALIGN_ALT:
673     case OP_LCTRL:
674     case OP_SCTRL:
675     case OP_PUSH_R:
676     case OP_PUSH_C:
677     case OP_PUSH:
678     case OP_PUSH_S:
679     case OP_STACK:
680     case OP_HEAP:
681     case OP_JREL:
682     case OP_SHL_C_PRI:
683     case OP_SHL_C_ALT:
684     case OP_SHR_C_PRI:
685     case OP_SHR_C_ALT:
686     case OP_ADD_C:
687     case OP_SMUL_C:
688     case OP_ZERO:
689     case OP_ZERO_S:
690     case OP_EQ_C_PRI:
691     case OP_EQ_C_ALT:
692     case OP_INC:
693     case OP_INC_S:
694     case OP_DEC:
695     case OP_DEC_S:
696     case OP_MOVS:
697     case OP_CMPS:
698     case OP_FILL:
699     case OP_HALT:
700     case OP_BOUNDS:
701     case OP_PUSH_ADR:
702       cip+=sizeof(cell);
703       break;
704 
705     case OP_LOAD_I:     /* instructions without parameters */
706     case OP_STOR_I:
707     case OP_LIDX:
708     case OP_IDXADDR:
709     case OP_MOVE_PRI:
710     case OP_MOVE_ALT:
711     case OP_XCHG:
712     case OP_PUSH_PRI:
713     case OP_PUSH_ALT:
714     case OP_POP_PRI:
715     case OP_POP_ALT:
716     case OP_PROC:
717     case OP_RET:
718     case OP_RETN:
719     case OP_CALL_PRI:
720     case OP_SHL:
721     case OP_SHR:
722     case OP_SSHR:
723     case OP_SMUL:
724     case OP_SDIV:
725     case OP_SDIV_ALT:
726     case OP_UMUL:
727     case OP_UDIV:
728     case OP_UDIV_ALT:
729     case OP_ADD:
730     case OP_SUB:
731     case OP_SUB_ALT:
732     case OP_AND:
733     case OP_OR:
734     case OP_XOR:
735     case OP_NOT:
736     case OP_NEG:
737     case OP_INVERT:
738     case OP_ZERO_PRI:
739     case OP_ZERO_ALT:
740     case OP_SIGN_PRI:
741     case OP_SIGN_ALT:
742     case OP_EQ:
743     case OP_NEQ:
744     case OP_LESS:
745     case OP_LEQ:
746     case OP_GRTR:
747     case OP_GEQ:
748     case OP_SLESS:
749     case OP_SLEQ:
750     case OP_SGRTR:
751     case OP_SGEQ:
752     case OP_INC_PRI:
753     case OP_INC_ALT:
754     case OP_INC_I:
755     case OP_DEC_PRI:
756     case OP_DEC_ALT:
757     case OP_DEC_I:
758     case OP_SYSREQ_PRI:
759     case OP_JUMP_PRI:
760     case OP_SWAP_PRI:
761     case OP_SWAP_ALT:
762     case OP_NOP:
763     case OP_BREAK:
764       break;
765 
766     case OP_CALL:       /* opcodes that need relocation */
767     case OP_JUMP:
768     case OP_JZER:
769     case OP_JNZ:
770     case OP_JEQ:
771     case OP_JNEQ:
772     case OP_JLESS:
773     case OP_JLEQ:
774     case OP_JGRTR:
775     case OP_JGEQ:
776     case OP_JSLESS:
777     case OP_JSLEQ:
778     case OP_JSGRTR:
779     case OP_JSGEQ:
780     case OP_SWITCH:
781       #if defined JIT
782         reloc_count++;
783       #endif
784       RELOC_ABS(code, cip);
785       cip+=sizeof(cell);
786       break;
787 
788     case OP_SYSREQ_C:
789       cip+=sizeof(cell);
790       sysreq_flg|=0x01; /* mark SYSREQ.C found */
791       break;
792 #if !defined AMX_NO_MACRO_INSTR
793     case OP_SYSREQ_N:
794       cip+=sizeof(cell)*2;
795       sysreq_flg|=0x02; /* mark SYSREQ.N found */
796       break;
797 #endif
798 
799     case OP_FILE:
800     case OP_SYMBOL: {
801       cell num;
802       DBGPARAM(num);
803       cip+=num;
804       break;
805     } /* case */
806     case OP_LINE:
807     case OP_SRANGE:
808       cip+=2*sizeof(cell);
809       break;
810     case OP_SYMTAG:
811       cip+=sizeof(cell);
812       break;
813     case OP_CASETBL: {
814       cell num;
815       int i;
816       DBGPARAM(num);    /* number of records follows the opcode */
817       for (i=0; i<=num; i++) {
818         RELOC_ABS(code, cip+2*i*sizeof(cell));
819         #if defined JIT
820           reloc_count++;
821         #endif
822       } /* for */
823       cip+=(2*num + 1)*sizeof(cell);
824       break;
825     } /* case */
826     default:
827       amx->flags &= ~AMX_FLAG_BROWSE;
828       return AMX_ERR_INVINSTR;
829     } /* switch */
830   } /* for */
831 
832   assert(sysreq_flg==0 || sysreq_flg==0x01 || sysreq_flg==0x02);
833   #if !defined AMX_DONT_RELOCATE
834     if (sysreq_flg==0x01 || sysreq_flg==0x02) {
835       /* only either type of system request opcode should be found (otherwise,
836        * we probably have a non-conforming compiler
837        */
838       // Grum: the below is wrong. Apart from the fact that I think it should
839       // work fine on 64bit systems, it now always takes the #else branch
840       // for 64bit, which is certainly wrong when using e.g. gcc.
841       //#if (defined __GNUC__ || defined __ICC || defined ASM32 || defined JIT) && !defined __64BIT__
842       #if defined __GNUC__ || defined __ICC || defined ASM32 || defined JIT
843         /* to use direct system requests, a function pointer must fit in a cell;
844          * because the native function's address will be stored as the parameter
845          * of SYSREQ.D
846          */
847         if ((amx->flags & AMX_FLAG_JITC)==0 && sizeof(AMX_NATIVE)<=sizeof(cell))
848           amx->sysreq_d=(sysreq_flg==0x01) ? opcode_list[OP_SYSREQ_D] : opcode_list[OP_SYSREQ_ND];
849       #else
850         /* ANSI C
851          * to use direct system requests, a function pointer must fit in a cell;
852          * see the comment above
853          */
854         if (sizeof(AMX_NATIVE)<=sizeof(cell))
855           amx->sysreq_d=(sysreq_flg==0x01) ? OP_SYSREQ_D : OP_SYSREQ_ND;
856       #endif
857     } /* if */
858   #endif
859 
860   #if defined JIT
861     amx->code_size = getMaxCodeSize()*opcode_count + hdr->cod
862                      + (hdr->stp - hdr->dat);
863     amx->reloc_size = 2*sizeof(cell)*reloc_count;
864   #endif
865 
866   amx->flags &= ~AMX_FLAG_BROWSE;
867   amx->flags |= AMX_FLAG_RELOC;
868   if (sysreq_flg & 0x02)
869     amx->flags |= AMX_FLAG_SYSREQN;
870   return AMX_ERR_NONE;
871 }
872 
873 #if AMX_COMPACTMARGIN > 2
874 static void expand(unsigned char *code, long codesize, long memsize)
875 {
876   ucell c;
877   struct {
878     long memloc;
879     ucell c;
880   } spare[AMX_COMPACTMARGIN];
881   int sh=0,st=0,sc=0;
882   int shift;
883 
884   /* for in-place expansion, move from the end backward */
885   assert(memsize % sizeof(cell) == 0);
886   while (codesize>0) {
887     c=0;
888     shift=0;
889     do {
890       codesize--;
891       /* no input byte should be shifted out completely */
892       assert(shift<8*sizeof(cell));
893       /* we work from the end of a sequence backwards; the final code in
894        * a sequence may not have the continuation bit set */
895       assert(shift>0 || (code[(size_t)codesize] & 0x80)==0);
896       c|=(ucell)(code[(size_t)codesize] & 0x7f) << shift;
897       shift+=7;
898     } while (codesize>0 && (code[(size_t)codesize-1] & 0x80)!=0);
899     /* sign expand */
900     if ((code[(size_t)codesize] & 0x40)!=0) {
901       while (shift < (int)(8*sizeof(cell))) {
902         c|=(ucell)0xff << shift;
903         shift+=8;
904       } /* while */
905     } /* if */
906     /* store */
907     while (sc && (spare[sh].memloc>codesize)) {
908       *(ucell *)(code+(int)spare[sh].memloc)=spare[sh].c;
909       sh=(sh+1)%AMX_COMPACTMARGIN;
910       sc--;
911     } /* while */
912     memsize -= sizeof(cell);
913     assert(memsize>=0);
914     if ((memsize>codesize)||((memsize==codesize)&&(memsize==0))) {
915       *(ucell *)(code+(size_t)memsize)=c;
916     } else {
917       assert(sc<AMX_COMPACTMARGIN);
918       spare[st].memloc=memsize;
919       spare[st].c=c;
920       st=(st+1)%AMX_COMPACTMARGIN;
921       sc++;
922     } /* if */
923   } /* while */
924   /* when all bytes have been expanded, the complete memory block should be done */
925   assert(memsize==0);
926 }
927 #endif /* AMX_COMPACTMARGIN > 2 */
928 
929 int AMXAPI amx_Init(AMX *amx,void *program)
930 {
931   AMX_HEADER *hdr;
932   int err;
933   unsigned char *data;
934   #if (defined _Windows || defined LINUX || defined __FreeBSD__ || defined __OpenBSD__) && !defined AMX_NODYNALOAD
935     #if defined _Windows
936       char libname[sNAMEMAX+8]; /* +1 for '\0', +3 for 'amx' prefix, +4 for extension */
937       typedef int (FAR WINAPI *AMX_ENTRY)(AMX _FAR *amx);
938       HINSTANCE hlib;
939     #elif defined LINUX || defined __FreeBSD__ || defined __OpenBSD__
940       char libname[_MAX_PATH];
941       char *root;
942       typedef int (*AMX_ENTRY)(AMX *amx);
943       void *hlib;
944       #if !defined AMX_LIBPATH
945         #define AMX_LIBPATH     "AMXLIB"
946       #endif
947     #endif
948     int numlibraries,i;
949     AMX_FUNCSTUB *lib;
950     AMX_ENTRY libinit;
951   #endif
952 
953   if ((amx->flags & AMX_FLAG_RELOC)!=0)
954     return AMX_ERR_INIT;  /* already initialized (may not do so twice) */
955 
956   hdr=(AMX_HEADER *)program;
957   /* the header is in Little Endian, on a Big Endian machine, swap all
958    * multi-byte words
959    */
960   assert(check_endian());
961   #if BYTE_ORDER==BIG_ENDIAN
962     amx_Align32((uint32_t*)&hdr->size);
963     amx_Align16(&hdr->magic);
964     amx_Align16((uint16_t*)&hdr->flags);
965     amx_Align16((uint16_t*)&hdr->defsize);
966     amx_Align32((uint32_t*)&hdr->cod);
967     amx_Align32((uint32_t*)&hdr->dat);
968     amx_Align32((uint32_t*)&hdr->hea);
969     amx_Align32((uint32_t*)&hdr->stp);
970     amx_Align32((uint32_t*)&hdr->cip);
971     amx_Align32((uint32_t*)&hdr->publics);
972     amx_Align32((uint32_t*)&hdr->natives);
973     amx_Align32((uint32_t*)&hdr->libraries);
974     amx_Align32((uint32_t*)&hdr->pubvars);
975     amx_Align32((uint32_t*)&hdr->tags);
976   #endif
977 
978   if (hdr->magic!=AMX_MAGIC)
979     return AMX_ERR_FORMAT;
980   if (hdr->file_version>CUR_FILE_VERSION || hdr->amx_version<MIN_FILE_VERSION)
981     return AMX_ERR_VERSION;
982   if (hdr->defsize!=sizeof(AMX_FUNCSTUB) && hdr->defsize!=sizeof(AMX_FUNCSTUBNT))
983     return AMX_ERR_FORMAT;
984   if (USENAMETABLE(hdr)) {
985     uint16_t *namelength;
986     /* when there is a separate name table, check the maximum name length
987      * in that table
988      */
989 #pragma GCC diagnostic push
990 #pragma GCC diagnostic ignored "-Waddress-of-packed-member"
991     amx_Align32((uint32_t*)&hdr->nametable);
992 #pragma GCC diagnostic pop
993     namelength=(uint16_t*)((unsigned char*)program + (unsigned)hdr->nametable);
994     amx_Align16(namelength);
995     if (*namelength>sNAMEMAX)
996       return AMX_ERR_FORMAT;
997   } /* if */
998   if (hdr->stp<=0)
999     return AMX_ERR_FORMAT;
1000   #if BYTE_ORDER==BIG_ENDIAN
1001     if ((hdr->flags & AMX_FLAG_COMPACT)==0) {
1002       ucell *code=(ucell *)((unsigned char *)program+(int)hdr->cod);
1003       while (code<(ucell *)((unsigned char *)program+(int)hdr->hea))
1004         swapcell(code++);
1005     } /* if */
1006   #endif
1007   assert((hdr->flags & AMX_FLAG_COMPACT)!=0 || hdr->hea == hdr->size);
1008   if ((hdr->flags & AMX_FLAG_COMPACT)!=0) {
1009     #if AMX_COMPACTMARGIN > 2
1010       expand((unsigned char *)program+(int)hdr->cod,
1011              hdr->size - hdr->cod, hdr->hea - hdr->cod);
1012     #else
1013       return AMX_ERR_FORMAT;
1014     #endif
1015   } /* if */
1016 
1017   amx->base=(unsigned char *)program;
1018 
1019   /* set initial values */
1020   amx->hlw=hdr->hea - hdr->dat; /* stack and heap relative to data segment */
1021   amx->stp=hdr->stp - hdr->dat - sizeof(cell);
1022   amx->hea=amx->hlw;
1023   amx->stk=amx->stp;
1024   #if defined AMX_DEFCALLBACK
1025     if (amx->callback==NULL)
1026       amx->callback=amx_Callback;
1027   #endif
1028   /* to split the data segment off the code segment, the "data" field must
1029    * be set to a non-NULL value on initialization, before calling amx_Init()
1030    */
1031   if (amx->data!=NULL) {
1032     data=amx->data;
1033     memcpy(data,amx->base+(int)hdr->dat,(size_t)(hdr->hea-hdr->dat));
1034   } else {
1035     data=amx->base+(int)hdr->dat;
1036   } /* if */
1037 
1038   /* Set a zero cell at the top of the stack, which functions
1039    * as a sentinel for strings.
1040    */
1041   * (cell *)(data+(int)(hdr->stp-hdr->dat-sizeof(cell)))=0;
1042 
1043   /* also align all addresses in the public function, public variable,
1044    * public tag and native function tables --offsets into the name table
1045    * (if present) must also be swapped.
1046    */
1047   #if BYTE_ORDER==BIG_ENDIAN
1048   { /* local */
1049     AMX_FUNCSTUB *fs;
1050     int i,num;
1051 
1052     fs=GETENTRY(hdr,natives,0);
1053     num=NUMENTRIES(hdr,natives,libraries);
1054     for (i=0; i<num; i++) {
1055       amx_AlignCell(&fs->address);      /* redundant, because it should be zero */
1056       if (USENAMETABLE(hdr))
1057         amx_Align32(&((AMX_FUNCSTUBNT*)fs)->nameofs);
1058       fs=(AMX_FUNCSTUB*)((unsigned char *)fs+hdr->defsize);
1059     } /* for */
1060 
1061     fs=GETENTRY(hdr,publics,0);
1062     assert(hdr->publics<=hdr->natives);
1063     num=NUMENTRIES(hdr,publics,natives);
1064     for (i=0; i<num; i++) {
1065       amx_AlignCell(&fs->address);
1066       if (USENAMETABLE(hdr))
1067         amx_Align32(&((AMX_FUNCSTUBNT*)fs)->nameofs);
1068       fs=(AMX_FUNCSTUB*)((unsigned char *)fs+hdr->defsize);
1069     } /* for */
1070 
1071     fs=GETENTRY(hdr,pubvars,0);
1072     assert(hdr->pubvars<=hdr->tags);
1073     num=NUMENTRIES(hdr,pubvars,tags);
1074     for (i=0; i<num; i++) {
1075       amx_AlignCell(&fs->address);
1076       if (USENAMETABLE(hdr))
1077         amx_Align32(&((AMX_FUNCSTUBNT*)fs)->nameofs);
1078       fs=(AMX_FUNCSTUB*)((unsigned char *)fs+hdr->defsize);
1079     } /* for */
1080 
1081     fs=GETENTRY(hdr,tags,0);
1082     if (hdr->file_version<7) {
1083       assert(hdr->tags<=hdr->cod);
1084       num=NUMENTRIES(hdr,tags,cod);
1085     } else {
1086       assert(hdr->tags<=hdr->nametable);
1087       num=NUMENTRIES(hdr,tags,nametable);
1088     } /* if */
1089     for (i=0; i<num; i++) {
1090       amx_AlignCell(&fs->address);
1091       if (USENAMETABLE(hdr))
1092         amx_Align32(&((AMX_FUNCSTUBNT*)fs)->nameofs);
1093       fs=(AMX_FUNCSTUB*)((unsigned char *)fs+hdr->defsize);
1094     } /* for */
1095   } /* local */
1096   #endif
1097 
1098   /* relocate call and jump instructions */
1099   if ((err=amx_BrowseRelocate(amx))!=AMX_ERR_NONE)
1100     return err;
1101 
1102   /* load any extension modules that the AMX refers to */
1103   #if (defined _Windows || defined LINUX || defined __FreeBSD__ || defined __OpenBSD__) && !defined AMX_NODYNALOAD
1104     #if defined LINUX || defined __FreeBSD__ || defined __OpenBSD__
1105       root=getenv("AMXLIB");
1106     #endif
1107     hdr=(AMX_HEADER *)amx->base;
1108     numlibraries=NUMENTRIES(hdr,libraries,pubvars);
1109     for (i=0; i<numlibraries; i++) {
1110       lib=GETENTRY(hdr,libraries,i);
1111       libname[0]='\0';
1112       #if defined LINUX || defined __FreeBSD__ || defined __OpenBSD__
1113         if (root!=NULL && *root!='\0') {
1114           strcpy(libname,root);
1115           if (libname[strlen(libname)-1]!='/')
1116             strcat(libname,"/");
1117         } /* if */
1118       #endif
1119       strcat(libname,"amx");
1120       strcat(libname,GETENTRYNAME(hdr,lib));
1121       #if defined _Windows
1122         strcat(libname,".dll");
1123         #if defined __WIN32__
1124           hlib=LoadLibraryA(libname);
1125         #else
1126           hlib=LoadLibrary(libname);
1127           if (hlib<=HINSTANCE_ERROR)
1128             hlib=NULL;
1129         #endif
1130       #elif defined LINUX || defined __FreeBSD__ || defined __OpenBSD__
1131         strcat(libname,".so");
1132         hlib=dlopen(libname,RTLD_NOW);
1133       #endif
1134       if (hlib!=NULL) {
1135         /* a library that cannot be loaded or that does not have the required
1136          * initialization function is simply ignored
1137          */
1138         char funcname[sNAMEMAX+9]; /* +1 for '\0', +4 for 'amx_', +4 for 'Init' */
1139         strcpy(funcname,"amx_");
1140         strcat(funcname,GETENTRYNAME(hdr,lib));
1141         strcat(funcname,"Init");
1142         #if defined _Windows
1143           libinit=(AMX_ENTRY)GetProcAddress(hlib,funcname);
1144         #elif defined LINUX || defined __FreeBSD__ || defined __OpenBSD__
1145           libinit=(AMX_ENTRY)dlsym(hlib,funcname);
1146         #endif
1147         if (libinit!=NULL)
1148           libinit(amx);
1149       } /* if */
1150       lib->address=(ucell)hlib;
1151     } /* for */
1152   #endif
1153 
1154   return AMX_ERR_NONE;
1155 }
1156 
1157 #if defined JIT
1158 
1159   #define CODESIZE_JIT    8192  /* approximate size of the code for the JIT */
1160 
1161   #if defined __WIN32__   /* this also applies to Win32 "console" applications */
1162 
1163     #define ALIGN(addr)     (addr)
1164 
1165     #define PROT_READ       0x1         /* page can be read */
1166     #define PROT_WRITE      0x2         /* page can be written */
1167     #define PROT_EXEC       0x4         /* page can be executed */
1168     #define PROT_NONE       0x0         /* page can not be accessed */
1169 
1170     static int mprotect(void *addr, size_t len, int prot)
1171     {
1172       DWORD prev, p = 0;
1173       if ((prot & PROT_WRITE)!=0)
1174         p = PAGE_EXECUTE_READWRITE;
1175       else
1176         p |= PAGE_EXECUTE_READ;
1177       return !VirtualProtect(addr, len, p, &prev);
1178     }
1179 
1180   #elif defined LINUX || defined __FreeBSD__ || defined __OpenBSD__
1181 
1182     /* Linux already has mprotect() */
1183     #define ALIGN(addr) (char *)(((long)addr + sysconf(_SC_PAGESIZE)-1) & ~(sysconf(_SC_PAGESIZE)-1))
1184 
1185   #else
1186 
1187     // TODO: Add cases for Linux, Unix, OS/2, ...
1188 
1189     /* DOS32 has no imposed limits on its segments */
1190     #define ALIGN(addr)     (addr)
1191     #define mprotect(addr, len, prot)   (0)
1192 
1193   #endif /* #if defined __WIN32 __ */
1194 
1195 int AMXAPI amx_InitJIT(AMX *amx, void *reloc_table, void *native_code)
1196 {
1197   int res;
1198   AMX_HEADER *hdr;
1199 
1200   if ((amx->flags & AMX_FLAG_JITC)==0)
1201     return AMX_ERR_INIT_JIT;    /* flag not set, this AMX is not prepared for JIT */
1202   if (hdr->file_version>MAX_FILE_VER_JIT)
1203     return AMX_ERR_VERSION;     /* JIT may not support the newest file version(s) */
1204 
1205   /* Patching SYSREQ.C opcodes to SYSREQ.D cannot work in the JIT, because the
1206    * program would need to be re-JIT-compiled after patching a P-code
1207    * instruction. If this field is not zero, something went wrong with the
1208    * amx_BrowseRelocate().
1209    */
1210   assert(amx->sysreq_d==0);
1211 
1212   if (mprotect(ALIGN(asm_runJIT), CODESIZE_JIT, PROT_READ | PROT_WRITE | PROT_EXEC) != 0)
1213     return AMX_ERR_INIT_JIT;
1214 
1215   /* copy the prefix */
1216   memcpy(native_code, amx->base, ((AMX_HEADER *)(amx->base))->cod);
1217   hdr = native_code;
1218 
1219   /* JIT rulz! (TM) */
1220   /* MP: added check for correct compilation */
1221   if ((res = asm_runJIT(amx->base, reloc_table, native_code)) == 0) {
1222     /* update the required memory size (the previous value was a
1223      * conservative estimate, now we know the exact size)
1224      */
1225     amx->code_size = (hdr->dat + hdr->stp + 3) & ~3;
1226     /* The compiled code is relocatable, since only relative jumps are
1227      * used for destinations within the generated code and absoulute
1228      * addresses for jumps into the runtime, which is fixed in memory.
1229      */
1230     amx->base = (unsigned char*) native_code;
1231     amx->cip = hdr->cip;
1232     amx->hea = hdr->hea;
1233     amx->hlw = hdr->hea;
1234     amx->stp = hdr->stp - sizeof(cell);
1235     /* also put a sentinel for strings at the top the stack */
1236     *(cell *)((char*)native_code + hdr->dat + hdr->stp - sizeof(cell)) = 0;
1237     amx->stk = amx->stp;
1238   } /* if */
1239 
1240   return (res == 0) ? AMX_ERR_NONE : AMX_ERR_INIT_JIT;
1241 }
1242 
1243 #else /* #if defined JIT */
1244 
1245 int AMXAPI amx_InitJIT(AMX *amx,void *compiled_program,void *reloc_table)
1246 {
1247   (void)amx;
1248   (void)compiled_program;
1249   (void)reloc_table;
1250   return AMX_ERR_INIT_JIT;
1251 }
1252 
1253 #endif  /* #if defined JIT */
1254 
1255 #endif  /* AMX_INIT */
1256 
1257 #if defined AMX_CLEANUP
1258 int AMXAPI amx_Cleanup(AMX *amx)
1259 {
1260   #if (defined _Windows || defined LINUX || defined __FreeBSD__ || defined __OpenBSD__) && !defined AMX_NODYNALOAD
1261     #if defined _Windows
1262       typedef int (FAR WINAPI *AMX_ENTRY)(AMX FAR *amx);
1263     #elif defined LINUX || defined __FreeBSD__ || defined __OpenBSD__
1264       typedef int (*AMX_ENTRY)(AMX *amx);
1265     #endif
1266     AMX_HEADER *hdr;
1267     int numlibraries,i;
1268     AMX_FUNCSTUB *lib;
1269     AMX_ENTRY libcleanup;
1270   #endif
1271 
1272   /* unload all extension modules */
1273   #if (defined _Windows || defined LINUX || defined __FreeBSD__ || defined __OpenBSD__) && !defined AMX_NODYNALOAD
1274     hdr=(AMX_HEADER *)amx->base;
1275     assert(hdr->magic==AMX_MAGIC);
1276     numlibraries=NUMENTRIES(hdr,libraries,pubvars);
1277     for (i=0; i<numlibraries; i++) {
1278       lib=GETENTRY(hdr,libraries,i);
1279       if (lib->address!=0) {
1280         char funcname[sNAMEMAX+12]; /* +1 for '\0', +4 for 'amx_', +7 for 'Cleanup' */
1281         strcpy(funcname,"amx_");
1282         strcat(funcname,GETENTRYNAME(hdr,lib));
1283         strcat(funcname,"Cleanup");
1284         #if defined _Windows
1285           libcleanup=(AMX_ENTRY)GetProcAddress((HINSTANCE)lib->address,funcname);
1286         #elif defined LINUX || defined __FreeBSD__ || defined __OpenBSD__
1287           libcleanup=(AMX_ENTRY)dlsym((void*)lib->address,funcname);
1288         #endif
1289         if (libcleanup!=NULL)
1290           libcleanup(amx);
1291         #if defined _Windows
1292           FreeLibrary((HINSTANCE)lib->address);
1293         #elif defined LINUX || defined __FreeBSD__ || defined __OpenBSD__
1294           dlclose((void*)lib->address);
1295         #endif
1296       } /* if */
1297     } /* for */
1298   #else
1299     (void)amx;
1300   #endif
1301   return AMX_ERR_NONE;
1302 }
1303 #endif /* AMX_CLEANUP */
1304 
1305 #if defined AMX_CLONE
1306 int AMXAPI amx_Clone(AMX *amxClone, AMX *amxSource, void *data)
1307 {
1308   AMX_HEADER *hdr;
1309   unsigned char _FAR *dataSource;
1310 
1311   if (amxSource==NULL)
1312     return AMX_ERR_FORMAT;
1313   if (amxClone==NULL)
1314     return AMX_ERR_PARAMS;
1315   if ((amxSource->flags & AMX_FLAG_RELOC)==0)
1316     return AMX_ERR_INIT;
1317   hdr=(AMX_HEADER *)amxSource->base;
1318   if (hdr->magic!=AMX_MAGIC)
1319     return AMX_ERR_FORMAT;
1320   if (hdr->file_version>CUR_FILE_VERSION || hdr->amx_version<MIN_FILE_VERSION)
1321     return AMX_ERR_VERSION;
1322 
1323   /* set initial values */
1324   amxClone->base=amxSource->base;
1325   amxClone->hlw=hdr->hea - hdr->dat; /* stack and heap relative to data segment */
1326   amxClone->stp=hdr->stp - hdr->dat - sizeof(cell);
1327   amxClone->hea=amxClone->hlw;
1328   amxClone->stk=amxClone->stp;
1329   if (amxClone->callback==NULL)
1330     amxClone->callback=amxSource->callback;
1331   if (amxClone->debug==NULL)
1332     amxClone->debug=amxSource->debug;
1333   amxClone->flags=amxSource->flags;
1334 
1335   /* copy the data segment; the stack and the heap can be left uninitialized */
1336   assert(data!=NULL);
1337   amxClone->data=(unsigned char _FAR *)data;
1338   dataSource=(amxSource->data!=NULL) ? amxSource->data : amxSource->base+(int)hdr->dat;
1339   memcpy(amxClone->data,dataSource,(size_t)(hdr->hea-hdr->dat));
1340 
1341   /* Set a zero cell at the top of the stack, which functions
1342    * as a sentinel for strings.
1343    */
1344   * (cell *)(amxClone->data+(int)amxClone->stp) = 0;
1345 
1346   return AMX_ERR_NONE;
1347 }
1348 #endif /* AMX_CLONE */
1349 
1350 #if defined AMX_MEMINFO
1351 int AMXAPI amx_MemInfo(AMX *amx, long *codesize, long *datasize, long *stackheap)
1352 {
1353   AMX_HEADER *hdr;
1354 
1355   if (amx==NULL)
1356     return AMX_ERR_FORMAT;
1357   hdr=(AMX_HEADER *)amx->base;
1358   if (hdr->magic!=AMX_MAGIC)
1359     return AMX_ERR_FORMAT;
1360   if (hdr->file_version>CUR_FILE_VERSION || hdr->amx_version<MIN_FILE_VERSION)
1361     return AMX_ERR_VERSION;
1362 
1363   if (codesize!=NULL)
1364     *codesize=hdr->dat - hdr->cod;
1365   if (datasize!=NULL)
1366     *datasize=hdr->hea - hdr->dat;
1367   if (stackheap!=NULL)
1368     *stackheap=hdr->stp - hdr->hea;
1369 
1370   return AMX_ERR_NONE;
1371 }
1372 #endif /* AMX_MEMINFO */
1373 
1374 #if defined AMX_NAMELENGTH
1375 int AMXAPI amx_NameLength(AMX *amx, int *length)
1376 {
1377   AMX_HEADER *hdr=(AMX_HEADER *)amx->base;
1378   assert(hdr!=NULL);
1379   assert(hdr->magic==AMX_MAGIC);
1380   if (USENAMETABLE(hdr)) {
1381     uint16_t *namelength=(uint16_t*)(amx->base + (unsigned)hdr->nametable);
1382     *length=*namelength;
1383     assert(hdr->file_version>=7); /* name table exists only for file version 7+ */
1384   } else {
1385     *length=hdr->defsize - sizeof(ucell);
1386   } /* if */
1387   return AMX_ERR_NONE;
1388 }
1389 #endif /* AMX_NAMELENGTH */
1390 
1391 #if defined AMX_XXXNATIVES
1392 int AMXAPI amx_NumNatives(AMX *amx, int *number)
1393 {
1394   AMX_HEADER *hdr=(AMX_HEADER *)amx->base;
1395   assert(hdr!=NULL);
1396   assert(hdr->magic==AMX_MAGIC);
1397   assert(hdr->natives<=hdr->libraries);
1398   *number=NUMENTRIES(hdr,natives,libraries);
1399   return AMX_ERR_NONE;
1400 }
1401 
1402 int AMXAPI amx_GetNative(AMX *amx, int index, char *funcname)
1403 {
1404   AMX_HEADER *hdr;
1405   AMX_FUNCSTUB *func;
1406 
1407   hdr=(AMX_HEADER *)amx->base;
1408   assert(hdr!=NULL);
1409   assert(hdr->magic==AMX_MAGIC);
1410   assert(hdr->natives<=hdr->libraries);
1411   if (index>=(cell)NUMENTRIES(hdr,natives,libraries))
1412     return AMX_ERR_INDEX;
1413 
1414   func=GETENTRY(hdr,natives,index);
1415   strcpy(funcname,GETENTRYNAME(hdr,func));
1416   return AMX_ERR_NONE;
1417 }
1418 
1419 int AMXAPI amx_FindNative(AMX *amx, const char *name, int *index)
1420 {
1421   int first,last,mid,result;
1422   char pname[sNAMEMAX+1];
1423 
1424   amx_NumNatives(amx, &last);
1425   last--;       /* last valid index is 1 less than the number of functions */
1426   first=0;
1427   /* binary search */
1428   while (first<=last) {
1429     mid=(first+last)/2;
1430     amx_GetNative(amx, mid, pname);
1431     result=strcmp(pname,name);
1432     if (result>0) {
1433       last=mid-1;
1434     } else if (result<0) {
1435       first=mid+1;
1436     } else {
1437       *index=mid;
1438       return AMX_ERR_NONE;
1439     } /* if */
1440   } /* while */
1441   /* not found, set to an invalid index, so amx_Exec() will fail */
1442   *index=INT_MAX;
1443   return AMX_ERR_NOTFOUND;
1444 }
1445 #endif /* AMX_XXXNATIVES */
1446 
1447 #if defined AMX_XXXPUBLICS
1448 int AMXAPI amx_NumPublics(AMX *amx, int *number)
1449 {
1450   AMX_HEADER *hdr=(AMX_HEADER *)amx->base;
1451   assert(hdr!=NULL);
1452   assert(hdr->magic==AMX_MAGIC);
1453   assert(hdr->publics<=hdr->natives);
1454   *number=NUMENTRIES(hdr,publics,natives);
1455   return AMX_ERR_NONE;
1456 }
1457 
1458 int AMXAPI amx_GetPublic(AMX *amx, int index, char *funcname)
1459 {
1460   AMX_HEADER *hdr;
1461   AMX_FUNCSTUB *func;
1462 
1463   hdr=(AMX_HEADER *)amx->base;
1464   assert(hdr!=NULL);
1465   assert(hdr->magic==AMX_MAGIC);
1466   assert(hdr->publics<=hdr->natives);
1467   if (index>=(cell)NUMENTRIES(hdr,publics,natives))
1468     return AMX_ERR_INDEX;
1469 
1470   func=GETENTRY(hdr,publics,index);
1471   strcpy(funcname,GETENTRYNAME(hdr,func));
1472   return AMX_ERR_NONE;
1473 }
1474 
1475 int AMXAPI amx_FindPublic(AMX *amx, const char *name, int *index)
1476 {
1477   int first,last,mid,result;
1478   char pname[sNAMEMAX+1];
1479 
1480   amx_NumPublics(amx, &last);
1481   last--;       /* last valid index is 1 less than the number of functions */
1482   first=0;
1483   /* binary search */
1484   while (first<=last) {
1485     mid=(first+last)/2;
1486     amx_GetPublic(amx, mid, pname);
1487     result=strcmp(pname,name);
1488     if (result>0) {
1489       last=mid-1;
1490     } else if (result<0) {
1491       first=mid+1;
1492     } else {
1493       *index=mid;
1494       return AMX_ERR_NONE;
1495     } /* if */
1496   } /* while */
1497   /* not found, set to an invalid index, so amx_Exec() will fail */
1498   *index=INT_MAX;
1499   return AMX_ERR_NOTFOUND;
1500 }
1501 #endif /* AMX_XXXPUBLICS */
1502 
1503 #if defined AMX_XXXPUBVARS
1504 int AMXAPI amx_NumPubVars(AMX *amx, int *number)
1505 {
1506   AMX_HEADER *hdr=(AMX_HEADER *)amx->base;
1507 
1508   assert(hdr!=NULL);
1509   assert(hdr->magic==AMX_MAGIC);
1510   assert(hdr->pubvars<=hdr->tags);
1511   *number=NUMENTRIES(hdr,pubvars,tags);
1512   return AMX_ERR_NONE;
1513 }
1514 
1515 int AMXAPI amx_GetPubVar(AMX *amx, int index, char *varname, cell *amx_addr)
1516 {
1517   AMX_HEADER *hdr;
1518   AMX_FUNCSTUB *var;
1519 
1520   hdr=(AMX_HEADER *)amx->base;
1521   assert(hdr!=NULL);
1522   assert(hdr->magic==AMX_MAGIC);
1523   assert(hdr->pubvars<=hdr->tags);
1524   if (index>=(cell)NUMENTRIES(hdr,pubvars,tags))
1525     return AMX_ERR_INDEX;
1526 
1527   var=GETENTRY(hdr,pubvars,index);
1528   strcpy(varname,GETENTRYNAME(hdr,var));
1529   *amx_addr=var->address;
1530   return AMX_ERR_NONE;
1531 }
1532 
1533 int AMXAPI amx_FindPubVar(AMX *amx, const char *varname, cell *amx_addr)
1534 {
1535   int first,last,mid,result;
1536   char pname[sNAMEMAX+1];
1537   cell paddr;
1538 
1539   amx_NumPubVars(amx, &last);
1540   last--;       /* last valid index is 1 less than the number of functions */
1541   first=0;
1542   /* binary search */
1543   while (first<=last) {
1544     mid=(first+last)/2;
1545     amx_GetPubVar(amx, mid, pname, &paddr);
1546     result=strcmp(pname,varname);
1547     if (result>0) {
1548       last=mid-1;
1549     } else if (result<0) {
1550       first=mid+1;
1551     } else {
1552       *amx_addr=paddr;
1553       return AMX_ERR_NONE;
1554     } /* if */
1555   } /* while */
1556   /* not found */
1557   *amx_addr=0;
1558   return AMX_ERR_NOTFOUND;
1559 }
1560 #endif /* AMX_XXXPUBVARS */
1561 
1562 #if defined AMX_XXXTAGS
1563 int AMXAPI amx_NumTags(AMX *amx, int *number)
1564 {
1565   AMX_HEADER *hdr=(AMX_HEADER *)amx->base;
1566   assert(hdr!=NULL);
1567   assert(hdr->magic==AMX_MAGIC);
1568   if (hdr->file_version<5) {    /* the tagname table appeared in file format 5 */
1569     *number=0;
1570     return AMX_ERR_VERSION;
1571   } /* if */
1572   if (hdr->file_version<7) {
1573     assert(hdr->tags<=hdr->cod);
1574     *number=NUMENTRIES(hdr,tags,cod);
1575   } else {
1576     assert(hdr->tags<=hdr->nametable);
1577     *number=NUMENTRIES(hdr,tags,nametable);
1578   } /* if */
1579   return AMX_ERR_NONE;
1580 }
1581 
1582 int AMXAPI amx_GetTag(AMX *amx, int index, char *tagname, cell *tag_id)
1583 {
1584   AMX_HEADER *hdr;
1585   AMX_FUNCSTUB *tag;
1586 
1587   hdr=(AMX_HEADER *)amx->base;
1588   assert(hdr!=NULL);
1589   assert(hdr->magic==AMX_MAGIC);
1590   if (hdr->file_version<5) {    /* the tagname table appeared in file format 5 */
1591     *tagname='\0';
1592     *tag_id=0;
1593     return AMX_ERR_VERSION;
1594   } /* if */
1595 
1596   if (hdr->file_version<7) {
1597     assert(hdr->tags<=hdr->cod);
1598     if (index>=(cell)NUMENTRIES(hdr,tags,cod))
1599       return AMX_ERR_INDEX;
1600   } else {
1601     assert(hdr->tags<=hdr->nametable);
1602     if (index>=(cell)NUMENTRIES(hdr,tags,nametable))
1603       return AMX_ERR_INDEX;
1604   } /* if */
1605 
1606   tag=GETENTRY(hdr,tags,index);
1607   strcpy(tagname,GETENTRYNAME(hdr,tag));
1608   *tag_id=tag->address;
1609 
1610   return AMX_ERR_NONE;
1611 }
1612 
1613 int AMXAPI amx_FindTagId(AMX *amx, cell tag_id, char *tagname)
1614 {
1615   int first,last,mid;
1616   cell mid_id;
1617 
1618   #if !defined NDEBUG
1619     /* verify that the tagname table is sorted on the tag_id */
1620     amx_NumTags(amx, &last);
1621     if (last>0) {
1622       cell cur_id;
1623       amx_GetTag(amx,0,tagname,&cur_id);
1624       for (first=1; first<last; first++) {
1625         amx_GetTag(amx,first,tagname,&mid_id);
1626         assert(cur_id<mid_id);
1627         cur_id=mid_id;
1628       } /* for */
1629     } /* if */
1630   #endif
1631 
1632   amx_NumTags(amx, &last);
1633   last--;       /* last valid index is 1 less than the number of functions */
1634   first=0;
1635   /* binary search */
1636   while (first<=last) {
1637     mid=(first+last)/2;
1638     amx_GetTag(amx,mid,tagname,&mid_id);
1639     if (mid_id>tag_id)
1640       last=mid-1;
1641     else if (mid_id<tag_id)
1642       first=mid+1;
1643     else
1644       return AMX_ERR_NONE;
1645   } /* while */
1646   /* not found */
1647   *tagname='\0';
1648   return AMX_ERR_NOTFOUND;
1649 }
1650 #endif /* AMX_XXXTAGS */
1651 
1652 #if defined AMX_XXXUSERDATA
1653 int AMXAPI amx_GetUserData(AMX *amx, long tag, void **ptr)
1654 {
1655   int index;
1656 
1657   assert(amx!=NULL);
1658   assert(tag!=0);
1659   for (index=0; index<AMX_USERNUM && amx->usertags[index]!=tag; index++)
1660     /* nothing */;
1661   if (index>=AMX_USERNUM)
1662     return AMX_ERR_USERDATA;
1663   *ptr=amx->userdata[index];
1664   return AMX_ERR_NONE;
1665 }
1666 
1667 int AMXAPI amx_SetUserData(AMX *amx, long tag, void *ptr)
1668 {
1669   int index;
1670 
1671   assert(amx!=NULL);
1672   assert(tag!=0);
1673   /* try to find existing tag */
1674   for (index=0; index<AMX_USERNUM && amx->usertags[index]!=tag; index++)
1675     /* nothing */;
1676   /* if not found, try to find empty tag */
1677   if (index>=AMX_USERNUM)
1678     for (index=0; index<AMX_USERNUM && amx->usertags[index]!=0; index++)
1679       /* nothing */;
1680   /* if still not found, quit with error */
1681   if (index>=AMX_USERNUM)
1682     return AMX_ERR_INDEX;
1683   /* set the tag and the value */
1684   amx->usertags[index]=tag;
1685   amx->userdata[index]=ptr;
1686   return AMX_ERR_NONE;
1687 }
1688 #endif /* AMX_XXXUSERDATA */
1689 
1690 #if defined AMX_REGISTER || defined AMX_EXEC || defined AMX_INIT
1691 static AMX_NATIVE findfunction(const char *name, const AMX_NATIVE_INFO *list, int number)
1692 {
1693   int i;
1694 
1695   assert(list!=NULL);
1696   for (i=0; list[i].name!=NULL && (i<number || number==-1); i++)
1697     if (strcmp(name,list[i].name)==0)
1698       return list[i].func;
1699 
1700   return NULL;
1701 }
1702 
1703 int AMXAPI amx_Register(AMX *amx, const AMX_NATIVE_INFO *list, int number)
1704 {
1705   AMX_FUNCSTUB *func;
1706   AMX_HEADER *hdr;
1707   int i,numnatives,err;
1708   AMX_NATIVE funcptr;
1709 
1710   hdr=(AMX_HEADER *)amx->base;
1711   assert(hdr!=NULL);
1712   assert(hdr->magic==AMX_MAGIC);
1713   assert(hdr->natives<=hdr->libraries);
1714   numnatives=NUMENTRIES(hdr,natives,libraries);
1715 
1716   err=AMX_ERR_NONE;
1717   func=GETENTRY(hdr,natives,0);
1718   for (i=0; i<numnatives; i++) {
1719     if (func->address==0) {
1720       /* this function is not yet located */
1721       funcptr=(list!=NULL) ? findfunction(GETENTRYNAME(hdr,func),list,number) : NULL;
1722       if (funcptr!=NULL)
1723         func->address=(ucell)funcptr;
1724       else
1725         err=AMX_ERR_NOTFOUND;
1726     } /* if */
1727     func=(AMX_FUNCSTUB*)((unsigned char*)func+hdr->defsize);
1728   } /* for */
1729   if (err==AMX_ERR_NONE)
1730     amx->flags|=AMX_FLAG_NTVREG;
1731   return err;
1732 }
1733 #endif /* AMX_REGISTER || AMX_EXEC || AMX_INIT */
1734 
1735 #if defined AMX_NATIVEINFO
1736 AMX_NATIVE_INFO * AMXAPI amx_NativeInfo(const char *name, AMX_NATIVE func)
1737 {
1738   static AMX_NATIVE_INFO n;
1739   n.name=name;
1740   n.func=func;
1741   return &n;
1742 }
1743 #endif /* AMX_NATIVEINFO */
1744 
1745 
1746 #define STKMARGIN       ((cell)(16*sizeof(cell)))
1747 
1748 #if defined AMX_PUSHXXX
1749 
1750 int AMXAPI amx_Push(AMX *amx, cell value)
1751 {
1752   AMX_HEADER *hdr;
1753   unsigned char *data;
1754 
1755   if (amx->hea+STKMARGIN>amx->stk)
1756     return AMX_ERR_STACKERR;
1757   hdr=(AMX_HEADER *)amx->base;
1758   data=(amx->data!=NULL) ? amx->data : amx->base+(int)hdr->dat;
1759   amx->stk-=sizeof(cell);
1760   amx->paramcount+=1;
1761   *(cell *)(data+(int)amx->stk)=value;
1762   return AMX_ERR_NONE;
1763 }
1764 
1765 int AMXAPI amx_PushArray(AMX *amx, cell *amx_addr, cell **phys_addr, const cell array[], int numcells)
1766 {
1767   cell *paddr,xaddr;
1768   int err;
1769 
1770   assert(amx!=NULL);
1771   assert(array!=NULL);
1772 
1773   err=amx_Allot(amx,numcells,&xaddr,&paddr);
1774   if (err==AMX_ERR_NONE) {
1775     if (amx_addr!=NULL)
1776       *amx_addr=xaddr;
1777     if (phys_addr!=NULL)
1778       *phys_addr=paddr;
1779     memcpy(paddr,array,numcells*sizeof(cell));
1780     err=amx_Push(amx,xaddr);
1781   } /* if */
1782   return err;
1783 }
1784 
1785 int AMXAPI amx_PushString(AMX *amx, cell *amx_addr, cell **phys_addr, const char *string, int pack, int use_wchar)
1786 {
1787   cell *paddr, xaddr;
1788   int numcells,err;
1789 
1790   assert(amx!=NULL);
1791   assert(string!=NULL);
1792 
1793   #if defined AMX_ANSIONLY
1794     numcells=strlen(string) + 1;
1795   #else
1796     numcells= (use_wchar ? wcslen((const wchar_t*)string) : strlen(string)) + 1;
1797   #endif
1798   if (pack)
1799     numcells=(numcells+sizeof(cell)-1)/sizeof(cell);
1800   err=amx_Allot(amx,numcells,&xaddr,&paddr);
1801   if (err==AMX_ERR_NONE) {
1802     if (amx_addr!=NULL)
1803       *amx_addr=xaddr;
1804     if (phys_addr!=NULL)
1805       *phys_addr=paddr;
1806     amx_SetString(paddr,string,pack,use_wchar,UNLIMITED);
1807     err=amx_Push(amx,xaddr);
1808   } /* if */
1809   return err;
1810 }
1811 #endif /* AMX_PUSHXXX */
1812 
1813 #if defined AMX_EXEC || defined AMX_INIT
1814 
1815 /* It is assumed that the abstract machine can simply access the memory area
1816  * for the global data and the stack. If this is not the case, you need to
1817  * define the macro sets _R() and _W(), for reading and writing to memory.
1818  */
1819 #if !defined _R
1820   #define _R_DEFAULT            /* mark default memory access */
1821   #define _R(base,addr)         (* (cell *)((unsigned char*)(base)+(int)(addr)))
1822   #define _R8(base,addr)        (* (unsigned char *)((unsigned char*)(base)+(int)(addr)))
1823   #define _R16(base,addr)       (* (uint16_t *)((unsigned char*)(base)+(int)(addr)))
1824   #define _R32(base,addr)       (* (uint32_t *)((unsigned char*)(base)+(int)(addr)))
1825 #endif
1826 #if !defined _W
1827   #define _W_DEFAULT            /* mark default memory access */
1828   #define _W(base,addr,value)   ((*(cell *)((unsigned char*)(base)+(int)(addr)))=(cell)(value))
1829   #define _W8(base,addr,value)  ((*(unsigned char *)((unsigned char*)(base)+(int)(addr)))=(unsigned char)(value))
1830   #define _W16(base,addr,value) ((*(uint16_t *)((unsigned char*)(base)+(int)(addr)))=(uint16_t)(value))
1831   #define _W32(base,addr,value) ((*(uint32_t *)((unsigned char*)(base)+(int)(addr)))=(uint32_t)(value))
1832 #endif
1833 
1834 #if -8/3==-2 && 8/-3==-2
1835   #define TRUNC_SDIV    /* signed divisions are truncated on this platform */
1836 #else
1837   #define IABS(a)       ((a)>=0 ? (a) : (-a))
1838 #endif
1839 
1840 /* The pseudo-instructions come from the code stream. Normally, these are just
1841  * accessed from memory. When the instructions must be fetched in some other
1842  * way, the definition below must be pre-defined.
1843  * N.B.:
1844  *   - reading from a code address should increment the instruction pointer
1845  *     (called "cip")
1846  *   - only cell-sized accesses occur in code memory
1847  */
1848 #if !defined _RCODE
1849   #define _RCODE()      ( *cip++ )
1850 #endif
1851 
1852 #if !defined GETPARAM
1853   #define GETPARAM(v)   ( v=_RCODE() )   /* read a parameter from the opcode stream */
1854 #endif
1855 #define SKIPPARAM(n)    ( cip=(cell *)cip+(n) ) /* for obsolete opcodes */
1856 
1857 /* PUSH() and POP() are defined in terms of the _R() and _W() macros */
1858 #define PUSH(v)         ( stk-=sizeof(cell), _W(data,stk,v) )
1859 #define POP(v)          ( v=_R(data,stk), stk+=sizeof(cell) )
1860 
1861 #define ABORT(amx,v)    { (amx)->stk=reset_stk; (amx)->hea=reset_hea; return v; }
1862 
1863 #define CHKMARGIN()     if (hea+STKMARGIN>stk) return AMX_ERR_STACKERR
1864 #define CHKSTACK()      if (stk>amx->stp) return AMX_ERR_STACKLOW
1865 #define CHKHEAP()       if (hea<amx->hlw) return AMX_ERR_HEAPLOW
1866 
1867 #if (defined __GNUC__ || defined __ICC) && !(defined ASM32 || defined JIT)
1868     /* GNU C version uses the "labels as values" extension to create
1869      * fast "indirect threaded" interpreter. The Intel C/C++ compiler
1870      * supports this too.
1871      */
1872 
1873 #define NEXT(cip)       goto *((void*)(*cip++))
1874 
1875 int AMXAPI amx_Exec(AMX *amx, cell *retval, int index)
1876 {
1877 static const void * const amx_opcodelist[] = {
1878         &&op_none,      &&op_load_pri,  &&op_load_alt,  &&op_load_s_pri,
1879         &&op_load_s_alt,&&op_lref_pri,  &&op_lref_alt,  &&op_lref_s_pri,
1880         &&op_lref_s_alt,&&op_load_i,    &&op_lodb_i,    &&op_const_pri,
1881         &&op_const_alt, &&op_addr_pri,  &&op_addr_alt,  &&op_stor_pri,
1882         &&op_stor_alt,  &&op_stor_s_pri,&&op_stor_s_alt,&&op_sref_pri,
1883         &&op_sref_alt,  &&op_sref_s_pri,&&op_sref_s_alt,&&op_stor_i,
1884         &&op_strb_i,    &&op_lidx,      &&op_lidx_b,    &&op_idxaddr,
1885         &&op_idxaddr_b, &&op_align_pri, &&op_align_alt, &&op_lctrl,
1886         &&op_sctrl,     &&op_move_pri,  &&op_move_alt,  &&op_xchg,
1887         &&op_push_pri,  &&op_push_alt,  &&op_push_r,    &&op_push_c,
1888         &&op_push,      &&op_push_s,    &&op_pop_pri,   &&op_pop_alt,
1889         &&op_stack,     &&op_heap,      &&op_proc,      &&op_ret,
1890         &&op_retn,      &&op_call,      &&op_call_pri,  &&op_jump,
1891         &&op_jrel,      &&op_jzer,      &&op_jnz,       &&op_jeq,
1892         &&op_jneq,      &&op_jless,     &&op_jleq,      &&op_jgrtr,
1893         &&op_jgeq,      &&op_jsless,    &&op_jsleq,     &&op_jsgrtr,
1894         &&op_jsgeq,     &&op_shl,       &&op_shr,       &&op_sshr,
1895         &&op_shl_c_pri, &&op_shl_c_alt, &&op_shr_c_pri, &&op_shr_c_alt,
1896         &&op_smul,      &&op_sdiv,      &&op_sdiv_alt,  &&op_umul,
1897         &&op_udiv,      &&op_udiv_alt,  &&op_add,       &&op_sub,
1898         &&op_sub_alt,   &&op_and,       &&op_or,        &&op_xor,
1899         &&op_not,       &&op_neg,       &&op_invert,    &&op_add_c,
1900         &&op_smul_c,    &&op_zero_pri,  &&op_zero_alt,  &&op_zero,
1901         &&op_zero_s,    &&op_sign_pri,  &&op_sign_alt,  &&op_eq,
1902         &&op_neq,       &&op_less,      &&op_leq,       &&op_grtr,
1903         &&op_geq,       &&op_sless,     &&op_sleq,      &&op_sgrtr,
1904         &&op_sgeq,      &&op_eq_c_pri,  &&op_eq_c_alt,  &&op_inc_pri,
1905         &&op_inc_alt,   &&op_inc,       &&op_inc_s,     &&op_inc_i,
1906         &&op_dec_pri,   &&op_dec_alt,   &&op_dec,       &&op_dec_s,
1907         &&op_dec_i,     &&op_movs,      &&op_cmps,      &&op_fill,
1908         &&op_halt,      &&op_bounds,    &&op_sysreq_pri,&&op_sysreq_c,
1909         &&op_file,      &&op_line,      &&op_symbol,    &&op_srange,
1910         &&op_jump_pri,  &&op_switch,    &&op_casetbl,   &&op_swap_pri,
1911         &&op_swap_alt,  &&op_push_adr,  &&op_nop,       &&op_sysreq_n,
1912         &&op_symtag,    &&op_break,     &&op_push2_c,   &&op_push2,
1913         &&op_push2_s,   &&op_push2_adr, &&op_push3_c,   &&op_push3,
1914         &&op_push3_s,   &&op_push3_adr, &&op_push4_c,   &&op_push4,
1915         &&op_push4_s,   &&op_push4_adr, &&op_push5_c,   &&op_push5,
1916         &&op_push5_s,   &&op_push5_adr, &&op_load_both, &&op_load_s_both,
1917         &&op_const,     &&op_const_s,   &&op_sysreq_d,  &&op_sysreq_nd };
1918   AMX_HEADER *hdr;
1919   AMX_FUNCSTUB *func;
1920   unsigned char *code, *data;
1921   cell pri,alt,stk,frm,hea;
1922   cell reset_stk, reset_hea, *cip;
1923   cell offs,val;
1924   ucell codesize;
1925   int num,i;
1926 
1927   /* HACK: return label table (for amx_BrowseRelocate) if amx structure
1928    * has the AMX_FLAG_BROWSE flag set.
1929    */
1930   assert(amx!=NULL);
1931   if ((amx->flags & AMX_FLAG_BROWSE)==AMX_FLAG_BROWSE) {
1932     assert(sizeof(cell)==sizeof(void *));
1933     assert(retval!=NULL);
1934     *retval=(cell)amx_opcodelist;
1935     return 0;
1936   } /* if */
1937 
1938   if (amx->callback==NULL)
1939     return AMX_ERR_CALLBACK;
1940   if ((amx->flags & AMX_FLAG_RELOC)==0)
1941     return AMX_ERR_INIT;
1942   if ((amx->flags & AMX_FLAG_NTVREG)==0) {
1943     if ((num=amx_Register(amx,NULL,0))!=AMX_ERR_NONE)
1944       return num;
1945   } /* if */
1946   assert((amx->flags & AMX_FLAG_BROWSE)==0);
1947 
1948   /* set up the registers */
1949   hdr=(AMX_HEADER *)amx->base;
1950   assert(hdr->magic==AMX_MAGIC);
1951   codesize=(ucell)(hdr->dat-hdr->cod);
1952   code=amx->base+(int)hdr->cod;
1953   data=(amx->data!=NULL) ? amx->data : amx->base+(int)hdr->dat;
1954   hea=amx->hea;
1955   stk=amx->stk;
1956   reset_stk=stk;
1957   reset_hea=hea;
1958   alt=frm=pri=0;/* just to avoid compiler warnings */
1959   num=0;        /* just to avoid compiler warnings */
1960 
1961   /* get the start address */
1962   if (index==AMX_EXEC_MAIN) {
1963     if (hdr->cip<0)
1964       return AMX_ERR_INDEX;
1965     cip=(cell *)(code + (int)hdr->cip);
1966   } else if (index==AMX_EXEC_CONT) {
1967     /* all registers: pri, alt, frm, cip, hea, stk, reset_stk, reset_hea */
1968     frm=amx->frm;
1969     stk=amx->stk;
1970     hea=amx->hea;
1971     pri=amx->pri;
1972     alt=amx->alt;
1973     reset_stk=amx->reset_stk;
1974     reset_hea=amx->reset_hea;
1975     cip=(cell *)(code + (int)amx->cip);
1976   } else if (index<0) {
1977     return AMX_ERR_INDEX;
1978   } else {
1979     if (index>=(int)NUMENTRIES(hdr,publics,natives))
1980       return AMX_ERR_INDEX;
1981     func=GETENTRY(hdr,publics,index);
1982     cip=(cell *)(code + (int)func->address);
1983   } /* if */
1984   /* check values just copied */
1985   CHKSTACK();
1986   CHKHEAP();
1987   assert(check_endian());
1988 
1989   /* sanity checks */
1990   assert(OP_PUSH_PRI==36);
1991   assert(OP_PROC==46);
1992   assert(OP_SHL==65);
1993   assert(OP_SMUL==72);
1994   assert(OP_EQ==95);
1995   assert(OP_INC_PRI==107);
1996   assert(OP_MOVS==117);
1997   assert(OP_SYMBOL==126);
1998   #if PAWN_CELL_SIZE==16
1999     assert(sizeof(cell)==2);
2000   #elif PAWN_CELL_SIZE==32
2001     assert(sizeof(cell)==4);
2002   #elif PAWN_CELL_SIZE==64
2003     assert(sizeof(cell)==8);
2004   #else
2005     #error Unsupported cell size
2006   #endif
2007 
2008   if (index!=AMX_EXEC_CONT) {
2009     reset_stk+=amx->paramcount*sizeof(cell);
2010     PUSH(amx->paramcount*sizeof(cell));
2011     amx->paramcount=0;          /* push the parameter count to the stack & reset */
2012     PUSH(0);                    /* zero return address */
2013   } /* if */
2014   /* check stack/heap before starting to run */
2015   CHKMARGIN();
2016 
2017   /* start running */
2018   NEXT(cip);
2019 
2020   op_none:
2021     ABORT(amx,AMX_ERR_INVINSTR);
2022   op_load_pri:
2023     GETPARAM(offs);
2024     pri=_R(data,offs);
2025     NEXT(cip);
2026   op_load_alt:
2027     GETPARAM(offs);
2028     alt=_R(data,offs);
2029     NEXT(cip);
2030   op_load_s_pri:
2031     GETPARAM(offs);
2032     pri=_R(data,frm+offs);
2033     NEXT(cip);
2034   op_load_s_alt:
2035     GETPARAM(offs);
2036     alt=_R(data,frm+offs);
2037     NEXT(cip);
2038   op_lref_pri:
2039     GETPARAM(offs);
2040     offs=_R(data,offs);
2041     pri=_R(data,offs);
2042     NEXT(cip);
2043   op_lref_alt:
2044     GETPARAM(offs);
2045     offs=_R(data,offs);
2046     alt=_R(data,offs);
2047     NEXT(cip);
2048   op_lref_s_pri:
2049     GETPARAM(offs);
2050     offs=_R(data,frm+offs);
2051     pri=_R(data,offs);
2052     NEXT(cip);
2053   op_lref_s_alt:
2054     GETPARAM(offs);
2055     offs=_R(data,frm+offs);
2056     alt=_R(data,offs);
2057     NEXT(cip);
2058   op_load_i:
2059     /* verify address */
2060     if ((pri>=hea && pri<stk) || (ucell)pri>=(ucell)amx->stp)
2061       ABORT(amx,AMX_ERR_MEMACCESS);
2062     pri=_R(data,pri);
2063     NEXT(cip);
2064   op_lodb_i:
2065     GETPARAM(offs);
2066     /* verify address */
2067     if ((pri>=hea && pri<stk) || (ucell)pri>=(ucell)amx->stp)
2068       ABORT(amx,AMX_ERR_MEMACCESS);
2069     switch (offs) {
2070     case 1:
2071       pri=_R8(data,pri);
2072       break;
2073     case 2:
2074       pri=_R16(data,pri);
2075       break;
2076     case 4:
2077       pri=_R32(data,pri);
2078       break;
2079     } /* switch */
2080     NEXT(cip);
2081   op_const_pri:
2082     GETPARAM(pri);
2083     NEXT(cip);
2084   op_const_alt:
2085     GETPARAM(alt);
2086     NEXT(cip);
2087   op_addr_pri:
2088     GETPARAM(pri);
2089     pri+=frm;
2090     NEXT(cip);
2091   op_addr_alt:
2092     GETPARAM(alt);
2093     alt+=frm;
2094     NEXT(cip);
2095   op_stor_pri:
2096     GETPARAM(offs);
2097     _W(data,offs,pri);
2098     NEXT(cip);
2099   op_stor_alt:
2100     GETPARAM(offs);
2101     _W(data,offs,alt);
2102     NEXT(cip);
2103   op_stor_s_pri:
2104     GETPARAM(offs);
2105     _W(data,frm+offs,pri);
2106     NEXT(cip);
2107   op_stor_s_alt:
2108     GETPARAM(offs);
2109     _W(data,frm+offs,alt);
2110     NEXT(cip);
2111   op_sref_pri:
2112     GETPARAM(offs);
2113     offs=_R(data,offs);
2114     _W(data,offs,pri);
2115     NEXT(cip);
2116   op_sref_alt:
2117     GETPARAM(offs);
2118     offs=_R(data,offs);
2119     _W(data,offs,alt);
2120     NEXT(cip);
2121   op_sref_s_pri:
2122     GETPARAM(offs);
2123     offs=_R(data,frm+offs);
2124     _W(data,offs,pri);
2125     NEXT(cip);
2126   op_sref_s_alt:
2127     GETPARAM(offs);
2128     offs=_R(data,frm+offs);
2129     _W(data,offs,alt);
2130     NEXT(cip);
2131   op_stor_i:
2132     /* verify address */
2133     if ((alt>=hea && alt<stk) || (ucell)alt>=(ucell)amx->stp)
2134       ABORT(amx,AMX_ERR_MEMACCESS);
2135     _W(data,alt,pri);
2136     NEXT(cip);
2137   op_strb_i:
2138     GETPARAM(offs);
2139     /* verify address */
2140     if ((alt>=hea && alt<stk) || (ucell)alt>=(ucell)amx->stp)
2141       ABORT(amx,AMX_ERR_MEMACCESS);
2142     switch (offs) {
2143     case 1:
2144       _W8(data,alt,pri);
2145       break;
2146     case 2:
2147       _W16(data,alt,pri);
2148       break;
2149     case 4:
2150       _W32(data,alt,pri);
2151       break;
2152     } /* switch */
2153     NEXT(cip);
2154   op_lidx:
2155     offs=pri*sizeof(cell)+alt;  /* implicit shift value for a cell */
2156     /* verify address */
2157     if ((offs>=hea && offs<stk) || (ucell)offs>=(ucell)amx->stp)
2158       ABORT(amx,AMX_ERR_MEMACCESS);
2159     pri=_R(data,offs);
2160     NEXT(cip);
2161   op_lidx_b:
2162     GETPARAM(offs);
2163     offs=(pri << (int)offs)+alt;
2164     /* verify address */
2165     if ((offs>=hea && offs<stk) || (ucell)offs>=(ucell)amx->stp)
2166       ABORT(amx,AMX_ERR_MEMACCESS);
2167     pri=_R(data,offs);
2168     NEXT(cip);
2169   op_idxaddr:
2170     pri=pri*sizeof(cell)+alt;
2171     NEXT(cip);
2172   op_idxaddr_b:
2173     GETPARAM(offs);
2174     pri=(pri << (int)offs)+alt;
2175     NEXT(cip);
2176   op_align_pri:
2177     GETPARAM(offs);
2178     #if BYTE_ORDER==LITTLE_ENDIAN
2179       if (offs<(int)sizeof(cell))
2180         pri ^= sizeof(cell)-offs;
2181     #endif
2182     NEXT(cip);
2183   op_align_alt:
2184     GETPARAM(offs);
2185     #if BYTE_ORDER==LITTLE_ENDIAN
2186       if (offs<(int)sizeof(cell))
2187         alt ^= sizeof(cell)-offs;
2188     #endif
2189     NEXT(cip);
2190   op_lctrl:
2191     GETPARAM(offs);
2192     switch (offs) {
2193     case 0:
2194       pri=hdr->cod;
2195       break;
2196     case 1:
2197       pri=hdr->dat;
2198       break;
2199     case 2:
2200       pri=hea;
2201       break;
2202     case 3:
2203       pri=amx->stp;
2204       break;
2205     case 4:
2206       pri=stk;
2207       break;
2208     case 5:
2209       pri=frm;
2210       break;
2211     case 6:
2212       pri=(cell)((unsigned char *)cip - code);
2213       break;
2214     } /* switch */
2215     NEXT(cip);
2216   op_sctrl:
2217     GETPARAM(offs);
2218     switch (offs) {
2219     case 0:
2220     case 1:
2221     case 3:
2222       /* cannot change these parameters */
2223       break;
2224     case 2:
2225       hea=pri;
2226       break;
2227     case 4:
2228       stk=pri;
2229       break;
2230     case 5:
2231       frm=pri;
2232       break;
2233     case 6:
2234       cip=(cell *)(code + (int)pri);
2235       break;
2236     } /* switch */
2237     NEXT(cip);
2238   op_move_pri:
2239     pri=alt;
2240     NEXT(cip);
2241   op_move_alt:
2242     alt=pri;
2243     NEXT(cip);
2244   op_xchg:
2245     offs=pri;         /* offs is a temporary variable */
2246     pri=alt;
2247     alt=offs;
2248     NEXT(cip);
2249   op_push_pri:
2250     PUSH(pri);
2251     NEXT(cip);
2252   op_push_alt:
2253     PUSH(alt);
2254     NEXT(cip);
2255   op_push_c:
2256     GETPARAM(offs);
2257     PUSH(offs);
2258     NEXT(cip);
2259   op_push_r:
2260     GETPARAM(offs);
2261     while (offs--)
2262       PUSH(pri);
2263     NEXT(cip);
2264   op_push:
2265     GETPARAM(offs);
2266     PUSH(_R(data,offs));
2267     NEXT(cip);
2268   op_push_s:
2269     GETPARAM(offs);
2270     PUSH(_R(data,frm+offs));
2271     NEXT(cip);
2272   op_pop_pri:
2273     POP(pri);
2274     NEXT(cip);
2275   op_pop_alt:
2276     POP(alt);
2277     NEXT(cip);
2278   op_stack:
2279     GETPARAM(offs);
2280     alt=stk;
2281     stk+=offs;
2282     CHKMARGIN();
2283     CHKSTACK();
2284     NEXT(cip);
2285   op_heap:
2286     GETPARAM(offs);
2287     alt=hea;
2288     hea+=offs;
2289     CHKMARGIN();
2290     CHKHEAP();
2291     NEXT(cip);
2292   op_proc:
2293     PUSH(frm);
2294     frm=stk;
2295     CHKMARGIN();
2296     NEXT(cip);
2297   op_ret:
2298     POP(frm);
2299     POP(offs);
2300     /* verify the return address */
2301     if ((ucell)offs>=codesize)
2302       ABORT(amx,AMX_ERR_MEMACCESS);
2303     cip=(cell *)(code+(int)offs);
2304     NEXT(cip);
2305   op_retn:
2306     POP(frm);
2307     POP(offs);
2308     /* verify the return address */
2309     if ((ucell)offs>=codesize)
2310       ABORT(amx,AMX_ERR_MEMACCESS);
2311     cip=(cell *)(code+(int)offs);
2312     stk+= _R(data,stk) + sizeof(cell);  /* remove parameters from the stack */
2313     NEXT(cip);
2314   op_call:
2315     PUSH(((unsigned char *)cip-code)+sizeof(cell));/* push address behind instruction */
2316     cip=JUMPABS(code, cip);                     /* jump to the address */
2317     NEXT(cip);
2318   op_call_pri:
2319     PUSH((unsigned char *)cip-code);
2320     cip=(cell *)(code+(int)pri);
2321     NEXT(cip);
2322   op_jump:
2323     /* since the GETPARAM() macro modifies cip, you cannot
2324      * do GETPARAM(cip) directly */
2325     cip=JUMPABS(code, cip);
2326     NEXT(cip);
2327   op_jrel:
2328     offs=*cip;
2329     cip=(cell *)((unsigned char *)cip + (int)offs + sizeof(cell));
2330     NEXT(cip);
2331   op_jzer:
2332     if (pri==0)
2333       cip=JUMPABS(code, cip);
2334     else
2335       cip=(cell *)((unsigned char *)cip+sizeof(cell));
2336     NEXT(cip);
2337   op_jnz:
2338     if (pri!=0)
2339       cip=JUMPABS(code, cip);
2340     else
2341       cip=(cell *)((unsigned char *)cip+sizeof(cell));
2342     NEXT(cip);
2343   op_jeq:
2344     if (pri==alt)
2345       cip=JUMPABS(code, cip);
2346     else
2347       cip=(cell *)((unsigned char *)cip+sizeof(cell));
2348     NEXT(cip);
2349   op_jneq:
2350     if (pri!=alt)
2351       cip=JUMPABS(code, cip);
2352     else
2353       cip=(cell *)((unsigned char *)cip+sizeof(cell));
2354     NEXT(cip);
2355   op_jless:
2356     if ((ucell)pri < (ucell)alt)
2357       cip=JUMPABS(code, cip);
2358     else
2359       cip=(cell *)((unsigned char *)cip+sizeof(cell));
2360     NEXT(cip);
2361   op_jleq:
2362     if ((ucell)pri <= (ucell)alt)
2363       cip=JUMPABS(code, cip);
2364     else
2365       cip=(cell *)((unsigned char *)cip+sizeof(cell));
2366     NEXT(cip);
2367   op_jgrtr:
2368     if ((ucell)pri > (ucell)alt)
2369       cip=JUMPABS(code, cip);
2370     else
2371       cip=(cell *)((unsigned char *)cip+sizeof(cell));
2372     NEXT(cip);
2373   op_jgeq:
2374     if ((ucell)pri >= (ucell)alt)
2375       cip=JUMPABS(code, cip);
2376     else
2377       cip=(cell *)((unsigned char *)cip+sizeof(cell));
2378     NEXT(cip);
2379   op_jsless:
2380     if (pri<alt)
2381       cip=JUMPABS(code, cip);
2382     else
2383       cip=(cell *)((unsigned char *)cip+sizeof(cell));
2384     NEXT(cip);
2385   op_jsleq:
2386     if (pri<=alt)
2387       cip=JUMPABS(code, cip);
2388     else
2389       cip=(cell *)((unsigned char *)cip+sizeof(cell));
2390     NEXT(cip);
2391   op_jsgrtr:
2392     if (pri>alt)
2393       cip=JUMPABS(code, cip);
2394     else
2395       cip=(cell *)((unsigned char *)cip+sizeof(cell));
2396     NEXT(cip);
2397   op_jsgeq:
2398     if (pri>=alt)
2399       cip=JUMPABS(code, cip);
2400     else
2401       cip=(cell *)((unsigned char *)cip+sizeof(cell));
2402     NEXT(cip);
2403   op_shl:
2404     pri<<=alt;
2405     NEXT(cip);
2406   op_shr:
2407     pri=(ucell)pri >> (ucell)alt;
2408     NEXT(cip);
2409   op_sshr:
2410     pri>>=alt;
2411     NEXT(cip);
2412   op_shl_c_pri:
2413     GETPARAM(offs);
2414     pri<<=offs;
2415     NEXT(cip);
2416   op_shl_c_alt:
2417     GETPARAM(offs);
2418     alt<<=offs;
2419     NEXT(cip);
2420   op_shr_c_pri:
2421     GETPARAM(offs);
2422     pri=(ucell)pri >> (ucell)offs;
2423     NEXT(cip);
2424   op_shr_c_alt:
2425     GETPARAM(offs);
2426     alt=(ucell)alt >> (ucell)offs;
2427     NEXT(cip);
2428   op_smul:
2429     pri*=alt;
2430     NEXT(cip);
2431   op_sdiv:
2432     if (alt==0)
2433       ABORT(amx,AMX_ERR_DIVIDE);
2434     /* use floored division and matching remainder */
2435     offs=alt;
2436     #if defined TRUNC_SDIV
2437       pri=pri/offs;
2438       alt=pri%offs;
2439     #else
2440       val=pri;                  /* portable routine for truncated division */
2441       pri=IABS(pri)/IABS(offs);
2442       if ((cell)(val ^ offs)<0)
2443         pri=-pri;
2444       alt=val-pri*offs;         /* calculate the matching remainder */
2445     #endif
2446     /* now "fiddle" with the values to get floored division */
2447     if (alt!=0 && (cell)(alt ^ offs)<0) {
2448       pri--;
2449       alt+=offs;
2450     } /* if */
2451     NEXT(cip);
2452   op_sdiv_alt:
2453     if (pri==0)
2454       ABORT(amx,AMX_ERR_DIVIDE);
2455     /* use floored division and matching remainder */
2456     offs=pri;
2457     #if defined TRUNC_SDIV
2458       pri=alt/offs;
2459       alt=alt%offs;
2460     #else
2461       val=alt;                  /* portable routine for truncated division */
2462       pri=IABS(alt)/IABS(offs);
2463       if ((cell)(val ^ offs)<0)
2464         pri=-pri;
2465       alt=val-pri*offs;         /* calculate the matching remainder */
2466     #endif
2467     /* now "fiddle" with the values to get floored division */
2468     if (alt!=0 && (cell)(alt ^ offs)<0) {
2469       pri--;
2470       alt+=offs;
2471     } /* if */
2472     NEXT(cip);
2473   op_umul:
2474     pri=(ucell)pri * (ucell)alt;
2475     NEXT(cip);
2476   op_udiv:
2477     if (alt==0)
2478       ABORT(amx,AMX_ERR_DIVIDE);
2479     offs=(ucell)pri % (ucell)alt;     /* temporary storage */
2480     pri=(ucell)pri / (ucell)alt;
2481     alt=offs;
2482     NEXT(cip);
2483   op_udiv_alt:
2484     if (pri==0)
2485       ABORT(amx,AMX_ERR_DIVIDE);
2486     offs=(ucell)alt % (ucell)pri;     /* temporary storage */
2487     pri=(ucell)alt / (ucell)pri;
2488     alt=offs;
2489     NEXT(cip);
2490   op_add:
2491     pri+=alt;
2492     NEXT(cip);
2493   op_sub:
2494     pri-=alt;
2495     NEXT(cip);
2496   op_sub_alt:
2497     pri=alt-pri;
2498     NEXT(cip);
2499   op_and:
2500     pri&=alt;
2501     NEXT(cip);
2502   op_or:
2503     pri|=alt;
2504     NEXT(cip);
2505   op_xor:
2506     pri^=alt;
2507     NEXT(cip);
2508   op_not:
2509     pri=!pri;
2510     NEXT(cip);
2511   op_neg:
2512     pri=-pri;
2513     NEXT(cip);
2514   op_invert:
2515     pri=~pri;
2516     NEXT(cip);
2517   op_add_c:
2518     GETPARAM(offs);
2519     pri+=offs;
2520     NEXT(cip);
2521   op_smul_c:
2522     GETPARAM(offs);
2523     pri*=offs;
2524     NEXT(cip);
2525   op_zero_pri:
2526     pri=0;
2527     NEXT(cip);
2528   op_zero_alt:
2529     alt=0;
2530     NEXT(cip);
2531   op_zero:
2532     GETPARAM(offs);
2533     _W(data,offs,0);
2534     NEXT(cip);
2535   op_zero_s:
2536     GETPARAM(offs);
2537     _W(data,frm+offs,0);
2538     NEXT(cip);
2539   op_sign_pri:
2540     if ((pri & 0xff)>=0x80)
2541       pri|= ~ (ucell)0xff;
2542     NEXT(cip);
2543   op_sign_alt:
2544     if ((alt & 0xff)>=0x80)
2545       alt|= ~ (ucell)0xff;
2546     NEXT(cip);
2547   op_eq:
2548     pri= pri==alt ? 1 : 0;
2549     NEXT(cip);
2550   op_neq:
2551     pri= pri!=alt ? 1 : 0;
2552     NEXT(cip);
2553   op_less:
2554     pri= (ucell)pri < (ucell)alt ? 1 : 0;
2555     NEXT(cip);
2556   op_leq:
2557     pri= (ucell)pri <= (ucell)alt ? 1 : 0;
2558     NEXT(cip);
2559   op_grtr:
2560     pri= (ucell)pri > (ucell)alt ? 1 : 0;
2561     NEXT(cip);
2562   op_geq:
2563     pri= (ucell)pri >= (ucell)alt ? 1 : 0;
2564     NEXT(cip);
2565   op_sless:
2566     pri= pri<alt ? 1 : 0;
2567     NEXT(cip);
2568   op_sleq:
2569     pri= pri<=alt ? 1 : 0;
2570     NEXT(cip);
2571   op_sgrtr:
2572     pri= pri>alt ? 1 : 0;
2573     NEXT(cip);
2574   op_sgeq:
2575     pri= pri>=alt ? 1 : 0;
2576     NEXT(cip);
2577   op_eq_c_pri:
2578     GETPARAM(offs);
2579     pri= pri==offs ? 1 : 0;
2580     NEXT(cip);
2581   op_eq_c_alt:
2582     GETPARAM(offs);
2583     pri= alt==offs ? 1 : 0;
2584     NEXT(cip);
2585   op_inc_pri:
2586     pri++;
2587     NEXT(cip);
2588   op_inc_alt:
2589     alt++;
2590     NEXT(cip);
2591   op_inc:
2592     GETPARAM(offs);
2593     #if defined _R_DEFAULT
2594       *(cell *)(data+(int)offs) += 1;
2595     #else
2596       val=_R(data,offs);
2597       _W(data,offs,val+1);
2598     #endif
2599     NEXT(cip);
2600   op_inc_s:
2601     GETPARAM(offs);
2602     #if defined _R_DEFAULT
2603       *(cell *)(data+(int)(frm+offs)) += 1;
2604     #else
2605       val=_R(data,frm+offs);
2606       _W(data,frm+offs,val+1);
2607     #endif
2608     NEXT(cip);
2609   op_inc_i:
2610     #if defined _R_DEFAULT
2611       *(cell *)(data+(int)pri) += 1;
2612     #else
2613       val=_R(data,pri);
2614       _W(data,pri,val+1);
2615     #endif
2616     NEXT(cip);
2617   op_dec_pri:
2618     pri--;
2619     NEXT(cip);
2620   op_dec_alt:
2621     alt--;
2622     NEXT(cip);
2623   op_dec:
2624     GETPARAM(offs);
2625     #if defined _R_DEFAULT
2626       *(cell *)(data+(int)offs) -= 1;
2627     #else
2628       val=_R(data,offs);
2629       _W(data,offs,val-1);
2630     #endif
2631     NEXT(cip);
2632   op_dec_s:
2633     GETPARAM(offs);
2634     #if defined _R_DEFAULT
2635       *(cell *)(data+(int)(frm+offs)) -= 1;
2636     #else
2637       val=_R(data,frm+offs);
2638       _W(data,frm+offs,val-1);
2639     #endif
2640     NEXT(cip);
2641   op_dec_i:
2642     #if defined _R_DEFAULT
2643       *(cell *)(data+(int)pri) -= 1;
2644     #else
2645       val=_R(data,pri);
2646       _W(data,pri,val-1);
2647     #endif
2648     NEXT(cip);
2649   op_movs:
2650     GETPARAM(offs);
2651     /* verify top & bottom memory addresses, for both source and destination
2652      * addresses
2653      */
2654     if ((pri>=hea && pri<stk) || (ucell)pri>=(ucell)amx->stp)
2655       ABORT(amx,AMX_ERR_MEMACCESS);
2656     if (((pri+offs)>hea && (pri+offs)<stk) || (ucell)(pri+offs)>(ucell)amx->stp)
2657       ABORT(amx,AMX_ERR_MEMACCESS);
2658     if ((alt>=hea && alt<stk) || (ucell)alt>=(ucell)amx->stp)
2659       ABORT(amx,AMX_ERR_MEMACCESS);
2660     if (((alt+offs)>hea && (alt+offs)<stk) || (ucell)(alt+offs)>(ucell)amx->stp)
2661       ABORT(amx,AMX_ERR_MEMACCESS);
2662     #if defined _R_DEFAULT
2663       memcpy(data+(int)alt, data+(int)pri, (int)offs);
2664     #else
2665       for (i=0; i+4<offs; i+=4) {
2666         val=_R32(data,pri+i);
2667         _W32(data,alt+i,val);
2668       } /* for */
2669       for ( ; i<offs; i++) {
2670         val=_R8(data,pri+i);
2671         _W8(data,alt+i,val);
2672       } /* for */
2673     #endif
2674     NEXT(cip);
2675   op_cmps:
2676     GETPARAM(offs);
2677     /* verify top & bottom memory addresses, for both source and destination
2678      * addresses
2679      */
2680     if ((pri>=hea && pri<stk) || (ucell)pri>=(ucell)amx->stp)
2681       ABORT(amx,AMX_ERR_MEMACCESS);
2682     if (((pri+offs)>hea && (pri+offs)<stk) || (ucell)(pri+offs)>(ucell)amx->stp)
2683       ABORT(amx,AMX_ERR_MEMACCESS);
2684     if ((alt>=hea && alt<stk) || (ucell)alt>=(ucell)amx->stp)
2685       ABORT(amx,AMX_ERR_MEMACCESS);
2686     if (((alt+offs)>hea && (alt+offs)<stk) || (ucell)(alt+offs)>(ucell)amx->stp)
2687       ABORT(amx,AMX_ERR_MEMACCESS);
2688     #if defined _R_DEFAULT
2689       pri=memcmp(data+(int)alt, data+(int)pri, (int)offs);
2690     #else
2691       pri=0;
2692       for (i=0; i+4<offs && pri==0; i+=4)
2693         pri=_R32(data,alt+i)-_R32(data,pri+i);
2694       for ( ; i<offs && pri==0; i++)
2695         pri=_R8(data,alt+i)-_R8(data,pri+i);
2696     #endif
2697     NEXT(cip);
2698   op_fill:
2699     GETPARAM(offs);
2700     /* verify top & bottom memory addresses */
2701     if ((alt>=hea && alt<stk) || (ucell)alt>=(ucell)amx->stp)
2702       ABORT(amx,AMX_ERR_MEMACCESS);
2703     if (((alt+offs)>hea && (alt+offs)<stk) || (ucell)(alt+offs)>(ucell)amx->stp)
2704       ABORT(amx,AMX_ERR_MEMACCESS);
2705     for (i=(int)alt; offs>=(int)sizeof(cell); i+=sizeof(cell), offs-=sizeof(cell))
2706       _W32(data,i,pri);
2707     NEXT(cip);
2708   op_halt:
2709     GETPARAM(offs);
2710     if (retval!=NULL)
2711       *retval=pri;
2712     /* store complete status (stk and hea are already set in the ABORT macro) */
2713     amx->frm=frm;
2714     amx->pri=pri;
2715     amx->alt=alt;
2716     amx->cip=(cell)((unsigned char*)cip-code);
2717     if (offs==AMX_ERR_SLEEP) {
2718       amx->stk=stk;
2719       amx->hea=hea;
2720       amx->reset_stk=reset_stk;
2721       amx->reset_hea=reset_hea;
2722       return (int)offs;
2723     } /* if */
2724     ABORT(amx,(int)offs);
2725   op_bounds:
2726     GETPARAM(offs);
2727     if ((ucell)pri>(ucell)offs) {
2728       amx->cip=(cell)((unsigned char *)cip-code);
2729       ABORT(amx,AMX_ERR_BOUNDS);
2730     } /* if */
2731     NEXT(cip);
2732   op_sysreq_pri:
2733     /* save a few registers */
2734     amx->cip=(cell)((unsigned char *)cip-code);
2735     amx->hea=hea;
2736     amx->frm=frm;
2737     amx->stk=stk;
2738     num=amx->callback(amx,pri,&pri,(cell *)(data+(int)stk));
2739     if (num!=AMX_ERR_NONE) {
2740       if (num==AMX_ERR_SLEEP) {
2741         amx->pri=pri;
2742         amx->alt=alt;
2743         amx->reset_stk=reset_stk;
2744         amx->reset_hea=reset_hea;
2745         return num;
2746       } /* if */
2747       ABORT(amx,num);
2748     } /* if */
2749     NEXT(cip);
2750   op_sysreq_c:
2751     GETPARAM(offs);
2752     /* save a few registers */
2753     amx->cip=(cell)((unsigned char *)cip-code);
2754     amx->hea=hea;
2755     amx->frm=frm;
2756     amx->stk=stk;
2757     num=amx->callback(amx,offs,&pri,(cell *)(data+(int)stk));
2758     if (num!=AMX_ERR_NONE) {
2759       if (num==AMX_ERR_SLEEP) {
2760         amx->pri=pri;
2761         amx->alt=alt;
2762         amx->reset_stk=reset_stk;
2763         amx->reset_hea=reset_hea;
2764         return num;
2765       } /* if */
2766       ABORT(amx,num);
2767     } /* if */
2768     NEXT(cip);
2769   op_file:
2770     assert(0);                  /* this code should not occur during execution */
2771     ABORT(amx,AMX_ERR_INVINSTR);
2772   op_line:
2773     SKIPPARAM(2);
2774     NEXT(cip);
2775   op_symbol:
2776     GETPARAM(offs);
2777     cip=(cell *)((unsigned char *)cip + (int)offs);
2778     NEXT(cip);
2779   op_srange:
2780     SKIPPARAM(2);
2781     NEXT(cip);
2782   op_symtag:
2783     SKIPPARAM(1);
2784     NEXT(cip);
2785   op_jump_pri:
2786     cip=(cell *)(code+(int)pri);
2787     NEXT(cip);
2788   op_switch: {
2789     cell *cptr;
2790     cptr=JUMPABS(code,cip)+1;   /* +1, to skip the "casetbl" opcode */
2791     cip=JUMPABS(code,cptr+1);   /* preset to "none-matched" case */
2792     num=(int)*cptr;             /* number of records in the case table */
2793     for (cptr+=2; num>0 && *cptr!=pri; num--,cptr+=2)
2794       /* nothing */;
2795     if (num>0)
2796       cip=JUMPABS(code,cptr+1); /* case found */
2797     NEXT(cip);
2798     }
2799   op_casetbl:
2800     assert(0);                  /* this should not occur during execution */
2801     ABORT(amx,AMX_ERR_INVINSTR);
2802   op_swap_pri:
2803     offs=_R(data,stk);
2804     _W(data,stk,pri);
2805     pri=offs;
2806     NEXT(cip);
2807   op_swap_alt:
2808     offs=_R(data,stk);
2809     _W(data,stk,alt);
2810     alt=offs;
2811     NEXT(cip);
2812   op_push_adr:
2813     GETPARAM(offs);
2814     PUSH(frm+offs);
2815     NEXT(cip);
2816   op_nop:
2817     NEXT(cip);
2818 #if !defined AMX_NO_MACRO_INSTR
2819   op_sysreq_n:
2820     GETPARAM(offs);
2821     GETPARAM(val);
2822     PUSH(val);
2823     /* save a few registers */
2824     amx->cip=(cell)((unsigned char *)cip-code);
2825     amx->hea=hea;
2826     amx->frm=frm;
2827     amx->stk=stk;
2828     num=amx->callback(amx,offs,&pri,(cell *)(data+(int)stk));
2829     stk+=val+4;
2830     if (num!=AMX_ERR_NONE) {
2831       if (num==AMX_ERR_SLEEP) {
2832         amx->pri=pri;
2833         amx->alt=alt;
2834         amx->reset_stk=reset_stk;
2835         amx->reset_hea=reset_hea;
2836         return num;
2837       } /* if */
2838       ABORT(amx,num);
2839     } /* if */
2840     NEXT(cip);
2841 #endif
2842   op_break:
2843     assert((amx->flags & AMX_FLAG_BROWSE)==0);
2844     if (amx->debug!=NULL) {
2845       /* store status */
2846       amx->frm=frm;
2847       amx->stk=stk;
2848       amx->hea=hea;
2849       amx->cip=(cell)((unsigned char*)cip-code);
2850       num=amx->debug(amx);
2851       if (num!=AMX_ERR_NONE) {
2852         if (num==AMX_ERR_SLEEP) {
2853           amx->pri=pri;
2854           amx->alt=alt;
2855           amx->reset_stk=reset_stk;
2856           amx->reset_hea=reset_hea;
2857           return num;
2858         } /* if */
2859         ABORT(amx,num);
2860       } /* if */
2861     } /* if */
2862     NEXT(cip);
2863 #if !defined AMX_NO_MACRO_INSTR
2864   op_push5:
2865     GETPARAM(offs);
2866     PUSH(_R(data,offs));
2867     /* drop through */
2868   op_push4:
2869     GETPARAM(offs);
2870     PUSH(_R(data,offs));
2871     /* drop through */
2872   op_push3:
2873     GETPARAM(offs);
2874     PUSH(_R(data,offs));
2875     /* drop through */
2876   op_push2:
2877     GETPARAM(offs);
2878     PUSH(_R(data,offs));
2879     GETPARAM(offs);
2880     PUSH(_R(data,offs));
2881     NEXT(cip);
2882   op_push5_s:
2883     GETPARAM(offs);
2884     PUSH(_R(data,frm+offs));
2885     /* drop through */
2886   op_push4_s:
2887     GETPARAM(offs);
2888     PUSH(_R(data,frm+offs));
2889     /* drop through */
2890   op_push3_s:
2891     GETPARAM(offs);
2892     PUSH(_R(data,frm+offs));
2893     /* drop through */
2894   op_push2_s:
2895     GETPARAM(offs);
2896     PUSH(_R(data,frm+offs));
2897     GETPARAM(offs);
2898     PUSH(_R(data,frm+offs));
2899     NEXT(cip);
2900   op_push5_c:
2901     GETPARAM(offs);
2902     PUSH(offs);
2903     /* drop through */
2904   op_push4_c:
2905     GETPARAM(offs);
2906     PUSH(offs);
2907     /* drop through */
2908   op_push3_c:
2909     GETPARAM(offs);
2910     PUSH(offs);
2911     /* drop through */
2912   op_push2_c:
2913     GETPARAM(offs);
2914     PUSH(offs);
2915     GETPARAM(offs);
2916     PUSH(offs);
2917     NEXT(cip);
2918   op_push5_adr:
2919     GETPARAM(offs);
2920     PUSH(frm+offs);
2921     /* drop through */
2922   op_push4_adr:
2923     GETPARAM(offs);
2924     PUSH(frm+offs);
2925     /* drop through */
2926   op_push3_adr:
2927     GETPARAM(offs);
2928     PUSH(frm+offs);
2929     /* drop through */
2930   op_push2_adr:
2931     GETPARAM(offs);
2932     PUSH(frm+offs);
2933     GETPARAM(offs);
2934     PUSH(frm+offs);
2935     NEXT(cip);
2936   op_load_both:
2937     GETPARAM(offs);
2938     pri=_R(data,offs);
2939     GETPARAM(offs);
2940     alt=_R(data,offs);
2941     NEXT(cip);
2942   op_load_s_both:
2943     GETPARAM(offs);
2944     pri=_R(data,frm+offs);
2945     GETPARAM(offs);
2946     alt=_R(data,frm+offs);
2947     NEXT(cip);
2948   op_const:
2949     GETPARAM(offs);
2950     GETPARAM(val);
2951     _W(data,offs,val);
2952     NEXT(cip);
2953   op_const_s:
2954     GETPARAM(offs);
2955     GETPARAM(val);
2956     _W(data,frm+offs,val);
2957     NEXT(cip);
2958 #endif
2959 #if !defined AMX_NO_MACRO_INSTR
2960   op_sysreq_d:          /* see op_sysreq_c */
2961     GETPARAM(offs);
2962     /* save a few registers */
2963     amx->cip=(cell)((unsigned char *)cip-code);
2964     amx->hea=hea;
2965     amx->frm=frm;
2966     amx->stk=stk;
2967     pri=((AMX_NATIVE)offs)(amx,(cell *)(data+(int)stk));
2968     if (amx->error!=AMX_ERR_NONE) {
2969       if (amx->error==AMX_ERR_SLEEP) {
2970         amx->pri=pri;
2971         amx->alt=alt;
2972         amx->reset_stk=reset_stk;
2973         amx->reset_hea=reset_hea;
2974         return AMX_ERR_SLEEP;
2975       } /* if */
2976       ABORT(amx,amx->error);
2977     } /* if */
2978     NEXT(cip);
2979 #endif
2980 #if !defined AMX_NO_MACRO_INSTR && !defined AMX_NO_MACRO_INSTR
2981   op_sysreq_nd:    /* see op_sysreq_n */
2982     GETPARAM(offs);
2983     GETPARAM(val);
2984     PUSH(val);
2985     /* save a few registers */
2986     amx->cip=(cell)((unsigned char *)cip-code);
2987     amx->hea=hea;
2988     amx->frm=frm;
2989     amx->stk=stk;
2990     pri=((AMX_NATIVE)offs)(amx,(cell *)(data+(int)stk));
2991     stk+=val+4;
2992     if (amx->error!=AMX_ERR_NONE) {
2993       if (amx->error==AMX_ERR_SLEEP) {
2994         amx->pri=pri;
2995         amx->alt=alt;
2996         amx->reset_stk=reset_stk;
2997         amx->reset_hea=reset_hea;
2998         return AMX_ERR_SLEEP;
2999       } /* if */
3000       ABORT(amx,amx->error);
3001     } /* if */
3002     NEXT(cip);
3003 #endif
3004 }
3005 
3006 #else
3007     /* ANSI C & assembler versions */
3008 
3009 #if defined ASM32 || defined JIT
3010   /* For Watcom C/C++ use register calling convention (faster); for
3011    * Microsoft C/C++ (and most other C compilers) use "cdecl".
3012    * The important point is that you assemble AMXEXEC.ASM with the matching
3013    * calling convention, or the right JIT, respectively.
3014    * AMXJITR.ASM is for Watcom's register calling convention, AMXJITS.ASM and
3015    * AMXJITSN.ASM are for "cdecl".
3016    */
3017   #if defined __WATCOMC__
3018     #if !defined STACKARGS  /* for AMX32.DLL */
3019       extern cell amx_exec_asm(cell *regs,cell *retval,cell stp,cell hea);
3020             /* The following pragma tells the compiler into which registers
3021              * the parameters have to go. */
3022             #pragma aux amx_exec_asm parm [eax] [edx] [ebx] [ecx];
3023       extern cell amx_exec_jit(cell *regs,cell *retval,cell stp,cell hea);
3024             #pragma aux amx_exec_jit parm [eax] [edx] [ebx] [ecx];
3025     #else
3026       extern cell __cdecl amx_exec_asm(cell *regs,cell *retval,cell stp,cell hea);
3027       extern cell __cdecl amx_exec_jit(cell *regs,cell *retval,cell stp,cell hea);
3028     #endif
3029   #elif defined __arm__
3030     /* AAPCS compliant */
3031     extern cell amx_exec_asm(cell *regs,cell *retval,cell stp,cell hea);
3032     extern cell amx_exec_jit(cell *regs,cell *retval,cell stp,cell hea);
3033   #elif defined __GNUC__
3034     /* force "cdecl" by adding an "attribute" to the declaration */
3035     extern cell amx_exec_asm(cell *regs,cell *retval,cell stp,cell hea) __attribute__((cdecl));
3036     extern cell amx_exec_jit(cell *regs,cell *retval,cell stp,cell hea) __attribute__((cdecl));
3037   #else
3038     /* force "cdecl" by specifying it as a "function class" with the "__cdecl" keyword */
3039     extern cell __cdecl amx_exec_asm(cell *regs,cell *retval,cell stp,cell hea);
3040     extern cell __cdecl amx_exec_jit(cell *regs,cell *retval,cell stp,cell hea);
3041   #endif
3042 #endif /* ASM32 || JIT */
3043 
3044 int AMXAPI amx_Exec(AMX *amx, cell *retval, int index)
3045 {
3046   AMX_HEADER *hdr;
3047   AMX_FUNCSTUB *func;
3048   unsigned char *code, *data;
3049   cell pri,alt,stk,frm,hea;
3050   cell reset_stk, reset_hea, *cip;
3051   ucell codesize;
3052   int i;
3053   #if defined ASM32 || defined JIT
3054     cell  parms[9];     /* registers and parameters for assembler AMX */
3055   #else
3056     OPCODE op;
3057     cell offs,val;
3058     int num;
3059   #endif
3060   #if defined ASM32
3061     extern void const *amx_opcodelist[];
3062     #ifdef __WATCOMC__
3063       #pragma aux amx_opcodelist "_*"
3064     #endif
3065   #endif
3066   #if defined JIT
3067     extern void const *amx_opcodelist_jit[];
3068     #ifdef __WATCOMC__
3069       #pragma aux amx_opcodelist_jit "_*"
3070     #endif
3071   #endif
3072 
3073   assert(amx!=NULL);
3074   #if defined ASM32 || defined JIT
3075     /* HACK: return label table (for amx_BrowseRelocate) if amx structure
3076      * is not passed.
3077      */
3078     if ((amx->flags & AMX_FLAG_BROWSE)==AMX_FLAG_BROWSE) {
3079       assert(sizeof(cell)==sizeof(void *));
3080       assert(retval!=NULL);
3081       #if defined ASM32 && defined JIT
3082         if ((amx->flags & AMX_FLAG_JITC)!=0)
3083           *retval=(cell)amx_opcodelist_jit;
3084         else
3085           *retval=(cell)amx_opcodelist;
3086       #elif defined ASM32
3087         *retval=(cell)amx_opcodelist;
3088       #else
3089         *retval=(cell)amx_opcodelist_jit;
3090       #endif
3091       return 0;
3092     } /* if */
3093   #endif
3094 
3095   if (amx->callback==NULL)
3096     return AMX_ERR_CALLBACK;
3097   if ((amx->flags & AMX_FLAG_RELOC)==0)
3098     return AMX_ERR_INIT;
3099   if ((amx->flags & AMX_FLAG_NTVREG)==0) {
3100     if ((i=amx_Register(amx,NULL,0))!=AMX_ERR_NONE)
3101       return i;
3102   } /* if */
3103   assert((amx->flags & AMX_FLAG_BROWSE)==0);
3104 
3105   /* set up the registers */
3106   hdr=(AMX_HEADER *)amx->base;
3107   assert(hdr->magic==AMX_MAGIC);
3108   codesize=(ucell)(hdr->dat-hdr->cod);
3109   code=amx->base+(int)hdr->cod;
3110   data=(amx->data!=NULL) ? amx->data : amx->base+(int)hdr->dat;
3111   hea=amx->hea;
3112   stk=amx->stk;
3113   reset_stk=stk;
3114   reset_hea=hea;
3115   alt=frm=pri=0;/* just to avoid compiler warnings */
3116 
3117   /* get the start address */
3118   if (index==AMX_EXEC_MAIN) {
3119     if (hdr->cip<0)
3120       return AMX_ERR_INDEX;
3121     cip=(cell *)(code + (int)hdr->cip);
3122   } else if (index==AMX_EXEC_CONT) {
3123     /* all registers: pri, alt, frm, cip, hea, stk, reset_stk, reset_hea */
3124     frm=amx->frm;
3125     stk=amx->stk;
3126     hea=amx->hea;
3127     pri=amx->pri;
3128     alt=amx->alt;
3129     reset_stk=amx->reset_stk;
3130     reset_hea=amx->reset_hea;
3131     cip=(cell *)(code + (int)amx->cip);
3132   } else if (index<0) {
3133     return AMX_ERR_INDEX;
3134   } else {
3135     if (index>=(cell)NUMENTRIES(hdr,publics,natives))
3136       return AMX_ERR_INDEX;
3137     func=GETENTRY(hdr,publics,index);
3138     cip=(cell *)(code + (int)func->address);
3139   } /* if */
3140   /* check values just copied */
3141   CHKSTACK();
3142   CHKHEAP();
3143   assert(check_endian());
3144 
3145   /* sanity checks */
3146   assert_static(OP_PUSH_PRI==36);
3147   assert_static(OP_PROC==46);
3148   assert_static(OP_SHL==65);
3149   assert_static(OP_SMUL==72);
3150   assert_static(OP_EQ==95);
3151   assert_static(OP_INC_PRI==107);
3152   assert_static(OP_MOVS==117);
3153   assert_static(OP_SYMBOL==126);
3154   assert_static(OP_PUSH2_C==138);
3155   assert_static(OP_LOAD_BOTH==154);
3156   #if PAWN_CELL_SIZE==16
3157     assert_static(sizeof(cell)==2);
3158   #elif PAWN_CELL_SIZE==32
3159     assert_static(sizeof(cell)==4);
3160   #elif PAWN_CELL_SIZE==64
3161     assert_static(sizeof(cell)==8);
3162   #else
3163     #error Unsupported cell size
3164   #endif
3165 
3166   if (index!=AMX_EXEC_CONT) {
3167     reset_stk+=amx->paramcount*sizeof(cell);
3168     PUSH(amx->paramcount*sizeof(cell));
3169     amx->paramcount=0;          /* push the parameter count to the stack & reset */
3170     #if defined ASM32 || defined JIT
3171       PUSH(RELOC_VALUE(code,0));/* relocated zero return address */
3172     #else
3173       PUSH(0);                  /* zero return address */
3174     #endif
3175   } /* if */
3176   /* check stack/heap before starting to run */
3177   CHKMARGIN();
3178 
3179   /* start running */
3180 #if defined ASM32 || defined JIT
3181   /* either the assembler abstract machine or the JIT; both by Marc Peter */
3182 
3183   parms[0] = pri;
3184   parms[1] = alt;
3185   parms[2] = (cell)cip;
3186   parms[3] = (cell)data;
3187   parms[4] = stk;
3188   parms[5] = frm;
3189   parms[6] = (cell)amx;
3190   parms[7] = (cell)code;
3191   parms[8] = (cell)codesize;
3192 
3193   #if defined ASM32 && defined JIT
3194     if ((amx->flags & AMX_FLAG_JITC)!=0)
3195       i = amx_exec_jit(parms,retval,amx->stp,hea);
3196     else
3197       i = amx_exec_asm(parms,retval,amx->stp,hea);
3198   #elif defined ASM32
3199     i = amx_exec_asm(parms,retval,amx->stp,hea);
3200   #else
3201     i = amx_exec_jit(parms,retval,amx->stp,hea);
3202   #endif
3203   if (i == AMX_ERR_SLEEP) {
3204     amx->reset_stk=reset_stk;
3205     amx->reset_hea=reset_hea;
3206   } else {
3207     /* remove parameters from the stack; do this the "hard" way, because
3208      * the assembler version has no internal knowledge of the local
3209      * variables, so any "clean" way would be a kludge anyway.
3210      */
3211     amx->stk=reset_stk;
3212     amx->hea=reset_hea;
3213   } /* if */
3214   return i;
3215 
3216 #else
3217 
3218   for ( ;; ) {
3219     op=(OPCODE) _RCODE();
3220     switch (op) {
3221     case OP_LOAD_PRI:
3222       GETPARAM(offs);
3223       pri=_R(data,offs);
3224       break;
3225     case OP_LOAD_ALT:
3226       GETPARAM(offs);
3227       alt=_R(data,offs);
3228       break;
3229     case OP_LOAD_S_PRI:
3230       GETPARAM(offs);
3231       pri=_R(data,frm+offs);
3232       break;
3233     case OP_LOAD_S_ALT:
3234       GETPARAM(offs);
3235       alt=_R(data,frm+offs);
3236       break;
3237     case OP_LREF_PRI:
3238       GETPARAM(offs);
3239       offs=_R(data,offs);
3240       pri=_R(data,offs);
3241       break;
3242     case OP_LREF_ALT:
3243       GETPARAM(offs);
3244       offs=_R(data,offs);
3245       alt=_R(data,offs);
3246       break;
3247     case OP_LREF_S_PRI:
3248       GETPARAM(offs);
3249       offs=_R(data,frm+offs);
3250       pri=_R(data,offs);
3251       break;
3252     case OP_LREF_S_ALT:
3253       GETPARAM(offs);
3254       offs=_R(data,frm+offs);
3255       alt=_R(data,offs);
3256       break;
3257     case OP_LOAD_I:
3258       /* verify address */
3259       if (pri>=hea && pri<stk || (ucell)pri>=(ucell)amx->stp)
3260         ABORT(amx,AMX_ERR_MEMACCESS);
3261       pri=_R(data,pri);
3262       break;
3263     case OP_LODB_I:
3264       GETPARAM(offs);
3265       /* verify address */
3266       if (pri>=hea && pri<stk || (ucell)pri>=(ucell)amx->stp)
3267         ABORT(amx,AMX_ERR_MEMACCESS);
3268       switch ((int)offs) {
3269       case 1:
3270         pri=_R8(data,pri);
3271         break;
3272       case 2:
3273         pri=_R16(data,pri);
3274         break;
3275       case 4:
3276         pri=_R32(data,pri);
3277         break;
3278       } /* switch */
3279       break;
3280     case OP_CONST_PRI:
3281       GETPARAM(pri);
3282       break;
3283     case OP_CONST_ALT:
3284       GETPARAM(alt);
3285       break;
3286     case OP_ADDR_PRI:
3287       GETPARAM(pri);
3288       pri+=frm;
3289       break;
3290     case OP_ADDR_ALT:
3291       GETPARAM(alt);
3292       alt+=frm;
3293       break;
3294     case OP_STOR_PRI:
3295       GETPARAM(offs);
3296       _W(data,offs,pri);
3297       break;
3298     case OP_STOR_ALT:
3299       GETPARAM(offs);
3300       _W(data,offs,alt);
3301       break;
3302     case OP_STOR_S_PRI:
3303       GETPARAM(offs);
3304       _W(data,frm+offs,pri);
3305       break;
3306     case OP_STOR_S_ALT:
3307       GETPARAM(offs);
3308       _W(data,frm+offs,alt);
3309       break;
3310     case OP_SREF_PRI:
3311       GETPARAM(offs);
3312       offs=_R(data,offs);
3313       _W(data,offs,pri);
3314       break;
3315     case OP_SREF_ALT:
3316       GETPARAM(offs);
3317       offs=_R(data,offs);
3318       _W(data,offs,alt);
3319       break;
3320     case OP_SREF_S_PRI:
3321       GETPARAM(offs);
3322       offs=_R(data,frm+offs);
3323       _W(data,offs,pri);
3324       break;
3325     case OP_SREF_S_ALT:
3326       GETPARAM(offs);
3327       offs=_R(data,frm+offs);
3328       _W(data,offs,alt);
3329       break;
3330     case OP_STOR_I:
3331       /* verify address */
3332       if (alt>=hea && alt<stk || (ucell)alt>=(ucell)amx->stp)
3333         ABORT(amx,AMX_ERR_MEMACCESS);
3334       _W(data,alt,pri);
3335       break;
3336     case OP_STRB_I:
3337       GETPARAM(offs);
3338       /* verify address */
3339       if (alt>=hea && alt<stk || (ucell)alt>=(ucell)amx->stp)
3340         ABORT(amx,AMX_ERR_MEMACCESS);
3341       switch ((int)offs) {
3342       case 1:
3343         _W8(data,alt,pri);
3344         break;
3345       case 2:
3346         _W16(data,alt,pri);
3347         break;
3348       case 4:
3349         _W32(data,alt,pri);
3350         break;
3351       } /* switch */
3352       break;
3353     case OP_LIDX:
3354       offs=pri*sizeof(cell)+alt;
3355       /* verify address */
3356       if (offs>=hea && offs<stk || (ucell)offs>=(ucell)amx->stp)
3357         ABORT(amx,AMX_ERR_MEMACCESS);
3358       pri=_R(data,offs);
3359       break;
3360     case OP_LIDX_B:
3361       GETPARAM(offs);
3362       offs=(pri << (int)offs)+alt;
3363       /* verify address */
3364       if (offs>=hea && offs<stk || (ucell)offs>=(ucell)amx->stp)
3365         ABORT(amx,AMX_ERR_MEMACCESS);
3366       pri=_R(data,offs);
3367       break;
3368     case OP_IDXADDR:
3369       pri=pri*sizeof(cell)+alt;
3370       break;
3371     case OP_IDXADDR_B:
3372       GETPARAM(offs);
3373       pri=(pri << (int)offs)+alt;
3374       break;
3375     case OP_ALIGN_PRI:
3376       GETPARAM(offs);
3377       #if BYTE_ORDER==LITTLE_ENDIAN
3378         if ((size_t)offs<sizeof(cell))
3379           pri ^= sizeof(cell)-offs;
3380       #endif
3381       break;
3382     case OP_ALIGN_ALT:
3383       GETPARAM(offs);
3384       #if BYTE_ORDER==LITTLE_ENDIAN
3385         if ((size_t)offs<sizeof(cell))
3386           alt ^= sizeof(cell)-offs;
3387       #endif
3388       break;
3389     case OP_LCTRL:
3390       GETPARAM(offs);
3391       switch ((int)offs) {
3392       case 0:
3393         pri=hdr->cod;
3394         break;
3395       case 1:
3396         pri=hdr->dat;
3397         break;
3398       case 2:
3399         pri=hea;
3400         break;
3401       case 3:
3402         pri=amx->stp;
3403         break;
3404       case 4:
3405         pri=stk;
3406         break;
3407       case 5:
3408         pri=frm;
3409         break;
3410       case 6:
3411         pri=(cell)((unsigned char *)cip - code);
3412         break;
3413       } /* switch */
3414       break;
3415     case OP_SCTRL:
3416       GETPARAM(offs);
3417       switch ((int)offs) {
3418       case 0:
3419       case 1:
3420       case 3:
3421         /* cannot change these parameters */
3422         break;
3423       case 2:
3424         hea=pri;
3425         break;
3426       case 4:
3427         stk=pri;
3428         break;
3429       case 5:
3430         frm=pri;
3431         break;
3432       case 6:
3433         cip=(cell *)(code + (int)pri);
3434         break;
3435       } /* switch */
3436       break;
3437     case OP_MOVE_PRI:
3438       pri=alt;
3439       break;
3440     case OP_MOVE_ALT:
3441       alt=pri;
3442       break;
3443     case OP_XCHG:
3444       offs=pri;         /* offs is a temporary variable */
3445       pri=alt;
3446       alt=offs;
3447       break;
3448     case OP_PUSH_PRI:
3449       PUSH(pri);
3450       break;
3451     case OP_PUSH_ALT:
3452       PUSH(alt);
3453       break;
3454     case OP_PUSH_C:
3455       GETPARAM(offs);
3456       PUSH(offs);
3457       break;
3458     case OP_PUSH_R:
3459       GETPARAM(offs);
3460       while (offs--)
3461         PUSH(pri);
3462       break;
3463     case OP_PUSH:
3464       GETPARAM(offs);
3465       PUSH(_R(data,offs));
3466       break;
3467     case OP_PUSH_S:
3468       GETPARAM(offs);
3469       PUSH(_R(data,frm+offs));
3470       break;
3471     case OP_POP_PRI:
3472       POP(pri);
3473       break;
3474     case OP_POP_ALT:
3475       POP(alt);
3476       break;
3477     case OP_STACK:
3478       GETPARAM(offs);
3479       alt=stk;
3480       stk+=offs;
3481       CHKMARGIN();
3482       CHKSTACK();
3483       break;
3484     case OP_HEAP:
3485       GETPARAM(offs);
3486       alt=hea;
3487       hea+=offs;
3488       CHKMARGIN();
3489       CHKHEAP();
3490       break;
3491     case OP_PROC:
3492       PUSH(frm);
3493       frm=stk;
3494       CHKMARGIN();
3495       break;
3496     case OP_RET:
3497       POP(frm);
3498       POP(offs);
3499       /* verify the return address */
3500       if ((ucell)offs>=codesize)
3501         ABORT(amx,AMX_ERR_MEMACCESS);
3502       cip=(cell *)(code+(int)offs);
3503       break;
3504     case OP_RETN:
3505       POP(frm);
3506       POP(offs);
3507       /* verify the return address */
3508       if ((ucell)offs>=codesize)
3509         ABORT(amx,AMX_ERR_MEMACCESS);
3510       cip=(cell *)(code+(int)offs);
3511       stk+=_R(data,stk)+sizeof(cell);   /* remove parameters from the stack */
3512       amx->stk=stk;
3513       break;
3514     case OP_CALL:
3515       PUSH(((unsigned char *)cip-code)+sizeof(cell));/* skip address */
3516       cip=JUMPABS(code, cip);                   /* jump to the address */
3517       break;
3518     case OP_CALL_PRI:
3519       PUSH((unsigned char *)cip-code);
3520       cip=(cell *)(code+(int)pri);
3521       break;
3522     case OP_JUMP:
3523       /* since the GETPARAM() macro modifies cip, you cannot
3524        * do GETPARAM(cip) directly */
3525       cip=JUMPABS(code, cip);
3526       break;
3527     case OP_JREL:
3528       offs=*cip;
3529       cip=(cell *)((unsigned char *)cip + (int)offs + sizeof(cell));
3530       break;
3531     case OP_JZER:
3532       if (pri==0)
3533         cip=JUMPABS(code, cip);
3534       else
3535         cip=(cell *)((unsigned char *)cip+sizeof(cell));
3536       break;
3537     case OP_JNZ:
3538       if (pri!=0)
3539         cip=JUMPABS(code, cip);
3540       else
3541         cip=(cell *)((unsigned char *)cip+sizeof(cell));
3542       break;
3543     case OP_JEQ:
3544       if (pri==alt)
3545         cip=JUMPABS(code, cip);
3546       else
3547         cip=(cell *)((unsigned char *)cip+sizeof(cell));
3548       break;
3549     case OP_JNEQ:
3550       if (pri!=alt)
3551         cip=JUMPABS(code, cip);
3552       else
3553         cip=(cell *)((unsigned char *)cip+sizeof(cell));
3554       break;
3555     case OP_JLESS:
3556       if ((ucell)pri < (ucell)alt)
3557         cip=JUMPABS(code, cip);
3558       else
3559         cip=(cell *)((unsigned char *)cip+sizeof(cell));
3560       break;
3561     case OP_JLEQ:
3562       if ((ucell)pri <= (ucell)alt)
3563         cip=JUMPABS(code, cip);
3564       else
3565         cip=(cell *)((unsigned char *)cip+sizeof(cell));
3566       break;
3567     case OP_JGRTR:
3568       if ((ucell)pri > (ucell)alt)
3569         cip=JUMPABS(code, cip);
3570       else
3571         cip=(cell *)((unsigned char *)cip+sizeof(cell));
3572       break;
3573     case OP_JGEQ:
3574       if ((ucell)pri >= (ucell)alt)
3575         cip=JUMPABS(code, cip);
3576       else
3577         cip=(cell *)((unsigned char *)cip+sizeof(cell));
3578       break;
3579     case OP_JSLESS:
3580       if (pri<alt)
3581         cip=JUMPABS(code, cip);
3582       else
3583         cip=(cell *)((unsigned char *)cip+sizeof(cell));
3584       break;
3585     case OP_JSLEQ:
3586       if (pri<=alt)
3587         cip=JUMPABS(code, cip);
3588       else
3589         cip=(cell *)((unsigned char *)cip+sizeof(cell));
3590       break;
3591     case OP_JSGRTR:
3592       if (pri>alt)
3593         cip=JUMPABS(code, cip);
3594       else
3595         cip=(cell *)((unsigned char *)cip+sizeof(cell));
3596       break;
3597     case OP_JSGEQ:
3598       if (pri>=alt)
3599         cip=JUMPABS(code, cip);
3600       else
3601         cip=(cell *)((unsigned char *)cip+sizeof(cell));
3602       break;
3603     case OP_SHL:
3604       pri<<=alt;
3605       break;
3606     case OP_SHR:
3607       pri=(ucell)pri >> (int)alt;
3608       break;
3609     case OP_SSHR:
3610       pri>>=alt;
3611       break;
3612     case OP_SHL_C_PRI:
3613       GETPARAM(offs);
3614       pri<<=offs;
3615       break;
3616     case OP_SHL_C_ALT:
3617       GETPARAM(offs);
3618       alt<<=offs;
3619       break;
3620     case OP_SHR_C_PRI:
3621       GETPARAM(offs);
3622       pri=(ucell)pri >> (int)offs;
3623       break;
3624     case OP_SHR_C_ALT:
3625       GETPARAM(offs);
3626       alt=(ucell)alt >> (int)offs;
3627       break;
3628     case OP_SMUL:
3629       pri*=alt;
3630       break;
3631     case OP_SDIV:
3632       if (alt==0)
3633         ABORT(amx,AMX_ERR_DIVIDE);
3634       /* use floored division and matching remainder */
3635       offs=alt;
3636       #if defined TRUNC_SDIV
3637         pri=pri/offs;
3638         alt=pri%offs;
3639       #else
3640         val=pri;                /* portable routine for truncated division */
3641         pri=IABS(pri)/IABS(offs);
3642         if ((cell)(val ^ offs)<0)
3643           pri=-pri;
3644         alt=val-pri*offs;       /* calculate the matching remainder */
3645       #endif
3646       /* now "fiddle" with the values to get floored division */
3647       if (alt!=0 && (cell)(alt ^ offs)<0) {
3648         pri--;
3649         alt+=offs;
3650       } /* if */
3651       break;
3652     case OP_SDIV_ALT:
3653       if (pri==0)
3654         ABORT(amx,AMX_ERR_DIVIDE);
3655       /* use floored division and matching remainder */
3656       offs=pri;
3657       #if defined TRUNC_SDIV
3658         pri=alt/offs;
3659         alt=alt%offs;
3660       #else
3661         val=alt;                /* portable routine for truncated division */
3662         pri=IABS(alt)/IABS(offs);
3663         if ((cell)(val ^ offs)<0)
3664           pri=-pri;
3665         alt=val-pri*offs;       /* calculate the matching remainder */
3666       #endif
3667       /* now "fiddle" with the values to get floored division */
3668       if (alt!=0 && (cell)(alt ^ offs)<0) {
3669         pri--;
3670         alt+=offs;
3671       } /* if */
3672       break;
3673     case OP_UMUL:
3674       pri=(ucell)pri * (ucell)alt;
3675       break;
3676     case OP_UDIV:
3677       if (alt==0)
3678         ABORT(amx,AMX_ERR_DIVIDE);
3679       offs=(ucell)pri % (ucell)alt;     /* temporary storage */
3680       pri=(ucell)pri / (ucell)alt;
3681       alt=offs;
3682       break;
3683     case OP_UDIV_ALT:
3684       if (pri==0)
3685         ABORT(amx,AMX_ERR_DIVIDE);
3686       offs=(ucell)alt % (ucell)pri;     /* temporary storage */
3687       pri=(ucell)alt / (ucell)pri;
3688       alt=offs;
3689       break;
3690     case OP_ADD:
3691       pri+=alt;
3692       break;
3693     case OP_SUB:
3694       pri-=alt;
3695       break;
3696     case OP_SUB_ALT:
3697       pri=alt-pri;
3698       break;
3699     case OP_AND:
3700       pri&=alt;
3701       break;
3702     case OP_OR:
3703       pri|=alt;
3704       break;
3705     case OP_XOR:
3706       pri^=alt;
3707       break;
3708     case OP_NOT:
3709       pri=!pri;
3710       break;
3711     case OP_NEG:
3712       pri=-pri;
3713       break;
3714     case OP_INVERT:
3715       pri=~pri;
3716       break;
3717     case OP_ADD_C:
3718       GETPARAM(offs);
3719       pri+=offs;
3720       break;
3721     case OP_SMUL_C:
3722       GETPARAM(offs);
3723       pri*=offs;
3724       break;
3725     case OP_ZERO_PRI:
3726       pri=0;
3727       break;
3728     case OP_ZERO_ALT:
3729       alt=0;
3730       break;
3731     case OP_ZERO:
3732       GETPARAM(offs);
3733       _W(data,offs,0);
3734       break;
3735     case OP_ZERO_S:
3736       GETPARAM(offs);
3737       _W(data,frm+offs,0);
3738       break;
3739     case OP_SIGN_PRI:
3740       if ((pri & 0xff)>=0x80)
3741         pri|= ~ (ucell)0xff;
3742       break;
3743     case OP_SIGN_ALT:
3744       if ((alt & 0xff)>=0x80)
3745         alt|= ~ (ucell)0xff;
3746       break;
3747     case OP_EQ:
3748       pri= pri==alt ? 1 : 0;
3749       break;
3750     case OP_NEQ:
3751       pri= pri!=alt ? 1 : 0;
3752       break;
3753     case OP_LESS:
3754       pri= (ucell)pri < (ucell)alt ? 1 : 0;
3755       break;
3756     case OP_LEQ:
3757       pri= (ucell)pri <= (ucell)alt ? 1 : 0;
3758       break;
3759     case OP_GRTR:
3760       pri= (ucell)pri > (ucell)alt ? 1 : 0;
3761       break;
3762     case OP_GEQ:
3763       pri= (ucell)pri >= (ucell)alt ? 1 : 0;
3764       break;
3765     case OP_SLESS:
3766       pri= pri<alt ? 1 : 0;
3767       break;
3768     case OP_SLEQ:
3769       pri= pri<=alt ? 1 : 0;
3770       break;
3771     case OP_SGRTR:
3772       pri= pri>alt ? 1 : 0;
3773       break;
3774     case OP_SGEQ:
3775       pri= pri>=alt ? 1 : 0;
3776       break;
3777     case OP_EQ_C_PRI:
3778       GETPARAM(offs);
3779       pri= pri==offs ? 1 : 0;
3780       break;
3781     case OP_EQ_C_ALT:
3782       GETPARAM(offs);
3783       pri= alt==offs ? 1 : 0;
3784       break;
3785     case OP_INC_PRI:
3786       pri++;
3787       break;
3788     case OP_INC_ALT:
3789       alt++;
3790       break;
3791     case OP_INC:
3792       GETPARAM(offs);
3793       #if defined _R_DEFAULT
3794         *(cell *)(data+(int)offs) += 1;
3795       #else
3796         val=_R(data,offs);
3797         _W(data,offs,val+1);
3798       #endif
3799       break;
3800     case OP_INC_S:
3801       GETPARAM(offs);
3802       #if defined _R_DEFAULT
3803         *(cell *)(data+(int)(frm+offs)) += 1;
3804       #else
3805         val=_R(data,frm+offs);
3806         _W(data,frm+offs,val+1);
3807       #endif
3808       break;
3809     case OP_INC_I:
3810       #if defined _R_DEFAULT
3811         *(cell *)(data+(int)pri) += 1;
3812       #else
3813         val=_R(data,pri);
3814         _W(data,pri,val+1);
3815       #endif
3816       break;
3817     case OP_DEC_PRI:
3818       pri--;
3819       break;
3820     case OP_DEC_ALT:
3821       alt--;
3822       break;
3823     case OP_DEC:
3824       GETPARAM(offs);
3825       #if defined _R_DEFAULT
3826         *(cell *)(data+(int)offs) -= 1;
3827       #else
3828         val=_R(data,offs);
3829         _W(data,offs,val-1);
3830       #endif
3831       break;
3832     case OP_DEC_S:
3833       GETPARAM(offs);
3834       #if defined _R_DEFAULT
3835         *(cell *)(data+(int)(frm+offs)) -= 1;
3836       #else
3837         val=_R(data,frm+offs);
3838         _W(data,frm+offs,val-1);
3839       #endif
3840       break;
3841     case OP_DEC_I:
3842       #if defined _R_DEFAULT
3843         *(cell *)(data+(int)pri) -= 1;
3844       #else
3845         val=_R(data,pri);
3846         _W(data,pri,val-1);
3847       #endif
3848       break;
3849     case OP_MOVS:
3850       GETPARAM(offs);
3851       /* verify top & bottom memory addresses, for both source and destination
3852        * addresses
3853        */
3854       if (pri>=hea && pri<stk || (ucell)pri>=(ucell)amx->stp)
3855         ABORT(amx,AMX_ERR_MEMACCESS);
3856       if ((pri+offs)>hea && (pri+offs)<stk || (ucell)(pri+offs)>(ucell)amx->stp)
3857         ABORT(amx,AMX_ERR_MEMACCESS);
3858       if (alt>=hea && alt<stk || (ucell)alt>=(ucell)amx->stp)
3859         ABORT(amx,AMX_ERR_MEMACCESS);
3860       if ((alt+offs)>hea && (alt+offs)<stk || (ucell)(alt+offs)>(ucell)amx->stp)
3861         ABORT(amx,AMX_ERR_MEMACCESS);
3862       #if defined _R_DEFAULT
3863         memcpy(data+(int)alt, data+(int)pri, (int)offs);
3864       #else
3865         for (i=0; i+4<offs; i+=4) {
3866           val=_R32(data,pri+i);
3867           _W32(data,alt+i,val);
3868         } /* for */
3869         for ( ; i<offs; i++) {
3870           val=_R8(data,pri+i);
3871           _W8(data,alt+i,val);
3872         } /* for */
3873       #endif
3874       break;
3875     case OP_CMPS:
3876       GETPARAM(offs);
3877       /* verify top & bottom memory addresses, for both source and destination
3878        * addresses
3879        */
3880       if (pri>=hea && pri<stk || (ucell)pri>=(ucell)amx->stp)
3881         ABORT(amx,AMX_ERR_MEMACCESS);
3882       if ((pri+offs)>hea && (pri+offs)<stk || (ucell)(pri+offs)>(ucell)amx->stp)
3883         ABORT(amx,AMX_ERR_MEMACCESS);
3884       if (alt>=hea && alt<stk || (ucell)alt>=(ucell)amx->stp)
3885         ABORT(amx,AMX_ERR_MEMACCESS);
3886       if ((alt+offs)>hea && (alt+offs)<stk || (ucell)(alt+offs)>(ucell)amx->stp)
3887         ABORT(amx,AMX_ERR_MEMACCESS);
3888       #if defined _R_DEFAULT
3889         pri=memcmp(data+(int)alt, data+(int)pri, (int)offs);
3890       #else
3891         pri=0;
3892         for (i=0; i+4<offs && pri==0; i+=4)
3893           pri=_R32(data,alt+i)-_R32(data,pri+i);
3894         for ( ; i<offs && pri==0; i++)
3895           pri=_R8(data,alt+i)-_R8(data,pri+i);
3896       #endif
3897       break;
3898     case OP_FILL:
3899       GETPARAM(offs);
3900       /* verify top & bottom memory addresses (destination only) */
3901       if (alt>=hea && alt<stk || (ucell)alt>=(ucell)amx->stp)
3902         ABORT(amx,AMX_ERR_MEMACCESS);
3903       if ((alt+offs)>hea && (alt+offs)<stk || (ucell)(alt+offs)>(ucell)amx->stp)
3904         ABORT(amx,AMX_ERR_MEMACCESS);
3905       for (i=(int)alt; (size_t)offs>=sizeof(cell); i+=sizeof(cell), offs-=sizeof(cell))
3906         _W32(data,i,pri);
3907       break;
3908     case OP_HALT:
3909       GETPARAM(offs);
3910       if (retval!=NULL)
3911         *retval=pri;
3912       /* store complete status (stk and hea are already set in the ABORT macro) */
3913       amx->frm=frm;
3914       amx->pri=pri;
3915       amx->alt=alt;
3916       amx->cip=(cell)((unsigned char*)cip-code);
3917       if (offs==AMX_ERR_SLEEP) {
3918         amx->stk=stk;
3919         amx->hea=hea;
3920         amx->reset_stk=reset_stk;
3921         amx->reset_hea=reset_hea;
3922         return (int)offs;
3923       } /* if */
3924       ABORT(amx,(int)offs);
3925     case OP_BOUNDS:
3926       GETPARAM(offs);
3927       if ((ucell)pri>(ucell)offs) {
3928         amx->cip=(cell)((unsigned char *)cip-code);
3929         ABORT(amx,AMX_ERR_BOUNDS);
3930       } /* if */
3931       break;
3932     case OP_SYSREQ_PRI:
3933       /* save a few registers */
3934       amx->cip=(cell)((unsigned char *)cip-code);
3935       amx->hea=hea;
3936       amx->frm=frm;
3937       amx->stk=stk;
3938       num=amx->callback(amx,pri,&pri,(cell *)(data+(int)stk));
3939       if (num!=AMX_ERR_NONE) {
3940         if (num==AMX_ERR_SLEEP) {
3941           amx->pri=pri;
3942           amx->alt=alt;
3943           amx->reset_stk=reset_stk;
3944           amx->reset_hea=reset_hea;
3945           return num;
3946         } /* if */
3947         ABORT(amx,num);
3948       } /* if */
3949       break;
3950     case OP_SYSREQ_C:
3951       GETPARAM(offs);
3952       /* save a few registers */
3953       amx->cip=(cell)((unsigned char *)cip-code);
3954       amx->hea=hea;
3955       amx->frm=frm;
3956       amx->stk=stk;
3957       num=amx->callback(amx,offs,&pri,(cell *)(data+(int)stk));
3958       if (num!=AMX_ERR_NONE) {
3959         if (num==AMX_ERR_SLEEP) {
3960           amx->pri=pri;
3961           amx->alt=alt;
3962           amx->reset_stk=reset_stk;
3963           amx->reset_hea=reset_hea;
3964           return num;
3965         } /* if */
3966         ABORT(amx,num);
3967       } /* if */
3968       break;
3969     case OP_LINE:
3970       SKIPPARAM(2);
3971       break;
3972     case OP_SYMBOL:
3973       GETPARAM(offs);
3974       cip=(cell *)((unsigned char *)cip + (int)offs);
3975       break;
3976     case OP_SRANGE:
3977       SKIPPARAM(2);
3978       break;
3979     case OP_SYMTAG:
3980       SKIPPARAM(1);
3981       break;
3982     case OP_JUMP_PRI:
3983       cip=(cell *)(code+(int)pri);
3984       break;
3985     case OP_SWITCH: {
3986       cell *cptr;
3987 
3988       cptr=JUMPABS(code,cip)+1; /* +1, to skip the "casetbl" opcode */
3989       cip=JUMPABS(code,cptr+1); /* preset to "none-matched" case */
3990       num=(int)*cptr;           /* number of records in the case table */
3991       for (cptr+=2; num>0 && *cptr!=pri; num--,cptr+=2)
3992         /* nothing */;
3993       if (num>0)
3994         cip=JUMPABS(code,cptr+1); /* case found */
3995       break;
3996     } /* case */
3997     case OP_SWAP_PRI:
3998       offs=_R(data,stk);
3999       _W32(data,stk,pri);
4000       pri=offs;
4001       break;
4002     case OP_SWAP_ALT:
4003       offs=_R(data,stk);
4004       _W32(data,stk,alt);
4005       alt=offs;
4006       break;
4007     case OP_PUSH_ADR:
4008       GETPARAM(offs);
4009       PUSH(frm+offs);
4010       break;
4011     case OP_NOP:
4012       break;
4013 #if !defined AMX_NO_MACRO_INSTR
4014     case OP_SYSREQ_N:
4015       GETPARAM(offs);
4016       GETPARAM(val);
4017       PUSH(val);
4018       /* save a few registers */
4019       amx->cip=(cell)((unsigned char *)cip-code);
4020       amx->hea=hea;
4021       amx->frm=frm;
4022       amx->stk=stk;
4023       num=amx->callback(amx,offs,&pri,(cell *)(data+(int)stk));
4024       stk+=val+4;
4025       if (num!=AMX_ERR_NONE) {
4026         if (num==AMX_ERR_SLEEP) {
4027           amx->pri=pri;
4028           amx->alt=alt;
4029           amx->reset_stk=reset_stk;
4030           amx->reset_hea=reset_hea;
4031           return num;
4032         } /* if */
4033         ABORT(amx,num);
4034       } /* if */
4035       break;
4036 #endif
4037     case OP_BREAK:
4038       assert((amx->flags & AMX_FLAG_BROWSE)==0);
4039       if (amx->debug!=NULL) {
4040         /* store status */
4041         amx->frm=frm;
4042         amx->stk=stk;
4043         amx->hea=hea;
4044         amx->cip=(cell)((unsigned char*)cip-code);
4045         num=amx->debug(amx);
4046         if (num!=AMX_ERR_NONE) {
4047           if (num==AMX_ERR_SLEEP) {
4048             amx->pri=pri;
4049             amx->alt=alt;
4050             amx->reset_stk=reset_stk;
4051             amx->reset_hea=reset_hea;
4052             return num;
4053           } /* if */
4054           ABORT(amx,num);
4055         } /* if */
4056       } /* if */
4057       break;
4058 #if !defined AMX_NO_MACRO_INSTR
4059     case OP_PUSH5:
4060       GETPARAM(offs);
4061       PUSH(_R(data,offs));
4062       /* drop through */
4063     case OP_PUSH4:
4064       GETPARAM(offs);
4065       PUSH(_R(data,offs));
4066       /* drop through */
4067     case OP_PUSH3:
4068       GETPARAM(offs);
4069       PUSH(_R(data,offs));
4070       /* drop through */
4071     case OP_PUSH2:
4072       GETPARAM(offs);
4073       PUSH(_R(data,offs));
4074       GETPARAM(offs);
4075       PUSH(_R(data,offs));
4076       break;
4077     case OP_PUSH5_S:
4078       GETPARAM(offs);
4079       PUSH(_R(data,frm+offs));
4080       /* drop through */
4081     case OP_PUSH4_S:
4082       GETPARAM(offs);
4083       PUSH(_R(data,frm+offs));
4084       /* drop through */
4085     case OP_PUSH3_S:
4086       GETPARAM(offs);
4087       PUSH(_R(data,frm+offs));
4088       /* drop through */
4089     case OP_PUSH2_S:
4090       GETPARAM(offs);
4091       PUSH(_R(data,frm+offs));
4092       GETPARAM(offs);
4093       PUSH(_R(data,frm+offs));
4094       break;
4095     case OP_PUSH5_C:
4096       GETPARAM(offs);
4097       PUSH(offs);
4098       /* drop through */
4099     case OP_PUSH4_C:
4100       GETPARAM(offs);
4101       PUSH(offs);
4102       /* drop through */
4103     case OP_PUSH3_C:
4104       GETPARAM(offs);
4105       PUSH(offs);
4106       /* drop through */
4107     case OP_PUSH2_C:
4108       GETPARAM(offs);
4109       PUSH(offs);
4110       GETPARAM(offs);
4111       PUSH(offs);
4112       break;
4113     case OP_PUSH5_ADR:
4114       GETPARAM(offs);
4115       PUSH(frm+offs);
4116       /* drop through */
4117     case OP_PUSH4_ADR:
4118       GETPARAM(offs);
4119       PUSH(frm+offs);
4120       /* drop through */
4121     case OP_PUSH3_ADR:
4122       GETPARAM(offs);
4123       PUSH(frm+offs);
4124       /* drop through */
4125     case OP_PUSH2_ADR:
4126       GETPARAM(offs);
4127       PUSH(frm+offs);
4128       GETPARAM(offs);
4129       PUSH(frm+offs);
4130       break;
4131     case OP_LOAD_BOTH:
4132       GETPARAM(offs);
4133       pri=_R(data,offs);
4134       GETPARAM(offs);
4135       alt=_R(data,offs);
4136       break;
4137     case OP_LOAD_S_BOTH:
4138       GETPARAM(offs);
4139       pri=_R(data,frm+offs);
4140       GETPARAM(offs);
4141       alt=_R(data,frm+offs);
4142       break;
4143     case OP_CONST:
4144       GETPARAM(offs);
4145       GETPARAM(val);
4146       _W32(data,offs,val);
4147       break;
4148     case OP_CONST_S:
4149       GETPARAM(offs);
4150       GETPARAM(val);
4151       _W32(data,frm+offs,val);
4152       break;
4153 #endif
4154 #if !defined AMX_DONT_RELOCATE
4155     case OP_SYSREQ_D: /* see OP_SYSREQ_C */
4156       GETPARAM(offs);
4157       /* save a few registers */
4158       amx->cip=(cell)((unsigned char *)cip-code);
4159       amx->hea=hea;
4160       amx->frm=frm;
4161       amx->stk=stk;
4162       pri=((AMX_NATIVE)offs)(amx,(cell *)(data+(int)stk));
4163       if (amx->error!=AMX_ERR_NONE) {
4164         if (amx->error==AMX_ERR_SLEEP) {
4165           amx->pri=pri;
4166           amx->alt=alt;
4167           amx->reset_stk=reset_stk;
4168           amx->reset_hea=reset_hea;
4169           return AMX_ERR_SLEEP;
4170         } /* if */
4171         ABORT(amx,amx->error);
4172       } /* if */
4173       break;
4174 #endif
4175 #if !defined AMX_NO_MACRO_INSTR && !defined AMX_DONT_RELOCATE
4176     case OP_SYSREQ_ND:    /* see SYSREQ_N */
4177       GETPARAM(offs);
4178       GETPARAM(val);
4179       PUSH(val);
4180       /* save a few registers */
4181       amx->cip=(cell)((unsigned char *)cip-code);
4182       amx->hea=hea;
4183       amx->frm=frm;
4184       amx->stk=stk;
4185       pri=((AMX_NATIVE)offs)(amx,(cell *)(data+(int)stk));
4186       stk+=val+4;
4187       if (amx->error!=AMX_ERR_NONE) {
4188         if (amx->error==AMX_ERR_SLEEP) {
4189           amx->pri=pri;
4190           amx->alt=alt;
4191           amx->reset_stk=reset_stk;
4192           amx->reset_hea=reset_hea;
4193           return AMX_ERR_SLEEP;
4194         } /* if */
4195         ABORT(amx,amx->error);
4196       } /* if */
4197       break;
4198 #endif
4199     default:
4200       /* case OP_FILE:          should not occur during execution
4201        * case OP_CASETBL:       should not occur during execution
4202        */
4203       assert(0);
4204       ABORT(amx,AMX_ERR_INVINSTR);
4205     } /* switch */
4206   } /* for */
4207 #endif
4208 }
4209 
4210 #endif  /* __GNUC__ || __ICC */
4211 
4212 #endif /* AMX_EXEC || AMX_INIT */
4213 
4214 #if defined AMX_SETCALLBACK
4215 int AMXAPI amx_SetCallback(AMX *amx,AMX_CALLBACK callback)
4216 {
4217   assert(amx!=NULL);
4218   assert(callback!=NULL);
4219   amx->callback=callback;
4220   return AMX_ERR_NONE;
4221 }
4222 #endif /* AMX_SETCALLBACK */
4223 
4224 #if defined AMX_SETDEBUGHOOK
4225 int AMXAPI amx_SetDebugHook(AMX *amx,AMX_DEBUG debug)
4226 {
4227   assert(amx!=NULL);
4228   amx->debug=debug;
4229   return AMX_ERR_NONE;
4230 }
4231 #endif /* AMX_SETDEBUGHOOK */
4232 
4233 #if defined AMX_RAISEERROR
4234 int AMXAPI amx_RaiseError(AMX *amx, int error)
4235 {
4236   assert(error>0);
4237   amx->error=error;
4238   return AMX_ERR_NONE;
4239 }
4240 #endif /* AMX_RAISEERROR */
4241 
4242 #if defined AMX_GETADDR
4243 int AMXAPI amx_GetAddr(AMX *amx,cell amx_addr,cell **phys_addr)
4244 {
4245   AMX_HEADER *hdr;
4246   unsigned char *data;
4247 
4248   assert(amx!=NULL);
4249   hdr=(AMX_HEADER *)amx->base;
4250   assert(hdr!=NULL);
4251   assert(hdr->magic==AMX_MAGIC);
4252   data=(amx->data!=NULL) ? amx->data : amx->base+(int)hdr->dat;
4253 
4254   assert(phys_addr!=NULL);
4255   if ((amx_addr>=amx->hea && amx_addr<amx->stk) || amx_addr<0 || amx_addr>=amx->stp) {
4256     *phys_addr=NULL;
4257     return AMX_ERR_MEMACCESS;
4258   } /* if */
4259 
4260   *phys_addr=(cell *)(data + (int)amx_addr);
4261   return AMX_ERR_NONE;
4262 }
4263 #endif /* AMX_GETADDR */
4264 
4265 #if defined AMX_ALLOT || defined AMX_EXEC
4266 int AMXAPI amx_Allot(AMX *amx,int cells,cell *amx_addr,cell **phys_addr)
4267 {
4268   AMX_HEADER *hdr;
4269   unsigned char *data;
4270 
4271   assert(amx!=NULL);
4272   hdr=(AMX_HEADER *)amx->base;
4273   assert(hdr!=NULL);
4274   assert(hdr->magic==AMX_MAGIC);
4275   data=(amx->data!=NULL) ? amx->data : amx->base+(int)hdr->dat;
4276 
4277   if (amx->stk - amx->hea - cells*sizeof(cell) < STKMARGIN)
4278     return AMX_ERR_MEMORY;
4279   assert(amx_addr!=NULL);
4280   assert(phys_addr!=NULL);
4281   *amx_addr=amx->hea;
4282   *phys_addr=(cell *)(data + (int)amx->hea);
4283   amx->hea += cells*sizeof(cell);
4284   return AMX_ERR_NONE;
4285 }
4286 
4287 int AMXAPI amx_Release(AMX *amx,cell amx_addr)
4288 {
4289   if (amx->hea > amx_addr)
4290     amx->hea=amx_addr;
4291   return AMX_ERR_NONE;
4292 }
4293 #endif /* AMX_ALLOT */
4294 
4295 #if defined AMX_XXXSTRING || defined AMX_UTF8XXX
4296 
4297 #define CHARBITS        (8*sizeof(char))
4298 #if PAWN_CELL_SIZE==16
4299   #define CHARMASK      (0xffffu << 8*(2-sizeof(char)))
4300 #elif PAWN_CELL_SIZE==32
4301   #define CHARMASK      (0xffffffffuL << 8*(4-sizeof(char)))
4302 #elif PAWN_CELL_SIZE==64
4303   #define CHARMASK      (0xffffffffffffffffuLL << 8*(8-sizeof(char)))
4304 #else
4305   #error Unsupported cell size
4306 #endif
4307 
4308 int AMXAPI amx_StrLen(const cell *cstr, int *length)
4309 {
4310   int len;
4311   #if BYTE_ORDER==LITTLE_ENDIAN
4312     cell c;
4313   #endif
4314 
4315   assert(length!=NULL);
4316   if (cstr==NULL) {
4317     *length=0;
4318     return AMX_ERR_PARAMS;
4319   } /* if */
4320 
4321   if ((ucell)*cstr>UNPACKEDMAX) {
4322     /* packed string */
4323     assert_static(sizeof(char)==1);
4324     len=strlen((char *)cstr);           /* find '\0' */
4325     assert(check_endian());
4326     #if BYTE_ORDER==LITTLE_ENDIAN
4327       /* on Little Endian machines, toggle the last bytes */
4328       c=cstr[len/sizeof(cell)];         /* get last cell */
4329       len=len - len % sizeof(cell);     /* len = multiple of "cell" bytes */
4330       while ((c & CHARMASK)!=0) {
4331         len++;
4332         c <<= 8*sizeof(char);
4333       } /* if */
4334     #endif
4335   } else {
4336     for (len=0; cstr[len]!=0; len++)
4337       /* nothing */;
4338   } /* if */
4339   *length = len;
4340   return AMX_ERR_NONE;
4341 }
4342 #endif
4343 
4344 #if defined AMX_XXXSTRING || defined AMX_EXEC
4345 int AMXAPI amx_SetString(cell *dest,const char *source,int pack,int use_wchar,size_t size)
4346 {                 /* the memory blocks should not overlap */
4347   int len, i;
4348 
4349   assert_static(UNLIMITED>0);
4350   #if defined AMX_ANSIONLY
4351     (void)use_wchar;
4352     len=strlen(source);
4353   #else
4354     len= use_wchar ? wcslen((const wchar_t*)source) : strlen(source);
4355   #endif
4356   if (pack) {
4357     /* create a packed string */
4358     if (size<UNLIMITED/sizeof(cell) && (size_t)len>=size*sizeof(cell))
4359       len=size*sizeof(cell)-1;
4360     dest[len/sizeof(cell)]=0;   /* clear last bytes of last (semi-filled) cell*/
4361     #if defined AMX_ANSIONLY
4362       memcpy(dest,source,len);
4363     #else
4364       if (use_wchar) {
4365         for (i=0; i<len; i++)
4366           ((char*)dest)[i]=(char)(((wchar_t*)source)[i]);
4367       } else {
4368         memcpy(dest,source,len);
4369       } /* if */
4370     #endif
4371     /* On Big Endian machines, the characters are well aligned in the
4372      * cells; on Little Endian machines, we must swap all cells.
4373      */
4374     assert(check_endian());
4375     #if BYTE_ORDER==LITTLE_ENDIAN
4376       len /= sizeof(cell);
4377       while (len>=0)
4378         swapcell((ucell *)&dest[len--]);
4379     #endif
4380 
4381   } else {
4382     /* create an unpacked string */
4383     if (size<UNLIMITED && (size_t)len>=size)
4384       len=size-1;
4385     #if defined AMX_ANSIONLY
4386       for (i=0; i<len; i++)
4387         dest[i]=(cell)source[i];
4388     #else
4389       if (use_wchar) {
4390         for (i=0; i<len; i++)
4391           dest[i]=(cell)(((wchar_t*)source)[i]);
4392       } else {
4393         for (i=0; i<len; i++)
4394           dest[i]=(cell)source[i];
4395       } /* if */
4396     #endif
4397     dest[len]=0;
4398   } /* if */
4399   return AMX_ERR_NONE;
4400 }
4401 #endif
4402 
4403 #if defined AMX_XXXSTRING
4404 int AMXAPI amx_GetString(char *dest,const cell *source,int use_wchar,size_t size)
4405 {
4406   int len=0;
4407   #if defined AMX_ANSIONLY
4408     (void)use_wchar;
4409   #endif
4410   if ((ucell)*source>UNPACKEDMAX) {
4411     /* source string is packed */
4412     cell c = 0;         /* to avoid a compiler warning */
4413     int i=sizeof(cell)-1;
4414     while ((size_t)len<size) {
4415       if (i==sizeof(cell)-1)
4416         c=*source++;
4417       #if defined AMX_ANSIONLY
4418         dest[len++]=(char)(c >> i*CHARBITS);
4419       #else
4420         if (use_wchar)
4421           ((wchar_t*)dest)[len++]=(char)(c >> i*CHARBITS);
4422         else
4423           dest[len++]=(char)(c >> i*CHARBITS);
4424       #endif
4425       if (dest[len-1]=='\0')
4426         break;          /* terminating zero character found */
4427       i=(i+sizeof(cell)-1) % sizeof(cell);
4428     } /* while */
4429   } else {
4430     /* source string is unpacked */
4431     #if defined AMX_ANSIONLY
4432       while (*source!=0 && (size_t)len<size)
4433         dest[len++]=(char)*source++;
4434     #else
4435       if (use_wchar) {
4436         while (*source!=0 && (size_t)len<size)
4437           ((wchar_t*)dest)[len++]=(wchar_t)*source++;
4438       } else {
4439         while (*source!=0 && (size_t)len<size)
4440           dest[len++]=(char)*source++;
4441       } /* if */
4442     #endif
4443   } /* if */
4444   if ((size_t)len>=size)
4445     len=size-1;
4446   if (len>=0)
4447     dest[len]='\0';   /* store terminator */
4448   return AMX_ERR_NONE;
4449 }
4450 #endif /* AMX_XXXSTRING */
4451 
4452 #if defined AMX_UTF8XXX
4453   #if defined __BORLANDC__
4454     #pragma warn -amb -8000     /* ambiguous operators need parentheses */
4455   #endif
4456 /* amx_UTF8Get()
4457  * Extract a single UTF-8 encoded character from a string and return a pointer
4458  * to the character just behind that UTF-8 character. The parameters "endptr"
4459  * and "value" may be NULL.
4460  * If the code is not valid UTF-8, "endptr" has the value of the input
4461  * parameter "string" and "value" is zero.
4462  */
4463 int AMXAPI amx_UTF8Get(const char *string, const char **endptr, cell *value)
4464 {
4465 static const char utf8_count[16]={ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 4 };
4466 static const long utf8_lowmark[5] = { 0x80, 0x800, 0x10000L, 0x200000L, 0x4000000L };
4467   unsigned char c;
4468   cell result;
4469   int followup;
4470 
4471   assert(string!=NULL);
4472   if (value!=NULL)      /* preset, in case of an error */
4473     *value=0;
4474   if (endptr!=NULL)
4475     *endptr=string;
4476 
4477   c = *(const unsigned char*)string++;
4478   if (c<0x80) {
4479     /* ASCII */
4480     result=c;
4481   } else {
4482     if (c<0xc0 || c>=0xfe)
4483       return AMX_ERR_PARAMS;  /* invalid or "follower" code, quit with error */
4484     /* At this point we know that the two top bits of c are ones. The two
4485      * bottom bits are always part of the code. We only need to consider
4486      * the 4 remaining bits; i.e., a 16-byte table. This is "utf8_count[]".
4487      * (Actually the utf8_count[] table records the number of follow-up
4488      * bytes minus 1. This is just for convenience.)
4489      */
4490     assert((c & 0xc0)==0xc0);
4491     followup=(int)utf8_count[(c >> 2) & 0x0f];
4492     /* The mask depends on the code length; this is just a very simple
4493      * relation.
4494      */
4495     #define utf8_mask   (0x1f >> followup)
4496     result= c & utf8_mask;
4497     /* Collect the follow-up codes using a drop-through switch statement;
4498      * this avoids a loop. In each case, verify the two leading bits.
4499      */
4500     assert(followup>=0 && followup<=4);
4501     switch (followup) {
4502     case 4:
4503       if (((c=*string++) & 0xc0) != 0x80) goto error;
4504       result = (result << 6) | (c & 0x3f);
4505     case 3:
4506       if (((c=*string++) & 0xc0) != 0x80) goto error;
4507       result = (result << 6) | (c & 0x3f);
4508     case 2:
4509       if (((c=*string++) & 0xc0) != 0x80) goto error;
4510       result = (result << 6) | (c & 0x3f);
4511     case 1:
4512       if (((c=*string++) & 0xc0) != 0x80) goto error;
4513       result = (result << 6) | (c & 0x3f);
4514     case 0:
4515       if (((c=*string++) & 0xc0) != 0x80) goto error;
4516       result = (result << 6) | (c & 0x3f);
4517     } /* switch */
4518     /* Do additional checks: shortest encoding & reserved positions. The
4519      * lowmark limits also depends on the code length; it can be read from
4520      * a table with 5 elements. This is "utf8_lowmark[]".
4521      */
4522     if (result<utf8_lowmark[followup])
4523       goto error;
4524     if ((result>=0xd800 && result<=0xdfff) || result==0xfffe || result==0xffff)
4525       goto error;
4526   } /* if */
4527 
4528   if (value!=NULL)
4529     *value=result;
4530   if (endptr!=NULL)
4531     *endptr=string;
4532 
4533   return AMX_ERR_NONE;
4534 
4535 error:
4536   return AMX_ERR_PARAMS;
4537 }
4538 
4539 /* amx_UTF8Put()
4540  * Encode a single character into a byte string. The character may result in
4541  * a string of up to 6 bytes. The function returns an error code if "maxchars"
4542  * is lower than the required number of characters; in this case nothing is
4543  * stored.
4544  * The function does not zero-terminate the string.
4545  */
4546 int AMXAPI amx_UTF8Put(char *string, char **endptr, int maxchars, cell value)
4547 {
4548   assert(string!=NULL);
4549   if (endptr!=NULL)     /* preset, in case of an error */
4550     *endptr=string;
4551 
4552   if (value<0x80) {
4553     /* 0xxxxxxx */
4554     if (maxchars < 1) goto error;
4555     *string++ = (char)value;
4556   } else if (value<0x800) {
4557     /* 110xxxxx 10xxxxxx */
4558     if (maxchars < 2) goto error;
4559     *string++ = (char)(((value>>6) & 0x1f) | 0xc0);
4560     *string++ = (char)((value & 0x3f) | 0x80);
4561   } else if (value<0x10000) {
4562     /* 1110xxxx 10xxxxxx 10xxxxxx (16 bits, BMP plane) */
4563     if (maxchars < 3) goto error;
4564     if ((value>=0xd800 && value<=0xdfff) || value==0xfffe || value==0xffff)
4565       goto error;       /* surrogate pairs and invalid characters */
4566     *string++ = (char)(((value>>12) & 0x0f) | 0xe0);
4567     *string++ = (char)(((value>>6) & 0x3f) | 0x80);
4568     *string++ = (char)((value & 0x3f) | 0x80);
4569   } else if (value<0x200000) {
4570     /* 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
4571     if (maxchars < 4) goto error;
4572     *string++ = (char)(((value>>18) & 0x07) | 0xf0);
4573     *string++ = (char)(((value>>12) & 0x3f) | 0x80);
4574     *string++ = (char)(((value>>6) & 0x3f) | 0x80);
4575     *string++ = (char)((value & 0x3f) | 0x80);
4576   } else if (value<0x4000000) {
4577     /* 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx */
4578     if (maxchars < 5) goto error;
4579     *string++ = (char)(((value>>24) & 0x03) | 0xf8);
4580     *string++ = (char)(((value>>18) & 0x3f) | 0x80);
4581     *string++ = (char)(((value>>12) & 0x3f) | 0x80);
4582     *string++ = (char)(((value>>6) & 0x3f) | 0x80);
4583     *string++ = (char)((value & 0x3f) | 0x80);
4584   } else {
4585     /* 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx (31 bits) */
4586     if (maxchars < 6) goto error;
4587     *string++ = (char)(((value>>30) & 0x01) | 0xfc);
4588     *string++ = (char)(((value>>24) & 0x3f) | 0x80);
4589     *string++ = (char)(((value>>18) & 0x3f) | 0x80);
4590     *string++ = (char)(((value>>12) & 0x3f) | 0x80);
4591     *string++ = (char)(((value>>6) & 0x3f) | 0x80);
4592     *string++ = (char)((value & 0x3f) | 0x80);
4593   } /* if */
4594 
4595   if (endptr!=NULL)
4596     *endptr=string;
4597   return AMX_ERR_NONE;
4598 
4599 error:
4600   return AMX_ERR_PARAMS;
4601 }
4602 
4603 /* amx_UTF8Check()
4604  * Run through a zero-terminated string and check the validity of the UTF-8
4605  * encoding. The function returns an error code, it is AMX_ERR_NONE if the
4606  * string is valid UTF-8 (or valid ASCII for that matter).
4607  */
4608 int AMXAPI amx_UTF8Check(const char *string, int *length)
4609 {
4610   int err=AMX_ERR_NONE;
4611   int len=0;
4612   while (err==AMX_ERR_NONE && *string!='\0') {
4613     err=amx_UTF8Get(string,&string,NULL);
4614     len++;
4615   } /* while */
4616   if (length!=NULL)
4617     *length=len;
4618   return err;
4619 }
4620 
4621 /* amx_UTF8Len()
4622  * Run through a wide string and return how many 8-bit characters are needed to
4623  * store the string in UTF-8 format. The returned cound excludes the terminating
4624  * zero byte. The function returns an error code.
4625  */
4626 int AMXAPI amx_UTF8Len(const cell *cstr, int *length)
4627 {
4628   int err;
4629 
4630   assert(length!=NULL);
4631   err=amx_StrLen(cstr, length);
4632   if (err==AMX_ERR_NONE && (ucell)*cstr<=UNPACKEDMAX) {
4633     char buffer[10];  /* maximum UTF-8 code is 6 characters */
4634     char *endptr;
4635     int len=*length, count=0;
4636     while (len-->0) {
4637       amx_UTF8Put(buffer, &endptr, sizeof buffer, *cstr++);
4638       count+=(int)(endptr-buffer);
4639     } /* while */
4640     *length=count;
4641   } /* while */
4642   return err;
4643 }
4644 #endif /* AMX_UTF8XXX */
4645 
4646 #endif // PAWN
4647