1 /* Pawn compiler - Binary code generation (the "assembler")
3 * Copyright (c) ITB CompuPhase, 1997-2006
5 * This software is provided "as-is", without any express or implied warranty.
6 * In no event will the authors be held liable for any damages arising from
7 * the use of this software.
9 * Permission is granted to anyone to use this software for any purpose,
10 * including commercial applications, and to alter it and redistribute it
11 * freely, subject to the following restrictions:
13 * 1. The origin of this software must not be misrepresented; you must not
14 * claim that you wrote the original software. If you use this software in
15 * a product, an acknowledgment in the product documentation would be
16 * appreciated but is not required.
17 * 2. Altered source versions must be plainly marked as such, and must not be
18 * misrepresented as being the original software.
19 * 3. This notice may not be removed or altered from any source distribution.
25 #include <stdlib.h> /* for macro max() */
26 #include <stddef.h> /* for macro offsetof() */
30 #include <alloc/fortify.h>
35 #if defined LINUX || defined __FreeBSD__ || defined __OpenBSD__
40 static void append_dbginfo(FILE *fout);
43 typedef cell (*OPCODE_PROC)(FILE *fbin,char *params,cell opcode);
48 int segment; /* sIN_CSEG=parse in cseg, sIN_DSEG=parse in dseg */
52 static cell codeindex; /* similar to "code_idx" */
53 static cell *lbltab; /* label table */
54 static int writeerror;
55 static int bytes_in, bytes_out;
56 static jmp_buf compact_err;
58 /* apparently, strtol() does not work correctly on very large (unsigned)
59 * hexadecimal values */
60 static ucell hex2long(const char *s,char **n)
66 /* ignore leading whitespace */
67 while (*s==' ' || *s=='\t')
70 /* allow a negation sign to create the two's complement of numbers */
76 assert((*s>='0' && *s<='9') || (*s>='a' && *s<='f') || (*s>='a' && *s<='f'));
78 if (*s>='0' && *s<='9')
80 else if (*s>='a' && *s<='f')
82 else if (*s>='A' && *s<='F')
85 break; /* probably whitespace */
86 result=(result<<4) | digit;
92 result=(~result)+1; /* take two's complement of the result */
96 static ucell getparam(const char *s,char **n)
100 result+=hex2long(s,(char**)&s);
110 #if BYTE_ORDER==BIG_ENDIAN
111 static uint16_t *align16(uint16_t *v)
113 unsigned char *s = (unsigned char *)v;
123 static uint32_t *align32(uint32_t *v)
125 unsigned char *s = (unsigned char *)v;
128 /* swap outer two bytes */
132 /* swap inner two bytes */
139 #if PAWN_CELL_SIZE>=64
140 static uint64_t *align64(uint64_t *v)
142 unsigned char *s = (unsigned char *)v;
165 #if PAWN_CELL_SIZE==16
166 #define aligncell(v) align16(v)
167 #elif PAWN_CELL_SIZE==32
168 #define aligncell(v) align32(v)
169 #elif PAWN_CELL_SIZE==64
170 #define aligncell(v) align64(v)
173 #define align16(v) (v)
174 #define align32(v) (v)
175 #define aligncell(v) (v)
178 static char *skipwhitespace(char *str)
180 while (isspace(*str))
185 static char *stripcomment(char *str)
187 char *ptr=strchr(str,';');
189 *ptr++='\n'; /* terminate the line, but leave the '\n' */
195 static void write_encoded(FILE *fbin,ucell *c,int num)
197 #if PAWN_CELL_SIZE == 16
198 #define ENC_MAX 3 /* a 16-bit cell is encoded in max. 3 bytes */
199 #define ENC_MASK 0x03 /* after 2x7 bits, 2 bits remain to make 16 bits */
200 #elif PAWN_CELL_SIZE == 32
201 #define ENC_MAX 5 /* a 32-bit cell is encoded in max. 5 bytes */
202 #define ENC_MASK 0x0f /* after 4x7 bits, 4 bits remain to make 32 bits */
203 #elif PAWN_CELL_SIZE == 64
204 #define ENC_MAX 10 /* a 32-bit cell is encoded in max. 10 bytes */
205 #define ENC_MASK 0x01 /* after 9x7 bits, 1 bit remains to make 64 bits */
212 unsigned char t[ENC_MAX];
215 for (index=0; index<ENC_MAX; index++) {
216 t[index]=(unsigned char)(p & 0x7f); /* store 7 bits */
219 /* skip leading zeros */
220 while (index>1 && t[index-1]==0 && (t[index-2] & 0x40)==0)
222 /* skip leading -1s */
223 if (index==ENC_MAX && t[index-1]==ENC_MASK && (t[index-2] & 0x40)!=0)
225 while (index>1 && t[index-1]==0x7f && (t[index-2] & 0x40)!=0)
227 /* write high byte first, write continuation bits */
230 code=(unsigned char)((index==0) ? t[index] : (t[index]|0x80));
231 writeerror |= !pc_writebin(fbin,&code,1);
235 assert(AMX_COMPACTMARGIN>2);
236 if (bytes_out-bytes_in>=AMX_COMPACTMARGIN-2)
237 longjmp(compact_err,1);
239 assert((pc_lengthbin(fbin) % sizeof(cell)) == 0);
240 writeerror |= !pc_writebin(fbin,aligncell(c),sizeof *c);
246 #if defined __BORLANDC__ || defined __WATCOMC__
249 static cell noop(FILE *fbin,char *params,cell opcode)
254 #if defined __BORLANDC__ || defined __WATCOMC__
257 static cell set_currentfile(FILE *fbin,char *params,cell opcode)
259 fcurrent=(short)getparam(params,NULL);
263 #if defined __BORLANDC__ || defined __WATCOMC__
266 static cell parm0(FILE *fbin,char *params,cell opcode)
269 write_encoded(fbin,(ucell*)&opcode,1);
273 static cell parm1(FILE *fbin,char *params,cell opcode)
275 ucell p=getparam(params,NULL);
277 write_encoded(fbin,(ucell*)&opcode,1);
278 write_encoded(fbin,&p,1);
280 return opcodes(1)+opargs(1);
283 static cell parm2(FILE *fbin,char *params,cell opcode)
285 ucell p1=getparam(params,¶ms);
286 ucell p2=getparam(params,NULL);
288 write_encoded(fbin,(ucell*)&opcode,1);
289 write_encoded(fbin,&p1,1);
290 write_encoded(fbin,&p2,1);
292 return opcodes(1)+opargs(2);
295 static cell parm3(FILE *fbin,char *params,cell opcode)
297 ucell p1=getparam(params,¶ms);
298 ucell p2=getparam(params,¶ms);
299 ucell p3=getparam(params,NULL);
301 write_encoded(fbin,(ucell*)&opcode,1);
302 write_encoded(fbin,&p1,1);
303 write_encoded(fbin,&p2,1);
304 write_encoded(fbin,&p3,1);
306 return opcodes(1)+opargs(3);
309 static cell parm4(FILE *fbin,char *params,cell opcode)
311 ucell p1=getparam(params,¶ms);
312 ucell p2=getparam(params,¶ms);
313 ucell p3=getparam(params,¶ms);
314 ucell p4=getparam(params,NULL);
316 write_encoded(fbin,(ucell*)&opcode,1);
317 write_encoded(fbin,&p1,1);
318 write_encoded(fbin,&p2,1);
319 write_encoded(fbin,&p3,1);
320 write_encoded(fbin,&p4,1);
322 return opcodes(1)+opargs(4);
325 static cell parm5(FILE *fbin,char *params,cell opcode)
327 ucell p1=getparam(params,¶ms);
328 ucell p2=getparam(params,¶ms);
329 ucell p3=getparam(params,¶ms);
330 ucell p4=getparam(params,¶ms);
331 ucell p5=getparam(params,NULL);
333 write_encoded(fbin,(ucell*)&opcode,1);
334 write_encoded(fbin,&p1,1);
335 write_encoded(fbin,&p2,1);
336 write_encoded(fbin,&p3,1);
337 write_encoded(fbin,&p4,1);
338 write_encoded(fbin,&p5,1);
340 return opcodes(1)+opargs(5);
343 #if defined __BORLANDC__ || defined __WATCOMC__
346 static cell do_dump(FILE *fbin,char *params,cell opcode)
351 while (*params!='\0') {
352 p=getparam(params,¶ms);
354 write_encoded(fbin,&p,1);
356 while (isspace(*params))
359 return num*sizeof(cell);
362 static cell do_call(FILE *fbin,char *params,cell opcode)
364 char name[sNAMEMAX+1];
369 for (i=0; !isspace(*params); i++,params++) {
370 assert(*params!='\0');
376 if (name[0]=='l' && name[1]=='.') {
377 /* this is a label, not a function symbol */
378 i=(int)hex2long(name+2,NULL);
379 assert(i>=0 && i<sc_labnum);
381 assert(lbltab!=NULL);
385 /* look up the function address; note that the correct file number must
386 * already have been set (in order for static globals to be found).
388 sym=findglb(name,sGLOBAL);
390 assert(sym->ident==iFUNCTN || sym->ident==iREFFUNC);
391 assert(sym->vclass==sGLOBAL);
396 write_encoded(fbin,(ucell*)&opcode,1);
397 write_encoded(fbin,&p,1);
399 return opcodes(1)+opargs(1);
402 static cell do_jump(FILE *fbin,char *params,cell opcode)
407 i=(int)hex2long(params,NULL);
408 assert(i>=0 && i<sc_labnum);
411 assert(lbltab!=NULL);
413 write_encoded(fbin,(ucell*)&opcode,1);
414 write_encoded(fbin,&p,1);
416 return opcodes(1)+opargs(1);
419 static cell do_switch(FILE *fbin,char *params,cell opcode)
424 i=(int)hex2long(params,NULL);
425 assert(i>=0 && i<sc_labnum);
428 assert(lbltab!=NULL);
430 write_encoded(fbin,(ucell*)&opcode,1);
431 write_encoded(fbin,&p,1);
433 return opcodes(1)+opargs(1);
436 #if defined __BORLANDC__ || defined __WATCOMC__
439 static cell do_case(FILE *fbin,char *params,cell opcode)
444 v=hex2long(params,¶ms);
445 i=(int)hex2long(params,NULL);
446 assert(i>=0 && i<sc_labnum);
449 assert(lbltab!=NULL);
451 write_encoded(fbin,&v,1);
452 write_encoded(fbin,&p,1);
454 return opcodes(0)+opargs(2);
457 static OPCODEC opcodelist[] = {
458 /* node for "invalid instruction" */
459 { 0, NULL, 0, noop },
460 /* opcodes in sorted order */
461 { 78, "add", sIN_CSEG, parm0 },
462 { 87, "add.c", sIN_CSEG, parm1 },
463 { 14, "addr.alt", sIN_CSEG, parm1 },
464 { 13, "addr.pri", sIN_CSEG, parm1 },
465 { 30, "align.alt", sIN_CSEG, parm1 },
466 { 29, "align.pri", sIN_CSEG, parm1 },
467 { 81, "and", sIN_CSEG, parm0 },
468 {121, "bounds", sIN_CSEG, parm1 },
469 {137, "break", sIN_CSEG, parm0 }, /* version 8 */
470 { 49, "call", sIN_CSEG, do_call },
471 { 50, "call.pri", sIN_CSEG, parm0 },
472 { 0, "case", sIN_CSEG, do_case },
473 {130, "casetbl", sIN_CSEG, parm0 }, /* version 1 */
474 {118, "cmps", sIN_CSEG, parm1 },
475 { 0, "code", sIN_CSEG, set_currentfile },
476 {156, "const", sIN_CSEG, parm2 }, /* version 9 */
477 { 12, "const.alt", sIN_CSEG, parm1 },
478 { 11, "const.pri", sIN_CSEG, parm1 },
479 {157, "const.s", sIN_CSEG, parm2 }, /* version 9 */
480 { 0, "data", sIN_DSEG, set_currentfile },
481 {114, "dec", sIN_CSEG, parm1 },
482 {113, "dec.alt", sIN_CSEG, parm0 },
483 {116, "dec.i", sIN_CSEG, parm0 },
484 {112, "dec.pri", sIN_CSEG, parm0 },
485 {115, "dec.s", sIN_CSEG, parm1 },
486 { 0, "dump", sIN_DSEG, do_dump },
487 { 95, "eq", sIN_CSEG, parm0 },
488 {106, "eq.c.alt", sIN_CSEG, parm1 },
489 {105, "eq.c.pri", sIN_CSEG, parm1 },
490 /*{124, "file", sIN_CSEG, do_file }, */
491 {119, "fill", sIN_CSEG, parm1 },
492 {162, "genarray", sIN_CSEG, parm1 },
493 {163, "genarray.z", sIN_CSEG, parm1 },
494 {100, "geq", sIN_CSEG, parm0 },
495 { 99, "grtr", sIN_CSEG, parm0 },
496 {120, "halt", sIN_CSEG, parm1 },
497 { 45, "heap", sIN_CSEG, parm1 },
498 { 27, "idxaddr", sIN_CSEG, parm0 },
499 { 28, "idxaddr.b", sIN_CSEG, parm1 },
500 {109, "inc", sIN_CSEG, parm1 },
501 {108, "inc.alt", sIN_CSEG, parm0 },
502 {111, "inc.i", sIN_CSEG, parm0 },
503 {107, "inc.pri", sIN_CSEG, parm0 },
504 {110, "inc.s", sIN_CSEG, parm1 },
505 { 86, "invert", sIN_CSEG, parm0 },
506 { 55, "jeq", sIN_CSEG, do_jump },
507 { 60, "jgeq", sIN_CSEG, do_jump },
508 { 59, "jgrtr", sIN_CSEG, do_jump },
509 { 58, "jleq", sIN_CSEG, do_jump },
510 { 57, "jless", sIN_CSEG, do_jump },
511 { 56, "jneq", sIN_CSEG, do_jump },
512 { 54, "jnz", sIN_CSEG, do_jump },
513 { 52, "jrel", sIN_CSEG, parm1 }, /* always a number */
514 { 64, "jsgeq", sIN_CSEG, do_jump },
515 { 63, "jsgrtr", sIN_CSEG, do_jump },
516 { 62, "jsleq", sIN_CSEG, do_jump },
517 { 61, "jsless", sIN_CSEG, do_jump },
518 { 51, "jump", sIN_CSEG, do_jump },
519 {128, "jump.pri", sIN_CSEG, parm0 }, /* version 1 */
520 { 53, "jzer", sIN_CSEG, do_jump },
521 { 31, "lctrl", sIN_CSEG, parm1 },
522 { 98, "leq", sIN_CSEG, parm0 },
523 { 97, "less", sIN_CSEG, parm0 },
524 { 25, "lidx", sIN_CSEG, parm0 },
525 { 26, "lidx.b", sIN_CSEG, parm1 },
526 /*{125, "line", sIN_CSEG, parm2 }, */
527 { 2, "load.alt", sIN_CSEG, parm1 },
528 {154, "load.both", sIN_CSEG, parm2 }, /* version 9 */
529 { 9, "load.i", sIN_CSEG, parm0 },
530 { 1, "load.pri", sIN_CSEG, parm1 },
531 { 4, "load.s.alt", sIN_CSEG, parm1 },
532 {155, "load.s.both",sIN_CSEG, parm2 }, /* version 9 */
533 { 3, "load.s.pri", sIN_CSEG, parm1 },
534 { 10, "lodb.i", sIN_CSEG, parm1 },
535 { 6, "lref.alt", sIN_CSEG, parm1 },
536 { 5, "lref.pri", sIN_CSEG, parm1 },
537 { 8, "lref.s.alt", sIN_CSEG, parm1 },
538 { 7, "lref.s.pri", sIN_CSEG, parm1 },
539 { 34, "move.alt", sIN_CSEG, parm0 },
540 { 33, "move.pri", sIN_CSEG, parm0 },
541 {117, "movs", sIN_CSEG, parm1 },
542 { 85, "neg", sIN_CSEG, parm0 },
543 { 96, "neq", sIN_CSEG, parm0 },
544 {134, "nop", sIN_CSEG, parm0 }, /* version 6 */
545 { 84, "not", sIN_CSEG, parm0 },
546 { 82, "or", sIN_CSEG, parm0 },
547 { 43, "pop.alt", sIN_CSEG, parm0 },
548 { 42, "pop.pri", sIN_CSEG, parm0 },
549 { 46, "proc", sIN_CSEG, parm0 },
550 { 40, "push", sIN_CSEG, parm1 },
551 {133, "push.adr", sIN_CSEG, parm1 }, /* version 4 */
552 { 37, "push.alt", sIN_CSEG, parm0 },
553 { 39, "push.c", sIN_CSEG, parm1 },
554 { 36, "push.pri", sIN_CSEG, parm0 },
555 { 38, "push.r", sIN_CSEG, parm1 }, /* obsolete (never generated) */
556 { 41, "push.s", sIN_CSEG, parm1 },
557 {139, "push2", sIN_CSEG, parm2 }, /* version 9 */
558 {141, "push2.adr", sIN_CSEG, parm2 }, /* version 9 */
559 {138, "push2.c", sIN_CSEG, parm2 }, /* version 9 */
560 {140, "push2.s", sIN_CSEG, parm2 }, /* version 9 */
561 {143, "push3", sIN_CSEG, parm3 }, /* version 9 */
562 {145, "push3.adr", sIN_CSEG, parm3 }, /* version 9 */
563 {142, "push3.c", sIN_CSEG, parm3 }, /* version 9 */
564 {144, "push3.s", sIN_CSEG, parm3 }, /* version 9 */
565 {147, "push4", sIN_CSEG, parm4 }, /* version 9 */
566 {149, "push4.adr", sIN_CSEG, parm4 }, /* version 9 */
567 {146, "push4.c", sIN_CSEG, parm4 }, /* version 9 */
568 {148, "push4.s", sIN_CSEG, parm4 }, /* version 9 */
569 {151, "push5", sIN_CSEG, parm5 }, /* version 9 */
570 {153, "push5.adr", sIN_CSEG, parm5 }, /* version 9 */
571 {150, "push5.c", sIN_CSEG, parm5 }, /* version 9 */
572 {152, "push5.s", sIN_CSEG, parm5 }, /* version 9 */
573 { 47, "ret", sIN_CSEG, parm0 },
574 { 48, "retn", sIN_CSEG, parm0 },
575 { 32, "sctrl", sIN_CSEG, parm1 },
576 { 73, "sdiv", sIN_CSEG, parm0 },
577 { 74, "sdiv.alt", sIN_CSEG, parm0 },
578 {104, "sgeq", sIN_CSEG, parm0 },
579 {103, "sgrtr", sIN_CSEG, parm0 },
580 { 65, "shl", sIN_CSEG, parm0 },
581 { 69, "shl.c.alt", sIN_CSEG, parm1 },
582 { 68, "shl.c.pri", sIN_CSEG, parm1 },
583 { 66, "shr", sIN_CSEG, parm0 },
584 { 71, "shr.c.alt", sIN_CSEG, parm1 },
585 { 70, "shr.c.pri", sIN_CSEG, parm1 },
586 { 94, "sign.alt", sIN_CSEG, parm0 },
587 { 93, "sign.pri", sIN_CSEG, parm0 },
588 {102, "sleq", sIN_CSEG, parm0 },
589 {101, "sless", sIN_CSEG, parm0 },
590 { 72, "smul", sIN_CSEG, parm0 },
591 { 88, "smul.c", sIN_CSEG, parm1 },
592 /*{127, "srange", sIN_CSEG, parm2 }, -- version 1 */
593 { 20, "sref.alt", sIN_CSEG, parm1 },
594 { 19, "sref.pri", sIN_CSEG, parm1 },
595 { 22, "sref.s.alt", sIN_CSEG, parm1 },
596 { 21, "sref.s.pri", sIN_CSEG, parm1 },
597 { 67, "sshr", sIN_CSEG, parm0 },
598 { 44, "stack", sIN_CSEG, parm1 },
599 { 0, "stksize", 0, noop },
600 { 16, "stor.alt", sIN_CSEG, parm1 },
601 { 23, "stor.i", sIN_CSEG, parm0 },
602 { 15, "stor.pri", sIN_CSEG, parm1 },
603 { 18, "stor.s.alt", sIN_CSEG, parm1 },
604 { 17, "stor.s.pri", sIN_CSEG, parm1 },
605 {164, "stradjust.pri", sIN_CSEG, parm0 },
606 { 24, "strb.i", sIN_CSEG, parm1 },
607 { 79, "sub", sIN_CSEG, parm0 },
608 { 80, "sub.alt", sIN_CSEG, parm0 },
609 {132, "swap.alt", sIN_CSEG, parm0 }, /* version 4 */
610 {131, "swap.pri", sIN_CSEG, parm0 }, /* version 4 */
611 {129, "switch", sIN_CSEG, do_switch }, /* version 1 */
612 /*{126, "symbol", sIN_CSEG, do_symbol }, */
613 /*{136, "symtag", sIN_CSEG, parm1 }, -- version 7 */
614 {123, "sysreq.c", sIN_CSEG, parm1 },
615 {135, "sysreq.n", sIN_CSEG, parm2 }, /* version 9 (replaces SYSREQ.d from earlier version) */
616 {122, "sysreq.pri", sIN_CSEG, parm0 },
617 {161, "tracker.pop.setheap", sIN_CSEG, parm0 },
618 {160, "tracker.push.c", sIN_CSEG, parm1 },
619 { 76, "udiv", sIN_CSEG, parm0 },
620 { 77, "udiv.alt", sIN_CSEG, parm0 },
621 { 75, "umul", sIN_CSEG, parm0 },
622 { 35, "xchg", sIN_CSEG, parm0 },
623 { 83, "xor", sIN_CSEG, parm0 },
624 { 91, "zero", sIN_CSEG, parm1 },
625 { 90, "zero.alt", sIN_CSEG, parm0 },
626 { 89, "zero.pri", sIN_CSEG, parm0 },
627 { 92, "zero.s", sIN_CSEG, parm1 },
630 #define MAX_INSTR_LEN 30
631 static int findopcode(char *instr,int maxlen)
633 int low,high,mid,cmp;
634 char str[MAX_INSTR_LEN];
636 if (maxlen>=MAX_INSTR_LEN)
638 strlcpy(str,instr,maxlen+1);
639 /* look up the instruction with a binary search
640 * the assembler is case insensitive to instructions (but case sensitive
643 low=1; /* entry 0 is reserved (for "not found") */
644 high=(sizeof opcodelist / sizeof opcodelist[0])-1;
647 assert(opcodelist[mid].name!=NULL);
648 cmp=stricmp(str,opcodelist[mid].name);
656 if (stricmp(str,opcodelist[low].name)==0)
657 return low; /* found */
658 return 0; /* not found, return special index */
661 SC_FUNC int assemble(FILE *fout,FILE *fin)
665 int numpublics,numnatives,numlibraries,numpubvars,numtags,padding;
666 long nametablesize,nameofs;
667 #if PAWN_CELL_SIZE > 32
675 symbol *sym, **nativelist;
676 constvalue *constptr;
680 /* if compression failed, restart the assembly with compaction switched off */
681 if (setjmp(compact_err)!=0) {
682 assert(sc_compress); /* cannot arrive here if compact encoding was disabled */
685 error(232); /* disabled compact encoding */
689 /* verify that the opcode list is sorted (skip entry 1; it is reserved
690 * for a non-existant opcode)
692 assert(opcodelist[1].name!=NULL);
693 for (i=2; i<(sizeof opcodelist / sizeof opcodelist[0]); i++) {
694 assert(opcodelist[i].name!=NULL);
695 assert(stricmp(opcodelist[i].name,opcodelist[i-1].name)>0);
700 nametablesize=sizeof(int16_t);
705 /* count number of public and native functions and public variables */
706 for (sym=glbtab.next; sym!=NULL; sym=sym->next) {
708 if (sym->ident==iFUNCTN) {
709 if ((sym->usage & uNATIVE)!=0 && (sym->usage & uREAD)!=0 && sym->addr>=0)
711 if ((sym->usage & uPUBLIC)!=0 && (sym->usage & uDEFINE)!=0)
713 if (strcmp(sym->name,uMAINFUNC)==0) {
714 assert(sym->vclass==sGLOBAL);
717 } else if (sym->ident==iVARIABLE || sym->ident == iARRAY || sym->ident == iREFARRAY) {
718 if ((sym->usage & uPUBLIC)!=0 && (sym->usage & (uREAD | uWRITTEN))!=0)
722 char alias[sNAMEMAX+1];
724 if ((sym->usage & uNATIVE)==0 || !lookup_alias(alias,sym->name)) {
725 assert(strlen(sym->name)<=sNAMEMAX);
726 strcpy(alias,sym->name);
728 nametablesize+=strlen(alias)+1;
731 assert(numnatives==ntv_funcid);
733 /* count number of libraries */
735 if (pc_addlibtable) {
736 for (constptr=libname_tab.next; constptr!=NULL; constptr=constptr->next) {
737 if (constptr->value>0) {
738 assert(strlen(constptr->name)>0);
740 nametablesize+=strlen(constptr->name)+1;
745 /* count number of public tags */
747 for (constptr=tagname_tab.next; constptr!=NULL; constptr=constptr->next) {
748 if ((constptr->value & PUBLICTAG)!=0) {
749 assert(strlen(constptr->name)>0);
751 nametablesize+=strlen(constptr->name)+1;
755 /* pad the header to sc_dataalign
756 * => thereby the code segment is aligned
757 * => since the code segment is padded to a sc_dataalign boundary, the data segment is aligned
758 * => and thereby the stack top is aligned too
760 assert(sc_dataalign!=0);
761 padding= (int)(sc_dataalign - (sizeof hdr + nametablesize) % sc_dataalign);
762 if (padding==sc_dataalign)
765 /* write the abstract machine header */
766 memset(&hdr, 0, sizeof hdr);
767 hdr.magic=(unsigned short)AMX_MAGIC;
768 hdr.file_version=(char)((pc_optimize<=sOPTIMIZE_NOMACRO) ? MAX_FILE_VER_JIT : CUR_FILE_VERSION);
769 hdr.amx_version=(char)((pc_optimize<=sOPTIMIZE_NOMACRO) ? MIN_AMX_VER_JIT : MIN_AMX_VERSION);
770 hdr.flags=(short)(sc_debug & sSYMBOLIC);
772 hdr.flags|=AMX_FLAG_COMPACT;
774 hdr.flags|=AMX_FLAG_NOCHECKS;
775 if (pc_memflags & suSLEEP_INSTR)
776 hdr.flags|=AMX_FLAG_SLEEP;
777 hdr.defsize=sizeof(AMX_FUNCSTUBNT);
778 hdr.publics=sizeof hdr; /* public table starts right after the header */
779 hdr.natives=hdr.publics + numpublics*sizeof(AMX_FUNCSTUBNT);
780 hdr.libraries=hdr.natives + numnatives*sizeof(AMX_FUNCSTUBNT);
781 hdr.pubvars=hdr.libraries + numlibraries*sizeof(AMX_FUNCSTUBNT);
782 hdr.tags=hdr.pubvars + numpubvars*sizeof(AMX_FUNCSTUBNT);
783 hdr.nametable=hdr.tags + numtags*sizeof(AMX_FUNCSTUBNT);
784 hdr.cod=hdr.nametable + nametablesize + padding;
785 hdr.dat=hdr.cod + code_idx;
786 hdr.hea=hdr.dat + glb_declared*sizeof(cell);
787 hdr.stp=hdr.hea + pc_stksize*sizeof(cell);
789 hdr.size=hdr.hea; /* preset, this is incorrect in case of compressed output */
790 pc_writebin(fout,&hdr,sizeof hdr);
792 /* dump zeros up to the rest of the header, so that we can easily "seek" */
794 for (nameofs=sizeof hdr; nameofs<hdr.cod; nameofs++)
795 pc_writebin(fout,&nullchar,1);
796 nameofs=hdr.nametable+sizeof(int16_t);
798 /* write the public functions table */
800 for (sym=glbtab.next; sym!=NULL; sym=sym->next) {
801 if (sym->ident==iFUNCTN
802 && (sym->usage & uPUBLIC)!=0 && (sym->usage & uDEFINE)!=0)
804 assert(sym->vclass==sGLOBAL);
805 func.address=sym->addr;
806 func.nameofs=nameofs;
807 #if BYTE_ORDER==BIG_ENDIAN
808 align32(&func.address);
809 align32(&func.nameofs);
811 pc_resetbin(fout,hdr.publics+count*sizeof(AMX_FUNCSTUBNT));
812 pc_writebin(fout,&func,sizeof func);
813 pc_resetbin(fout,nameofs);
814 pc_writebin(fout,sym->name,strlen(sym->name)+1);
815 nameofs+=strlen(sym->name)+1;
820 /* write the natives table */
821 /* The native functions must be written in sorted order. (They are
822 * sorted on their "id", not on their name). A nested loop to find
823 * each successive function would be an O(n^2) operation. But we
824 * do not really need to sort, because the native function id's
825 * are sequential and there are no duplicates. So we first walk
826 * through the complete symbol list and store a pointer to every
827 * native function of interest in a temporary table, where its id
828 * serves as the index in the table. Now we can walk the table and
829 * have all native functions in sorted order.
832 nativelist=(symbol **)malloc(numnatives*sizeof(symbol *));
833 if (nativelist==NULL)
834 error(103); /* insufficient memory */
836 memset(nativelist,0,numnatives*sizeof(symbol *)); /* for NULL checking */
838 for (sym=glbtab.next; sym!=NULL; sym=sym->next) {
839 if (sym->ident==iFUNCTN && (sym->usage & uNATIVE)!=0 && (sym->usage & uREAD)!=0 && sym->addr>=0) {
840 assert(sym->addr < numnatives);
841 nativelist[(int)sym->addr]=sym;
845 for (i=0; i<numnatives; i++) {
846 char alias[sNAMEMAX+1];
849 if (!lookup_alias(alias,sym->name)) {
850 assert(strlen(sym->name)<=sNAMEMAX);
851 strcpy(alias,sym->name);
853 assert(sym->vclass==sGLOBAL);
855 func.nameofs=nameofs;
856 #if BYTE_ORDER==BIG_ENDIAN
857 align32(&func.address);
858 align32(&func.nameofs);
860 pc_resetbin(fout,hdr.natives+count*sizeof(AMX_FUNCSTUBNT));
861 pc_writebin(fout,&func,sizeof func);
862 pc_resetbin(fout,nameofs);
863 pc_writebin(fout,alias,strlen(alias)+1);
864 nameofs+=strlen(alias)+1;
870 /* write the libraries table */
871 if (pc_addlibtable) {
873 for (constptr=libname_tab.next; constptr!=NULL; constptr=constptr->next) {
874 if (constptr->value>0) {
875 assert(strlen(constptr->name)>0);
877 func.nameofs=nameofs;
878 #if BYTE_ORDER==BIG_ENDIAN
879 align32(&func.address);
880 align32(&func.nameofs);
882 pc_resetbin(fout,hdr.libraries+count*sizeof(AMX_FUNCSTUBNT));
883 pc_writebin(fout,&func,sizeof func);
884 pc_resetbin(fout,nameofs);
885 pc_writebin(fout,constptr->name,strlen(constptr->name)+1);
886 nameofs+=strlen(constptr->name)+1;
892 /* write the public variables table */
894 for (sym=glbtab.next; sym!=NULL; sym=sym->next) {
895 if ((sym->ident==iVARIABLE || sym->ident==iARRAY || sym->ident==iREFARRAY)
896 && (sym->usage & uPUBLIC)!=0 && (sym->usage & (uREAD | uWRITTEN))!=0) {
897 //removed until structs don't seem to mess this up
898 //assert((sym->usage & uDEFINE)!=0);
899 assert(sym->vclass==sGLOBAL);
900 func.address=sym->addr;
901 func.nameofs=nameofs;
902 #if BYTE_ORDER==BIG_ENDIAN
903 align32(&func.address);
904 align32(&func.nameofs);
906 pc_resetbin(fout,hdr.pubvars+count*sizeof(AMX_FUNCSTUBNT));
907 pc_writebin(fout,&func,sizeof func);
908 pc_resetbin(fout,nameofs);
909 pc_writebin(fout,sym->name,strlen(sym->name)+1);
910 nameofs+=strlen(sym->name)+1;
915 /* write the public tagnames table */
917 for (constptr=tagname_tab.next; constptr!=NULL; constptr=constptr->next) {
918 if ((constptr->value & PUBLICTAG)!=0) {
919 assert(strlen(constptr->name)>0);
920 func.address=constptr->value & TAGMASK;
921 func.nameofs=nameofs;
922 #if BYTE_ORDER==BIG_ENDIAN
923 align32(&func.address);
924 align32(&func.nameofs);
926 pc_resetbin(fout,hdr.tags+count*sizeof(AMX_FUNCSTUBNT));
927 pc_writebin(fout,&func,sizeof func);
928 pc_resetbin(fout,nameofs);
929 pc_writebin(fout,constptr->name,strlen(constptr->name)+1);
930 nameofs+=strlen(constptr->name)+1;
935 /* write the "maximum name length" field in the name table */
936 assert(nameofs==hdr.nametable+nametablesize);
937 pc_resetbin(fout,hdr.nametable);
939 #if BYTE_ORDER==BIG_ENDIAN
942 pc_writebin(fout,&count,sizeof count);
943 pc_resetbin(fout,hdr.cod);
945 /* First pass: relocate all labels */
946 /* This pass is necessary because the code addresses of labels is only known
947 * after the peephole optimization flag. Labels can occur inside expressions
948 * (e.g. the conditional operator), which are optimized.
952 /* only very short programs have zero labels; no first pass is needed
953 * if there are no labels */
954 lbltab=(cell *)malloc(sc_labnum*sizeof(cell));
956 error(103); /* insufficient memory */
959 while (pc_readasm(fin,line,sizeof line)!=NULL) {
961 instr=skipwhitespace(line);
962 /* ignore empty lines */
965 if (tolower(*instr)=='l' && *(instr+1)=='.') {
966 int lindex=(int)hex2long(instr+2,NULL);
967 assert(lindex>=0 && lindex<sc_labnum);
968 lbltab[lindex]=codeindex;
970 /* get to the end of the instruction (make use of the '\n' that fgets()
971 * added at the end of the line; this way we will *always* drop on a
972 * whitespace character) */
973 for (params=instr; *params!='\0' && !isspace(*params); params++)
975 assert(params>instr);
976 i=findopcode(instr,(int)(params-instr));
977 if (opcodelist[i].name==NULL) {
979 error(104,instr); /* invalid assembler instruction */
981 if (opcodelist[i].segment==sIN_CSEG)
982 codeindex+=opcodelist[i].func(NULL,skipwhitespace(params),opcodelist[i].opcode);
987 /* Second pass (actually 2 more passes, one for all code and one for all data) */
990 for (pass=sIN_CSEG; pass<=sIN_DSEG; pass++) {
992 while (pc_readasm(fin,line,sizeof line)!=NULL) {
994 instr=skipwhitespace(line);
995 /* ignore empty lines and labels (labels have a special syntax, so these
996 * must be parsed separately) */
997 if (*instr=='\0' || tolower(*instr)=='l' && *(instr+1)=='.')
999 /* get to the end of the instruction (make use of the '\n' that fgets()
1000 * added at the end of the line; this way we will *always* drop on a
1001 * whitespace character) */
1002 for (params=instr; *params!='\0' && !isspace(*params); params++)
1004 assert(params>instr);
1005 i=findopcode(instr,(int)(params-instr));
1006 assert(opcodelist[i].name!=NULL);
1007 if (opcodelist[i].segment==pass)
1008 opcodelist[i].func(fout,skipwhitespace(params),opcodelist[i].opcode);
1011 if (bytes_out-bytes_in>0)
1012 error(106); /* compression buffer overflow */
1022 hdr.size=pc_lengthbin(fout);/* get this value before appending debug info */
1023 if (!writeerror && (sc_debug & sSYMBOLIC)!=0)
1024 append_dbginfo(fout); /* optionally append debug file */
1027 error(101,"disk full");
1029 /* adjust the header */
1030 size=(int)hdr.cod; /* save, the value in the header may be swapped */
1031 #if BYTE_ORDER==BIG_ENDIAN
1033 align16(&hdr.magic);
1034 align16(&hdr.flags);
1035 align16(&hdr.defsize);
1036 align32(&hdr.publics);
1037 align32(&hdr.natives);
1038 align32(&hdr.libraries);
1039 align32(&hdr.pubvars);
1041 align32(&hdr.nametable);
1048 pc_resetbin(fout,0);
1049 pc_writebin(fout,&hdr,sizeof hdr);
1051 /* return the size of the header (including name tables, but excluding code
1057 static void append_dbginfo(FILE *fout)
1060 AMX_DBG_LINE dbgline;
1061 AMX_DBG_SYMBOL dbgsym;
1062 AMX_DBG_SYMDIM dbgidxtag[sDIMEN_MAX];
1063 int index,dim,dbgsymdim;
1064 char *str,*prevstr,*name,*prevname;
1065 ucell codeidx,previdx;
1066 constvalue *constptr;
1067 char symname[2*sNAMEMAX+16];
1071 /* header with general information */
1072 memset(&dbghdr, 0, sizeof dbghdr);
1073 dbghdr.size=sizeof dbghdr;
1074 dbghdr.magic=AMX_DBG_MAGIC;
1075 dbghdr.file_version=CUR_FILE_VERSION;
1076 dbghdr.amx_version=MIN_AMX_VERSION;
1078 /* first pass: collect the number of items in various tables */
1084 for (index=0; (str=get_dbgstring(index))!=NULL; index++) {
1086 assert(str[0]!='\0' && str[1]==':');
1088 codeidx=hex2long(str+2,&name);
1089 if (codeidx!=previdx) {
1090 if (prevstr!=NULL) {
1091 assert(prevname!=NULL);
1093 dbghdr.size+=sizeof(cell)+strlen(prevname)+1;
1098 prevname=skipwhitespace(name);
1101 if (prevstr!=NULL) {
1102 assert(prevname!=NULL);
1104 dbghdr.size+=sizeof(cell)+strlen(prevname)+1;
1107 /* line number table */
1108 for (index=0; (str=get_dbgstring(index))!=NULL; index++) {
1110 assert(str[0]!='\0' && str[1]==':');
1113 dbghdr.size+=sizeof(AMX_DBG_LINE);
1118 for (index=0; (str=get_dbgstring(index))!=NULL; index++) {
1120 assert(str[0]!='\0' && str[1]==':');
1123 name=strchr(str+2,':');
1125 dbghdr.size+=sizeof(AMX_DBG_SYMBOL)+strlen(skipwhitespace(name+1));
1126 if ((prevstr=strchr(name,'['))!=NULL)
1127 while ((prevstr=strchr(prevstr+1,':'))!=NULL)
1128 dbghdr.size+=sizeof(AMX_DBG_SYMDIM);
1133 for (constptr=tagname_tab.next; constptr!=NULL; constptr=constptr->next) {
1134 assert(strlen(constptr->name)>0);
1136 dbghdr.size+=sizeof(AMX_DBG_TAG)+strlen(constptr->name);
1139 /* automaton table */
1140 for (constptr=sc_automaton_tab.next; constptr!=NULL; constptr=constptr->next) {
1141 assert(constptr->index==0 && strlen(constptr->name)==0 || strlen(constptr->name)>0);
1142 dbghdr.automatons++;
1143 dbghdr.size+=sizeof(AMX_DBG_MACHINE)+strlen(constptr->name);
1147 for (constptr=sc_state_tab.next; constptr!=NULL; constptr=constptr->next) {
1148 assert(strlen(constptr->name)>0);
1150 dbghdr.size+=sizeof(AMX_DBG_STATE)+strlen(constptr->name);
1154 /* pass 2: generate the tables */
1155 #if BYTE_ORDER==BIG_ENDIAN
1156 align32((uint32_t*)&dbghdr.size);
1157 align16(&dbghdr.magic);
1158 align16(&dbghdr.flags);
1159 align16(&dbghdr.files);
1160 align16(&dbghdr.lines);
1161 align16(&dbghdr.symbols);
1162 align16(&dbghdr.tags);
1163 align16(&dbghdr.automatons);
1164 align16(&dbghdr.states);
1166 writeerror |= !pc_writebin(fout,&dbghdr,sizeof dbghdr);
1172 for (index=0; (str=get_dbgstring(index))!=NULL; index++) {
1174 assert(str[0]!='\0' && str[1]==':');
1176 codeidx=hex2long(str+2,&name);
1177 if (codeidx!=previdx) {
1178 if (prevstr!=NULL) {
1179 assert(prevname!=NULL);
1180 #if BYTE_ORDER==BIG_ENDIAN
1181 aligncell(&previdx);
1183 writeerror |= !pc_writebin(fout,&previdx,sizeof previdx);
1184 writeerror |= !pc_writebin(fout,prevname,strlen(prevname)+1);
1189 prevname=skipwhitespace(name);
1192 if (prevstr!=NULL) {
1193 assert(prevname!=NULL);
1194 #if BYTE_ORDER==BIG_ENDIAN
1195 aligncell(&previdx);
1197 writeerror |= !pc_writebin(fout,&previdx,sizeof previdx);
1198 writeerror |= !pc_writebin(fout,prevname,strlen(prevname)+1);
1201 /* line number table */
1202 for (index=0; (str=get_dbgstring(index))!=NULL; index++) {
1204 assert(str[0]!='\0' && str[1]==':');
1206 dbgline.address=hex2long(str+2,&str);
1207 dbgline.line=(int32_t)hex2long(str,NULL);
1208 #if BYTE_ORDER==BIG_ENDIAN
1209 aligncell(&dbgline.address);
1210 align32(&dbgline.line);
1212 writeerror |= !pc_writebin(fout,&dbgline,sizeof dbgline);
1217 for (index=0; (str=get_dbgstring(index))!=NULL; index++) {
1219 assert(str[0]!='\0' && str[1]==':');
1221 dbgsym.address=hex2long(str+2,&str);
1222 dbgsym.tag=(int16_t)hex2long(str,&str);
1223 str=skipwhitespace(str);
1225 name=skipwhitespace(str+1);
1226 str=strchr(name,' ');
1228 assert((int)(str-name)<sizeof symname);
1229 strlcpy(symname,name,(int)(str-name)+1);
1230 dbgsym.codestart=hex2long(str,&str);
1231 dbgsym.codeend=hex2long(str,&str);
1232 dbgsym.ident=(char)hex2long(str,&str);
1233 dbgsym.vclass=(char)hex2long(str,&str);
1235 str=skipwhitespace(str);
1237 while (*(str=skipwhitespace(str+1))!=']') {
1238 dbgidxtag[dbgsym.dim].tag=(int16_t)hex2long(str,&str);
1239 str=skipwhitespace(str);
1241 dbgidxtag[dbgsym.dim].size=hex2long(str+1,&str);
1245 dbgsymdim = dbgsym.dim;
1246 #if BYTE_ORDER==BIG_ENDIAN
1247 aligncell(&dbgsym.address);
1248 align16(&dbgsym.tag);
1249 aligncell(&dbgsym.codestart);
1250 aligncell(&dbgsym.codeend);
1251 align16(&dbgsym.dim);
1253 writeerror |= !pc_writebin(fout,&dbgsym,offsetof(AMX_DBG_SYMBOL, name));
1254 writeerror |= !pc_writebin(fout,symname,strlen(symname)+1);
1255 for (dim=0; dim<dbgsymdim; dim++) {
1256 #if BYTE_ORDER==BIG_ENDIAN
1257 align16(&dbgidxtag[dim].tag);
1258 aligncell(&dbgidxtag[dim].size);
1260 writeerror |= !pc_writebin(fout,&dbgidxtag[dim],sizeof dbgidxtag[dim]);
1266 for (constptr=tagname_tab.next; constptr!=NULL; constptr=constptr->next) {
1267 assert(strlen(constptr->name)>0);
1268 id1=(int16_t)(constptr->value & TAGMASK);
1269 #if BYTE_ORDER==BIG_ENDIAN
1272 writeerror |= !pc_writebin(fout,&id1,sizeof id1);
1273 writeerror |= !pc_writebin(fout,constptr->name,strlen(constptr->name)+1);
1276 /* automaton table */
1277 for (constptr=sc_automaton_tab.next; constptr!=NULL; constptr=constptr->next) {
1278 assert(constptr->index==0 && strlen(constptr->name)==0 || strlen(constptr->name)>0);
1279 id1=(int16_t)constptr->index;
1280 address=(ucell)constptr->value;
1281 #if BYTE_ORDER==BIG_ENDIAN
1283 aligncell(&address);
1285 writeerror |= !pc_writebin(fout,&id1,sizeof id1);
1286 writeerror |= !pc_writebin(fout,&address,sizeof address);
1287 writeerror |= !pc_writebin(fout,constptr->name,strlen(constptr->name)+1);
1291 for (constptr=sc_state_tab.next; constptr!=NULL; constptr=constptr->next) {
1292 assert(strlen(constptr->name)>0);
1293 id1=(int16_t)constptr->value;
1294 id2=(int16_t)constptr->index;
1295 address=(ucell)constptr->value;
1296 #if BYTE_ORDER==BIG_ENDIAN
1300 writeerror |= !pc_writebin(fout,&id1,sizeof id1);
1301 writeerror |= !pc_writebin(fout,&id2,sizeof id2);
1302 writeerror |= !pc_writebin(fout,constptr->name,strlen(constptr->name)+1);
1305 delete_dbgstringtable();