static void write_encoded(FILE *fbin,ucell *c,int num) { #if PAWN_CELL_SIZE == 16 #define ENC_MAX 3 /* a 16-bit cell is encoded in max. 3 bytes */ #define ENC_MASK 0x03 /* after 2x7 bits, 2 bits remain to make 16 bits */ #elif PAWN_CELL_SIZE == 32 #define ENC_MAX 5 /* a 32-bit cell is encoded in max. 5 bytes */ #define ENC_MASK 0x0f /* after 4x7 bits, 4 bits remain to make 32 bits */ #elif PAWN_CELL_SIZE == 64 #define ENC_MAX 10 /* a 32-bit cell is encoded in max. 10 bytes */ #define ENC_MASK 0x01 /* after 9x7 bits, 1 bit remains to make 64 bits */ #endif assert(fbin!=NULL); while (num-->0) { if (pc_compress) { ucell p=(ucell)*c; unsigned char t[ENC_MAX]; unsigned char code; int index; for (index=0; index<ENC_MAX; index++) { t[index]=(unsigned char)(p & 0x7f); /* store 7 bits */ p>>=7; } /* for */ /* skip leading zeros */ while (index>1 && t[index-1]==0 && (t[index-2] & 0x40)==0) index--; /* skip leading -1s */ if (index==ENC_MAX && t[index-1]==ENC_MASK && (t[index-2] & 0x40)!=0) index--; while (index>1 && t[index-1]==0x7f && (t[index-2] & 0x40)!=0) index--; /* write high byte first, write continuation bits */ assert(index>0); while (index-->0) { code=(unsigned char)((index==0) ? t[index] : (t[index]|0x80)); writeerror |= !pc_writebin(fbin,&code,1); bytes_out++; } /* while */ bytes_in+=sizeof *c; assert(AMX_COMPACTMARGIN>2); if (bytes_out-bytes_in>=AMX_COMPACTMARGIN-2) longjmp(compact_err,1); } else { assert((pc_lengthbin(fbin) % sizeof(cell)) == 0); writeerror |= !pc_writebin(fbin,aligncell(c),sizeof *c); } /* if */ c++; } /* while */
static void write_cell(FILE *fbin,ucell c) { assert(fbin!=NULL); assert((pc_lengthbin(fbin) % pc_cellsize) == 0); if (pc_cryptkey!=0) { uint32_t *ptr=(uint32_t*)&c; assert(pc_cellsize==4 || pc_cellsize==8); *ptr=KeeLoq_Encrypt(*ptr,pc_cryptkey); if (pc_cellsize==8) { ptr++; *ptr=KeeLoq_Encrypt(*ptr,pc_cryptkey); } /* if */ } /* if */ writeerror |= !pc_writebin(fbin,aligncell(&c),pc_cellsize); }
SC_FUNC int assemble(FILE *fout,FILE *fin) { AMX_HEADER hdr; AMX_FUNCSTUB func; int numpublics,numnatives,numoverlays,numlibraries,numpubvars,numtags; int padding; long nametablesize,nameofs; char line[512]; char *instr,*params; int i,pass,size; int16_t count; symbol *sym; symbol **nativelist; constvalue *constptr; cell mainaddr; char nullchar; #if !defined NDEBUG /* verify that the opcode list is sorted (skip entry 1; it is reserved * for a non-existant opcode) */ { #define MAX_OPCODE 176 unsigned char opcodearray[MAX_OPCODE+1]; assert(opcodelist[1].name!=NULL); memset(opcodearray,0,sizeof opcodearray); for (i=2; i<(sizeof opcodelist / sizeof opcodelist[0]); i++) { assert(opcodelist[i].name!=NULL); assert(stricmp(opcodelist[i].name,opcodelist[i-1].name)>0); /* also verify that no opcode number appears twice */ assert((int)opcodelist[i].opcode<=MAX_OPCODE); assert(opcodelist[i].opcode==0 || opcodearray[(int)opcodelist[i].opcode]==0); opcodearray[(int)opcodelist[i].opcode] += 1; } /* for */ } #endif writeerror=FALSE; nametablesize=sizeof(int16_t); numpublics=0; numnatives=0; numpubvars=0; numoverlays=0; mainaddr=-1; /* count number of public and native functions and public variables */ for (sym=glbtab.next; sym!=NULL; sym=sym->next) { int match=0; if (sym->ident==iFUNCTN) { if ((sym->usage & uNATIVE)!=0 && (sym->usage & uREAD)!=0 && sym->index>=0) match=++numnatives; if ((sym->usage & uPUBLIC)!=0 && (sym->usage & uDEFINE)!=0) match=++numpublics; if (pc_overlays>0 && (sym->usage & uNATIVE)==0 && (sym->usage & (uREAD | uPUBLIC))!=0 && (sym->usage & uDEFINE)!=0) { if (strcmp(sym->name,uENTRYFUNC)!=0) ++numoverlays; /* there is no stub function for state entry functions */ if (sym->states!=NULL) { /* for functions with states, write an overlay block for every implementation */ statelist *stlist; for (stlist=sym->states->next; stlist!=NULL; stlist=stlist->next) ++numoverlays; } /* if */ } /* if */ if (strcmp(sym->name,uMAINFUNC)==0) { assert(sym->vclass==sGLOBAL); mainaddr=(pc_overlays>0) ? sym->index : sym->addr; } /* if */ } else if (sym->ident==iVARIABLE) { if ((sym->usage & uPUBLIC)!=0 && (sym->usage & (uREAD | uWRITTEN))!=0) match=++numpubvars; } /* if */ if (match) { char alias[sNAMEMAX+1]; assert(sym!=NULL); if ((sym->usage & uNATIVE)==0 || !lookup_alias(alias,sym->name)) { assert(strlen(sym->name)<=sNAMEMAX); strcpy(alias,sym->name); } /* if */ nametablesize+=(int)strlen(alias)+1; } /* if */ } /* for */ assert(numnatives==ntv_funcid); /* count number of libraries */ numlibraries=0; if (pc_addlibtable) { for (constptr=libname_tab.next; constptr!=NULL; constptr=constptr->next) { if (constptr->value>0) { assert(strlen(constptr->name)>0); numlibraries++; nametablesize+=(int)strlen(constptr->name)+1; } /* if */ } /* for */ } /* if */ /* count number of public tags */ numtags=0; for (constptr=tagname_tab.next; constptr!=NULL; constptr=constptr->next) { if ((constptr->value & PUBLICTAG)!=0) { assert(strlen(constptr->name)>0); numtags++; nametablesize+=(int)strlen(constptr->name)+1; } /* if */ } /* for */ /* adjust the number of overlays by the special overlays */ if (pc_overlays>0) for (i=0; i<ovlFIRST; i++) if (pc_ovl0size[i][1]!=0) numoverlays++; /* pad the header to sc_dataalign * => thereby the code segment is aligned * => since the code segment is padded to a sc_dataalign boundary, the data segment is aligned * => and thereby the stack top is aligned too */ assert(sc_dataalign!=0); padding= (int)(sc_dataalign - (sizeof hdr + nametablesize) % sc_dataalign); if (padding==sc_dataalign) padding=0; /* write the abstract machine header */ memset(&hdr, 0, sizeof hdr); if (pc_cellsize==2) hdr.magic=(unsigned short)AMX_MAGIC_16; else if (pc_cellsize==4) hdr.magic=(unsigned short)AMX_MAGIC_32; else if (pc_cellsize==8) hdr.magic=(unsigned short)AMX_MAGIC_64; hdr.file_version=CUR_FILE_VERSION; hdr.amx_version=MIN_AMX_VERSION; hdr.flags=(short)(sc_debug & sSYMBOLIC); if (sc_debug==0) hdr.flags|=AMX_FLAG_NOCHECKS; if (pc_memflags & suSLEEP_INSTR) hdr.flags|=AMX_FLAG_SLEEP; if (pc_overlays>0) hdr.flags|=AMX_FLAG_OVERLAY; if (pc_cryptkey!=0) hdr.flags|=AMX_FLAG_CRYPT; hdr.defsize=sizeof(AMX_FUNCSTUB); hdr.publics=sizeof hdr; /* public table starts right after the header */ hdr.natives=hdr.publics + numpublics*sizeof(AMX_FUNCSTUB); hdr.libraries=hdr.natives + numnatives*sizeof(AMX_FUNCSTUB); hdr.pubvars=hdr.libraries + numlibraries*sizeof(AMX_FUNCSTUB); hdr.tags=hdr.pubvars + numpubvars*sizeof(AMX_FUNCSTUB); hdr.overlays=hdr.tags + numtags*sizeof(AMX_FUNCSTUB); hdr.nametable=hdr.overlays + numoverlays*sizeof(AMX_OVERLAYINFO); hdr.cod=hdr.nametable + nametablesize + padding; hdr.dat=(int32_t)(hdr.cod + code_idx); hdr.hea=(int32_t)(hdr.dat + glb_declared*pc_cellsize); hdr.stp=(int32_t)(hdr.hea + pc_stksize*pc_cellsize); hdr.cip=(int32_t)(mainaddr); hdr.size=hdr.hea; pc_writebin(fout,&hdr,sizeof hdr); /* dump zeros up to the rest of the header, so that we can easily "seek" */ nullchar='\0'; for (nameofs=sizeof hdr; nameofs<hdr.cod; nameofs++) pc_writebin(fout,&nullchar,1); nameofs=hdr.nametable+sizeof(int16_t); /* write the public functions table */ count=0; for (sym=glbtab.next; sym!=NULL; sym=sym->next) { if (sym->ident==iFUNCTN && (sym->usage & uPUBLIC)!=0 && (sym->usage & uDEFINE)!=0) { assert(sym->vclass==sGLOBAL); /* in the case of overlays, write the overlay index rather than the address */ func.address=(uint32_t)((pc_overlays>0) ? sym->index : sym->addr); func.nameofs=nameofs; #if BYTE_ORDER==BIG_ENDIAN align32(&func.address); align32(&func.nameofs); #endif pc_resetbin(fout,hdr.publics+count*sizeof(AMX_FUNCSTUB)); pc_writebin(fout,&func,sizeof func); pc_resetbin(fout,nameofs); pc_writebin(fout,sym->name,(int)strlen(sym->name)+1); nameofs+=(int)strlen(sym->name)+1; count++; } /* if */ } /* for */ /* write the natives table */ /* The native functions must be written in sorted order. (They are * sorted on their "id", not on their name). A nested loop to find * each successive function would be an O(n^2) operation. But we * do not really need to sort, because the native function id's * are sequential and there are no duplicates. So we first walk * through the complete symbol list and store a pointer to every * native function of interest in a temporary table, where its id * serves as the index in the table. Now we can walk the table and * have all native functions in sorted order. */ if (numnatives>0) { nativelist=(symbol **)malloc(numnatives*sizeof(symbol *)); if (nativelist==NULL) error(103); /* insufficient memory */ #if !defined NDEBUG memset(nativelist,0,numnatives*sizeof(symbol *)); /* for NULL checking */ #endif for (sym=glbtab.next; sym!=NULL; sym=sym->next) { if (sym->ident==iFUNCTN && (sym->usage & uNATIVE)!=0 && (sym->usage & uREAD)!=0 && sym->index>=0) { assert(sym->index < numnatives); nativelist[(int)sym->index]=sym; } /* if */ } /* for */ count=0; for (i=0; i<numnatives; i++) { char alias[sNAMEMAX+1]; sym=nativelist[i]; assert(sym!=NULL); if (!lookup_alias(alias,sym->name)) { assert(strlen(sym->name)<=sNAMEMAX); strcpy(alias,sym->name); } /* if */ assert(sym->vclass==sGLOBAL); func.address=0; func.nameofs=nameofs; #if BYTE_ORDER==BIG_ENDIAN align32(&func.address); align32(&func.nameofs); #endif pc_resetbin(fout,hdr.natives+count*sizeof(AMX_FUNCSTUB)); pc_writebin(fout,&func,sizeof func); pc_resetbin(fout,nameofs); pc_writebin(fout,alias,(int)strlen(alias)+1); nameofs+=(int)strlen(alias)+1; count++; } /* for */ free(nativelist); } /* if */ /* write the libraries table */ if (pc_addlibtable) { count=0; for (constptr=libname_tab.next; constptr!=NULL; constptr=constptr->next) { if (constptr->value>0) { assert(strlen(constptr->name)>0); func.address=0; func.nameofs=nameofs; #if BYTE_ORDER==BIG_ENDIAN align32(&func.address); align32(&func.nameofs); #endif pc_resetbin(fout,hdr.libraries+count*sizeof(AMX_FUNCSTUB)); pc_writebin(fout,&func,sizeof func); pc_resetbin(fout,nameofs); pc_writebin(fout,constptr->name,(int)strlen(constptr->name)+1); nameofs+=(int)strlen(constptr->name)+1; count++; } /* if */ } /* for */ } /* if */ /* write the public variables table */ count=0; for (sym=glbtab.next; sym!=NULL; sym=sym->next) { if (sym->ident==iVARIABLE && (sym->usage & uPUBLIC)!=0 && (sym->usage & (uREAD | uWRITTEN))!=0) { assert((sym->usage & uDEFINE)!=0); assert(sym->vclass==sGLOBAL); func.address=(uint32_t)sym->addr; func.nameofs=nameofs; #if BYTE_ORDER==BIG_ENDIAN align32(&func.address); align32(&func.nameofs); #endif pc_resetbin(fout,hdr.pubvars+count*sizeof(AMX_FUNCSTUB)); pc_writebin(fout,&func,sizeof func); pc_resetbin(fout,nameofs); pc_writebin(fout,sym->name,(int)strlen(sym->name)+1); nameofs+=(int)strlen(sym->name)+1; count++; } /* if */ } /* for */ /* write the public tagnames table */ count=0; for (constptr=tagname_tab.next; constptr!=NULL; constptr=constptr->next) { if ((constptr->value & PUBLICTAG)!=0) { assert(strlen(constptr->name)>0); func.address=(uint32_t)(constptr->value & TAGMASK); func.nameofs=nameofs; #if BYTE_ORDER==BIG_ENDIAN align32(&func.address); align32(&func.nameofs); #endif pc_resetbin(fout,hdr.tags+count*sizeof(AMX_FUNCSTUB)); pc_writebin(fout,&func,sizeof func); pc_resetbin(fout,nameofs); pc_writebin(fout,constptr->name,(int)strlen(constptr->name)+1); nameofs+=(int)strlen(constptr->name)+1; count++; } /* if */ } /* for */ /* write the "maximum name length" field in the name table */ assert(nameofs==hdr.nametable+nametablesize); pc_resetbin(fout,hdr.nametable); count=sNAMEMAX; #if BYTE_ORDER==BIG_ENDIAN align16(&count); #endif pc_writebin(fout,&count,sizeof count); /* write the overlay table */ if (pc_overlays>0) { AMX_OVERLAYINFO info; #if !defined NDEBUG int count=0; #endif pc_resetbin(fout,hdr.overlays); /* first the special overlay(s) for the return point(s) */ for (i=0; i<ovlFIRST; i++) { if (pc_ovl0size[i][1]!=0) { info.offset=pc_ovl0size[i][0]; info.size=pc_ovl0size[i][1]; #if BYTE_ORDER==BIG_ENDIAN align32(&info.offset); align32(&info.size); #endif pc_writebin(fout,&info,sizeof info); #if !defined NDEBUG count++; #endif } /* if */ } /* for */ /* now all real overlay functions */ for (sym=glbtab.next; sym!=NULL; sym=sym->next) { if (sym->ident==iFUNCTN && (sym->usage & uNATIVE)==0 && (sym->usage & (uREAD | uPUBLIC))!=0 && (sym->usage & uDEFINE)!=0) { assert(sym->vclass==sGLOBAL); assert(strcmp(sym->name,uENTRYFUNC)==0 || sym->index==count++);/* overlay indices must be in sequential order */ assert(strcmp(sym->name,uENTRYFUNC)==0 || sym->addr<sym->codeaddr); /* write the overlay for the stub function first */ if (strcmp(sym->name,uENTRYFUNC)!=0) { /* there is no stub function for state entry functions */ info.offset=(int32_t)sym->addr; info.size=(uint32_t)(sym->codeaddr - sym->addr); #if BYTE_ORDER==BIG_ENDIAN align32(&info.offset); align32(&info.size); #endif pc_writebin(fout,&info,sizeof info); } /* if */ if (sym->states!=NULL) { /* for functions with states, write an overlay block for every implementation */ statelist *stlist; for (stlist=sym->states->next; stlist!=NULL; stlist=stlist->next) { assert(stlist->label==count++); info.offset=(int32_t)stlist->addr; info.size=(int32_t)(stlist->endaddr - stlist->addr); #if BYTE_ORDER==BIG_ENDIAN align32(&info.offset); align32(&info.size); #endif pc_writebin(fout,&info,sizeof info); } /* for */ } /* if */ } /* if */ } /* for */ } /* if */ pc_resetbin(fout,hdr.cod); /* First pass: relocate all labels */ /* This pass is necessary because the code addresses of labels is only known * after the peephole optimization flag. Labels can occur inside expressions * (e.g. the conditional operator), which are optimized. */ lbltab=NULL; if (sc_labnum>0) { cell codeindex=0; /* address of the current opcode similar to "code_idx" */ /* only very short programs have zero labels; no first pass is needed * if there are no labels */ lbltab=(cell *)malloc(sc_labnum*sizeof(cell)); if (lbltab==NULL) error(103); /* insufficient memory */ memset(lbltab,0,sc_labnum*sizeof(cell)); pc_resetasm(fin); while (pc_readasm(fin,line,sizeof line)!=NULL) { stripcomment(line); instr=skipwhitespace(line); /* ignore empty lines */ if (*instr=='\0') continue; if (tolower(*instr)=='l' && *(instr+1)=='.') { int lindex=(int)hex2ucell(instr+2,NULL); assert(lindex>=0 && lindex<sc_labnum); assert(lbltab[lindex]==0); /* should not already be declared */ lbltab[lindex]=codeindex; } else { /* get to the end of the instruction (make use of the '\n' that fgets() * added at the end of the line; this way we will *always* drop on a * whitespace character) */ for (params=instr; *params!='\0' && !isspace(*params); params++) /* nothing */; assert(params>instr); i=findopcode(instr,(int)(params-instr)); assert(opcodelist[i].name!=NULL); assert(opcodelist[i].opt_level<=pc_optimize || pc_optimize==0 && opcodelist[i].opt_level<=1); if (opcodelist[i].segment==sIN_CSEG) codeindex+=opcodelist[i].func(NULL,skipwhitespace(params),opcodelist[i].opcode,codeindex); } /* if */ } /* while */ } /* if */ /* Second pass (actually 2 more passes, one for all code and one for all data) */ for (pass=sIN_CSEG; pass<=sIN_DSEG; pass++) { cell codeindex=0; /* address of the current opcode similar to "code_idx" */ pc_resetasm(fin); while (pc_readasm(fin,line,sizeof line)!=NULL) { stripcomment(line); instr=skipwhitespace(line); /* ignore empty lines and labels (labels have a special syntax, so these * must be parsed separately) */ if (*instr=='\0' || tolower(*instr)=='l' && *(instr+1)=='.') continue; /* get to the end of the instruction (make use of the '\n' that fgets() * added at the end of the line; this way we will *always* drop on a * whitespace character) */ for (params=instr; *params!='\0' && !isspace(*params); params++) /* nothing */; assert(params>instr); i=findopcode(instr,(int)(params-instr)); assert(opcodelist[i].name!=NULL); assert(opcodelist[i].opt_level<=pc_optimize || pc_optimize==0 && opcodelist[i].opt_level<=1); if (opcodelist[i].segment==pass) codeindex+=opcodelist[i].func(fout,skipwhitespace(params),opcodelist[i].opcode,codeindex); } /* while */ } /* for */ if (lbltab!=NULL) { free(lbltab); #if !defined NDEBUG lbltab=NULL; #endif } /* if */ assert(hdr.size==pc_lengthbin(fout)); if (!writeerror && (sc_debug & sSYMBOLIC)!=0) append_dbginfo(fout); /* optionally append debug file */ if (writeerror) error(101,"disk full"); /* adjust the header (for Big Endian architectures) */ size=(int)hdr.cod; /* save, the value in the header may need to be swapped */ #if BYTE_ORDER==BIG_ENDIAN align32(&hdr.size); align16(&hdr.magic); align16(&hdr.flags); align16(&hdr.defsize); align32(&hdr.publics); align32(&hdr.natives); align32(&hdr.libraries); align32(&hdr.pubvars); align32(&hdr.tags); align32(&hdr.nametable); align32(&hdr.cod); align32(&hdr.dat); align32(&hdr.hea); align32(&hdr.stp); align32(&hdr.cip); pc_resetbin(fout,0); pc_writebin(fout,&hdr,sizeof hdr); #endif /* return the size of the header (including name tables, but excluding code * or data sections) */ return size; }