📄 tc-m68k.c
字号:
/* These are the machine dependent pseudo-ops. These are included so the assembler can work on the output from the SUN C compiler, which generates these. *//* This table describes all the machine specific pseudo-ops the assembler has to support. The fields are: pseudo-op name without dot function to call to execute this pseudo-op Integer arg to pass to the function */const pseudo_typeS md_pseudo_table[] ={ {"data1", s_data1, 0}, {"data2", s_data2, 0}, {"bss", s_bss, 0}, {"even", s_even, 0}, {"skip", s_space, 0}, {"proc", s_proc, 0},#if defined (TE_SUN3) || defined (OBJ_ELF) {"align", s_align_bytes, 0},#endif#ifdef OBJ_ELF {"swbeg", s_ignore, 0},#endif {"extend", float_cons, 'x'}, {"ldouble", float_cons, 'x'}, /* The following pseudo-ops are supported for MRI compatibility. */ {"chip", s_chip, 0}, {"comline", s_space, 1}, {"fopt", s_fopt, 0}, {"mask2", s_ignore, 0}, {"opt", s_opt, 0}, {"reg", s_reg, 0}, {"restore", s_restore, 0}, {"save", s_save, 0}, {"if", s_mri_if, 0}, {"if.b", s_mri_if, 'b'}, {"if.w", s_mri_if, 'w'}, {"if.l", s_mri_if, 'l'}, {"else", s_mri_else, 0}, {"else.s", s_mri_else, 's'}, {"else.l", s_mri_else, 'l'}, {"endi", s_mri_endi, 0}, {"break", s_mri_break, 0}, {"break.s", s_mri_break, 's'}, {"break.l", s_mri_break, 'l'}, {"next", s_mri_next, 0}, {"next.s", s_mri_next, 's'}, {"next.l", s_mri_next, 'l'}, {"for", s_mri_for, 0}, {"for.b", s_mri_for, 'b'}, {"for.w", s_mri_for, 'w'}, {"for.l", s_mri_for, 'l'}, {"endf", s_mri_endf, 0}, {"repeat", s_mri_repeat, 0}, {"until", s_mri_until, 0}, {"until.b", s_mri_until, 'b'}, {"until.w", s_mri_until, 'w'}, {"until.l", s_mri_until, 'l'}, {"while", s_mri_while, 0}, {"while.b", s_mri_while, 'b'}, {"while.w", s_mri_while, 'w'}, {"while.l", s_mri_while, 'l'}, {"endw", s_mri_endw, 0}, {0, 0, 0}};/* The mote pseudo ops are put into the opcode table, since they don't start with a . they look like opcodes to gas. */#ifdef M68KCOFFextern void obj_coff_section PARAMS ((int));#endifCONST pseudo_typeS mote_pseudo_table[] ={ {"dcl", cons, 4}, {"dc", cons, 2}, {"dcw", cons, 2}, {"dcb", cons, 1}, {"dsl", s_space, 4}, {"ds", s_space, 2}, {"dsw", s_space, 2}, {"dsb", s_space, 1}, {"xdef", s_globl, 0},#ifdef OBJ_ELF {"align", s_align_bytes, 0},#else {"align", s_align_ptwo, 0},#endif#ifdef M68KCOFF {"sect", obj_coff_section, 0}, {"section", obj_coff_section, 0},#endif {0, 0, 0}};#define issbyte(x) ((x)>=-128 && (x)<=127)#define isubyte(x) ((x)>=0 && (x)<=255)#define issword(x) ((x)>=-32768 && (x)<=32767)#define isuword(x) ((x)>=0 && (x)<=65535)#define isbyte(x) ((x)>= -255 && (x)<=255)#define isword(x) ((x)>=-65536 && (x)<=65535)#define islong(x) (1)extern char *input_line_pointer;static char mklower_table[256];#define mklower(c) (mklower_table[(unsigned char) (c)])static char notend_table[256];static char alt_notend_table[256];#define notend(s) \ (! (notend_table[(unsigned char) *s] \ || (*s == ':' \ && alt_notend_table[(unsigned char) s[1]])))#if defined (M68KCOFF) && !defined (BFD_ASSEMBLER)#ifdef NO_PCREL_RELOCSintmake_pcrel_absolute(fixP, add_number) fixS *fixP; long *add_number;{ register unsigned char *opcode = fixP->fx_frag->fr_opcode; /* rewrite the PC relative instructions to absolute address ones. * these are rumoured to be faster, and the apollo linker refuses * to deal with the PC relative relocations. */ if (opcode[0] == 0x60 && opcode[1] == 0xff) /* BRA -> JMP */ { opcode[0] = 0x4e; opcode[1] = 0xf9; } else if (opcode[0] == 0x61 && opcode[1] == 0xff) /* BSR -> JSR */ { opcode[0] = 0x4e; opcode[1] = 0xb9; } else as_fatal (_("Unknown PC relative instruction")); *add_number -= 4; return 0;}#endif /* NO_PCREL_RELOCS */shorttc_coff_fix2rtype (fixP) fixS *fixP;{ if (fixP->fx_tcbit && fixP->fx_size == 4) return R_RELLONG_NEG;#ifdef NO_PCREL_RELOCS know (fixP->fx_pcrel == 0); return (fixP->fx_size == 1 ? R_RELBYTE : fixP->fx_size == 2 ? R_DIR16 : R_DIR32);#else return (fixP->fx_pcrel ? (fixP->fx_size == 1 ? R_PCRBYTE : fixP->fx_size == 2 ? R_PCRWORD : R_PCRLONG) : (fixP->fx_size == 1 ? R_RELBYTE : fixP->fx_size == 2 ? R_RELWORD : R_RELLONG));#endif}#endif#ifdef OBJ_ELF/* Return zero if the reference to SYMBOL from within the same segment may be relaxed. *//* On an ELF system, we can't relax an externally visible symbol, because it may be overridden by a shared library. However, if TARGET_OS is "elf", then we presume that we are assembling for an embedded system, in which case we don't have to worry about shared libraries, and we can relax any external sym. */#define relaxable_symbol(symbol) \ (!((S_IS_EXTERNAL (symbol) && strcmp (TARGET_OS, "elf") != 0) \ || S_IS_WEAK (symbol)))/* Compute the relocation code for a fixup of SIZE bytes, using pc relative relocation if PCREL is non-zero. PIC says whether a special pic relocation was requested. */static bfd_reloc_code_real_type get_reloc_code PARAMS ((int, int, enum pic_relocation));static bfd_reloc_code_real_typeget_reloc_code (size, pcrel, pic) int size; int pcrel; enum pic_relocation pic;{ switch (pic) { case pic_got_pcrel: switch (size) { case 1: return BFD_RELOC_8_GOT_PCREL; case 2: return BFD_RELOC_16_GOT_PCREL; case 4: return BFD_RELOC_32_GOT_PCREL; } break; case pic_got_off: switch (size) { case 1: return BFD_RELOC_8_GOTOFF; case 2: return BFD_RELOC_16_GOTOFF; case 4: return BFD_RELOC_32_GOTOFF; } break; case pic_plt_pcrel: switch (size) { case 1: return BFD_RELOC_8_PLT_PCREL; case 2: return BFD_RELOC_16_PLT_PCREL; case 4: return BFD_RELOC_32_PLT_PCREL; } break; case pic_plt_off: switch (size) { case 1: return BFD_RELOC_8_PLTOFF; case 2: return BFD_RELOC_16_PLTOFF; case 4: return BFD_RELOC_32_PLTOFF; } break; case pic_none: if (pcrel) { switch (size) { case 1: return BFD_RELOC_8_PCREL; case 2: return BFD_RELOC_16_PCREL; case 4: return BFD_RELOC_32_PCREL; } } else { switch (size) { case 1: return BFD_RELOC_8; case 2: return BFD_RELOC_16; case 4: return BFD_RELOC_32; } } } if (pcrel) { if (pic == pic_none) as_bad (_("Can not do %d byte pc-relative relocation"), size); else as_bad (_("Can not do %d byte pc-relative pic relocation"), size); } else { if (pic == pic_none) as_bad (_("Can not do %d byte relocation"), size); else as_bad (_("Can not do %d byte pic relocation"), size); } return BFD_RELOC_NONE;}/* Here we decide which fixups can be adjusted to make them relative to the beginning of the section instead of the symbol. Basically we need to make sure that the dynamic relocations are done correctly, so in some cases we force the original symbol to be used. */inttc_m68k_fix_adjustable (fixP) fixS *fixP;{ /* Prevent all adjustments to global symbols. */ if (! relaxable_symbol (fixP->fx_addsy)) return 0; /* adjust_reloc_syms doesn't know about the GOT */ switch (fixP->fx_r_type) { case BFD_RELOC_8_GOT_PCREL: case BFD_RELOC_16_GOT_PCREL: case BFD_RELOC_32_GOT_PCREL: case BFD_RELOC_8_GOTOFF: case BFD_RELOC_16_GOTOFF: case BFD_RELOC_32_GOTOFF: case BFD_RELOC_8_PLT_PCREL: case BFD_RELOC_16_PLT_PCREL: case BFD_RELOC_32_PLT_PCREL: case BFD_RELOC_8_PLTOFF: case BFD_RELOC_16_PLTOFF: case BFD_RELOC_32_PLTOFF: return 0; case BFD_RELOC_VTABLE_INHERIT: case BFD_RELOC_VTABLE_ENTRY: return 0; default: return 1; }}#else /* !OBJ_ELF */#define get_reloc_code(SIZE,PCREL,OTHER) NO_RELOC#define relaxable_symbol(symbol) 1#endif /* OBJ_ELF */#ifdef BFD_ASSEMBLERarelent *tc_gen_reloc (section, fixp) asection *section; fixS *fixp;{ arelent *reloc; bfd_reloc_code_real_type code; /* If the tcbit is set, then this was a fixup of a negative value that was never resolved. We do not have a reloc to handle this, so just return. We assume that other code will have detected this situation and produced a helpful error message, so we just tell the user that the reloc cannot be produced. */ if (fixp->fx_tcbit) { if (fixp->fx_addsy) as_bad (_("Unable to produce reloc against symbol '%s'"), S_GET_NAME (fixp->fx_addsy)); return NULL; } if (fixp->fx_r_type != BFD_RELOC_NONE) { code = fixp->fx_r_type; /* Since DIFF_EXPR_OK is defined in tc-m68k.h, it is possible that fixup_segment converted a non-PC relative reloc into a PC relative reloc. In such a case, we need to convert the reloc code. */ if (fixp->fx_pcrel) { switch (code) { case BFD_RELOC_8: code = BFD_RELOC_8_PCREL; break; case BFD_RELOC_16: code = BFD_RELOC_16_PCREL; break; case BFD_RELOC_32: code = BFD_RELOC_32_PCREL; break; case BFD_RELOC_8_PCREL: case BFD_RELOC_16_PCREL: case BFD_RELOC_32_PCREL: case BFD_RELOC_8_GOT_PCREL: case BFD_RELOC_16_GOT_PCREL: case BFD_RELOC_32_GOT_PCREL: case BFD_RELOC_8_GOTOFF: case BFD_RELOC_16_GOTOFF: case BFD_RELOC_32_GOTOFF: case BFD_RELOC_8_PLT_PCREL: case BFD_RELOC_16_PLT_PCREL: case BFD_RELOC_32_PLT_PCREL: case BFD_RELOC_8_PLTOFF: case BFD_RELOC_16_PLTOFF: case BFD_RELOC_32_PLTOFF: break; default: as_bad_where (fixp->fx_file, fixp->fx_line, _("Cannot make %s relocation PC relative"), bfd_get_reloc_code_name (code)); } } } else {#define F(SZ,PCREL) (((SZ) << 1) + (PCREL)) switch (F (fixp->fx_size, fixp->fx_pcrel)) {#define MAP(SZ,PCREL,TYPE) case F(SZ,PCREL): code = (TYPE); break MAP (1, 0, BFD_RELOC_8); MAP (2, 0, BFD_RELOC_16); MAP (4, 0, BFD_RELOC_32); MAP (1, 1, BFD_RELOC_8_PCREL); MAP (2, 1, BFD_RELOC_16_PCREL); MAP (4, 1, BFD_RELOC_32_PCREL); default: abort (); } }#undef F#undef MAP reloc = (arelent *) xmalloc (sizeof (arelent)); reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *)); *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy); reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;#ifndef OBJ_ELF if (fixp->fx_pcrel) reloc->addend = fixp->fx_addnumber; else reloc->addend = 0;#else if (!fixp->fx_pcrel) reloc->addend = fixp->fx_addnumber; else reloc->addend = (section->vma /* Explicit sign extension in case char is unsigned. */ + ((fixp->fx_pcrel_adjust & 0xff) ^ 0x80) - 0x80 + fixp->fx_addnumber + md_pcrel_from (fixp));#endif reloc->howto = bfd_reloc_type_lookup (stdoutput, code); assert (reloc->howto != 0); return reloc;}#endif /* BFD_ASSEMBLER *//* Handle of the OPCODE hash table. NULL means any use before m68k_ip_begin() will crash. */static struct hash_control *op_hash;/* Assemble an m68k instruction. */static voidm68k_ip (instring) char *instring;{ register char *p; register struct m68k_op *opP; register const struct m68k_incant *opcode; register const char *s; register int tmpreg = 0, baseo = 0, outro = 0, nextword; char *pdot, *pdotmove; enum m68k_size siz1, siz2; char c; int losing; int opsfound; LITTLENUM_TYPE words[6]; LITTLENUM_TYPE *wordp; unsigned long ok_arch = 0; if (*instring == ' ') instring++; /* skip leading whitespace */ /* Scan up to end of operation-code, which MUST end in end-of-string or exactly 1 space. */ pdot = 0; for (p = instring; *p != '\0'; p++) { if (*p == ' ') break; if (*p == '.') pdot = p; } if (p == instring) { the_ins.error = _("No operator"); return; } /* p now points to the end of the opcode name, probably whitespace. Make sure the name is null terminated by clobbering the whitespace, look it up in the hash table, then fix it back. Remove a dot, first, since the opcode tables have none. */ if (pdot != NULL) { for (pdotmove = pdot; pdotmove < p; pdotmove++) *pdotmove = pdotmove[1]; p--; } c = *p; *p = '\0'; opcode = (const struct m68k_incant *) hash_find (op_hash, instring); *p = c; if (pdot != NULL) { for (pdotmove = p; pdotmove > pdot; pdotmove--)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -