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;
679 char testalias[sNAMEMAX+1];
681 /* if compression failed, restart the assembly with compaction switched off */
682 if (setjmp(compact_err)!=0) {
683 assert(sc_compress); /* cannot arrive here if compact encoding was disabled */
686 error(232); /* disabled compact encoding */
690 /* verify that the opcode list is sorted (skip entry 1; it is reserved
691 * for a non-existant opcode)
693 assert(opcodelist[1].name!=NULL);
694 for (i=2; i<(sizeof opcodelist / sizeof opcodelist[0]); i++) {
695 assert(opcodelist[i].name!=NULL);
696 assert(stricmp(opcodelist[i].name,opcodelist[i-1].name)>0);
701 nametablesize=sizeof(int16_t);
706 /* count number of public and native functions and public variables */
707 for (sym=glbtab.next; sym!=NULL; sym=sym->next) {
709 if (sym->ident==iFUNCTN) {
710 if ((sym->usage & uNATIVE)!=0 && (sym->usage & uREAD)!=0 && sym->addr>=0) {
713 if ((sym->usage & uPUBLIC)!=0 && (sym->usage & uDEFINE)!=0)
715 if (strcmp(sym->name,uMAINFUNC)==0) {
716 assert(sym->vclass==sGLOBAL);
719 } else if (sym->ident==iVARIABLE || sym->ident == iARRAY || sym->ident == iREFARRAY) {
720 if ((sym->usage & uPUBLIC)!=0 && (sym->usage & (uREAD | uWRITTEN))!=0)
724 const char *aliasptr = sym->name;
726 if (((sym->usage & uNATIVE)!=0) && lookup_alias(testalias,sym->name)) {
729 nametablesize+=strlen(aliasptr)+1;
732 assert(numnatives==ntv_funcid);
734 /* count number of libraries */
736 if (pc_addlibtable) {
737 for (constptr=libname_tab.next; constptr!=NULL; constptr=constptr->next) {
738 if (constptr->value>0) {
739 assert(strlen(constptr->name)>0);
741 nametablesize+=strlen(constptr->name)+1;
746 /* count number of public tags */
748 for (constptr=tagname_tab.next; constptr!=NULL; constptr=constptr->next) {
749 /*if ((constptr->value & PUBLICTAG)!=0) {*/
750 assert(strlen(constptr->name)>0);
752 nametablesize+=strlen(constptr->name)+1;
756 /* pad the header to sc_dataalign
757 * => thereby the code segment is aligned
758 * => since the code segment is padded to a sc_dataalign boundary, the data segment is aligned
759 * => and thereby the stack top is aligned too
761 assert(sc_dataalign!=0);
762 padding= (int)(sc_dataalign - (sizeof hdr + nametablesize) % sc_dataalign);
763 if (padding==sc_dataalign)
766 /* write the abstract machine header */
767 memset(&hdr, 0, sizeof hdr);
768 hdr.magic=(unsigned short)AMX_MAGIC;
769 hdr.file_version=(char)((pc_optimize<=sOPTIMIZE_NOMACRO) ? MAX_FILE_VER_JIT : CUR_FILE_VERSION);
770 hdr.amx_version=(char)((pc_optimize<=sOPTIMIZE_NOMACRO) ? MIN_AMX_VER_JIT : MIN_AMX_VERSION);
771 hdr.flags=(short)(sc_debug & sSYMBOLIC);
773 hdr.flags|=AMX_FLAG_COMPACT;
775 hdr.flags|=AMX_FLAG_NOCHECKS;
776 if (pc_memflags & suSLEEP_INSTR)
777 hdr.flags|=AMX_FLAG_SLEEP;
778 hdr.defsize=sizeof(AMX_FUNCSTUBNT);
779 hdr.publics=sizeof hdr; /* public table starts right after the header */
780 hdr.natives=hdr.publics + numpublics*sizeof(AMX_FUNCSTUBNT);
781 hdr.libraries=hdr.natives + numnatives*sizeof(AMX_FUNCSTUBNT);
782 hdr.pubvars=hdr.libraries + numlibraries*sizeof(AMX_FUNCSTUBNT);
783 hdr.tags=hdr.pubvars + numpubvars*sizeof(AMX_FUNCSTUBNT);
784 hdr.nametable=hdr.tags + numtags*sizeof(AMX_FUNCSTUBNT);
785 hdr.cod=hdr.nametable + nametablesize + padding;
786 hdr.dat=hdr.cod + code_idx;
787 hdr.hea=hdr.dat + glb_declared*sizeof(cell);
788 hdr.stp=hdr.hea + pc_stksize*sizeof(cell);
790 hdr.size=hdr.hea; /* preset, this is incorrect in case of compressed output */
791 pc_writebin(fout,&hdr,sizeof hdr);
793 /* dump zeros up to the rest of the header, so that we can easily "seek" */
795 for (nameofs=sizeof hdr; nameofs<hdr.cod; nameofs++)
796 pc_writebin(fout,&nullchar,1);
797 nameofs=hdr.nametable+sizeof(int16_t);
799 /* write the public functions table */
801 for (sym=glbtab.next; sym!=NULL; sym=sym->next) {
802 if (sym->ident==iFUNCTN
803 && (sym->usage & uPUBLIC)!=0 && (sym->usage & uDEFINE)!=0)
805 assert(sym->vclass==sGLOBAL);
806 func.address=sym->addr;
807 func.nameofs=nameofs;
808 #if BYTE_ORDER==BIG_ENDIAN
809 align32(&func.address);
810 align32(&func.nameofs);
812 pc_resetbin(fout,hdr.publics+count*sizeof(AMX_FUNCSTUBNT));
813 pc_writebin(fout,&func,sizeof func);
814 pc_resetbin(fout,nameofs);
815 pc_writebin(fout,sym->name,strlen(sym->name)+1);
816 nameofs+=strlen(sym->name)+1;
821 /* write the natives table */
822 /* The native functions must be written in sorted order. (They are
823 * sorted on their "id", not on their name). A nested loop to find
824 * each successive function would be an O(n^2) operation. But we
825 * do not really need to sort, because the native function id's
826 * are sequential and there are no duplicates. So we first walk
827 * through the complete symbol list and store a pointer to every
828 * native function of interest in a temporary table, where its id
829 * serves as the index in the table. Now we can walk the table and
830 * have all native functions in sorted order.
833 nativelist=(symbol **)malloc(numnatives*sizeof(symbol *));
834 if (nativelist==NULL)
835 error(103); /* insufficient memory */
837 memset(nativelist,0,numnatives*sizeof(symbol *)); /* for NULL checking */
839 for (sym=glbtab.next; sym!=NULL; sym=sym->next) {
840 if (sym->ident==iFUNCTN && (sym->usage & uNATIVE)!=0 && (sym->usage & uREAD)!=0 && sym->addr>=0) {
841 assert(sym->addr < numnatives);
842 nativelist[(int)sym->addr]=sym;
846 for (i=0; i<numnatives; i++) {
847 const char *aliasptr;
850 aliasptr = sym->name;
851 if (lookup_alias(testalias,sym->name)) {
854 assert(sym->vclass==sGLOBAL);
856 func.nameofs=nameofs;
857 #if BYTE_ORDER==BIG_ENDIAN
858 align32(&func.address);
859 align32(&func.nameofs);
861 pc_resetbin(fout,hdr.natives+count*sizeof(AMX_FUNCSTUBNT));
862 pc_writebin(fout,&func,sizeof func);
863 pc_resetbin(fout,nameofs);
864 pc_writebin(fout,(void *)aliasptr,strlen(aliasptr)+1);
865 nameofs+=strlen(aliasptr)+1;
871 /* write the libraries table */
872 if (pc_addlibtable) {
874 for (constptr=libname_tab.next; constptr!=NULL; constptr=constptr->next) {
875 if (constptr->value>0) {
876 assert(strlen(constptr->name)>0);
878 func.nameofs=nameofs;
879 #if BYTE_ORDER==BIG_ENDIAN
880 align32(&func.address);
881 align32(&func.nameofs);
883 pc_resetbin(fout,hdr.libraries+count*sizeof(AMX_FUNCSTUBNT));
884 pc_writebin(fout,&func,sizeof func);
885 pc_resetbin(fout,nameofs);
886 pc_writebin(fout,constptr->name,strlen(constptr->name)+1);
887 nameofs+=strlen(constptr->name)+1;
893 /* write the public variables table */
895 for (sym=glbtab.next; sym!=NULL; sym=sym->next) {
896 if ((sym->ident==iVARIABLE || sym->ident==iARRAY || sym->ident==iREFARRAY)
897 && (sym->usage & uPUBLIC)!=0 && (sym->usage & (uREAD | uWRITTEN))!=0) {
898 //removed until structs don't seem to mess this up
899 //assert((sym->usage & uDEFINE)!=0);
900 assert(sym->vclass==sGLOBAL);
901 func.address=sym->addr;
902 func.nameofs=nameofs;
903 #if BYTE_ORDER==BIG_ENDIAN
904 align32(&func.address);
905 align32(&func.nameofs);
907 pc_resetbin(fout,hdr.pubvars+count*sizeof(AMX_FUNCSTUBNT));
908 pc_writebin(fout,&func,sizeof func);
909 pc_resetbin(fout,nameofs);
910 pc_writebin(fout,sym->name,strlen(sym->name)+1);
911 nameofs+=strlen(sym->name)+1;
916 /* write the public tagnames table */
918 for (constptr=tagname_tab.next; constptr!=NULL; constptr=constptr->next) {
919 /*if ((constptr->value & PUBLICTAG)!=0) {*/
920 assert(strlen(constptr->name)>0);
921 func.address=constptr->value & TAGMASK;
922 func.nameofs=nameofs;
923 #if BYTE_ORDER==BIG_ENDIAN
924 align32(&func.address);
925 align32(&func.nameofs);
927 pc_resetbin(fout,hdr.tags+count*sizeof(AMX_FUNCSTUBNT));
928 pc_writebin(fout,&func,sizeof func);
929 pc_resetbin(fout,nameofs);
930 pc_writebin(fout,constptr->name,strlen(constptr->name)+1);
931 nameofs+=strlen(constptr->name)+1;
936 /* write the "maximum name length" field in the name table */
937 assert(nameofs==hdr.nametable+nametablesize);
938 pc_resetbin(fout,hdr.nametable);
940 #if BYTE_ORDER==BIG_ENDIAN
943 pc_writebin(fout,&count,sizeof count);
944 pc_resetbin(fout,hdr.cod);
946 /* First pass: relocate all labels */
947 /* This pass is necessary because the code addresses of labels is only known
948 * after the peephole optimization flag. Labels can occur inside expressions
949 * (e.g. the conditional operator), which are optimized.
953 /* only very short programs have zero labels; no first pass is needed
954 * if there are no labels */
955 lbltab=(cell *)malloc(sc_labnum*sizeof(cell));
957 error(103); /* insufficient memory */
960 while (pc_readasm(fin,line,sizeof line)!=NULL) {
962 instr=skipwhitespace(line);
963 /* ignore empty lines */
966 if (tolower(*instr)=='l' && *(instr+1)=='.') {
967 int lindex=(int)hex2long(instr+2,NULL);
968 assert(lindex>=0 && lindex<sc_labnum);
969 lbltab[lindex]=codeindex;
971 /* get to the end of the instruction (make use of the '\n' that fgets()
972 * added at the end of the line; this way we will *always* drop on a
973 * whitespace character) */
974 for (params=instr; *params!='\0' && !isspace(*params); params++)
976 assert(params>instr);
977 i=findopcode(instr,(int)(params-instr));
978 if (opcodelist[i].name==NULL) {
980 error(104,instr); /* invalid assembler instruction */
982 if (opcodelist[i].segment==sIN_CSEG)
983 codeindex+=opcodelist[i].func(NULL,skipwhitespace(params),opcodelist[i].opcode);
988 /* Second pass (actually 2 more passes, one for all code and one for all data) */
991 for (pass=sIN_CSEG; pass<=sIN_DSEG; pass++) {
993 while (pc_readasm(fin,line,sizeof line)!=NULL) {
995 instr=skipwhitespace(line);
996 /* ignore empty lines and labels (labels have a special syntax, so these
997 * must be parsed separately) */
998 if (*instr=='\0' || tolower(*instr)=='l' && *(instr+1)=='.')
1000 /* get to the end of the instruction (make use of the '\n' that fgets()
1001 * added at the end of the line; this way we will *always* drop on a
1002 * whitespace character) */
1003 for (params=instr; *params!='\0' && !isspace(*params); params++)
1005 assert(params>instr);
1006 i=findopcode(instr,(int)(params-instr));
1007 assert(opcodelist[i].name!=NULL);
1008 if (opcodelist[i].segment==pass)
1009 opcodelist[i].func(fout,skipwhitespace(params),opcodelist[i].opcode);
1012 if (bytes_out-bytes_in>0)
1013 error(106); /* compression buffer overflow */
1023 hdr.size=pc_lengthbin(fout);/* get this value before appending debug info */
1024 if (!writeerror && (sc_debug & sSYMBOLIC)!=0)
1025 append_dbginfo(fout); /* optionally append debug file */
1028 error(101,"disk full");
1030 /* adjust the header */
1031 size=(int)hdr.cod; /* save, the value in the header may be swapped */
1032 #if BYTE_ORDER==BIG_ENDIAN
1034 align16(&hdr.magic);
1035 align16(&hdr.flags);
1036 align16(&hdr.defsize);
1037 align32(&hdr.publics);
1038 align32(&hdr.natives);
1039 align32(&hdr.libraries);
1040 align32(&hdr.pubvars);
1042 align32(&hdr.nametable);
1049 pc_resetbin(fout,0);
1050 pc_writebin(fout,&hdr,sizeof hdr);
1052 /* return the size of the header (including name tables, but excluding code
1058 static void append_dbginfo(FILE *fout)
1061 AMX_DBG_LINE dbgline;
1062 AMX_DBG_SYMBOL dbgsym;
1063 AMX_DBG_SYMDIM dbgidxtag[sDIMEN_MAX];
1064 int index,dim,dbgsymdim;
1065 char *str,*prevstr,*name,*prevname;
1066 ucell codeidx,previdx;
1067 constvalue *constptr;
1068 char symname[2*sNAMEMAX+16];
1072 /* header with general information */
1073 memset(&dbghdr, 0, sizeof dbghdr);
1074 dbghdr.size=sizeof dbghdr;
1075 dbghdr.magic=AMX_DBG_MAGIC;
1076 dbghdr.file_version=CUR_FILE_VERSION;
1077 dbghdr.amx_version=MIN_AMX_VERSION;
1079 /* first pass: collect the number of items in various tables */
1085 for (index=0; (str=get_dbgstring(index))!=NULL; index++) {
1087 assert(str[0]!='\0' && str[1]==':');
1089 codeidx=hex2long(str+2,&name);
1090 if (codeidx!=previdx) {
1091 if (prevstr!=NULL) {
1092 assert(prevname!=NULL);
1094 dbghdr.size+=sizeof(cell)+strlen(prevname)+1;
1099 prevname=skipwhitespace(name);
1102 if (prevstr!=NULL) {
1103 assert(prevname!=NULL);
1105 dbghdr.size+=sizeof(cell)+strlen(prevname)+1;
1108 /* line number table */
1109 for (index=0; (str=get_dbgstring(index))!=NULL; index++) {
1111 assert(str[0]!='\0' && str[1]==':');
1114 dbghdr.size+=sizeof(AMX_DBG_LINE);
1119 for (index=0; (str=get_dbgstring(index))!=NULL; index++) {
1121 assert(str[0]!='\0' && str[1]==':');
1124 name=strchr(str+2,':');
1126 dbghdr.size+=sizeof(AMX_DBG_SYMBOL)+strlen(skipwhitespace(name+1));
1127 if ((prevstr=strchr(name,'['))!=NULL)
1128 while ((prevstr=strchr(prevstr+1,':'))!=NULL)
1129 dbghdr.size+=sizeof(AMX_DBG_SYMDIM);
1134 for (constptr=tagname_tab.next; constptr!=NULL; constptr=constptr->next) {
1135 assert(strlen(constptr->name)>0);
1137 dbghdr.size+=sizeof(AMX_DBG_TAG)+strlen(constptr->name);
1140 /* automaton table */
1141 for (constptr=sc_automaton_tab.next; constptr!=NULL; constptr=constptr->next) {
1142 assert(constptr->index==0 && strlen(constptr->name)==0 || strlen(constptr->name)>0);
1143 dbghdr.automatons++;
1144 dbghdr.size+=sizeof(AMX_DBG_MACHINE)+strlen(constptr->name);
1148 for (constptr=sc_state_tab.next; constptr!=NULL; constptr=constptr->next) {
1149 assert(strlen(constptr->name)>0);
1151 dbghdr.size+=sizeof(AMX_DBG_STATE)+strlen(constptr->name);
1155 /* pass 2: generate the tables */
1156 #if BYTE_ORDER==BIG_ENDIAN
1157 align32((uint32_t*)&dbghdr.size);
1158 align16(&dbghdr.magic);
1159 align16(&dbghdr.flags);
1160 align16(&dbghdr.files);
1161 align16(&dbghdr.lines);
1162 align16(&dbghdr.symbols);
1163 align16(&dbghdr.tags);
1164 align16(&dbghdr.automatons);
1165 align16(&dbghdr.states);
1167 writeerror |= !pc_writebin(fout,&dbghdr,sizeof dbghdr);
1173 for (index=0; (str=get_dbgstring(index))!=NULL; index++) {
1175 assert(str[0]!='\0' && str[1]==':');
1177 codeidx=hex2long(str+2,&name);
1178 if (codeidx!=previdx) {
1179 if (prevstr!=NULL) {
1180 assert(prevname!=NULL);
1181 #if BYTE_ORDER==BIG_ENDIAN
1182 aligncell(&previdx);
1184 writeerror |= !pc_writebin(fout,&previdx,sizeof previdx);
1185 writeerror |= !pc_writebin(fout,prevname,strlen(prevname)+1);
1190 prevname=skipwhitespace(name);
1193 if (prevstr!=NULL) {
1194 assert(prevname!=NULL);
1195 #if BYTE_ORDER==BIG_ENDIAN
1196 aligncell(&previdx);
1198 writeerror |= !pc_writebin(fout,&previdx,sizeof previdx);
1199 writeerror |= !pc_writebin(fout,prevname,strlen(prevname)+1);
1202 /* line number table */
1203 for (index=0; (str=get_dbgstring(index))!=NULL; index++) {
1205 assert(str[0]!='\0' && str[1]==':');
1207 dbgline.address=hex2long(str+2,&str);
1208 dbgline.line=(int32_t)hex2long(str,NULL);
1209 #if BYTE_ORDER==BIG_ENDIAN
1210 aligncell(&dbgline.address);
1211 align32(&dbgline.line);
1213 writeerror |= !pc_writebin(fout,&dbgline,sizeof dbgline);
1218 for (index=0; (str=get_dbgstring(index))!=NULL; index++) {
1220 assert(str[0]!='\0' && str[1]==':');
1222 dbgsym.address=hex2long(str+2,&str);
1223 dbgsym.tag=(int16_t)hex2long(str,&str);
1224 str=skipwhitespace(str);
1226 name=skipwhitespace(str+1);
1227 str=strchr(name,' ');
1229 assert((int)(str-name)<sizeof symname);
1230 strlcpy(symname,name,(int)(str-name)+1);
1231 dbgsym.codestart=hex2long(str,&str);
1232 dbgsym.codeend=hex2long(str,&str);
1233 dbgsym.ident=(char)hex2long(str,&str);
1234 dbgsym.vclass=(char)hex2long(str,&str);
1236 str=skipwhitespace(str);
1238 while (*(str=skipwhitespace(str+1))!=']') {
1239 dbgidxtag[dbgsym.dim].tag=(int16_t)hex2long(str,&str);
1240 str=skipwhitespace(str);
1242 dbgidxtag[dbgsym.dim].size=hex2long(str+1,&str);
1246 dbgsymdim = dbgsym.dim;
1247 #if BYTE_ORDER==BIG_ENDIAN
1248 aligncell(&dbgsym.address);
1249 align16(&dbgsym.tag);
1250 aligncell(&dbgsym.codestart);
1251 aligncell(&dbgsym.codeend);
1252 align16(&dbgsym.dim);
1254 writeerror |= !pc_writebin(fout,&dbgsym,offsetof(AMX_DBG_SYMBOL, name));
1255 writeerror |= !pc_writebin(fout,symname,strlen(symname)+1);
1256 for (dim=0; dim<dbgsymdim; dim++) {
1257 #if BYTE_ORDER==BIG_ENDIAN
1258 align16(&dbgidxtag[dim].tag);
1259 aligncell(&dbgidxtag[dim].size);
1261 writeerror |= !pc_writebin(fout,&dbgidxtag[dim],sizeof dbgidxtag[dim]);
1267 for (constptr=tagname_tab.next; constptr!=NULL; constptr=constptr->next) {
1268 assert(strlen(constptr->name)>0);
1269 id1=(int16_t)(constptr->value & TAGMASK);
1270 #if BYTE_ORDER==BIG_ENDIAN
1273 writeerror |= !pc_writebin(fout,&id1,sizeof id1);
1274 writeerror |= !pc_writebin(fout,constptr->name,strlen(constptr->name)+1);
1277 /* automaton table */
1278 for (constptr=sc_automaton_tab.next; constptr!=NULL; constptr=constptr->next) {
1279 assert(constptr->index==0 && strlen(constptr->name)==0 || strlen(constptr->name)>0);
1280 id1=(int16_t)constptr->index;
1281 address=(ucell)constptr->value;
1282 #if BYTE_ORDER==BIG_ENDIAN
1284 aligncell(&address);
1286 writeerror |= !pc_writebin(fout,&id1,sizeof id1);
1287 writeerror |= !pc_writebin(fout,&address,sizeof address);
1288 writeerror |= !pc_writebin(fout,constptr->name,strlen(constptr->name)+1);
1292 for (constptr=sc_state_tab.next; constptr!=NULL; constptr=constptr->next) {
1293 assert(strlen(constptr->name)>0);
1294 id1=(int16_t)constptr->value;
1295 id2=(int16_t)constptr->index;
1296 address=(ucell)constptr->value;
1297 #if BYTE_ORDER==BIG_ENDIAN
1301 writeerror |= !pc_writebin(fout,&id1,sizeof id1);
1302 writeerror |= !pc_writebin(fout,&id2,sizeof id2);
1303 writeerror |= !pc_writebin(fout,constptr->name,strlen(constptr->name)+1);
1306 delete_dbgstringtable();