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