📄 m68k.c
字号:
if(!*str && parens) { /* ERROR */ opP->error="Missing )"; return str; } c= *str; *str='\0'; if(m68k_ip_op(beg_str,opP)==FAIL) { *str=c; return str; } *str=c; if(c=='}') c= *++str; /* JF bitfield hack */ if(c) { c= *++str; if(!c) as_bad("Missing operand"); } return str;}/* See the comment up above where the #define notend(... is */#if 0notend(s)char *s;{ if(*s==',') return 0; if(*s=='{' || *s=='}') return 0; if(*s!=':') return 1; /* This kludge here is for the division cmd, which is a kludge */ if(index("aAdD#",s[1])) return 0; return 1;}#endif/* This is the guts of the machine-dependent assembler. STR points to a machine dependent instruction. This funciton is supposed to emit the frags/bytes it assembles to. */voidmd_assemble(str)char *str;{ char *er; short *fromP; char *toP; int m,n; char *to_beg_P; int shorts_this_frag; bzero((char *)(&the_ins),sizeof(the_ins)); /* JF for paranoia sake */ m68_ip(str); er=the_ins.error; if(!er) { for(n=the_ins.numargs;n;--n) if(the_ins.operands[n].error) { er=the_ins.operands[n].error; break; } } if(er) { as_bad("\"%s\" -- Statement '%s' ignored",er,str); return; } if(the_ins.nfrag==0) { /* No frag hacking involved; just put it out */ toP=frag_more(2*the_ins.numo); fromP= &the_ins.opcode[0]; for(m=the_ins.numo;m;--m) { md_number_to_chars(toP,(long)(*fromP),2); toP+=2; fromP++; } /* put out symbol-dependent info */ for(m=0;m<the_ins.nrel;m++) { switch(the_ins.reloc[m].wid) { case 'B': n=1; break; case 'b': n=1; break; case '3': n=2; break; case 'w': n=2; break; case 'l': n=4; break; default: as_fatal("Don't know how to figure width of %c in md_assemble()",the_ins.reloc[m].wid); } fix_new(frag_now, (toP-frag_now->fr_literal)-the_ins.numo*2+the_ins.reloc[m].n, n, the_ins.reloc[m].add, the_ins.reloc[m].sub, the_ins.reloc[m].off, the_ins.reloc[m].pcrel); } return; } /* There's some frag hacking */ for(n=0,fromP= &the_ins.opcode[0];n<the_ins.nfrag;n++) { int wid; if(n==0) wid=2*the_ins.fragb[n].fragoff; else wid=2*(the_ins.numo-the_ins.fragb[n-1].fragoff); toP=frag_more(wid); to_beg_P=toP; shorts_this_frag=0; for(m=wid/2;m;--m) { md_number_to_chars(toP,(long)(*fromP),2); toP+=2; fromP++; shorts_this_frag++; } for(m=0;m<the_ins.nrel;m++) { if((the_ins.reloc[m].n)>= 2*shorts_this_frag /* 2*the_ins.fragb[n].fragoff */) { the_ins.reloc[m].n-= 2*shorts_this_frag /* 2*the_ins.fragb[n].fragoff */; break; } wid=the_ins.reloc[m].wid; if(wid==0) continue; the_ins.reloc[m].wid=0; wid = (wid=='b') ? 1 : (wid=='w') ? 2 : (wid=='l') ? 4 : 4000; fix_new(frag_now, (toP-frag_now->fr_literal)-the_ins.numo*2+the_ins.reloc[m].n, wid, the_ins.reloc[m].add, the_ins.reloc[m].sub, the_ins.reloc[m].off, the_ins.reloc[m].pcrel); } know(the_ins.fragb[n].fadd); (void)frag_var(rs_machine_dependent,10,0,(relax_substateT)(the_ins.fragb[n].fragty), the_ins.fragb[n].fadd,the_ins.fragb[n].foff,to_beg_P); } n=(the_ins.numo-the_ins.fragb[n-1].fragoff); shorts_this_frag=0; if(n) { toP=frag_more(n*sizeof(short)); while(n--) { md_number_to_chars(toP,(long)(*fromP),2); toP+=2; fromP++; shorts_this_frag++; } } for(m=0;m<the_ins.nrel;m++) { int wid; wid=the_ins.reloc[m].wid; if(wid==0) continue; the_ins.reloc[m].wid=0; wid = (wid=='b') ? 1 : (wid=='w') ? 2 : (wid=='l') ? 4 : 4000; fix_new(frag_now, (the_ins.reloc[m].n + toP-frag_now->fr_literal)-/* the_ins.numo */ shorts_this_frag*2, wid, the_ins.reloc[m].add, the_ins.reloc[m].sub, the_ins.reloc[m].off, the_ins.reloc[m].pcrel); }}/* This function is called once, at assembler startup time. This should set up all the tables, etc that the MD part of the assembler needs */voidmd_begin(){/* * md_begin -- set up hash tables with 68000 instructions. * similar to what the vax assembler does. ---phr */ /* RMS claims the thing to do is take the m68k-opcode.h table, and make a copy of it at runtime, adding in the information we want but isn't there. I think it'd be better to have an awk script hack the table at compile time. Or even just xstr the table and use it as-is. But my lord ghod hath spoken, so we do it this way. Excuse the ugly var names. */ register struct m68k_opcode *ins; register struct m68_incant *hack, *slak; register char *retval = 0; /* empty string, or error msg text */ register int i; register char c; if ((op_hash = hash_new()) == NULL) as_fatal("Virtual memory exhausted"); obstack_begin(&robyn,4000); for (ins = m68k_opcodes; ins < endop; ins++) { hack=slak=(struct m68_incant *)obstack_alloc(&robyn,sizeof(struct m68_incant)); do { slak->m_operands=ins->args; slak->m_opnum=strlen(slak->m_operands)/2; slak->m_opcode=ins->opcode; /* This is kludgey */ slak->m_codenum=((ins->match)&0xffffL) ? 2 : 1; if((ins+1)!=endop && !strcmp(ins->name,(ins+1)->name)) { slak->m_next=(struct m68_incant *)obstack_alloc(&robyn,sizeof(struct m68_incant)); ins++; } else slak->m_next=0; slak=slak->m_next; } while(slak); retval = hash_insert (op_hash, ins->name,(char *)hack); /* Didn't his mommy tell him about null pointers? */ if(retval && *retval) as_fatal("Internal Error: Can't hash %s: %s",ins->name,retval); } for (i = 0; i < sizeof(mklower_table) ; i++) mklower_table[i] = (isupper(c = (char) i)) ? tolower(c) : c; for (i = 0 ; i < sizeof(notend_table) ; i++) { notend_table[i] = 0; alt_notend_table[i] = 0; } notend_table[','] = 1; notend_table['{'] = 1; notend_table['}'] = 1; alt_notend_table['a'] = 1; alt_notend_table['A'] = 1; alt_notend_table['d'] = 1; alt_notend_table['D'] = 1; alt_notend_table['#'] = 1; alt_notend_table['f'] = 1; alt_notend_table['F'] = 1;#ifdef REGISTER_PREFIX alt_notend_table[REGISTER_PREFIX] = 1;#endif}#if 0#define notend(s) ((*s == ',' || *s == '}' || *s == '{' \ || (*s == ':' && index("aAdD#", s[1]))) \ ? 0 : 1)#endif/* This funciton is called once, before the assembler exits. It is supposed to do any final cleanup for this part of the assembler. */voidmd_end(){}/* Equal to MAX_PRECISION in atof-ieee.c */#define MAX_LITTLENUMS 6/* Turn a string in input_line_pointer into a floating point constant of type type, and store the appropriate bytes in *litP. The number of LITTLENUMS emitted is stored in *sizeP . An error message is returned, or NULL on OK. */char *md_atof(type,litP,sizeP)char type;char *litP;int *sizeP;{ int prec; LITTLENUM_TYPE words[MAX_LITTLENUMS]; LITTLENUM_TYPE *wordP; char *t; char *atof_ieee(); switch(type) { case 'f': case 'F': case 's': case 'S': prec = 2; break; case 'd': case 'D': case 'r': case 'R': prec = 4; break; case 'x': case 'X': prec = 6; break; case 'p': case 'P': prec = 6; break; default: *sizeP=0; return "Bad call to MD_ATOF()"; } t=atof_ieee(input_line_pointer,type,words); if(t) input_line_pointer=t; *sizeP=prec * sizeof(LITTLENUM_TYPE); for(wordP=words;prec--;) { md_number_to_chars(litP,(long)(*wordP++),sizeof(LITTLENUM_TYPE)); litP+=sizeof(LITTLENUM_TYPE); } return ""; /* Someone should teach Dean about null pointers */}/* Turn an integer of n bytes (in val) into a stream of bytes appropriate for use in the a.out file, and stores them in the array pointed to by buf. This knows about the endian-ness of the target machine and does THE RIGHT THING, whatever it is. Possible values for n are 1 (byte) 2 (short) and 4 (long) Floating numbers are put out as a series of LITTLENUMS (shorts, here at least) */voidmd_number_to_chars(buf,val,n)char *buf;long val;int n;{ switch(n) { case 1: *buf++=val; break; case 2: *buf++=(val>>8); *buf++=val; break; case 4: *buf++=(val>>24); *buf++=(val>>16); *buf++=(val>>8); *buf++=val; break; default: abort(); }}voidmd_number_to_imm(buf,val,n)char *buf;long val;int n;{ switch(n) { case 1: *buf++=val; break; case 2: *buf++=(val>>8); *buf++=val; break; case 4: *buf++=(val>>24); *buf++=(val>>16); *buf++=(val>>8); *buf++=val; break; default: abort(); }}voidmd_number_to_disp(buf,val,n)char *buf;long val;int n;{ abort();}voidmd_number_to_field(buf,val,fix)char *buf;long val;void *fix;{ abort();}/* *fragP has been relaxed to its final size, and now needs to have the bytes inside it modified to conform to the new size There is UGLY MAGIC here. .. */voidmd_convert_frag(fragP)register fragS *fragP;{ long disp; long ext; /* Address in gas core of the place to store the displacement. */ register char *buffer_address = fragP -> fr_fix + fragP -> fr_literal; /* Address in object code of the displacement. */ register int object_address = fragP -> fr_fix + fragP -> fr_address; know(fragP->fr_symbol); /* The displacement of the address, from current location. */ disp = (fragP->fr_symbol->sy_value + fragP->fr_offset) - object_address; switch(fragP->fr_subtype) { case TAB(BCC68000,BYTE): case TAB(BRANCH,BYTE): know(issbyte(disp)); if(disp==0) as_bad("short branch with zero offset: use :w"); fragP->fr_opcode[1]=disp; ext=0; break; case TAB(DBCC,SHORT): know(issword(disp)); ext=2; break; case TAB(BCC68000,SHORT): case TAB(BRANCH,SHORT): know(issword(disp)); fragP->fr_opcode[1]=0x00; ext=2; break; case TAB(BRANCH,LONG): if(flagseen['m']) { if(fragP->fr_opcode[0]==0x61) { fragP->fr_opcode[0]= 0x4E; fragP->fr_opcode[1]= 0xB9; /* JBSR with ABSL LONG offset */ subseg_change(SEG_TEXT, 0); fix_new(fragP, fragP->fr_fix, 4, fragP->fr_symbol, 0, fragP->fr_offset, 0); fragP->fr_fix+=4; ext=0; } else if(fragP->fr_opcode[0]==0x60) { fragP->fr_opcode[0]= 0x4E; fragP->fr_opcode[1]= 0xF9; /* JMP with ABSL LONG offset */ subseg_change(SEG_TEXT, 0); fix_new(fragP, fragP->fr_fix, 4, fragP->fr_symbol, 0, fragP->fr_offset,0); fragP->fr_fix+=4; ext=0; }else { as_bad("Long branch offset not supported."); } } else { fragP->fr_opcode[1]=0xff; ext=4; } break; case TAB(BCC68000,LONG): /* only Bcc 68000 instructions can come here */ /* change bcc into b!cc/jmp absl long */ fragP->fr_opcode[0] ^= 0x01; /* invert bcc */ fragP->fr_opcode[1] = 0x6; /* branch offset = 6 */ /* JF: these used to be fr_opcode[2,3], but they may be in a different frag, in which case refering to them is a no-no. Only fr_opcode[0,1] are guaranteed to work. */ *buffer_address++ = 0x4e; /* put in jmp long (0x4ef9) */ *buffer_address++ = 0xf9; fragP->fr_fix += 2; /* account for jmp instruction */ subseg_change(SEG_TEXT,0); fix_new(fragP, fragP->fr_fix, 4, fragP->fr_symbol, 0, fragP->fr_offset,0); fragP->fr_fix += 4; ext=0; break; case TAB(DBCC,LONG): /* only DBcc 68000 instructions can come here */ /* change dbcc into dbcc/jmp absl long */ /* JF: these used to be fr_opcode[2-7], but that's wrong */ *buffer_address++ = 0x00; /* branch offset = 4 */ *buffer_address++ = 0x04; *buffer_address++ = 0x60; /* put in bra pc+6 */ *buffer_address++ = 0x06; *buffer_address++ = 0x4e; /* put in jmp long (0x4ef9) */ *buffer_address++ = 0xf9; fragP->fr_fix += 6; /* account for bra/jmp instructions */ subseg_change(SEG_TEXT,0); fix_new(fragP, fragP->fr_fix, 4, fragP->fr_symbol, 0, fragP->fr_offset,0); fragP->fr_fix += 4; ext=0; break; case TAB(FBRANCH,SHORT): know((fragP->fr_opcode[1]&0x40)==0); ext=2; break; case TAB(FBRANCH,LONG): fragP->fr_opcode[1]|=0x40; /* Turn on LONG bit */ ext=4; break; case TAB(PCREL,SHORT): ext=2; break; case TAB(PCREL,LONG): /* The thing to do here is force it to ABSOLUTE LONG, since PCREL is really trying to shorten an ABSOLUTE address anyway */ /* JF FOO This code has not been tested */ subseg_change(SEG_TEXT,0); fix_new(fragP, fragP->fr_fix, 4, fragP->fr_symbol, 0, fragP->fr_offset, 0); if((fragP->fr_opcode[1] & 0x3F) != 0x3A) as_bad("Internal error (long PC-relative operand) for insn 0x%04lx at 0x%lx", fragP->fr_opcode[0],fragP->fr_address); fragP->fr_opcode[1]&= ~0x3F; fragP->fr_opcode[1]|=0x39; /* Mode 7.1 */ fragP->fr_fix+=4; /* md_number_to_chars(buffer_address, (long)(fragP->fr_symbol->sy_value + fragP->fr_offset), 4); */ ext=0; break; case TAB(PCLEA,SHORT): subseg_change(SEG_TEXT,0); fix_new(fragP,(int)(fragP->fr_fix),2,fragP->fr_symbol,(symbolS *)0,fragP->fr_offset,1); fragP->fr_opcode[1] &= ~0x3F; fragP->fr_opcode[1] |= 0x3A; ext=2; break; case TAB(PCLEA,LONG): subseg_change(SEG_TEXT,0); fix_new(fragP,(int)(fragP->fr_fix)+2,4,fragP->fr_symbol,(symbolS *)0,fragP->fr_offset+2,1); *buffer_address++ = 0x01; *buffer_address++ = 0x70; fragP->fr_fix+=2; /* buffer_address+=2; */ ext=4; break; } if(ext) { md_number_to_chars(buffer_address,(long)disp,(int)ext); fragP->fr_fix+=ext; }}/* Force truly undefined symbols to their maximum size, and generally set up the frag list to be relaxed */intmd_estimate_size_before_relax(fragP,segtype)register fragS *fragP;int segtype;{ int old_fix; register char *buffer_address = fragP -> fr_fix + fragP -> fr_literal; old_fix=fragP->fr_fix; /* handle SZ_UNDEF first, it can be changed to BYTE or SHORT */ switch(fragP->fr_subtype) { case TAB(BRANCH,SZ_UNDEF): if((fragP->fr_symbol->sy_type&N_TYPE)==segtype) { fragP->fr_subtype=TAB(TABTYPE(fragP->fr_subtype),BYTE); break; } else if(flagseen['m']) { if(fragP->fr_opcode[0]==0x61) { if(flagseen['l']) { fragP->fr_opcode[0]= 0x4E; fragP->fr_opcode[1]= 0xB8; /* JBSR with ABSL WORD offset */ subseg_change(SEG_TEXT, 0); fix_new(fragP, fragP->fr_fix, 2, fragP->fr_symbol, 0, fragP->fr_offset, 0); fragP->fr_fix+=2; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -