1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/sourcepawn/compiler/sc6.c Sun Mar 30 07:00:22 2008 +0000
1.3 @@ -0,0 +1,1308 @@
1.4 +/* Pawn compiler - Binary code generation (the "assembler")
1.5 + *
1.6 + * Copyright (c) ITB CompuPhase, 1997-2006
1.7 + *
1.8 + * This software is provided "as-is", without any express or implied warranty.
1.9 + * In no event will the authors be held liable for any damages arising from
1.10 + * the use of this software.
1.11 + *
1.12 + * Permission is granted to anyone to use this software for any purpose,
1.13 + * including commercial applications, and to alter it and redistribute it
1.14 + * freely, subject to the following restrictions:
1.15 + *
1.16 + * 1. The origin of this software must not be misrepresented; you must not
1.17 + * claim that you wrote the original software. If you use this software in
1.18 + * a product, an acknowledgment in the product documentation would be
1.19 + * appreciated but is not required.
1.20 + * 2. Altered source versions must be plainly marked as such, and must not be
1.21 + * misrepresented as being the original software.
1.22 + * 3. This notice may not be removed or altered from any source distribution.
1.23 + *
1.24 + * Version: $Id$
1.25 + */
1.26 +#include <assert.h>
1.27 +#include <stdio.h>
1.28 +#include <stdlib.h> /* for macro max() */
1.29 +#include <stddef.h> /* for macro offsetof() */
1.30 +#include <string.h>
1.31 +#include <ctype.h>
1.32 +#if defined FORTIFY
1.33 + #include <alloc/fortify.h>
1.34 +#endif
1.35 +#include "lstring.h"
1.36 +#include "sc.h"
1.37 +#include "amxdbg.h"
1.38 +#if defined LINUX || defined __FreeBSD__ || defined __OpenBSD__
1.39 + #include <sclinux.h>
1.40 +#endif
1.41 +
1.42 +
1.43 +static void append_dbginfo(FILE *fout);
1.44 +
1.45 +
1.46 +typedef cell (*OPCODE_PROC)(FILE *fbin,char *params,cell opcode);
1.47 +
1.48 +typedef struct {
1.49 + cell opcode;
1.50 + char *name;
1.51 + int segment; /* sIN_CSEG=parse in cseg, sIN_DSEG=parse in dseg */
1.52 + OPCODE_PROC func;
1.53 +} OPCODEC;
1.54 +
1.55 +static cell codeindex; /* similar to "code_idx" */
1.56 +static cell *lbltab; /* label table */
1.57 +static int writeerror;
1.58 +static int bytes_in, bytes_out;
1.59 +static jmp_buf compact_err;
1.60 +
1.61 +/* apparently, strtol() does not work correctly on very large (unsigned)
1.62 + * hexadecimal values */
1.63 +static ucell hex2long(const char *s,char **n)
1.64 +{
1.65 + ucell result=0L;
1.66 + int negate=FALSE;
1.67 + int digit;
1.68 +
1.69 + /* ignore leading whitespace */
1.70 + while (*s==' ' || *s=='\t')
1.71 + s++;
1.72 +
1.73 + /* allow a negation sign to create the two's complement of numbers */
1.74 + if (*s=='-') {
1.75 + negate=TRUE;
1.76 + s++;
1.77 + } /* if */
1.78 +
1.79 + assert((*s>='0' && *s<='9') || (*s>='a' && *s<='f') || (*s>='a' && *s<='f'));
1.80 + for ( ;; ) {
1.81 + if (*s>='0' && *s<='9')
1.82 + digit=*s-'0';
1.83 + else if (*s>='a' && *s<='f')
1.84 + digit=*s-'a' + 10;
1.85 + else if (*s>='A' && *s<='F')
1.86 + digit=*s-'A' + 10;
1.87 + else
1.88 + break; /* probably whitespace */
1.89 + result=(result<<4) | digit;
1.90 + s++;
1.91 + } /* for */
1.92 + if (n!=NULL)
1.93 + *n=(char*)s;
1.94 + if (negate)
1.95 + result=(~result)+1; /* take two's complement of the result */
1.96 + return (ucell)result;
1.97 +}
1.98 +
1.99 +static ucell getparam(const char *s,char **n)
1.100 +{
1.101 + ucell result=0;
1.102 + for ( ;; ) {
1.103 + result+=hex2long(s,(char**)&s);
1.104 + if (*s!='+')
1.105 + break;
1.106 + s++;
1.107 + } /* for */
1.108 + if (n!=NULL)
1.109 + *n=(char*)s;
1.110 + return result;
1.111 +}
1.112 +
1.113 +#if BYTE_ORDER==BIG_ENDIAN
1.114 +static uint16_t *align16(uint16_t *v)
1.115 +{
1.116 + unsigned char *s = (unsigned char *)v;
1.117 + unsigned char t;
1.118 +
1.119 + /* swap two bytes */
1.120 + t=s[0];
1.121 + s[0]=s[1];
1.122 + s[1]=t;
1.123 + return v;
1.124 +}
1.125 +
1.126 +static uint32_t *align32(uint32_t *v)
1.127 +{
1.128 + unsigned char *s = (unsigned char *)v;
1.129 + unsigned char t;
1.130 +
1.131 + /* swap outer two bytes */
1.132 + t=s[0];
1.133 + s[0]=s[3];
1.134 + s[3]=t;
1.135 + /* swap inner two bytes */
1.136 + t=s[1];
1.137 + s[1]=s[2];
1.138 + s[2]=t;
1.139 + return v;
1.140 +}
1.141 +
1.142 +#if PAWN_CELL_SIZE>=64
1.143 +static uint64_t *align64(uint64_t *v)
1.144 +{
1.145 + unsigned char *s = (unsigned char *)v;
1.146 + unsigned char t;
1.147 +
1.148 + t=s[0];
1.149 + s[0]=s[7];
1.150 + s[7]=t;
1.151 +
1.152 + t=s[1];
1.153 + s[1]=s[6];
1.154 + s[6]=t;
1.155 +
1.156 + t=s[2];
1.157 + s[2]=s[5];
1.158 + s[5]=t;
1.159 +
1.160 + t=s[3];
1.161 + s[3]=s[4];
1.162 + s[4]=t;
1.163 +
1.164 + return v;
1.165 +}
1.166 +#endif
1.167 +
1.168 + #if PAWN_CELL_SIZE==16
1.169 + #define aligncell(v) align16(v)
1.170 + #elif PAWN_CELL_SIZE==32
1.171 + #define aligncell(v) align32(v)
1.172 + #elif PAWN_CELL_SIZE==64
1.173 + #define aligncell(v) align64(v)
1.174 + #endif
1.175 +#else
1.176 + #define align16(v) (v)
1.177 + #define align32(v) (v)
1.178 + #define aligncell(v) (v)
1.179 +#endif
1.180 +
1.181 +static char *skipwhitespace(char *str)
1.182 +{
1.183 + while (isspace(*str))
1.184 + str++;
1.185 + return str;
1.186 +}
1.187 +
1.188 +static char *stripcomment(char *str)
1.189 +{
1.190 + char *ptr=strchr(str,';');
1.191 + if (ptr!=NULL) {
1.192 + *ptr++='\n'; /* terminate the line, but leave the '\n' */
1.193 + *ptr='\0';
1.194 + } /* if */
1.195 + return str;
1.196 +}
1.197 +
1.198 +static void write_encoded(FILE *fbin,ucell *c,int num)
1.199 +{
1.200 + #if PAWN_CELL_SIZE == 16
1.201 + #define ENC_MAX 3 /* a 16-bit cell is encoded in max. 3 bytes */
1.202 + #define ENC_MASK 0x03 /* after 2x7 bits, 2 bits remain to make 16 bits */
1.203 + #elif PAWN_CELL_SIZE == 32
1.204 + #define ENC_MAX 5 /* a 32-bit cell is encoded in max. 5 bytes */
1.205 + #define ENC_MASK 0x0f /* after 4x7 bits, 4 bits remain to make 32 bits */
1.206 + #elif PAWN_CELL_SIZE == 64
1.207 + #define ENC_MAX 10 /* a 32-bit cell is encoded in max. 10 bytes */
1.208 + #define ENC_MASK 0x01 /* after 9x7 bits, 1 bit remains to make 64 bits */
1.209 + #endif
1.210 +
1.211 + assert(fbin!=NULL);
1.212 + while (num-->0) {
1.213 + if (sc_compress) {
1.214 + ucell p=(ucell)*c;
1.215 + unsigned char t[ENC_MAX];
1.216 + unsigned char code;
1.217 + int index;
1.218 + for (index=0; index<ENC_MAX; index++) {
1.219 + t[index]=(unsigned char)(p & 0x7f); /* store 7 bits */
1.220 + p>>=7;
1.221 + } /* for */
1.222 + /* skip leading zeros */
1.223 + while (index>1 && t[index-1]==0 && (t[index-2] & 0x40)==0)
1.224 + index--;
1.225 + /* skip leading -1s */
1.226 + if (index==ENC_MAX && t[index-1]==ENC_MASK && (t[index-2] & 0x40)!=0)
1.227 + index--;
1.228 + while (index>1 && t[index-1]==0x7f && (t[index-2] & 0x40)!=0)
1.229 + index--;
1.230 + /* write high byte first, write continuation bits */
1.231 + assert(index>0);
1.232 + while (index-->0) {
1.233 + code=(unsigned char)((index==0) ? t[index] : (t[index]|0x80));
1.234 + writeerror |= !pc_writebin(fbin,&code,1);
1.235 + bytes_out++;
1.236 + } /* while */
1.237 + bytes_in+=sizeof *c;
1.238 + assert(AMX_COMPACTMARGIN>2);
1.239 + if (bytes_out-bytes_in>=AMX_COMPACTMARGIN-2)
1.240 + longjmp(compact_err,1);
1.241 + } else {
1.242 + assert((pc_lengthbin(fbin) % sizeof(cell)) == 0);
1.243 + writeerror |= !pc_writebin(fbin,aligncell(c),sizeof *c);
1.244 + } /* if */
1.245 + c++;
1.246 + } /* while */
1.247 +}
1.248 +
1.249 +#if defined __BORLANDC__ || defined __WATCOMC__
1.250 + #pragma argsused
1.251 +#endif
1.252 +static cell noop(FILE *fbin,char *params,cell opcode)
1.253 +{
1.254 + return 0;
1.255 +}
1.256 +
1.257 +#if defined __BORLANDC__ || defined __WATCOMC__
1.258 + #pragma argsused
1.259 +#endif
1.260 +static cell set_currentfile(FILE *fbin,char *params,cell opcode)
1.261 +{
1.262 + fcurrent=(short)getparam(params,NULL);
1.263 + return 0;
1.264 +}
1.265 +
1.266 +#if defined __BORLANDC__ || defined __WATCOMC__
1.267 + #pragma argsused
1.268 +#endif
1.269 +static cell parm0(FILE *fbin,char *params,cell opcode)
1.270 +{
1.271 + if (fbin!=NULL)
1.272 + write_encoded(fbin,(ucell*)&opcode,1);
1.273 + return opcodes(1);
1.274 +}
1.275 +
1.276 +static cell parm1(FILE *fbin,char *params,cell opcode)
1.277 +{
1.278 + ucell p=getparam(params,NULL);
1.279 + if (fbin!=NULL) {
1.280 + write_encoded(fbin,(ucell*)&opcode,1);
1.281 + write_encoded(fbin,&p,1);
1.282 + } /* if */
1.283 + return opcodes(1)+opargs(1);
1.284 +}
1.285 +
1.286 +static cell parm2(FILE *fbin,char *params,cell opcode)
1.287 +{
1.288 + ucell p1=getparam(params,¶ms);
1.289 + ucell p2=getparam(params,NULL);
1.290 + if (fbin!=NULL) {
1.291 + write_encoded(fbin,(ucell*)&opcode,1);
1.292 + write_encoded(fbin,&p1,1);
1.293 + write_encoded(fbin,&p2,1);
1.294 + } /* if */
1.295 + return opcodes(1)+opargs(2);
1.296 +}
1.297 +
1.298 +static cell parm3(FILE *fbin,char *params,cell opcode)
1.299 +{
1.300 + ucell p1=getparam(params,¶ms);
1.301 + ucell p2=getparam(params,¶ms);
1.302 + ucell p3=getparam(params,NULL);
1.303 + if (fbin!=NULL) {
1.304 + write_encoded(fbin,(ucell*)&opcode,1);
1.305 + write_encoded(fbin,&p1,1);
1.306 + write_encoded(fbin,&p2,1);
1.307 + write_encoded(fbin,&p3,1);
1.308 + } /* if */
1.309 + return opcodes(1)+opargs(3);
1.310 +}
1.311 +
1.312 +static cell parm4(FILE *fbin,char *params,cell opcode)
1.313 +{
1.314 + ucell p1=getparam(params,¶ms);
1.315 + ucell p2=getparam(params,¶ms);
1.316 + ucell p3=getparam(params,¶ms);
1.317 + ucell p4=getparam(params,NULL);
1.318 + if (fbin!=NULL) {
1.319 + write_encoded(fbin,(ucell*)&opcode,1);
1.320 + write_encoded(fbin,&p1,1);
1.321 + write_encoded(fbin,&p2,1);
1.322 + write_encoded(fbin,&p3,1);
1.323 + write_encoded(fbin,&p4,1);
1.324 + } /* if */
1.325 + return opcodes(1)+opargs(4);
1.326 +}
1.327 +
1.328 +static cell parm5(FILE *fbin,char *params,cell opcode)
1.329 +{
1.330 + ucell p1=getparam(params,¶ms);
1.331 + ucell p2=getparam(params,¶ms);
1.332 + ucell p3=getparam(params,¶ms);
1.333 + ucell p4=getparam(params,¶ms);
1.334 + ucell p5=getparam(params,NULL);
1.335 + if (fbin!=NULL) {
1.336 + write_encoded(fbin,(ucell*)&opcode,1);
1.337 + write_encoded(fbin,&p1,1);
1.338 + write_encoded(fbin,&p2,1);
1.339 + write_encoded(fbin,&p3,1);
1.340 + write_encoded(fbin,&p4,1);
1.341 + write_encoded(fbin,&p5,1);
1.342 + } /* if */
1.343 + return opcodes(1)+opargs(5);
1.344 +}
1.345 +
1.346 +#if defined __BORLANDC__ || defined __WATCOMC__
1.347 + #pragma argsused
1.348 +#endif
1.349 +static cell do_dump(FILE *fbin,char *params,cell opcode)
1.350 +{
1.351 + ucell p;
1.352 + int num = 0;
1.353 +
1.354 + while (*params!='\0') {
1.355 + p=getparam(params,¶ms);
1.356 + if (fbin!=NULL)
1.357 + write_encoded(fbin,&p,1);
1.358 + num++;
1.359 + while (isspace(*params))
1.360 + params++;
1.361 + } /* while */
1.362 + return num*sizeof(cell);
1.363 +}
1.364 +
1.365 +static cell do_call(FILE *fbin,char *params,cell opcode)
1.366 +{
1.367 + char name[sNAMEMAX+1];
1.368 + int i;
1.369 + symbol *sym;
1.370 + ucell p;
1.371 +
1.372 + for (i=0; !isspace(*params); i++,params++) {
1.373 + assert(*params!='\0');
1.374 + assert(i<sNAMEMAX);
1.375 + name[i]=*params;
1.376 + } /* for */
1.377 + name[i]='\0';
1.378 +
1.379 + if (name[0]=='l' && name[1]=='.') {
1.380 + /* this is a label, not a function symbol */
1.381 + i=(int)hex2long(name+2,NULL);
1.382 + assert(i>=0 && i<sc_labnum);
1.383 + if (fbin!=NULL) {
1.384 + assert(lbltab!=NULL);
1.385 + p=lbltab[i];
1.386 + } /* if */
1.387 + } else {
1.388 + /* look up the function address; note that the correct file number must
1.389 + * already have been set (in order for static globals to be found).
1.390 + */
1.391 + sym=findglb(name,sGLOBAL);
1.392 + assert(sym!=NULL);
1.393 + assert(sym->ident==iFUNCTN || sym->ident==iREFFUNC);
1.394 + assert(sym->vclass==sGLOBAL);
1.395 + p=sym->addr;
1.396 + } /* if */
1.397 +
1.398 + if (fbin!=NULL) {
1.399 + write_encoded(fbin,(ucell*)&opcode,1);
1.400 + write_encoded(fbin,&p,1);
1.401 + } /* if */
1.402 + return opcodes(1)+opargs(1);
1.403 +}
1.404 +
1.405 +static cell do_jump(FILE *fbin,char *params,cell opcode)
1.406 +{
1.407 + int i;
1.408 + ucell p;
1.409 +
1.410 + i=(int)hex2long(params,NULL);
1.411 + assert(i>=0 && i<sc_labnum);
1.412 +
1.413 + if (fbin!=NULL) {
1.414 + assert(lbltab!=NULL);
1.415 + p=lbltab[i];
1.416 + write_encoded(fbin,(ucell*)&opcode,1);
1.417 + write_encoded(fbin,&p,1);
1.418 + } /* if */
1.419 + return opcodes(1)+opargs(1);
1.420 +}
1.421 +
1.422 +static cell do_switch(FILE *fbin,char *params,cell opcode)
1.423 +{
1.424 + int i;
1.425 + ucell p;
1.426 +
1.427 + i=(int)hex2long(params,NULL);
1.428 + assert(i>=0 && i<sc_labnum);
1.429 +
1.430 + if (fbin!=NULL) {
1.431 + assert(lbltab!=NULL);
1.432 + p=lbltab[i];
1.433 + write_encoded(fbin,(ucell*)&opcode,1);
1.434 + write_encoded(fbin,&p,1);
1.435 + } /* if */
1.436 + return opcodes(1)+opargs(1);
1.437 +}
1.438 +
1.439 +#if defined __BORLANDC__ || defined __WATCOMC__
1.440 + #pragma argsused
1.441 +#endif
1.442 +static cell do_case(FILE *fbin,char *params,cell opcode)
1.443 +{
1.444 + int i;
1.445 + ucell p,v;
1.446 +
1.447 + v=hex2long(params,¶ms);
1.448 + i=(int)hex2long(params,NULL);
1.449 + assert(i>=0 && i<sc_labnum);
1.450 +
1.451 + if (fbin!=NULL) {
1.452 + assert(lbltab!=NULL);
1.453 + p=lbltab[i];
1.454 + write_encoded(fbin,&v,1);
1.455 + write_encoded(fbin,&p,1);
1.456 + } /* if */
1.457 + return opcodes(0)+opargs(2);
1.458 +}
1.459 +
1.460 +static OPCODEC opcodelist[] = {
1.461 + /* node for "invalid instruction" */
1.462 + { 0, NULL, 0, noop },
1.463 + /* opcodes in sorted order */
1.464 + { 78, "add", sIN_CSEG, parm0 },
1.465 + { 87, "add.c", sIN_CSEG, parm1 },
1.466 + { 14, "addr.alt", sIN_CSEG, parm1 },
1.467 + { 13, "addr.pri", sIN_CSEG, parm1 },
1.468 + { 30, "align.alt", sIN_CSEG, parm1 },
1.469 + { 29, "align.pri", sIN_CSEG, parm1 },
1.470 + { 81, "and", sIN_CSEG, parm0 },
1.471 + {121, "bounds", sIN_CSEG, parm1 },
1.472 + {137, "break", sIN_CSEG, parm0 }, /* version 8 */
1.473 + { 49, "call", sIN_CSEG, do_call },
1.474 + { 50, "call.pri", sIN_CSEG, parm0 },
1.475 + { 0, "case", sIN_CSEG, do_case },
1.476 + {130, "casetbl", sIN_CSEG, parm0 }, /* version 1 */
1.477 + {118, "cmps", sIN_CSEG, parm1 },
1.478 + { 0, "code", sIN_CSEG, set_currentfile },
1.479 + {156, "const", sIN_CSEG, parm2 }, /* version 9 */
1.480 + { 12, "const.alt", sIN_CSEG, parm1 },
1.481 + { 11, "const.pri", sIN_CSEG, parm1 },
1.482 + {157, "const.s", sIN_CSEG, parm2 }, /* version 9 */
1.483 + { 0, "data", sIN_DSEG, set_currentfile },
1.484 + {114, "dec", sIN_CSEG, parm1 },
1.485 + {113, "dec.alt", sIN_CSEG, parm0 },
1.486 + {116, "dec.i", sIN_CSEG, parm0 },
1.487 + {112, "dec.pri", sIN_CSEG, parm0 },
1.488 + {115, "dec.s", sIN_CSEG, parm1 },
1.489 + { 0, "dump", sIN_DSEG, do_dump },
1.490 + { 95, "eq", sIN_CSEG, parm0 },
1.491 + {106, "eq.c.alt", sIN_CSEG, parm1 },
1.492 + {105, "eq.c.pri", sIN_CSEG, parm1 },
1.493 +/*{124, "file", sIN_CSEG, do_file }, */
1.494 + {119, "fill", sIN_CSEG, parm1 },
1.495 + {162, "genarray", sIN_CSEG, parm1 },
1.496 + {163, "genarray.z", sIN_CSEG, parm1 },
1.497 + {100, "geq", sIN_CSEG, parm0 },
1.498 + { 99, "grtr", sIN_CSEG, parm0 },
1.499 + {120, "halt", sIN_CSEG, parm1 },
1.500 + { 45, "heap", sIN_CSEG, parm1 },
1.501 + { 27, "idxaddr", sIN_CSEG, parm0 },
1.502 + { 28, "idxaddr.b", sIN_CSEG, parm1 },
1.503 + {109, "inc", sIN_CSEG, parm1 },
1.504 + {108, "inc.alt", sIN_CSEG, parm0 },
1.505 + {111, "inc.i", sIN_CSEG, parm0 },
1.506 + {107, "inc.pri", sIN_CSEG, parm0 },
1.507 + {110, "inc.s", sIN_CSEG, parm1 },
1.508 + { 86, "invert", sIN_CSEG, parm0 },
1.509 + { 55, "jeq", sIN_CSEG, do_jump },
1.510 + { 60, "jgeq", sIN_CSEG, do_jump },
1.511 + { 59, "jgrtr", sIN_CSEG, do_jump },
1.512 + { 58, "jleq", sIN_CSEG, do_jump },
1.513 + { 57, "jless", sIN_CSEG, do_jump },
1.514 + { 56, "jneq", sIN_CSEG, do_jump },
1.515 + { 54, "jnz", sIN_CSEG, do_jump },
1.516 + { 52, "jrel", sIN_CSEG, parm1 }, /* always a number */
1.517 + { 64, "jsgeq", sIN_CSEG, do_jump },
1.518 + { 63, "jsgrtr", sIN_CSEG, do_jump },
1.519 + { 62, "jsleq", sIN_CSEG, do_jump },
1.520 + { 61, "jsless", sIN_CSEG, do_jump },
1.521 + { 51, "jump", sIN_CSEG, do_jump },
1.522 + {128, "jump.pri", sIN_CSEG, parm0 }, /* version 1 */
1.523 + { 53, "jzer", sIN_CSEG, do_jump },
1.524 + { 31, "lctrl", sIN_CSEG, parm1 },
1.525 + { 98, "leq", sIN_CSEG, parm0 },
1.526 + { 97, "less", sIN_CSEG, parm0 },
1.527 + { 25, "lidx", sIN_CSEG, parm0 },
1.528 + { 26, "lidx.b", sIN_CSEG, parm1 },
1.529 +/*{125, "line", sIN_CSEG, parm2 }, */
1.530 + { 2, "load.alt", sIN_CSEG, parm1 },
1.531 + {154, "load.both", sIN_CSEG, parm2 }, /* version 9 */
1.532 + { 9, "load.i", sIN_CSEG, parm0 },
1.533 + { 1, "load.pri", sIN_CSEG, parm1 },
1.534 + { 4, "load.s.alt", sIN_CSEG, parm1 },
1.535 + {155, "load.s.both",sIN_CSEG, parm2 }, /* version 9 */
1.536 + { 3, "load.s.pri", sIN_CSEG, parm1 },
1.537 + { 10, "lodb.i", sIN_CSEG, parm1 },
1.538 + { 6, "lref.alt", sIN_CSEG, parm1 },
1.539 + { 5, "lref.pri", sIN_CSEG, parm1 },
1.540 + { 8, "lref.s.alt", sIN_CSEG, parm1 },
1.541 + { 7, "lref.s.pri", sIN_CSEG, parm1 },
1.542 + { 34, "move.alt", sIN_CSEG, parm0 },
1.543 + { 33, "move.pri", sIN_CSEG, parm0 },
1.544 + {117, "movs", sIN_CSEG, parm1 },
1.545 + { 85, "neg", sIN_CSEG, parm0 },
1.546 + { 96, "neq", sIN_CSEG, parm0 },
1.547 + {134, "nop", sIN_CSEG, parm0 }, /* version 6 */
1.548 + { 84, "not", sIN_CSEG, parm0 },
1.549 + { 82, "or", sIN_CSEG, parm0 },
1.550 + { 43, "pop.alt", sIN_CSEG, parm0 },
1.551 + { 42, "pop.pri", sIN_CSEG, parm0 },
1.552 + { 46, "proc", sIN_CSEG, parm0 },
1.553 + { 40, "push", sIN_CSEG, parm1 },
1.554 + {133, "push.adr", sIN_CSEG, parm1 }, /* version 4 */
1.555 + { 37, "push.alt", sIN_CSEG, parm0 },
1.556 + { 39, "push.c", sIN_CSEG, parm1 },
1.557 + { 36, "push.pri", sIN_CSEG, parm0 },
1.558 + { 38, "push.r", sIN_CSEG, parm1 }, /* obsolete (never generated) */
1.559 + { 41, "push.s", sIN_CSEG, parm1 },
1.560 + {139, "push2", sIN_CSEG, parm2 }, /* version 9 */
1.561 + {141, "push2.adr", sIN_CSEG, parm2 }, /* version 9 */
1.562 + {138, "push2.c", sIN_CSEG, parm2 }, /* version 9 */
1.563 + {140, "push2.s", sIN_CSEG, parm2 }, /* version 9 */
1.564 + {143, "push3", sIN_CSEG, parm3 }, /* version 9 */
1.565 + {145, "push3.adr", sIN_CSEG, parm3 }, /* version 9 */
1.566 + {142, "push3.c", sIN_CSEG, parm3 }, /* version 9 */
1.567 + {144, "push3.s", sIN_CSEG, parm3 }, /* version 9 */
1.568 + {147, "push4", sIN_CSEG, parm4 }, /* version 9 */
1.569 + {149, "push4.adr", sIN_CSEG, parm4 }, /* version 9 */
1.570 + {146, "push4.c", sIN_CSEG, parm4 }, /* version 9 */
1.571 + {148, "push4.s", sIN_CSEG, parm4 }, /* version 9 */
1.572 + {151, "push5", sIN_CSEG, parm5 }, /* version 9 */
1.573 + {153, "push5.adr", sIN_CSEG, parm5 }, /* version 9 */
1.574 + {150, "push5.c", sIN_CSEG, parm5 }, /* version 9 */
1.575 + {152, "push5.s", sIN_CSEG, parm5 }, /* version 9 */
1.576 + { 47, "ret", sIN_CSEG, parm0 },
1.577 + { 48, "retn", sIN_CSEG, parm0 },
1.578 + { 32, "sctrl", sIN_CSEG, parm1 },
1.579 + { 73, "sdiv", sIN_CSEG, parm0 },
1.580 + { 74, "sdiv.alt", sIN_CSEG, parm0 },
1.581 + {104, "sgeq", sIN_CSEG, parm0 },
1.582 + {103, "sgrtr", sIN_CSEG, parm0 },
1.583 + { 65, "shl", sIN_CSEG, parm0 },
1.584 + { 69, "shl.c.alt", sIN_CSEG, parm1 },
1.585 + { 68, "shl.c.pri", sIN_CSEG, parm1 },
1.586 + { 66, "shr", sIN_CSEG, parm0 },
1.587 + { 71, "shr.c.alt", sIN_CSEG, parm1 },
1.588 + { 70, "shr.c.pri", sIN_CSEG, parm1 },
1.589 + { 94, "sign.alt", sIN_CSEG, parm0 },
1.590 + { 93, "sign.pri", sIN_CSEG, parm0 },
1.591 + {102, "sleq", sIN_CSEG, parm0 },
1.592 + {101, "sless", sIN_CSEG, parm0 },
1.593 + { 72, "smul", sIN_CSEG, parm0 },
1.594 + { 88, "smul.c", sIN_CSEG, parm1 },
1.595 +/*{127, "srange", sIN_CSEG, parm2 }, -- version 1 */
1.596 + { 20, "sref.alt", sIN_CSEG, parm1 },
1.597 + { 19, "sref.pri", sIN_CSEG, parm1 },
1.598 + { 22, "sref.s.alt", sIN_CSEG, parm1 },
1.599 + { 21, "sref.s.pri", sIN_CSEG, parm1 },
1.600 + { 67, "sshr", sIN_CSEG, parm0 },
1.601 + { 44, "stack", sIN_CSEG, parm1 },
1.602 + {165, "stackadjust",sIN_CSEG, parm1 },
1.603 + { 0, "stksize", 0, noop },
1.604 + { 16, "stor.alt", sIN_CSEG, parm1 },
1.605 + { 23, "stor.i", sIN_CSEG, parm0 },
1.606 + { 15, "stor.pri", sIN_CSEG, parm1 },
1.607 + { 18, "stor.s.alt", sIN_CSEG, parm1 },
1.608 + { 17, "stor.s.pri", sIN_CSEG, parm1 },
1.609 + {164, "stradjust.pri", sIN_CSEG, parm0 },
1.610 + { 24, "strb.i", sIN_CSEG, parm1 },
1.611 + { 79, "sub", sIN_CSEG, parm0 },
1.612 + { 80, "sub.alt", sIN_CSEG, parm0 },
1.613 + {132, "swap.alt", sIN_CSEG, parm0 }, /* version 4 */
1.614 + {131, "swap.pri", sIN_CSEG, parm0 }, /* version 4 */
1.615 + {129, "switch", sIN_CSEG, do_switch }, /* version 1 */
1.616 +/*{126, "symbol", sIN_CSEG, do_symbol }, */
1.617 +/*{136, "symtag", sIN_CSEG, parm1 }, -- version 7 */
1.618 + {123, "sysreq.c", sIN_CSEG, parm1 },
1.619 + {135, "sysreq.n", sIN_CSEG, parm2 }, /* version 9 (replaces SYSREQ.d from earlier version) */
1.620 + {122, "sysreq.pri", sIN_CSEG, parm0 },
1.621 + {161, "tracker.pop.setheap", sIN_CSEG, parm0 },
1.622 + {160, "tracker.push.c", sIN_CSEG, parm1 },
1.623 + { 76, "udiv", sIN_CSEG, parm0 },
1.624 + { 77, "udiv.alt", sIN_CSEG, parm0 },
1.625 + { 75, "umul", sIN_CSEG, parm0 },
1.626 + { 35, "xchg", sIN_CSEG, parm0 },
1.627 + { 83, "xor", sIN_CSEG, parm0 },
1.628 + { 91, "zero", sIN_CSEG, parm1 },
1.629 + { 90, "zero.alt", sIN_CSEG, parm0 },
1.630 + { 89, "zero.pri", sIN_CSEG, parm0 },
1.631 + { 92, "zero.s", sIN_CSEG, parm1 },
1.632 +};
1.633 +
1.634 +#define MAX_INSTR_LEN 30
1.635 +static int findopcode(char *instr,int maxlen)
1.636 +{
1.637 + int low,high,mid,cmp;
1.638 + char str[MAX_INSTR_LEN];
1.639 +
1.640 + if (maxlen>=MAX_INSTR_LEN)
1.641 + return 0;
1.642 + strlcpy(str,instr,maxlen+1);
1.643 + /* look up the instruction with a binary search
1.644 + * the assembler is case insensitive to instructions (but case sensitive
1.645 + * to symbols)
1.646 + */
1.647 + low=1; /* entry 0 is reserved (for "not found") */
1.648 + high=(sizeof opcodelist / sizeof opcodelist[0])-1;
1.649 + while (low<high) {
1.650 + mid=(low+high)/2;
1.651 + assert(opcodelist[mid].name!=NULL);
1.652 + cmp=stricmp(str,opcodelist[mid].name);
1.653 + if (cmp>0)
1.654 + low=mid+1;
1.655 + else
1.656 + high=mid;
1.657 + } /* while */
1.658 +
1.659 + assert(low==high);
1.660 + if (stricmp(str,opcodelist[low].name)==0)
1.661 + return low; /* found */
1.662 + return 0; /* not found, return special index */
1.663 +}
1.664 +
1.665 +SC_FUNC int assemble(FILE *fout,FILE *fin)
1.666 +{
1.667 + AMX_HEADER hdr;
1.668 + AMX_FUNCSTUBNT func;
1.669 + int numpublics,numnatives,numlibraries,numpubvars,numtags,padding;
1.670 + long nametablesize,nameofs;
1.671 + #if PAWN_CELL_SIZE > 32
1.672 + char line[512];
1.673 + #else
1.674 + char line[256];
1.675 + #endif
1.676 + char *instr,*params;
1.677 + int i,pass,size;
1.678 + int16_t count;
1.679 + symbol *sym, **nativelist;
1.680 + constvalue *constptr;
1.681 + cell mainaddr;
1.682 + char nullchar;
1.683 + char testalias[sNAMEMAX+1];
1.684 +
1.685 + /* if compression failed, restart the assembly with compaction switched off */
1.686 + if (setjmp(compact_err)!=0) {
1.687 + assert(sc_compress); /* cannot arrive here if compact encoding was disabled */
1.688 + sc_compress=FALSE;
1.689 + pc_resetbin(fout,0);
1.690 + error(232); /* disabled compact encoding */
1.691 + } /* if */
1.692 +
1.693 + #if !defined NDEBUG
1.694 + /* verify that the opcode list is sorted (skip entry 1; it is reserved
1.695 + * for a non-existant opcode)
1.696 + */
1.697 + assert(opcodelist[1].name!=NULL);
1.698 + for (i=2; i<(sizeof opcodelist / sizeof opcodelist[0]); i++) {
1.699 + assert(opcodelist[i].name!=NULL);
1.700 + assert(stricmp(opcodelist[i].name,opcodelist[i-1].name)>0);
1.701 + } /* for */
1.702 + #endif
1.703 +
1.704 + writeerror=FALSE;
1.705 + nametablesize=sizeof(int16_t);
1.706 + numpublics=0;
1.707 + numnatives=0;
1.708 + numpubvars=0;
1.709 + mainaddr=-1;
1.710 + /* count number of public and native functions and public variables */
1.711 + for (sym=glbtab.next; sym!=NULL; sym=sym->next) {
1.712 + int match=0;
1.713 + if (sym->ident==iFUNCTN) {
1.714 + if ((sym->usage & uNATIVE)!=0 && (sym->usage & uREAD)!=0 && sym->addr>=0) {
1.715 + match=++numnatives;
1.716 + }
1.717 + if ((sym->usage & uPUBLIC)!=0 && (sym->usage & uDEFINE)!=0)
1.718 + match=++numpublics;
1.719 + if (strcmp(sym->name,uMAINFUNC)==0) {
1.720 + assert(sym->vclass==sGLOBAL);
1.721 + mainaddr=sym->addr;
1.722 + } /* if */
1.723 + } else if (sym->ident==iVARIABLE || sym->ident == iARRAY || sym->ident == iREFARRAY) {
1.724 + if ((sym->usage & uPUBLIC)!=0 && (sym->usage & (uREAD | uWRITTEN))!=0)
1.725 + match=++numpubvars;
1.726 + } /* if */
1.727 + if (match) {
1.728 + const char *aliasptr = sym->name;
1.729 + assert(sym!=NULL);
1.730 + if (((sym->usage & uNATIVE)!=0) && lookup_alias(testalias,sym->name)) {
1.731 + aliasptr = "@";
1.732 + } /* if */
1.733 + nametablesize+=strlen(aliasptr)+1;
1.734 + } /* if */
1.735 + } /* for */
1.736 + assert(numnatives==ntv_funcid);
1.737 +
1.738 + /* count number of libraries */
1.739 + numlibraries=0;
1.740 + if (pc_addlibtable) {
1.741 + for (constptr=libname_tab.next; constptr!=NULL; constptr=constptr->next) {
1.742 + if (constptr->value>0) {
1.743 + assert(strlen(constptr->name)>0);
1.744 + numlibraries++;
1.745 + nametablesize+=strlen(constptr->name)+1;
1.746 + } /* if */
1.747 + } /* for */
1.748 + } /* if */
1.749 +
1.750 + /* count number of public tags */
1.751 + numtags=0;
1.752 + for (constptr=tagname_tab.next; constptr!=NULL; constptr=constptr->next) {
1.753 + /*if ((constptr->value & PUBLICTAG)!=0) {*/
1.754 + assert(strlen(constptr->name)>0);
1.755 + numtags++;
1.756 + nametablesize+=strlen(constptr->name)+1;
1.757 + /*} if */
1.758 + } /* for */
1.759 +
1.760 + /* pad the header to sc_dataalign
1.761 + * => thereby the code segment is aligned
1.762 + * => since the code segment is padded to a sc_dataalign boundary, the data segment is aligned
1.763 + * => and thereby the stack top is aligned too
1.764 + */
1.765 + assert(sc_dataalign!=0);
1.766 + padding= (int)(sc_dataalign - (sizeof hdr + nametablesize) % sc_dataalign);
1.767 + if (padding==sc_dataalign)
1.768 + padding=0;
1.769 +
1.770 + /* write the abstract machine header */
1.771 + memset(&hdr, 0, sizeof hdr);
1.772 + hdr.magic=(unsigned short)AMX_MAGIC;
1.773 + hdr.file_version=(char)((pc_optimize<=sOPTIMIZE_NOMACRO) ? MAX_FILE_VER_JIT : CUR_FILE_VERSION);
1.774 + hdr.amx_version=(char)((pc_optimize<=sOPTIMIZE_NOMACRO) ? MIN_AMX_VER_JIT : MIN_AMX_VERSION);
1.775 + hdr.flags=(short)(sc_debug & sSYMBOLIC);
1.776 + if (sc_compress)
1.777 + hdr.flags|=AMX_FLAG_COMPACT;
1.778 + if (sc_debug==0)
1.779 + hdr.flags|=AMX_FLAG_NOCHECKS;
1.780 + if (pc_memflags & suSLEEP_INSTR)
1.781 + hdr.flags|=AMX_FLAG_SLEEP;
1.782 + hdr.defsize=sizeof(AMX_FUNCSTUBNT);
1.783 + hdr.publics=sizeof hdr; /* public table starts right after the header */
1.784 + hdr.natives=hdr.publics + numpublics*sizeof(AMX_FUNCSTUBNT);
1.785 + hdr.libraries=hdr.natives + numnatives*sizeof(AMX_FUNCSTUBNT);
1.786 + hdr.pubvars=hdr.libraries + numlibraries*sizeof(AMX_FUNCSTUBNT);
1.787 + hdr.tags=hdr.pubvars + numpubvars*sizeof(AMX_FUNCSTUBNT);
1.788 + hdr.nametable=hdr.tags + numtags*sizeof(AMX_FUNCSTUBNT);
1.789 + hdr.cod=hdr.nametable + nametablesize + padding;
1.790 + hdr.dat=hdr.cod + code_idx;
1.791 + hdr.hea=hdr.dat + glb_declared*sizeof(cell);
1.792 + hdr.stp=hdr.hea + pc_stksize*sizeof(cell);
1.793 + hdr.cip=mainaddr;
1.794 + hdr.size=hdr.hea; /* preset, this is incorrect in case of compressed output */
1.795 + pc_writebin(fout,&hdr,sizeof hdr);
1.796 +
1.797 + /* dump zeros up to the rest of the header, so that we can easily "seek" */
1.798 + nullchar='\0';
1.799 + for (nameofs=sizeof hdr; nameofs<hdr.cod; nameofs++)
1.800 + pc_writebin(fout,&nullchar,1);
1.801 + nameofs=hdr.nametable+sizeof(int16_t);
1.802 +
1.803 + /* write the public functions table */
1.804 + count=0;
1.805 + for (sym=glbtab.next; sym!=NULL; sym=sym->next) {
1.806 + if (sym->ident==iFUNCTN
1.807 + && (sym->usage & uPUBLIC)!=0 && (sym->usage & uDEFINE)!=0)
1.808 + {
1.809 + assert(sym->vclass==sGLOBAL);
1.810 + func.address=sym->addr;
1.811 + func.nameofs=nameofs;
1.812 + #if BYTE_ORDER==BIG_ENDIAN
1.813 + align32(&func.address);
1.814 + align32(&func.nameofs);
1.815 + #endif
1.816 + pc_resetbin(fout,hdr.publics+count*sizeof(AMX_FUNCSTUBNT));
1.817 + pc_writebin(fout,&func,sizeof func);
1.818 + pc_resetbin(fout,nameofs);
1.819 + pc_writebin(fout,sym->name,strlen(sym->name)+1);
1.820 + nameofs+=strlen(sym->name)+1;
1.821 + count++;
1.822 + } /* if */
1.823 + } /* for */
1.824 +
1.825 + /* write the natives table */
1.826 + /* The native functions must be written in sorted order. (They are
1.827 + * sorted on their "id", not on their name). A nested loop to find
1.828 + * each successive function would be an O(n^2) operation. But we
1.829 + * do not really need to sort, because the native function id's
1.830 + * are sequential and there are no duplicates. So we first walk
1.831 + * through the complete symbol list and store a pointer to every
1.832 + * native function of interest in a temporary table, where its id
1.833 + * serves as the index in the table. Now we can walk the table and
1.834 + * have all native functions in sorted order.
1.835 + */
1.836 + if (numnatives>0) {
1.837 + nativelist=(symbol **)malloc(numnatives*sizeof(symbol *));
1.838 + if (nativelist==NULL)
1.839 + error(103); /* insufficient memory */
1.840 + #if !defined NDEBUG
1.841 + memset(nativelist,0,numnatives*sizeof(symbol *)); /* for NULL checking */
1.842 + #endif
1.843 + for (sym=glbtab.next; sym!=NULL; sym=sym->next) {
1.844 + if (sym->ident==iFUNCTN && (sym->usage & uNATIVE)!=0 && (sym->usage & uREAD)!=0 && sym->addr>=0) {
1.845 + assert(sym->addr < numnatives);
1.846 + nativelist[(int)sym->addr]=sym;
1.847 + } /* if */
1.848 + } /* for */
1.849 + count=0;
1.850 + for (i=0; i<numnatives; i++) {
1.851 + const char *aliasptr;
1.852 + sym=nativelist[i];
1.853 + assert(sym!=NULL);
1.854 + aliasptr = sym->name;
1.855 + if (lookup_alias(testalias,sym->name)) {
1.856 + aliasptr = "@";
1.857 + }
1.858 + assert(sym->vclass==sGLOBAL);
1.859 + func.address=0;
1.860 + func.nameofs=nameofs;
1.861 + #if BYTE_ORDER==BIG_ENDIAN
1.862 + align32(&func.address);
1.863 + align32(&func.nameofs);
1.864 + #endif
1.865 + pc_resetbin(fout,hdr.natives+count*sizeof(AMX_FUNCSTUBNT));
1.866 + pc_writebin(fout,&func,sizeof func);
1.867 + pc_resetbin(fout,nameofs);
1.868 + pc_writebin(fout,(void *)aliasptr,strlen(aliasptr)+1);
1.869 + nameofs+=strlen(aliasptr)+1;
1.870 + count++;
1.871 + } /* for */
1.872 + free(nativelist);
1.873 + } /* if */
1.874 +
1.875 + /* write the libraries table */
1.876 + if (pc_addlibtable) {
1.877 + count=0;
1.878 + for (constptr=libname_tab.next; constptr!=NULL; constptr=constptr->next) {
1.879 + if (constptr->value>0) {
1.880 + assert(strlen(constptr->name)>0);
1.881 + func.address=0;
1.882 + func.nameofs=nameofs;
1.883 + #if BYTE_ORDER==BIG_ENDIAN
1.884 + align32(&func.address);
1.885 + align32(&func.nameofs);
1.886 + #endif
1.887 + pc_resetbin(fout,hdr.libraries+count*sizeof(AMX_FUNCSTUBNT));
1.888 + pc_writebin(fout,&func,sizeof func);
1.889 + pc_resetbin(fout,nameofs);
1.890 + pc_writebin(fout,constptr->name,strlen(constptr->name)+1);
1.891 + nameofs+=strlen(constptr->name)+1;
1.892 + count++;
1.893 + } /* if */
1.894 + } /* for */
1.895 + } /* if */
1.896 +
1.897 + /* write the public variables table */
1.898 + count=0;
1.899 + for (sym=glbtab.next; sym!=NULL; sym=sym->next) {
1.900 + if ((sym->ident==iVARIABLE || sym->ident==iARRAY || sym->ident==iREFARRAY)
1.901 + && (sym->usage & uPUBLIC)!=0 && (sym->usage & (uREAD | uWRITTEN))!=0) {
1.902 + //removed until structs don't seem to mess this up
1.903 + //assert((sym->usage & uDEFINE)!=0);
1.904 + assert(sym->vclass==sGLOBAL);
1.905 + func.address=sym->addr;
1.906 + func.nameofs=nameofs;
1.907 + #if BYTE_ORDER==BIG_ENDIAN
1.908 + align32(&func.address);
1.909 + align32(&func.nameofs);
1.910 + #endif
1.911 + pc_resetbin(fout,hdr.pubvars+count*sizeof(AMX_FUNCSTUBNT));
1.912 + pc_writebin(fout,&func,sizeof func);
1.913 + pc_resetbin(fout,nameofs);
1.914 + pc_writebin(fout,sym->name,strlen(sym->name)+1);
1.915 + nameofs+=strlen(sym->name)+1;
1.916 + count++;
1.917 + } /* if */
1.918 + } /* for */
1.919 +
1.920 + /* write the public tagnames table */
1.921 + count=0;
1.922 + for (constptr=tagname_tab.next; constptr!=NULL; constptr=constptr->next) {
1.923 + /*if ((constptr->value & PUBLICTAG)!=0) {*/
1.924 + assert(strlen(constptr->name)>0);
1.925 + func.address=constptr->value & TAGMASK;
1.926 + func.nameofs=nameofs;
1.927 + #if BYTE_ORDER==BIG_ENDIAN
1.928 + align32(&func.address);
1.929 + align32(&func.nameofs);
1.930 + #endif
1.931 + pc_resetbin(fout,hdr.tags+count*sizeof(AMX_FUNCSTUBNT));
1.932 + pc_writebin(fout,&func,sizeof func);
1.933 + pc_resetbin(fout,nameofs);
1.934 + pc_writebin(fout,constptr->name,strlen(constptr->name)+1);
1.935 + nameofs+=strlen(constptr->name)+1;
1.936 + count++;
1.937 + /*} if */
1.938 + } /* for */
1.939 +
1.940 + /* write the "maximum name length" field in the name table */
1.941 + assert(nameofs==hdr.nametable+nametablesize);
1.942 + pc_resetbin(fout,hdr.nametable);
1.943 + count=sNAMEMAX;
1.944 + #if BYTE_ORDER==BIG_ENDIAN
1.945 + align16(&count);
1.946 + #endif
1.947 + pc_writebin(fout,&count,sizeof count);
1.948 + pc_resetbin(fout,hdr.cod);
1.949 +
1.950 + /* First pass: relocate all labels */
1.951 + /* This pass is necessary because the code addresses of labels is only known
1.952 + * after the peephole optimization flag. Labels can occur inside expressions
1.953 + * (e.g. the conditional operator), which are optimized.
1.954 + */
1.955 + lbltab=NULL;
1.956 + if (sc_labnum>0) {
1.957 + /* only very short programs have zero labels; no first pass is needed
1.958 + * if there are no labels */
1.959 + lbltab=(cell *)malloc(sc_labnum*sizeof(cell));
1.960 + if (lbltab==NULL)
1.961 + error(103); /* insufficient memory */
1.962 + codeindex=0;
1.963 + pc_resetasm(fin);
1.964 + while (pc_readasm(fin,line,sizeof line)!=NULL) {
1.965 + stripcomment(line);
1.966 + instr=skipwhitespace(line);
1.967 + /* ignore empty lines */
1.968 + if (*instr=='\0')
1.969 + continue;
1.970 + if (tolower(*instr)=='l' && *(instr+1)=='.') {
1.971 + int lindex=(int)hex2long(instr+2,NULL);
1.972 + assert(lindex>=0 && lindex<sc_labnum);
1.973 + lbltab[lindex]=codeindex;
1.974 + } else {
1.975 + /* get to the end of the instruction (make use of the '\n' that fgets()
1.976 + * added at the end of the line; this way we will *always* drop on a
1.977 + * whitespace character) */
1.978 + for (params=instr; *params!='\0' && !isspace(*params); params++)
1.979 + /* nothing */;
1.980 + assert(params>instr);
1.981 + i=findopcode(instr,(int)(params-instr));
1.982 + if (opcodelist[i].name==NULL) {
1.983 + *params='\0';
1.984 + error(104,instr); /* invalid assembler instruction */
1.985 + } /* if */
1.986 + if (opcodelist[i].segment==sIN_CSEG)
1.987 + codeindex+=opcodelist[i].func(NULL,skipwhitespace(params),opcodelist[i].opcode);
1.988 + } /* if */
1.989 + } /* while */
1.990 + } /* if */
1.991 +
1.992 + /* Second pass (actually 2 more passes, one for all code and one for all data) */
1.993 + bytes_in=0;
1.994 + bytes_out=0;
1.995 + for (pass=sIN_CSEG; pass<=sIN_DSEG; pass++) {
1.996 + pc_resetasm(fin);
1.997 + while (pc_readasm(fin,line,sizeof line)!=NULL) {
1.998 + stripcomment(line);
1.999 + instr=skipwhitespace(line);
1.1000 + /* ignore empty lines and labels (labels have a special syntax, so these
1.1001 + * must be parsed separately) */
1.1002 + if (*instr=='\0' || tolower(*instr)=='l' && *(instr+1)=='.')
1.1003 + continue;
1.1004 + /* get to the end of the instruction (make use of the '\n' that fgets()
1.1005 + * added at the end of the line; this way we will *always* drop on a
1.1006 + * whitespace character) */
1.1007 + for (params=instr; *params!='\0' && !isspace(*params); params++)
1.1008 + /* nothing */;
1.1009 + assert(params>instr);
1.1010 + i=findopcode(instr,(int)(params-instr));
1.1011 + assert(opcodelist[i].name!=NULL);
1.1012 + if (opcodelist[i].segment==pass)
1.1013 + opcodelist[i].func(fout,skipwhitespace(params),opcodelist[i].opcode);
1.1014 + } /* while */
1.1015 + } /* for */
1.1016 + if (bytes_out-bytes_in>0)
1.1017 + error(106); /* compression buffer overflow */
1.1018 +
1.1019 + if (lbltab!=NULL) {
1.1020 + free(lbltab);
1.1021 + #if !defined NDEBUG
1.1022 + lbltab=NULL;
1.1023 + #endif
1.1024 + } /* if */
1.1025 +
1.1026 + if (sc_compress)
1.1027 + hdr.size=pc_lengthbin(fout);/* get this value before appending debug info */
1.1028 + if (!writeerror && (sc_debug & sSYMBOLIC)!=0)
1.1029 + append_dbginfo(fout); /* optionally append debug file */
1.1030 +
1.1031 + if (writeerror)
1.1032 + error(101,"disk full");
1.1033 +
1.1034 + /* adjust the header */
1.1035 + size=(int)hdr.cod; /* save, the value in the header may be swapped */
1.1036 + #if BYTE_ORDER==BIG_ENDIAN
1.1037 + align32(&hdr.size);
1.1038 + align16(&hdr.magic);
1.1039 + align16(&hdr.flags);
1.1040 + align16(&hdr.defsize);
1.1041 + align32(&hdr.publics);
1.1042 + align32(&hdr.natives);
1.1043 + align32(&hdr.libraries);
1.1044 + align32(&hdr.pubvars);
1.1045 + align32(&hdr.tags);
1.1046 + align32(&hdr.nametable);
1.1047 + align32(&hdr.cod);
1.1048 + align32(&hdr.dat);
1.1049 + align32(&hdr.hea);
1.1050 + align32(&hdr.stp);
1.1051 + align32(&hdr.cip);
1.1052 + #endif
1.1053 + pc_resetbin(fout,0);
1.1054 + pc_writebin(fout,&hdr,sizeof hdr);
1.1055 +
1.1056 + /* return the size of the header (including name tables, but excluding code
1.1057 + * or data sections)
1.1058 + */
1.1059 + return size;
1.1060 +}
1.1061 +
1.1062 +static void append_dbginfo(FILE *fout)
1.1063 +{
1.1064 + AMX_DBG_HDR dbghdr;
1.1065 + AMX_DBG_LINE dbgline;
1.1066 + AMX_DBG_SYMBOL dbgsym;
1.1067 + AMX_DBG_SYMDIM dbgidxtag[sDIMEN_MAX];
1.1068 + int index,dim,dbgsymdim;
1.1069 + char *str,*prevstr,*name,*prevname;
1.1070 + ucell codeidx,previdx;
1.1071 + constvalue *constptr;
1.1072 + char symname[2*sNAMEMAX+16];
1.1073 + int16_t id1,id2;
1.1074 + ucell address;
1.1075 +
1.1076 + /* header with general information */
1.1077 + memset(&dbghdr, 0, sizeof dbghdr);
1.1078 + dbghdr.size=sizeof dbghdr;
1.1079 + dbghdr.magic=AMX_DBG_MAGIC;
1.1080 + dbghdr.file_version=CUR_FILE_VERSION;
1.1081 + dbghdr.amx_version=MIN_AMX_VERSION;
1.1082 +
1.1083 + /* first pass: collect the number of items in various tables */
1.1084 +
1.1085 + /* file table */
1.1086 + previdx=0;
1.1087 + prevstr=NULL;
1.1088 + prevname=NULL;
1.1089 + for (index=0; (str=get_dbgstring(index))!=NULL; index++) {
1.1090 + assert(str!=NULL);
1.1091 + assert(str[0]!='\0' && str[1]==':');
1.1092 + if (str[0]=='F') {
1.1093 + codeidx=hex2long(str+2,&name);
1.1094 + if (codeidx!=previdx) {
1.1095 + if (prevstr!=NULL) {
1.1096 + assert(prevname!=NULL);
1.1097 + dbghdr.files++;
1.1098 + dbghdr.size+=sizeof(cell)+strlen(prevname)+1;
1.1099 + } /* if */
1.1100 + previdx=codeidx;
1.1101 + } /* if */
1.1102 + prevstr=str;
1.1103 + prevname=skipwhitespace(name);
1.1104 + } /* if */
1.1105 + } /* for */
1.1106 + if (prevstr!=NULL) {
1.1107 + assert(prevname!=NULL);
1.1108 + dbghdr.files++;
1.1109 + dbghdr.size+=sizeof(cell)+strlen(prevname)+1;
1.1110 + } /* if */
1.1111 +
1.1112 + /* line number table */
1.1113 + for (index=0; (str=get_dbgstring(index))!=NULL; index++) {
1.1114 + assert(str!=NULL);
1.1115 + assert(str[0]!='\0' && str[1]==':');
1.1116 + if (str[0]=='L') {
1.1117 + dbghdr.lines++;
1.1118 + dbghdr.size+=sizeof(AMX_DBG_LINE);
1.1119 + } /* if */
1.1120 + } /* for */
1.1121 +
1.1122 + /* symbol table */
1.1123 + for (index=0; (str=get_dbgstring(index))!=NULL; index++) {
1.1124 + assert(str!=NULL);
1.1125 + assert(str[0]!='\0' && str[1]==':');
1.1126 + if (str[0]=='S') {
1.1127 + dbghdr.symbols++;
1.1128 + name=strchr(str+2,':');
1.1129 + assert(name!=NULL);
1.1130 + dbghdr.size+=sizeof(AMX_DBG_SYMBOL)+strlen(skipwhitespace(name+1));
1.1131 + if ((prevstr=strchr(name,'['))!=NULL)
1.1132 + while ((prevstr=strchr(prevstr+1,':'))!=NULL)
1.1133 + dbghdr.size+=sizeof(AMX_DBG_SYMDIM);
1.1134 + } /* if */
1.1135 + } /* for */
1.1136 +
1.1137 + /* tag table */
1.1138 + for (constptr=tagname_tab.next; constptr!=NULL; constptr=constptr->next) {
1.1139 + assert(strlen(constptr->name)>0);
1.1140 + dbghdr.tags++;
1.1141 + dbghdr.size+=sizeof(AMX_DBG_TAG)+strlen(constptr->name);
1.1142 + } /* for */
1.1143 +
1.1144 + /* automaton table */
1.1145 + for (constptr=sc_automaton_tab.next; constptr!=NULL; constptr=constptr->next) {
1.1146 + assert(constptr->index==0 && strlen(constptr->name)==0 || strlen(constptr->name)>0);
1.1147 + dbghdr.automatons++;
1.1148 + dbghdr.size+=sizeof(AMX_DBG_MACHINE)+strlen(constptr->name);
1.1149 + } /* for */
1.1150 +
1.1151 + /* state table */
1.1152 + for (constptr=sc_state_tab.next; constptr!=NULL; constptr=constptr->next) {
1.1153 + assert(strlen(constptr->name)>0);
1.1154 + dbghdr.states++;
1.1155 + dbghdr.size+=sizeof(AMX_DBG_STATE)+strlen(constptr->name);
1.1156 + } /* for */
1.1157 +
1.1158 +
1.1159 + /* pass 2: generate the tables */
1.1160 + #if BYTE_ORDER==BIG_ENDIAN
1.1161 + align32((uint32_t*)&dbghdr.size);
1.1162 + align16(&dbghdr.magic);
1.1163 + align16(&dbghdr.flags);
1.1164 + align16(&dbghdr.files);
1.1165 + align16(&dbghdr.lines);
1.1166 + align16(&dbghdr.symbols);
1.1167 + align16(&dbghdr.tags);
1.1168 + align16(&dbghdr.automatons);
1.1169 + align16(&dbghdr.states);
1.1170 + #endif
1.1171 + writeerror |= !pc_writebin(fout,&dbghdr,sizeof dbghdr);
1.1172 +
1.1173 + /* file table */
1.1174 + previdx=0;
1.1175 + prevstr=NULL;
1.1176 + prevname=NULL;
1.1177 + for (index=0; (str=get_dbgstring(index))!=NULL; index++) {
1.1178 + assert(str!=NULL);
1.1179 + assert(str[0]!='\0' && str[1]==':');
1.1180 + if (str[0]=='F') {
1.1181 + codeidx=hex2long(str+2,&name);
1.1182 + if (codeidx!=previdx) {
1.1183 + if (prevstr!=NULL) {
1.1184 + assert(prevname!=NULL);
1.1185 + #if BYTE_ORDER==BIG_ENDIAN
1.1186 + aligncell(&previdx);
1.1187 + #endif
1.1188 + writeerror |= !pc_writebin(fout,&previdx,sizeof previdx);
1.1189 + writeerror |= !pc_writebin(fout,prevname,strlen(prevname)+1);
1.1190 + } /* if */
1.1191 + previdx=codeidx;
1.1192 + } /* if */
1.1193 + prevstr=str;
1.1194 + prevname=skipwhitespace(name);
1.1195 + } /* if */
1.1196 + } /* for */
1.1197 + if (prevstr!=NULL) {
1.1198 + assert(prevname!=NULL);
1.1199 + #if BYTE_ORDER==BIG_ENDIAN
1.1200 + aligncell(&previdx);
1.1201 + #endif
1.1202 + writeerror |= !pc_writebin(fout,&previdx,sizeof previdx);
1.1203 + writeerror |= !pc_writebin(fout,prevname,strlen(prevname)+1);
1.1204 + } /* if */
1.1205 +
1.1206 + /* line number table */
1.1207 + for (index=0; (str=get_dbgstring(index))!=NULL; index++) {
1.1208 + assert(str!=NULL);
1.1209 + assert(str[0]!='\0' && str[1]==':');
1.1210 + if (str[0]=='L') {
1.1211 + dbgline.address=hex2long(str+2,&str);
1.1212 + dbgline.line=(int32_t)hex2long(str,NULL);
1.1213 + #if BYTE_ORDER==BIG_ENDIAN
1.1214 + aligncell(&dbgline.address);
1.1215 + align32(&dbgline.line);
1.1216 + #endif
1.1217 + writeerror |= !pc_writebin(fout,&dbgline,sizeof dbgline);
1.1218 + } /* if */
1.1219 + } /* for */
1.1220 +
1.1221 + /* symbol table */
1.1222 + for (index=0; (str=get_dbgstring(index))!=NULL; index++) {
1.1223 + assert(str!=NULL);
1.1224 + assert(str[0]!='\0' && str[1]==':');
1.1225 + if (str[0]=='S') {
1.1226 + dbgsym.address=hex2long(str+2,&str);
1.1227 + dbgsym.tag=(int16_t)hex2long(str,&str);
1.1228 + str=skipwhitespace(str);
1.1229 + assert(*str==':');
1.1230 + name=skipwhitespace(str+1);
1.1231 + str=strchr(name,' ');
1.1232 + assert(str!=NULL);
1.1233 + assert((int)(str-name)<sizeof symname);
1.1234 + strlcpy(symname,name,(int)(str-name)+1);
1.1235 + dbgsym.codestart=hex2long(str,&str);
1.1236 + dbgsym.codeend=hex2long(str,&str);
1.1237 + dbgsym.ident=(char)hex2long(str,&str);
1.1238 + dbgsym.vclass=(char)hex2long(str,&str);
1.1239 + dbgsym.dim=0;
1.1240 + str=skipwhitespace(str);
1.1241 + if (*str=='[') {
1.1242 + while (*(str=skipwhitespace(str+1))!=']') {
1.1243 + dbgidxtag[dbgsym.dim].tag=(int16_t)hex2long(str,&str);
1.1244 + str=skipwhitespace(str);
1.1245 + assert(*str==':');
1.1246 + dbgidxtag[dbgsym.dim].size=hex2long(str+1,&str);
1.1247 + dbgsym.dim++;
1.1248 + } /* while */
1.1249 + } /* if */
1.1250 + dbgsymdim = dbgsym.dim;
1.1251 + #if BYTE_ORDER==BIG_ENDIAN
1.1252 + aligncell(&dbgsym.address);
1.1253 + align16(&dbgsym.tag);
1.1254 + aligncell(&dbgsym.codestart);
1.1255 + aligncell(&dbgsym.codeend);
1.1256 + align16(&dbgsym.dim);
1.1257 + #endif
1.1258 + writeerror |= !pc_writebin(fout,&dbgsym,offsetof(AMX_DBG_SYMBOL, name));
1.1259 + writeerror |= !pc_writebin(fout,symname,strlen(symname)+1);
1.1260 + for (dim=0; dim<dbgsymdim; dim++) {
1.1261 + #if BYTE_ORDER==BIG_ENDIAN
1.1262 + align16(&dbgidxtag[dim].tag);
1.1263 + aligncell(&dbgidxtag[dim].size);
1.1264 + #endif
1.1265 + writeerror |= !pc_writebin(fout,&dbgidxtag[dim],sizeof dbgidxtag[dim]);
1.1266 + } /* for */
1.1267 + } /* if */
1.1268 + } /* for */
1.1269 +
1.1270 + /* tag table */
1.1271 + for (constptr=tagname_tab.next; constptr!=NULL; constptr=constptr->next) {
1.1272 + assert(strlen(constptr->name)>0);
1.1273 + id1=(int16_t)(constptr->value & TAGMASK);
1.1274 + #if BYTE_ORDER==BIG_ENDIAN
1.1275 + align16(&id1);
1.1276 + #endif
1.1277 + writeerror |= !pc_writebin(fout,&id1,sizeof id1);
1.1278 + writeerror |= !pc_writebin(fout,constptr->name,strlen(constptr->name)+1);
1.1279 + } /* for */
1.1280 +
1.1281 + /* automaton table */
1.1282 + for (constptr=sc_automaton_tab.next; constptr!=NULL; constptr=constptr->next) {
1.1283 + assert(constptr->index==0 && strlen(constptr->name)==0 || strlen(constptr->name)>0);
1.1284 + id1=(int16_t)constptr->index;
1.1285 + address=(ucell)constptr->value;
1.1286 + #if BYTE_ORDER==BIG_ENDIAN
1.1287 + align16(&id1);
1.1288 + aligncell(&address);
1.1289 + #endif
1.1290 + writeerror |= !pc_writebin(fout,&id1,sizeof id1);
1.1291 + writeerror |= !pc_writebin(fout,&address,sizeof address);
1.1292 + writeerror |= !pc_writebin(fout,constptr->name,strlen(constptr->name)+1);
1.1293 + } /* for */
1.1294 +
1.1295 + /* state table */
1.1296 + for (constptr=sc_state_tab.next; constptr!=NULL; constptr=constptr->next) {
1.1297 + assert(strlen(constptr->name)>0);
1.1298 + id1=(int16_t)constptr->value;
1.1299 + id2=(int16_t)constptr->index;
1.1300 + address=(ucell)constptr->value;
1.1301 + #if BYTE_ORDER==BIG_ENDIAN
1.1302 + align16(&id1);
1.1303 + align16(&id2);
1.1304 + #endif
1.1305 + writeerror |= !pc_writebin(fout,&id1,sizeof id1);
1.1306 + writeerror |= !pc_writebin(fout,&id2,sizeof id2);
1.1307 + writeerror |= !pc_writebin(fout,constptr->name,strlen(constptr->name)+1);
1.1308 + } /* for */
1.1309 +
1.1310 + delete_dbgstringtable();
1.1311 +}