static void handle_align(char *s) { taddr align=parse_constexpr(&s); atom *a=new_space_atom(number_expr(0),1,0); a->align=1<<align; add_atom(0,a); eol(s); }
static void stab_entry(char *name,int type,int othr,int desc,char *s) { section *stabs; if (!(stabs = find_section(stabname,stabattr))) { section *str; dblock *db; stabs = new_section(stabname,stabattr,4); if (!(str = find_section(stabstrname,stabstrattr))) { str = new_section(stabstrname,stabstrattr,1); } else { if (str->pc != 0) ierror(0); } /* first byte of .stabstr is 0 */ add_atom(str,new_space_atom(number_expr(1),1,0)); /* compilation unit header has to be patched by output module */ new_stabstr(getfilename()); db = new_dblock(); db->size = 12; db->data = mymalloc(12); add_atom(stabs,new_data_atom(db,1)); } add_const_datadef(stabs,name?new_stabstr(name):0,32,1); add_const_datadef(stabs,type,8,1); add_const_datadef(stabs,othr,8,1); add_const_datadef(stabs,desc,16,1); if (s) { operand *op = new_operand(); int len = oplen(skip_operand(s),s); if (parse_operand(s,len,op,DATA_OPERAND(32))) { atom *a = new_datadef_atom(32,op); a->align = 1; add_atom(stabs,a); } else syntax_error(8); } else add_atom(stabs,new_space_atom(number_expr(4),1,0)); /* no value */ }
static void do_align(taddr align,expr *fill,taddr max) /* @@@ 'max' alignment is not really supported at the moment */ { atom *a = new_space_atom(number_expr(0),1,fill); a->align = align; add_atom(0,a); }
static void handle_align(char *s) { taddr a = parse_constexpr(&s); if (a > 63) syntax_error(21); /* bad alignment */ do_alignment(1LL<<a,number_expr(0)); eol(s); }
static void new_bss(char *s,int global) { char *name; symbol *sym; atom *a; taddr size; section *bss; if(!(name=parse_identifier(&s))){ syntax_error(10); /* identifier expected */ return; } size=comma_constexpr(&s); if(size<=sdlimit){ if(!(bss=find_section(sbssname,sbssattr))) bss=new_section(sbssname,sbssattr,1); } else{ if(!(bss=find_section(bssname,bssattr))) bss=new_section(bssname,bssattr,1); } sym=new_labsym(bss,name); sym->flags|=TYPE_OBJECT; if(global) sym->flags|=EXPORT; sym->size=number_expr(size); myfree(name); s=skip(s); if(*s==','){ s=skip(s+1); sym->align=parse_constexpr(&s); } else sym->align=(size>=8)?8:4; a=new_label_atom(sym); if(sym->align) a->align=sym->align; add_atom(bss,a); a=new_space_atom(number_expr(size),1,0); if(sym->align) a->align=sym->align; add_atom(bss,a); eol(s); }
static void handle_data_offset(char *s,int size,int offset) { for (;;) { char *opstart = s; operand *op; dblock *db = NULL; if (size==8 && (*s=='\"' || *s=='\'')) { if (db = parse_string(&opstart,*s,8)) { if (offset != 0) { int i; for (i=0; i<db->size; i++) db->data[i] = db->data[i] + offset; } add_atom(0,new_data_atom(db,1)); s = opstart; } } if (!db) { op = new_operand(); s = skip_operand(s); if (parse_operand(opstart,s-opstart,op,DATA_OPERAND(size))) { atom *a; if (offset != 0) op->value = make_expr(ADD,number_expr(offset),op->value); a = new_datadef_atom(abs(size),op); a->align = 1; add_atom(0,a); } else syntax_error(8); /* invalid data operand */ } s = skip(s); if (*s == ',') { s = skip(s+1); } else if (*s == commentchar) { break; } else if (*s) { syntax_error(9); /* , expected */ return; } else break; } eol(s); }
static void handle_even(char *s) { do_alignment(2,number_expr(0)); eol(s); }
int main(int argc,char **argv) { int i; for(i=1; i<argc; i++) { if(argv[i][0]=='-'&&argv[i][1]=='F') { output_format=argv[i]+2; argv[i][0]=0; } if(!strcmp("-quiet",argv[i])) { verbose=0; argv[i][0]=0; } } if(!init_output(output_format)) general_error(16,output_format); if(!init_main()) general_error(10,"main"); if(verbose) printf("%s\n%s\n%s\n%s\n",copyright,cpu_copyright,syntax_copyright,output_copyright); for(i=1; i<argc; i++) { if(argv[i][0]==0) continue; if(argv[i][0]!='-') { if(inname) general_error(11); inname=argv[i]; continue; } if(!strcmp("-o",argv[i])&&i<argc-1) { if(outname) general_error(28,'o'); outname=argv[++i]; continue; } if(!strcmp("-L",argv[i])&&i<argc-1) { if(listname) general_error(28,'L'); listname=argv[++i]; produce_listing=1; continue; } if(!strcmp("-Lnf",argv[i])) { listformfeed=0; continue; } if(!strcmp("-Lns",argv[i])) { listnosyms=1; continue; } if(!strncmp("-Ll",argv[i],3)) { sscanf(argv[i]+3,"%i",&listlinesperpage); continue; } if(!strncmp("-D",argv[i],2)) { char *def=NULL; expr *val; if(argv[i][2]) def=&argv[i][2]; else if (i<argc-1) def=argv[++i]; if(def) { char *s=def; if(ISIDSTART(*s)) { s++; while(ISIDCHAR(*s)) s++; def=cnvstr(def,s-def); if(*s=='=') { s++; val=parse_expr(&s); } else val=number_expr(1); if(*s) general_error(23,'D'); /* trailing garbage after option */ new_abs(def,val); myfree(def); continue; } } } if(!strncmp("-I",argv[i],2)) { char *path=NULL; if(argv[i][2]) path=&argv[i][2]; else if (i<argc-1) path=argv[++i]; if(path) { new_include_path(path); continue; } } if(!strcmp("-unnamed-sections",argv[i])) { unnamed_sections=1; continue; } if(!strcmp("-ignore-mult-inc",argv[i])) { ignore_multinc=1; continue; } if(!strcmp("-nocase",argv[i])) { nocase=1; continue; } if(!strcmp("-noesc",argv[i])) { esc_sequences=0; continue; } if(!strcmp("-nosym",argv[i])) { no_symbols=1; continue; } if(!strncmp("-nowarn=",argv[i],8)) { int wno; sscanf(argv[i]+8,"%i",&wno); disable_warning(wno); continue; } else if(!strcmp("-w",argv[i])) { no_warn=1; continue; } if(!strncmp("-maxerrors=",argv[i],11)) { sscanf(argv[i]+11,"%i",&max_errors); continue; } else if(!strcmp("-pic",argv[i])) { pic_check=1; continue; } if(cpu_args(argv[i])) continue; if(syntax_args(argv[i])) continue; if(output_args(argv[i])) continue; if (!strncmp("-x",argv[i],2)) { auto_import=0; continue; } general_error(14,argv[i]); } if(inname) { setfilename(inname); setdebugname(inname); include_source(inname); } else general_error(15); if(!init_parse()) general_error(10,"parse"); if(!init_syntax()) general_error(10,"syntax"); if(!init_cpu()) general_error(10,"cpu"); parse(); if(errors==0||produce_listing) resolve(); if(errors==0||produce_listing) assemble(); if(errors==0&&!auto_import) undef_syms(); if(!listname) listname="a.lst"; if(produce_listing) write_listing(listname); if(!outname) outname="a.out"; if(errors==0) { if(verbose) statistics(); outfile=fopen(outname,"wb"); if(!outfile) general_error(13,outname); write_object(outfile,first_section,first_symbol); } leave(); return 0; /* not reached */ }
static void assemble(void) { section *sec; atom *p; char *attr; int bss; final_pass=1; for(sec=first_section; sec; sec=sec->next) { source *lasterrsrc=NULL; int lasterrline=0; sec->pc=sec->org; attr=sec->attr; bss=0; while(*attr) { if(*attr++=='u') { bss=1; break; } } for(p=sec->first; p; p=p->next) { sec->pc=(sec->pc+p->align-1)/p->align*p->align; cur_src=p->src; cur_src->line=p->line; if(p->list&&p->list->atom==p) { p->list->sec=sec; p->list->pc=sec->pc; } if(p->type==INSTRUCTION) { dblock *db; cur_listing=p->list; db=eval_instruction(p->content.inst,sec,sec->pc); if(pic_check) do_pic_check(db->relocs); cur_listing=0; if(DEBUG) { if(db->size!=instruction_size(p->content.inst,sec,sec->pc)) ierror(0); } /*FIXME: sauber freigeben */ myfree(p->content.inst); p->content.db=db; p->type=DATA; } else if(p->type==DATADEF) { dblock *db; cur_listing=p->list; db=eval_data(p->content.defb->op,p->content.defb->bitsize,sec,sec->pc); if(pic_check) do_pic_check(db->relocs); cur_listing=0; /*FIXME: sauber freigeben */ myfree(p->content.defb); p->content.db=db; p->type=DATA; } else if(p->type==RORG) { sblock *sb; taddr space; if(eval_expr(p->content.roffs,&space,sec,sec->pc)) { space=sec->org+space-sec->pc; if (space>=0) { sb=new_sblock(number_expr(space),1,0); p->content.sb=sb; p->type=SPACE; } else general_error(20); /* rorg is lower than current pc */ } else general_error(30); /* expression must be constant */ } else if(p->type==DATA&&bss) { if(lasterrsrc!=p->src||lasterrline!=p->line) { general_error(31); /* initialized data in bss */ lasterrsrc=p->src; lasterrline=p->line; } } #ifdef HAVE_CPU_OPTS else if(p->type==OPTS) cpu_opts(p->content.opts); #endif else if(p->type==PRINTTEXT) printf("%s\n",p->content.ptext); else if (p->type==PRINTEXPR) { taddr val; eval_expr(p->content.pexpr,&val,sec,sec->pc); printf("%ld (0x%lx)\n",(long)val,(unsigned long)val); } sec->pc+=atom_size(p,sec,sec->pc); } } }
static void handle_string(char *s) { handle_data(s,8,0); add_atom(0,new_space_atom(number_expr(1),1,0)); /* terminating zero */ }
static void handle_qphrase(char *s) { do_alignment(32,number_expr(0),1,NULL); eol(s); }
static void handle_long(char *s) { do_alignment(4,number_expr(0),1,NULL); eol(s); }
int parse_operand(char *p,int len,operand *op,int req) { int r; char *s,*start=p; op->type=-1; p=skip(p); if(req>=OP_REG&&req<=OP_LR){ int reg; s=skip_reg(p,&r); if(s!=p){ if((req==OP_REG&&r<=31)|| (req==OP_SREG&&r<=15)|| (req==OP_PC&&r==31)|| (req==OP_LR&&r==26)|| (req==OP_MREG&&(r==0||r==6||r==16||r==24))){ op->type=OP_REG; op->reg=r; }else return 0; }else return 0; p=skip(s); }else if(req==OP_MREG){ int first; s=skip_reg(p,&r); if(s==p) return 0; if(r==0) op->dreg=0; else if(r==6) op->dreg=1; else if(r==16) op->dreg=2; else if(r==24) op->dreg=3; else return 0; s=skip(s); if(*s!='-') return 0; p=skip(s+1); first=r; s=skip_reg(p,&r); if(s==p) return 0; p=skip(s); op->reg=(r-first)&31; }else if(req==OP_IND){ p=skip(p); if(*p!='(') return 0; p=skip(p+1); s=skip_reg(p,&r); if(s==p) return 0; if(r>15) return 0; p=skip(s); op->reg=r; if(*p!=')') return 0; p=skip(p+1); op->type=OP_IND; }else if(req==OP_VIND){ int nodisp=0; p=skip(p); if(*p=='('){ char *m; m=s=skip(p+1); s=skip_reg(s,&r); if((m!=s)||(*s=='0')) nodisp=1; } if(!nodisp){ op->offset=parse_expr(&p); if(!op->offset) return 0; }else op->offset=0; if(*p!='(') return 0; p=skip(p+1); s=skip_reg(p,&r); if (s==p){ /* Special case: Allow '0' instead of a register */ if (*p=='0'){ p=skip(p+1); op->reg=15; } else return 0; }else{ if(r>14) return 0; p=skip(s); op->reg=r; } op->dreg=15; if(*p=='+'&&p[1]=='='){ p=skip(p+2); s=skip_reg(p,&r); if(s==p) return 0; if(r>14) return 0; p=skip(s); op->dreg=r; } if(*p!=')') return 0; p=skip(p+1); op->type=OP_IND; }else if(req==OP_PREDEC){ p=skip(p); if(p[0]!='-'||p[1]!='-') return 0; p=skip(p+2); if(*p!='(') return 0; p=skip(p+1); s=skip_reg(p,&r); if(s==p) return 0; p=skip(s); if(*p!=')') return 0; p=skip(p+1); op->reg=r; op->type=OP_PREDEC; }else if(req==OP_POSTINC){ p=skip(p); if(*p!='(') return 0; p=skip(p+1); s=skip_reg(p,&r); if(s==p) return 0; p=skip(s); if(*p!=')') return 0; p=skip(p+1); if(*p++!='+') return 0; if(*p!='+') return 0; p=skip(p+1); op->reg=r; op->type=OP_POSTINC; }else if(req==OP_REGIND){ p=skip(p); if(*p!='(') return 0; p=skip(p+1); s=skip_reg(p,&op->reg); if(s==p) return 0; p=skip(s); if(*p!=',') return 0; p=skip(p+1); s=skip_reg(p,&op->dreg); if(s==p) return 0; p=skip(s); if(*p!=')') return 0; op->type=OP_REGIND; p=skip(p+1); }else if(req==OP_IMMIND|| req==OP_IMMINDSP|| req==OP_IMMINDSD|| req==OP_IMMINDR0|| req==OP_IMMINDS|| req==OP_IMMINDPC){ op->offset=0; if(*p=='('){ char *p2; p2=skip(p+1); s=skip_reg(p2,&r); if(s!=p2){ p=skip(s); if(*p==')'){ p=skip(p+1); op->offset=number_expr(0); } } } if(!op->offset){ op->offset=parse_expr(&p); if(!op->offset) return 0; p=skip(p); if(*p!='(') return 0; p=skip(p+1); s=skip_reg(p,&r); if(s==p) return 0; p=skip(s); if(*p!=')') return 0; } if(req==OP_IMMINDSP&&r!=25) return 0; if(req==OP_IMMINDPC&&r!=31) return 0; if(req==OP_IMMINDSD&&r!=24) return 0; if(req==OP_IMMINDR0&&r!=0) return 0; if(req==OP_IMMINDS&&r>15) return 0; op->reg=r; op->type=OP_IMMIND; p=skip(p+1); }else if(req>=OP_IMM4&&req<=OP_IMM32&&skip_reg(p,&r)==p){ op->type=OP_IMM32; op->offset=parse_expr(&p); simplify_expr(op->offset); p=skip(p); }else if((req==OP_ABS||req==OP_REL)&&skip_reg(p,&r)==p){ op->type=req; op->offset=parse_expr(&p); simplify_expr(op->offset); p=skip(p); }else if(req==OP_VREG||req==OP_VREGM||req==OP_VREGMM||req==OP_VREGA80){ s=skip_reg(p,&r); op->offset=0; if(s!=p){ if (*s=='+'||*s=='-'){ if(req==OP_VREG) return 0; op->offset=parse_expr(&s); } p=skip(s); op->type=OP_VREG; if(req==OP_VREG){ op->reg=(0xE<<6)|r; op->dreg=0x3c; }else{ op->reg=(0xE<<6); op->dreg=r<<2; } }else if(*p=='-'){ p=skip(p+1); op->type=OP_VREG; op->reg=(0xF<<6); op->dreg=0x3c; }else{ int size,vert,x,y,inc=15<<2; expr *e; if(*p=='H'||*p=='h') vert=0; // Disable vertical registers in 48-bit instructions for now else if((req!=OP_VREG)&&(*p=='V'||*p=='v')) vert=1; else return 0; p=skip(p+1); if(*p=='X'||*p=='x'){ size=2; p=skip(p+1); }else if(*p=='1'&&p[1]=='6'){ size=2; p=skip(p+2); }else if(*p=='Y'||*p=='y'){ size=4; p=skip(p+1); }else if(*p=='3'&&p[1]=='2'){ size=4; p=skip(p+2); }else if(*p=='8'){ size=1; p=skip(p+1); }else{ size=1; p=skip(p); } if(*p!='(') return 0; p=skip(p+1); e=parse_expr(&p); if(e->type!=NUM) return 0; y=e->c.val; p=skip(p); #if 1 if(req!=OP_VREG&&*p=='+'){ p++; if(*p!='+') return 0; if(vert) { cpu_error(4); return 0; } p=skip(p+1); inc|=2; } #endif if(*p!=',') return 0; p=skip(p+1); if((*p=='c')||(*p=='C')) { p++; if (*p!='b'&&*p!='B') return 0; p++; if (*p!='+') return 0; inc|=1; } e=parse_expr(&p); if(e->type!=NUM) return 0; x=e->c.val; p=skip(p); #if 1 if(req!=OP_VREG&&*p=='+'){ p++; if(*p!='+') return 0; if(!vert) { cpu_error(4); return 0; } p=skip(p+1); inc|=2; } #endif if(*p!=')') return 0; p=skip(p+1); if(req!=OP_VREG&&*p=='*'){ p=skip(p+1); inc|=1; } if(req!=OP_VREG&&*p=='+'){ p=skip(p+1); s=skip_reg(p,&r); if(s==p) return 0; p=skip(s); inc&=~0x3c; inc|=(r<<2); } if(req==OP_VREGA80){ if(size==1){ op->reg=(vert<<6)|((x&48)<<3); }else if(size==2){ if(x&16) return 0; op->reg=(vert<<6)|(8<<6)|((x&32)<<2); }else{ if(x&48) return 0; op->reg=(vert<<6)|(12<<6); } if(y<0||y>63) return 0; op->reg|=y&63; inc|=(x&15)<<6; }else{ if(vert){ if(size==1){ op->reg=(1<<6)|((x&48)<<3); }else if(size==2){ if(x&16) return 0; op->reg=(9<<6)|((x&32)<<2); }else{ if(x&48) return 0; op->reg=13<<6; } if(y<0||y>63||(y&15)) return 0; op->reg|=(y&48)|(x&15); } else{ if(size==1){ if(x&15) return 0; op->reg=(x&48)<<3; }else if(size==2){ if(x&31) return 0; op->reg=(8<<6)|((x&32)<<2); }else{ if(x) return 0; op->reg=12<<6; } if(y<0||y>63) return 0; op->reg|=y&63; } } op->dreg=inc; op->type=OP_VREG; } }else return 0; if(req==OP_VREGMM||req==OP_IMM32M||req==OP_VIND){ int vecmod=0,i; while(1){ if(!strncasecmp(p,"rep",3)&&isspace((unsigned char)p[3])){ expr *e; taddr x; p=skip(p+3); if((*p=='r')&&(p[1]=='0')&&!isdigit(p[2])){ p=skip(p+2); vecmod|=7<<16; i=0; }else{ e=parse_expr(&p); if(e->type!=NUM) return 0; x=e->c.val; for(i=0;i<8;i++){ if((1<<i)==x){ vecmod|=i<<16; break; } } } if(i>=8) return 0; p=skip(p); continue; } for(i=0;i<sizeof(vflags)/sizeof(vflags[0]);i++){ if((!strncasecmp(p,vflags[i],strlen(vflags[i])))&& (!isalpha(p[strlen(vflags[i])]))){ if(vecmod&0x380) return 0; vecmod|=i<<7; p=skip(p+strlen(vflags[i])); continue; } } for (i=0;i<sizeof(sru)/sizeof(sru[0]);i++){ if(!strncasecmp(p,sru[i],strlen(sru[i]))){ p=skip(p+strlen(sru[i])); p=skip_reg(p,&r); if((r<0)||(r>7)) return 0; vecmod|=(1<<6)|(i<<3)|r; continue; } } for (i=0;i<sizeof(accs)/sizeof(accs[0]);i++){ if((!strncasecmp(p,accs[i],strlen(accs[i])))&& (!isalpha(p[strlen(accs[i])]))){ if(vecmod&0x40) return 0; vecmod|=i; p=skip(p+strlen(accs[i])); continue; } } if(!strncasecmp(p,"ena",3)){ if(vecmod&0x40) return 0; p=skip(p+3); vecmod|=32; } if(!strncasecmp(p,"setf",4)){ p=skip(p+4); vecmod|=1<<20; continue; } break; } op->vecmod=vecmod; } if(p>=start+len) return 1; else return 0; }