home *** CD-ROM | disk | FTP | other *** search
/ Amiga ACS 1998 #4 / amigaacscoverdisc1998-041998.iso / utilities / shareware / dev / vbcc / pasm / pass.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-02-17  |  12.6 KB  |  474 lines

  1. /* $VER: pasm pass.c V0.8 (14.02.98)
  2.  *
  3.  * This file is part of pasm, a portable PowerPC assembler.
  4.  * Copyright (c) 1997-98  Frank Wille
  5.  *
  6.  * pasm is freeware and part of the portable and retargetable ANSI C
  7.  * compiler vbcc, copyright (c) 1995-98 by Volker Barthelmann.
  8.  * pasm may be freely redistributed as long as no modifications are
  9.  * made and nothing is charged for it. Non-commercial usage is allowed
  10.  * without any restrictions.
  11.  * EVERY PRODUCT OR PROGRAM DERIVED DIRECTLY FROM MY SOURCE MAY NOT BE
  12.  * SOLD COMMERCIALLY WITHOUT PERMISSION FROM THE AUTHOR.
  13.  *
  14.  *
  15.  * v0.8 (14.02.98) phx
  16.  *      Alignment list for each section. This fixes the problems
  17.  *      with optimizations.
  18.  * v0.7 (02.01.98) phx
  19.  *      Allow more than two assembler passes, as required for
  20.  *      optimizations.
  21.  * v0.6 (26.10.97) phx
  22.  *      Bug in conditional assembly fixed.
  23.  *      @object and @function symbols are always defined before
  24.  *      pass 1 is executed.
  25.  * v0.5 (12.10.97) phx
  26.  *      Support for user symbol definitions by -D option.
  27.  *      The opcode field is automatically converted to lower case,
  28.  *      so upper case directives and instructions are also allowed.
  29.  * v0.3 (10.04.97) phx
  30.  *      Some vbcc-specific changes.
  31.  * v0.2 (25.03.97) phx
  32.  *      Writes ELF object for 32-bit PowerPC big-endian. Either absolute
  33.  *      or ELF output format may be selected. ELF is default for all
  34.  *      currently supported platforms. PPCasm supports nine different
  35.  *      relocation types (there are much more...).
  36.  *      Compiles and works also under NetBSD/amiga (68k).
  37.  *      Changed function declaration to 'new style' in all sources
  38.  *      (to avoid problems with '...' for example).
  39.  * v0.1 (11.03.97) phx
  40.  *      First test version with all PowerPC instructions and most
  41.  *      important directives. Only raw, absolute output.
  42.  * v0.0 (15.02.97) phx
  43.  *      File created.
  44.  */
  45.  
  46.  
  47. #define PASS_C
  48. #include "ppcasm.h"
  49.  
  50.  
  51. void exec_pass1(struct GlobalVars *);
  52. void pass1(struct GlobalVars *,struct SourceText *,
  53.            struct MacroParams *,struct SourceThread *);
  54. struct SourceText *include_source(struct GlobalVars *,char *);
  55. void exec_pass2(struct GlobalVars *);
  56. void pass2(struct GlobalVars *,struct SourceText *,
  57.            struct MacroParams *,struct SourceThread *);
  58. struct SourceText *get_source(struct GlobalVars *);
  59.  
  60. static char *insert_macro_params(struct GlobalVars *,struct ParsedLine *,
  61.                                  char *,struct MacroParams *);
  62. static char *readline(struct GlobalVars *,struct ParsedLine *,char *);
  63. static char *getlabel(struct GlobalVars *,char *);
  64. static struct SourceText *add_source(struct GlobalVars *,char *,char *,long);
  65. static void prepare_sections(struct GlobalVars *);
  66.  
  67.  
  68.  
  69. void exec_pass1(struct GlobalVars *gv)
  70. {
  71.   struct Symbol *sym;
  72.   char asmname[20];
  73.   char **p,*xmnemobuf,*usrdefbuf;
  74.   size_t xmsize=0,udsize=0;
  75.   struct UserDefine *nextudn;
  76.   struct UserDefine *udn = (struct UserDefine *)gv->userdeflist.first;
  77.   struct Section dummySec;
  78.  
  79.   sprintf(asmname,PNAME "_V%d.%02d",VERSION,REVISION);
  80.   memset(&dummySec,0,sizeof(struct Section));
  81.   gv->csect = &dummySec;  /* to avoid SEGVs during start up */
  82.   sym = add_symbol(gv,asmname,SYM_ABS,0);
  83.   sym->bind = SYMB_LOCAL;
  84.   gv->lcsym = add_symbol(gv,"$",SYM_RELOC,0);
  85.   gv->nargsym = add_symbol(gv,"$NARG",SYM_ABS,0);
  86.   add_symbol(gv,"@object",SYM_ABS,1);
  87.   add_symbol(gv,"@function",SYM_ABS,2);
  88.   gv->ifcond[0] = TRUE;
  89.  
  90.   pass1(gv,add_source(gv,"<standard sections>",stdsects,
  91.         strlen(stdsects)),NULL,NULL);
  92.  
  93.   if (!gv->noregsymbols)
  94.     pass1(gv,add_source(gv,"<standard definitions>",stdsets,
  95.           strlen(stdsets)),NULL,NULL);
  96.  
  97.   while (nextudn = (struct UserDefine *)udn->n.next) {
  98.     udsize += strlen(udn->line);
  99.     udn = nextudn;
  100.   }
  101.   if (udsize) {
  102.     usrdefbuf = alloc(udsize+1);
  103.     *usrdefbuf = 0;
  104.     while (udn = (struct UserDefine *)remhead(&gv->userdeflist)) {
  105.       strcat(usrdefbuf,udn->line);
  106.       free(udn->line);
  107.       free(udn);
  108.     }
  109.     gv->usrdefs = TRUE;
  110.     pass1(gv,add_source(gv,"<user definitions>",usrdefbuf,udsize),
  111.           NULL,NULL);
  112.   }
  113.  
  114.   if (!gv->noextmnemo) {
  115.     p = xmnemos;
  116.     while (*p) {
  117.       xmsize += strlen(*p);
  118.       p++;
  119.     }
  120.     xmnemobuf = alloc(xmsize+1);
  121.     *xmnemobuf = 0;
  122.     p = xmnemos;
  123.     while (*p) {
  124.       strcat(xmnemobuf,*p);
  125.       p++;
  126.     }
  127.     pass1(gv,add_source(gv,"<extended mnemonics>",xmnemobuf,xmsize),
  128.           NULL,NULL);
  129.   }
  130.  
  131.   pass1(gv,include_source(gv,gv->source_name),NULL,NULL);
  132.   if (gv->vc) {
  133.     activate_section(gv,(struct Section *)gv->sectionlist.first);
  134.     alignment(gv,2);
  135.     pcadd(gv,4);
  136.   }
  137. }
  138.  
  139.  
  140. void pass1(struct GlobalVars *gv,struct SourceText *srctxt,
  141.            struct MacroParams *macro,struct SourceThread *prev_st)
  142. /* Assembler Pass 1 */
  143. {
  144.   struct SourceThread st;
  145.   unsigned long nlines = srctxt->nlines;
  146.   char *lp,c;
  147.   struct ParsedLine *pl = srctxt->plin;
  148.  
  149.   /* init SourceThread structure */
  150.   st.prev = prev_st;
  151.   st.macro = macro;
  152.   st.csource = srctxt;
  153.   st.srcptr = srctxt->text;  /* current source pointer */
  154.   st.line = 1;
  155.   st.macskip = NULL;
  156.   gv->cthread = &st;  /* set current source thread */
  157.  
  158.   while (nlines--) {
  159.     gv->absline++;
  160.     pl->lineptr = st.lineptr = st.srcptr;
  161.  
  162.     /* get next line of source text */
  163.     if (macro && gv->ifcond[gv->iflevel]) {  /* insert macro parameters? */
  164.       st.srcptr = insert_macro_params(gv,pl,st.srcptr,macro);
  165.     }
  166.     else {
  167.       st.srcptr = readline(gv,pl,st.srcptr);
  168.     }
  169.     lp = gv->linebuf;
  170.  
  171.     /* evaluate label field */
  172.     lp = getlabel(gv,lp);
  173.     if (*gv->strbuf)
  174.       if (!st.macskip && gv->ifcond[gv->iflevel])
  175.         add_symbol(gv,gv->strbuf,SYM_RELOC,gv->csect->pc);
  176.     lp = skipspaces(lp);
  177.  
  178.     /* evaluate opcode field */
  179.     lp = getsymbol(gv,lp);
  180.     if (*gv->strbuf) {
  181.       lower_case(gv->strbuf);  /* convert opcode to lower case */
  182.  
  183.       if (st.macskip) {  /* macros */
  184.         if (!strcmp(gv->strbuf,".endm")) {
  185.           st.macskip->nlines = gv->absline - st.macskip->nlines;
  186.           add_macro(gv,st.macskip);
  187.           st.macskip = NULL;
  188.         }
  189.       }
  190.  
  191.       else if (!gv->ifcond[gv->iflevel]) {  /* conditional assembly */
  192.         if (!strncmp(gv->strbuf,".if",3))
  193.           gv->ifignore++;
  194.         else if (!strcmp(gv->strbuf,".else")) {
  195.           if (gv->ifignore == 0)
  196.             gv->ifcond[gv->iflevel] = TRUE;
  197.         }
  198.         else if (!strcmp(gv->strbuf,".endif")) {
  199.           if (gv->ifignore)
  200.             gv->ifignore--;
  201.           else
  202.             gv->iflevel--;
  203.         }
  204.       }
  205.  
  206.       else {  /* search opcode */
  207.         c = *lp;  /* branch hint given? */
  208.         if (c=='+') {
  209.           lp++;
  210.           pl->branch_hint = 1;
  211.         }
  212.         else if (c=='-') {
  213.           lp++;
  214.           pl->branch_hint = -1;
  215.         }
  216.         search_opcode(gv,pl,gv->strbuf,skipspaces(lp));
  217.       }
  218.     }
  219.  
  220.     if (!(pl->flags&PLF_NONEWLINE))
  221.       st.line++;
  222.     ++pl;
  223.   }
  224.   gv->cthread = prev_st;
  225. }
  226.  
  227.  
  228. static char *insert_macro_params(struct GlobalVars *gv,struct ParsedLine *pl,
  229.                                  char *s,struct MacroParams *mp)
  230. {
  231.   char **par = mp->param;
  232.   char c,callidbuf[16];
  233.   char *pp,*d=gv->linebuf;
  234.   int n;
  235.  
  236.   do {
  237.     if ((c=*s++) == '\\') {
  238.       if (*s>='0' && *s<='9') {  /* macro parameter? */
  239.         n = (int)(*s++ - '0');
  240.         if (pp = par[n]) {
  241.           while (*d++ = *pp++);  /* insert parameter */
  242.           d--;
  243.           continue;
  244.         }
  245.         else {
  246.           error(9,n);  /* reference to undefined macro parameter n */
  247.           continue;
  248.         }
  249.       }
  250.       else if (*s=='@') {  /* insert macro call id */
  251.         s++;
  252.         pp = callidbuf;
  253.         sprintf(pp,"$%d",(int)mp->call_id);
  254.         while (*d++ = *pp++);
  255.         d--;
  256.         continue;
  257.       }
  258.     }
  259.     *d++ = c;
  260.   }
  261.   while (c!=0 && c!=1);
  262.   if (c==1) {
  263.     *(--d) = 0;
  264.     pl->flags |= PLF_NONEWLINE;
  265.   }
  266.   return (s);
  267. }
  268.  
  269.  
  270. static char *readline(struct GlobalVars *gv,struct ParsedLine *pl,char *s)
  271. {
  272.   char c,*d = gv->linebuf;
  273.  
  274.   do {
  275.     c = *s++;
  276.     *d++ = c;
  277.   }
  278.   while (c!=0 && c!=1);
  279.   if (c==1) {
  280.     *(--d) = 0;
  281.     pl->flags |= PLF_NONEWLINE;
  282.   }
  283.   return (s);
  284. }
  285.  
  286.  
  287. static char *getlabel(struct GlobalVars *gv,char *s)
  288. /* read label to gv->strbuf, s points to the beginning of a line */
  289. {
  290.   char *s_old = s;
  291.  
  292.   s = getsymbol(gv,s);  /* read label to buffer */
  293.   if ((s != s_old) && (*s == ':'))  /* colon indicates a valid label */
  294.     return (++s);
  295.   *gv->strbuf = 0;
  296.   return (s_old);
  297. }
  298.  
  299.  
  300. struct SourceText *include_source(struct GlobalVars *gv,char *name)
  301. /* called when encountering an .include directive */
  302. {
  303.   char *s = mapfile(gv,name);
  304.   long len = *(size_t *)(s - sizeof(size_t));  /* mapfile stores size here */
  305.  
  306.   return (add_source(gv,name,s,len));
  307. }
  308.  
  309.  
  310. static struct SourceText *add_source(struct GlobalVars *gv,char *name,
  311.                                      char *s,  /* source text pointer */
  312.                                      long len) /* text length in bytes */
  313. /* create a new SourceText node and add it to the source list */
  314. {
  315.   struct SourceText *stxt = alloc(sizeof(struct SourceText));
  316.   bool comm=FALSE;
  317.   char quote=0;
  318.  
  319.   stxt->name = name;
  320.   stxt->text = s;
  321.   stxt->nlines = 0;
  322.  
  323.   /* replace '\n' and ';' by \0 and determine number of lines */
  324.   for (; len>0; len--,s++) {
  325.     switch (*s) {
  326.       case '\n':
  327.         *s = 0;
  328.         stxt->nlines++;
  329.         comm = FALSE;  /* \n ends a comment */
  330.         break;
  331.       case '\r':  /* ignore CRs */
  332.         *s = 0;
  333.         break;
  334.       case ';':   /* ';' allows multiple statements per line */
  335.         if (!comm && !quote) {
  336.           if (*(s+1)=='\n' || *(s+1)=='\r')
  337.             *s = ' ';
  338.           else {
  339.             *s = 1;
  340.             stxt->nlines++;
  341.           }
  342.         }
  343.         break;
  344.       case '#':   /* comment: ignore ';' in rest of line */
  345.         comm = TRUE;
  346.         break;
  347.       case 0x22:  /* ignore ';' in strings too */
  348.         if (quote==0x22)
  349.           quote = 0;
  350.         else if (!quote)
  351.           quote = 0x22;
  352.         break;
  353.       case 0x27:
  354.         if (quote==0x27)
  355.           quote = 0;
  356.         else if (!quote)
  357.           quote = 0x27;
  358.         break;
  359.     }
  360.   }
  361.  
  362.   stxt->plin = alloczero(stxt->nlines * sizeof(struct ParsedLine));
  363.   addtail(&gv->sourcelist,&stxt->n);
  364.   return (stxt);
  365. }
  366.  
  367.  
  368. static void prepare_sections(struct GlobalVars *gv)
  369. /* prepare sections for receiving code in pass 2 */
  370. {
  371.   struct Section *nexts,*sec=(struct Section *)gv->sectionlist.first;
  372.  
  373.   while (nexts = (struct Section *)sec->n.next) {
  374.     sec->size = sec->pc;
  375.     sec->pc = 0;
  376.     sec->current_align = sec->first_align;
  377.     if (!(sec->flags & SF_UNINITIALIZED))
  378.       if (sec->size)
  379.         sec->data = sec->contents = alloc((size_t)sec->size);
  380.     sec = nexts;
  381.   }
  382. }
  383.  
  384.  
  385. void exec_pass2(struct GlobalVars *gv)
  386. {
  387.   gv->absline = 0;
  388.   gv->pass++;
  389.   prepare_sections(gv);
  390.   gv->srctxtp = (struct SourceText *)gv->sourcelist.first;
  391.  
  392.   pass2(gv,get_source(gv),NULL,NULL);  /* <standard sections> */
  393.   if (!gv->noregsymbols)
  394.     pass2(gv,get_source(gv),NULL,NULL);  /* <standard definitions> */
  395.   if (gv->usrdefs)
  396.     pass2(gv,get_source(gv),NULL,NULL);  /* <user definitions> */
  397.   if (!gv->noextmnemo)
  398.     pass2(gv,get_source(gv),NULL,NULL);  /* <extended mnemonics> */
  399.  
  400.   pass2(gv,get_source(gv),NULL,NULL); 
  401.   if (gv->vc) {
  402.     activate_section(gv,(struct Section *)gv->sectionlist.first);
  403.     alignment(gv,2);
  404.     store_word(gv,0x76626363);
  405.   }
  406. }
  407.  
  408.  
  409. void pass2(struct GlobalVars *gv,struct SourceText *srctxt,
  410.            struct MacroParams *macro,struct SourceThread *prev_st)
  411. /* Assembler Pass 2 */
  412. {
  413.   struct SourceThread st;
  414.   unsigned long nlines = srctxt->nlines;
  415.   struct ParsedLine *pl = srctxt->plin;
  416.   struct ParsedLine *p;
  417.   uint32 oldnarg;
  418.  
  419.   /* init SourceThread structure */
  420.   st.prev = prev_st;
  421.   st.macro = macro;
  422.   st.csource = srctxt;
  423.   st.line = 1;
  424.   gv->cthread = &st;  /* set current source thread */
  425.  
  426.   while (nlines--) {
  427.     gv->absline++;
  428.     st.lineptr = pl->lineptr;
  429.     p = pl;
  430.  
  431.     do {
  432.       /* evaluate opcode field */
  433.       switch (p->type) {
  434.  
  435.         case OT_INSTRUCTION:
  436.           instr(gv,p);
  437.           break;
  438.  
  439.         case OT_DIRECTIVE:
  440.           (((struct Directive *)p->opcode)->dfunct)(gv,p);
  441.           break;
  442.  
  443.         case OT_MACRO:
  444.           oldnarg = gv->nargsym->value;
  445.           gv->nargsym->value = (uint32)p->narg;
  446.           pass2(gv,get_source(gv),(struct MacroParams *)gv,gv->cthread);
  447.           /* the MacroParams pointer is set to gv, because we */
  448.           /* only need a non-zero pointer here... */
  449.           gv->nargsym->value = oldnarg;
  450.           break;
  451.  
  452.         case OT_SECTION:
  453.           activate_section(gv,(struct Section *)p->opcode);
  454.           break;
  455.       }
  456.     }
  457.     while (p = p->next);
  458.  
  459.     if (!(pl->flags&PLF_NONEWLINE))
  460.       st.line++;
  461.     ++pl;
  462.   }
  463.   gv->cthread = prev_st;
  464. }
  465.  
  466.  
  467. struct SourceText *get_source(struct GlobalVars *gv)
  468. {
  469.   struct SourceText *st = gv->srctxtp;
  470.  
  471.   gv->srctxtp = (struct SourceText *)st->n.next;
  472.   return (st);
  473. }
  474.