示例#1
0
文件: sc6.c 项目: lukesalisbury/pawn
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 */
示例#2
0
文件: sc6.c 项目: diego3/scriptorium
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);
}
示例#3
0
文件: sc6.c 项目: diego3/scriptorium
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;
}