home *** CD-ROM | disk | FTP | other *** search
- /* $VER: pasm pass.c V0.8 (14.02.98)
- *
- * This file is part of pasm, a portable PowerPC assembler.
- * Copyright (c) 1997-98 Frank Wille
- *
- * pasm is freeware and part of the portable and retargetable ANSI C
- * compiler vbcc, copyright (c) 1995-98 by Volker Barthelmann.
- * pasm may be freely redistributed as long as no modifications are
- * made and nothing is charged for it. Non-commercial usage is allowed
- * without any restrictions.
- * EVERY PRODUCT OR PROGRAM DERIVED DIRECTLY FROM MY SOURCE MAY NOT BE
- * SOLD COMMERCIALLY WITHOUT PERMISSION FROM THE AUTHOR.
- *
- *
- * v0.8 (14.02.98) phx
- * Alignment list for each section. This fixes the problems
- * with optimizations.
- * v0.7 (02.01.98) phx
- * Allow more than two assembler passes, as required for
- * optimizations.
- * v0.6 (26.10.97) phx
- * Bug in conditional assembly fixed.
- * @object and @function symbols are always defined before
- * pass 1 is executed.
- * v0.5 (12.10.97) phx
- * Support for user symbol definitions by -D option.
- * The opcode field is automatically converted to lower case,
- * so upper case directives and instructions are also allowed.
- * v0.3 (10.04.97) phx
- * Some vbcc-specific changes.
- * v0.2 (25.03.97) phx
- * Writes ELF object for 32-bit PowerPC big-endian. Either absolute
- * or ELF output format may be selected. ELF is default for all
- * currently supported platforms. PPCasm supports nine different
- * relocation types (there are much more...).
- * Compiles and works also under NetBSD/amiga (68k).
- * Changed function declaration to 'new style' in all sources
- * (to avoid problems with '...' for example).
- * v0.1 (11.03.97) phx
- * First test version with all PowerPC instructions and most
- * important directives. Only raw, absolute output.
- * v0.0 (15.02.97) phx
- * File created.
- */
-
-
- #define PASS_C
- #include "ppcasm.h"
-
-
- void exec_pass1(struct GlobalVars *);
- void pass1(struct GlobalVars *,struct SourceText *,
- struct MacroParams *,struct SourceThread *);
- struct SourceText *include_source(struct GlobalVars *,char *);
- void exec_pass2(struct GlobalVars *);
- void pass2(struct GlobalVars *,struct SourceText *,
- struct MacroParams *,struct SourceThread *);
- struct SourceText *get_source(struct GlobalVars *);
-
- static char *insert_macro_params(struct GlobalVars *,struct ParsedLine *,
- char *,struct MacroParams *);
- static char *readline(struct GlobalVars *,struct ParsedLine *,char *);
- static char *getlabel(struct GlobalVars *,char *);
- static struct SourceText *add_source(struct GlobalVars *,char *,char *,long);
- static void prepare_sections(struct GlobalVars *);
-
-
-
- void exec_pass1(struct GlobalVars *gv)
- {
- struct Symbol *sym;
- char asmname[20];
- char **p,*xmnemobuf,*usrdefbuf;
- size_t xmsize=0,udsize=0;
- struct UserDefine *nextudn;
- struct UserDefine *udn = (struct UserDefine *)gv->userdeflist.first;
- struct Section dummySec;
-
- sprintf(asmname,PNAME "_V%d.%02d",VERSION,REVISION);
- memset(&dummySec,0,sizeof(struct Section));
- gv->csect = &dummySec; /* to avoid SEGVs during start up */
- sym = add_symbol(gv,asmname,SYM_ABS,0);
- sym->bind = SYMB_LOCAL;
- gv->lcsym = add_symbol(gv,"$",SYM_RELOC,0);
- gv->nargsym = add_symbol(gv,"$NARG",SYM_ABS,0);
- add_symbol(gv,"@object",SYM_ABS,1);
- add_symbol(gv,"@function",SYM_ABS,2);
- gv->ifcond[0] = TRUE;
-
- pass1(gv,add_source(gv,"<standard sections>",stdsects,
- strlen(stdsects)),NULL,NULL);
-
- if (!gv->noregsymbols)
- pass1(gv,add_source(gv,"<standard definitions>",stdsets,
- strlen(stdsets)),NULL,NULL);
-
- while (nextudn = (struct UserDefine *)udn->n.next) {
- udsize += strlen(udn->line);
- udn = nextudn;
- }
- if (udsize) {
- usrdefbuf = alloc(udsize+1);
- *usrdefbuf = 0;
- while (udn = (struct UserDefine *)remhead(&gv->userdeflist)) {
- strcat(usrdefbuf,udn->line);
- free(udn->line);
- free(udn);
- }
- gv->usrdefs = TRUE;
- pass1(gv,add_source(gv,"<user definitions>",usrdefbuf,udsize),
- NULL,NULL);
- }
-
- if (!gv->noextmnemo) {
- p = xmnemos;
- while (*p) {
- xmsize += strlen(*p);
- p++;
- }
- xmnemobuf = alloc(xmsize+1);
- *xmnemobuf = 0;
- p = xmnemos;
- while (*p) {
- strcat(xmnemobuf,*p);
- p++;
- }
- pass1(gv,add_source(gv,"<extended mnemonics>",xmnemobuf,xmsize),
- NULL,NULL);
- }
-
- pass1(gv,include_source(gv,gv->source_name),NULL,NULL);
- if (gv->vc) {
- activate_section(gv,(struct Section *)gv->sectionlist.first);
- alignment(gv,2);
- pcadd(gv,4);
- }
- }
-
-
- void pass1(struct GlobalVars *gv,struct SourceText *srctxt,
- struct MacroParams *macro,struct SourceThread *prev_st)
- /* Assembler Pass 1 */
- {
- struct SourceThread st;
- unsigned long nlines = srctxt->nlines;
- char *lp,c;
- struct ParsedLine *pl = srctxt->plin;
-
- /* init SourceThread structure */
- st.prev = prev_st;
- st.macro = macro;
- st.csource = srctxt;
- st.srcptr = srctxt->text; /* current source pointer */
- st.line = 1;
- st.macskip = NULL;
- gv->cthread = &st; /* set current source thread */
-
- while (nlines--) {
- gv->absline++;
- pl->lineptr = st.lineptr = st.srcptr;
-
- /* get next line of source text */
- if (macro && gv->ifcond[gv->iflevel]) { /* insert macro parameters? */
- st.srcptr = insert_macro_params(gv,pl,st.srcptr,macro);
- }
- else {
- st.srcptr = readline(gv,pl,st.srcptr);
- }
- lp = gv->linebuf;
-
- /* evaluate label field */
- lp = getlabel(gv,lp);
- if (*gv->strbuf)
- if (!st.macskip && gv->ifcond[gv->iflevel])
- add_symbol(gv,gv->strbuf,SYM_RELOC,gv->csect->pc);
- lp = skipspaces(lp);
-
- /* evaluate opcode field */
- lp = getsymbol(gv,lp);
- if (*gv->strbuf) {
- lower_case(gv->strbuf); /* convert opcode to lower case */
-
- if (st.macskip) { /* macros */
- if (!strcmp(gv->strbuf,".endm")) {
- st.macskip->nlines = gv->absline - st.macskip->nlines;
- add_macro(gv,st.macskip);
- st.macskip = NULL;
- }
- }
-
- else if (!gv->ifcond[gv->iflevel]) { /* conditional assembly */
- if (!strncmp(gv->strbuf,".if",3))
- gv->ifignore++;
- else if (!strcmp(gv->strbuf,".else")) {
- if (gv->ifignore == 0)
- gv->ifcond[gv->iflevel] = TRUE;
- }
- else if (!strcmp(gv->strbuf,".endif")) {
- if (gv->ifignore)
- gv->ifignore--;
- else
- gv->iflevel--;
- }
- }
-
- else { /* search opcode */
- c = *lp; /* branch hint given? */
- if (c=='+') {
- lp++;
- pl->branch_hint = 1;
- }
- else if (c=='-') {
- lp++;
- pl->branch_hint = -1;
- }
- search_opcode(gv,pl,gv->strbuf,skipspaces(lp));
- }
- }
-
- if (!(pl->flags&PLF_NONEWLINE))
- st.line++;
- ++pl;
- }
- gv->cthread = prev_st;
- }
-
-
- static char *insert_macro_params(struct GlobalVars *gv,struct ParsedLine *pl,
- char *s,struct MacroParams *mp)
- {
- char **par = mp->param;
- char c,callidbuf[16];
- char *pp,*d=gv->linebuf;
- int n;
-
- do {
- if ((c=*s++) == '\\') {
- if (*s>='0' && *s<='9') { /* macro parameter? */
- n = (int)(*s++ - '0');
- if (pp = par[n]) {
- while (*d++ = *pp++); /* insert parameter */
- d--;
- continue;
- }
- else {
- error(9,n); /* reference to undefined macro parameter n */
- continue;
- }
- }
- else if (*s=='@') { /* insert macro call id */
- s++;
- pp = callidbuf;
- sprintf(pp,"$%d",(int)mp->call_id);
- while (*d++ = *pp++);
- d--;
- continue;
- }
- }
- *d++ = c;
- }
- while (c!=0 && c!=1);
- if (c==1) {
- *(--d) = 0;
- pl->flags |= PLF_NONEWLINE;
- }
- return (s);
- }
-
-
- static char *readline(struct GlobalVars *gv,struct ParsedLine *pl,char *s)
- {
- char c,*d = gv->linebuf;
-
- do {
- c = *s++;
- *d++ = c;
- }
- while (c!=0 && c!=1);
- if (c==1) {
- *(--d) = 0;
- pl->flags |= PLF_NONEWLINE;
- }
- return (s);
- }
-
-
- static char *getlabel(struct GlobalVars *gv,char *s)
- /* read label to gv->strbuf, s points to the beginning of a line */
- {
- char *s_old = s;
-
- s = getsymbol(gv,s); /* read label to buffer */
- if ((s != s_old) && (*s == ':')) /* colon indicates a valid label */
- return (++s);
- *gv->strbuf = 0;
- return (s_old);
- }
-
-
- struct SourceText *include_source(struct GlobalVars *gv,char *name)
- /* called when encountering an .include directive */
- {
- char *s = mapfile(gv,name);
- long len = *(size_t *)(s - sizeof(size_t)); /* mapfile stores size here */
-
- return (add_source(gv,name,s,len));
- }
-
-
- static struct SourceText *add_source(struct GlobalVars *gv,char *name,
- char *s, /* source text pointer */
- long len) /* text length in bytes */
- /* create a new SourceText node and add it to the source list */
- {
- struct SourceText *stxt = alloc(sizeof(struct SourceText));
- bool comm=FALSE;
- char quote=0;
-
- stxt->name = name;
- stxt->text = s;
- stxt->nlines = 0;
-
- /* replace '\n' and ';' by \0 and determine number of lines */
- for (; len>0; len--,s++) {
- switch (*s) {
- case '\n':
- *s = 0;
- stxt->nlines++;
- comm = FALSE; /* \n ends a comment */
- break;
- case '\r': /* ignore CRs */
- *s = 0;
- break;
- case ';': /* ';' allows multiple statements per line */
- if (!comm && !quote) {
- if (*(s+1)=='\n' || *(s+1)=='\r')
- *s = ' ';
- else {
- *s = 1;
- stxt->nlines++;
- }
- }
- break;
- case '#': /* comment: ignore ';' in rest of line */
- comm = TRUE;
- break;
- case 0x22: /* ignore ';' in strings too */
- if (quote==0x22)
- quote = 0;
- else if (!quote)
- quote = 0x22;
- break;
- case 0x27:
- if (quote==0x27)
- quote = 0;
- else if (!quote)
- quote = 0x27;
- break;
- }
- }
-
- stxt->plin = alloczero(stxt->nlines * sizeof(struct ParsedLine));
- addtail(&gv->sourcelist,&stxt->n);
- return (stxt);
- }
-
-
- static void prepare_sections(struct GlobalVars *gv)
- /* prepare sections for receiving code in pass 2 */
- {
- struct Section *nexts,*sec=(struct Section *)gv->sectionlist.first;
-
- while (nexts = (struct Section *)sec->n.next) {
- sec->size = sec->pc;
- sec->pc = 0;
- sec->current_align = sec->first_align;
- if (!(sec->flags & SF_UNINITIALIZED))
- if (sec->size)
- sec->data = sec->contents = alloc((size_t)sec->size);
- sec = nexts;
- }
- }
-
-
- void exec_pass2(struct GlobalVars *gv)
- {
- gv->absline = 0;
- gv->pass++;
- prepare_sections(gv);
- gv->srctxtp = (struct SourceText *)gv->sourcelist.first;
-
- pass2(gv,get_source(gv),NULL,NULL); /* <standard sections> */
- if (!gv->noregsymbols)
- pass2(gv,get_source(gv),NULL,NULL); /* <standard definitions> */
- if (gv->usrdefs)
- pass2(gv,get_source(gv),NULL,NULL); /* <user definitions> */
- if (!gv->noextmnemo)
- pass2(gv,get_source(gv),NULL,NULL); /* <extended mnemonics> */
-
- pass2(gv,get_source(gv),NULL,NULL);
- if (gv->vc) {
- activate_section(gv,(struct Section *)gv->sectionlist.first);
- alignment(gv,2);
- store_word(gv,0x76626363);
- }
- }
-
-
- void pass2(struct GlobalVars *gv,struct SourceText *srctxt,
- struct MacroParams *macro,struct SourceThread *prev_st)
- /* Assembler Pass 2 */
- {
- struct SourceThread st;
- unsigned long nlines = srctxt->nlines;
- struct ParsedLine *pl = srctxt->plin;
- struct ParsedLine *p;
- uint32 oldnarg;
-
- /* init SourceThread structure */
- st.prev = prev_st;
- st.macro = macro;
- st.csource = srctxt;
- st.line = 1;
- gv->cthread = &st; /* set current source thread */
-
- while (nlines--) {
- gv->absline++;
- st.lineptr = pl->lineptr;
- p = pl;
-
- do {
- /* evaluate opcode field */
- switch (p->type) {
-
- case OT_INSTRUCTION:
- instr(gv,p);
- break;
-
- case OT_DIRECTIVE:
- (((struct Directive *)p->opcode)->dfunct)(gv,p);
- break;
-
- case OT_MACRO:
- oldnarg = gv->nargsym->value;
- gv->nargsym->value = (uint32)p->narg;
- pass2(gv,get_source(gv),(struct MacroParams *)gv,gv->cthread);
- /* the MacroParams pointer is set to gv, because we */
- /* only need a non-zero pointer here... */
- gv->nargsym->value = oldnarg;
- break;
-
- case OT_SECTION:
- activate_section(gv,(struct Section *)p->opcode);
- break;
- }
- }
- while (p = p->next);
-
- if (!(pl->flags&PLF_NONEWLINE))
- st.line++;
- ++pl;
- }
- gv->cthread = prev_st;
- }
-
-
- struct SourceText *get_source(struct GlobalVars *gv)
- {
- struct SourceText *st = gv->srctxtp;
-
- gv->srctxtp = (struct SourceText *)st->n.next;
- return (st);
- }
-