📄 tc-ppc.c
字号:
unsigned longppc_mach (){ return (ppc_size == PPC_OPCODE_64) ? 620 : 0;}intppc_subseg_align(){ return (ppc_xcoff64) ? 3 : 2;}extern char*ppc_target_format(){#ifdef OBJ_COFF#ifdef TE_PE return (target_big_endian ? "pe-powerpc" : "pe-powerpcle");#elif TE_POWERMAC#else return (ppc_xcoff64 ? "aixcoff64-rs6000" : "aixcoff-rs6000");#endif#ifdef TE_POWERMAC return "xcoff-powermac";#endif#endif#ifdef OBJ_ELF return (target_big_endian ? "elf32-powerpc" : "elf32-powerpcle");#endif}/* This function is called when the assembler starts up. It is called after the options have been parsed and the output file has been opened. */voidmd_begin (){ register const struct powerpc_opcode *op; const struct powerpc_opcode *op_end; const struct powerpc_macro *macro; const struct powerpc_macro *macro_end; boolean dup_insn = false; ppc_set_cpu ();#ifdef OBJ_ELF /* Set the ELF flags if desired. */ if (ppc_flags && !msolaris) bfd_set_private_flags (stdoutput, ppc_flags);#endif /* Insert the opcodes into a hash table. */ ppc_hash = hash_new (); op_end = powerpc_opcodes + powerpc_num_opcodes; for (op = powerpc_opcodes; op < op_end; op++) { know ((op->opcode & op->mask) == op->opcode); if ((op->flags & ppc_cpu) != 0 && ((op->flags & (PPC_OPCODE_32 | PPC_OPCODE_64)) == 0 || (op->flags & (PPC_OPCODE_32 | PPC_OPCODE_64)) == ppc_size || (ppc_cpu & PPC_OPCODE_64_BRIDGE) != 0)) { const char *retval; retval = hash_insert (ppc_hash, op->name, (PTR) op); if (retval != (const char *) NULL) { /* Ignore Power duplicates for -m601 */ if ((ppc_cpu & PPC_OPCODE_601) != 0 && (op->flags & PPC_OPCODE_POWER) != 0) continue; as_bad (_("Internal assembler error for instruction %s"), op->name); dup_insn = true; } } } /* Insert the macros into a hash table. */ ppc_macro_hash = hash_new (); macro_end = powerpc_macros + powerpc_num_macros; for (macro = powerpc_macros; macro < macro_end; macro++) { if ((macro->flags & ppc_cpu) != 0) { const char *retval; retval = hash_insert (ppc_macro_hash, macro->name, (PTR) macro); if (retval != (const char *) NULL) { as_bad (_("Internal assembler error for macro %s"), macro->name); dup_insn = true; } } } if (dup_insn) abort (); /* Tell the main code what the endianness is if it is not overidden by the user. */ if (!set_target_endian) { set_target_endian = 1; target_big_endian = PPC_BIG_ENDIAN; }#ifdef OBJ_XCOFF ppc_coff_debug_section = coff_section_from_bfd_index (stdoutput, N_DEBUG); /* Create dummy symbols to serve as initial csects. This forces the text csects to precede the data csects. These symbols will not be output. */ ppc_text_csects = symbol_make ("dummy\001"); symbol_get_tc (ppc_text_csects)->within = ppc_text_csects; ppc_data_csects = symbol_make ("dummy\001"); symbol_get_tc (ppc_data_csects)->within = ppc_data_csects;#endif#ifdef TE_PE ppc_current_section = text_section; ppc_previous_section = 0;#endif}/* Insert an operand value into an instruction. */static unsigned longppc_insert_operand (insn, operand, val, file, line) unsigned long insn; const struct powerpc_operand *operand; offsetT val; char *file; unsigned int line;{ if (operand->bits != 32) { long min, max; offsetT test; if ((operand->flags & PPC_OPERAND_SIGNED) != 0) { if ((operand->flags & PPC_OPERAND_SIGNOPT) != 0) max = (1 << operand->bits) - 1; else max = (1 << (operand->bits - 1)) - 1; min = - (1 << (operand->bits - 1)); if (ppc_size == PPC_OPCODE_32) { /* Some people write 32 bit hex constants with the sign extension done by hand. This shouldn't really be valid, but, to permit this code to assemble on a 64 bit host, we sign extend the 32 bit value. */ if (val > 0 && (val & (offsetT) 0x80000000) != 0 && (val & (offsetT) 0xffffffff) == val) { val -= 0x80000000; val -= 0x80000000; } } } else { max = (1 << operand->bits) - 1; min = 0; } if ((operand->flags & PPC_OPERAND_NEGATIVE) != 0) test = - val; else test = val; if (test < (offsetT) min || test > (offsetT) max) { const char *err = _("operand out of range (%s not between %ld and %ld)"); char buf[100]; sprint_value (buf, test); if (file == (char *) NULL) as_bad (err, buf, min, max); else as_bad_where (file, line, err, buf, min, max); } } if (operand->insert) { const char *errmsg; errmsg = NULL; insn = (*operand->insert) (insn, (long) val, &errmsg); if (errmsg != (const char *) NULL) as_bad (errmsg); } else insn |= (((long) val & ((1 << operand->bits) - 1)) << operand->shift); return insn;}#ifdef OBJ_ELF/* Parse @got, etc. and return the desired relocation. */static bfd_reloc_code_real_typeppc_elf_suffix (str_p, exp_p) char **str_p; expressionS *exp_p;{ struct map_bfd { char *string; int length; bfd_reloc_code_real_type reloc; }; char ident[20]; char *str = *str_p; char *str2; int ch; int len; struct map_bfd *ptr;#define MAP(str,reloc) { str, sizeof (str)-1, reloc } static struct map_bfd mapping[] = { MAP ("l", BFD_RELOC_LO16), MAP ("h", BFD_RELOC_HI16), MAP ("ha", BFD_RELOC_HI16_S), MAP ("brtaken", BFD_RELOC_PPC_B16_BRTAKEN), MAP ("brntaken", BFD_RELOC_PPC_B16_BRNTAKEN), MAP ("got", BFD_RELOC_16_GOTOFF), MAP ("got@l", BFD_RELOC_LO16_GOTOFF), MAP ("got@h", BFD_RELOC_HI16_GOTOFF), MAP ("got@ha", BFD_RELOC_HI16_S_GOTOFF), MAP ("fixup", BFD_RELOC_CTOR), /* warnings with -mrelocatable */ MAP ("plt", BFD_RELOC_24_PLT_PCREL), MAP ("pltrel24", BFD_RELOC_24_PLT_PCREL), MAP ("copy", BFD_RELOC_PPC_COPY), MAP ("globdat", BFD_RELOC_PPC_GLOB_DAT), MAP ("local24pc", BFD_RELOC_PPC_LOCAL24PC), MAP ("local", BFD_RELOC_PPC_LOCAL24PC), MAP ("pltrel", BFD_RELOC_32_PLT_PCREL), MAP ("plt@l", BFD_RELOC_LO16_PLTOFF), MAP ("plt@h", BFD_RELOC_HI16_PLTOFF), MAP ("plt@ha", BFD_RELOC_HI16_S_PLTOFF), MAP ("sdarel", BFD_RELOC_GPREL16), MAP ("sectoff", BFD_RELOC_32_BASEREL), MAP ("sectoff@l", BFD_RELOC_LO16_BASEREL), MAP ("sectoff@h", BFD_RELOC_HI16_BASEREL), MAP ("sectoff@ha", BFD_RELOC_HI16_S_BASEREL), MAP ("naddr", BFD_RELOC_PPC_EMB_NADDR32), MAP ("naddr16", BFD_RELOC_PPC_EMB_NADDR16), MAP ("naddr@l", BFD_RELOC_PPC_EMB_NADDR16_LO), MAP ("naddr@h", BFD_RELOC_PPC_EMB_NADDR16_HI), MAP ("naddr@ha", BFD_RELOC_PPC_EMB_NADDR16_HA), MAP ("sdai16", BFD_RELOC_PPC_EMB_SDAI16), MAP ("sda2rel", BFD_RELOC_PPC_EMB_SDA2REL), MAP ("sda2i16", BFD_RELOC_PPC_EMB_SDA2I16), MAP ("sda21", BFD_RELOC_PPC_EMB_SDA21), MAP ("mrkref", BFD_RELOC_PPC_EMB_MRKREF), MAP ("relsect", BFD_RELOC_PPC_EMB_RELSEC16), MAP ("relsect@l", BFD_RELOC_PPC_EMB_RELST_LO), MAP ("relsect@h", BFD_RELOC_PPC_EMB_RELST_HI), MAP ("relsect@ha", BFD_RELOC_PPC_EMB_RELST_HA), MAP ("bitfld", BFD_RELOC_PPC_EMB_BIT_FLD), MAP ("relsda", BFD_RELOC_PPC_EMB_RELSDA), MAP ("xgot", BFD_RELOC_PPC_TOC16), { (char *)0, 0, BFD_RELOC_UNUSED } }; if (*str++ != '@') return BFD_RELOC_UNUSED; for (ch = *str, str2 = ident; (str2 < ident + sizeof (ident) - 1 && (isalnum (ch) || ch == '@')); ch = *++str) { *str2++ = (islower (ch)) ? ch : tolower (ch); } *str2 = '\0'; len = str2 - ident; ch = ident[0]; for (ptr = &mapping[0]; ptr->length > 0; ptr++) if (ch == ptr->string[0] && len == ptr->length && memcmp (ident, ptr->string, ptr->length) == 0) { if (exp_p->X_add_number != 0 && (ptr->reloc == BFD_RELOC_16_GOTOFF || ptr->reloc == BFD_RELOC_LO16_GOTOFF || ptr->reloc == BFD_RELOC_HI16_GOTOFF || ptr->reloc == BFD_RELOC_HI16_S_GOTOFF)) as_warn (_("identifier+constant@got means identifier@got+constant")); /* Now check for identifier@suffix+constant */ if (*str == '-' || *str == '+') { char *orig_line = input_line_pointer; expressionS new_exp; input_line_pointer = str; expression (&new_exp); if (new_exp.X_op == O_constant) { exp_p->X_add_number += new_exp.X_add_number; str = input_line_pointer; } if (&input_line_pointer != str_p) input_line_pointer = orig_line; } *str_p = str; return ptr->reloc; } return BFD_RELOC_UNUSED;}/* Like normal .long/.short/.word, except support @got, etc. *//* clobbers input_line_pointer, checks *//* end-of-line. */static voidppc_elf_cons (nbytes) register int nbytes; /* 1=.byte, 2=.word, 4=.long */{ expressionS exp; bfd_reloc_code_real_type reloc; if (is_it_end_of_statement ()) { demand_empty_rest_of_line (); return; } do { expression (&exp); if (exp.X_op == O_symbol && *input_line_pointer == '@' && (reloc = ppc_elf_suffix (&input_line_pointer, &exp)) != BFD_RELOC_UNUSED) { reloc_howto_type *reloc_howto = bfd_reloc_type_lookup (stdoutput, reloc); int size = bfd_get_reloc_size (reloc_howto); if (size > nbytes) as_bad (_("%s relocations do not fit in %d bytes\n"), reloc_howto->name, nbytes); else { register char *p = frag_more ((int) nbytes); int offset = nbytes - size; fix_new_exp (frag_now, p - frag_now->fr_literal + offset, size, &exp, 0, reloc); } } else emit_expr (&exp, (unsigned int) nbytes); } while (*input_line_pointer++ == ','); input_line_pointer--; /* Put terminator back into stream. */ demand_empty_rest_of_line ();}/* Solaris pseduo op to change to the .rodata section. */static voidppc_elf_rdata (xxx) int xxx;{ char *save_line = input_line_pointer; static char section[] = ".rodata\n"; /* Just pretend this is .section .rodata */ input_line_pointer = section; obj_elf_section (xxx); input_line_pointer = save_line;}/* Pseudo op to make file scope bss items */static voidppc_elf_lcomm(xxx) int xxx ATTRIBUTE_UNUSED;{ register char *name; register char c; register char *p; offsetT size; register symbolS *symbolP; offsetT align; segT old_sec; int old_subsec; char *pfrag; int align2; name = input_line_pointer; c = get_symbol_end (); /* just after name is now '\0' */ p = input_line_pointer; *p = c; SKIP_WHITESPACE (); if (*input_line_pointer != ',') { as_bad (_("Expected comma after symbol-name: rest of line ignored.")); ignore_rest_of_line (); return; } input_line_pointer++; /* skip ',' */ if ((size = get_absolute_expression ()) < 0) { as_warn (_(".COMMon length (%ld.) <0! Ignored."), (long) size); ignore_rest_of_line (); return; } /* The third argument to .lcomm is the alignment. */ if (*input_line_pointer != ',') align = 8; else { ++input_line_pointer; align = get_absolute_expression (); if (align <= 0) { as_warn (_("ignoring bad alignment")); align = 8; } } *p = 0; symbolP = symbol_find_or_make (name); *p = c; if (S_IS_DEFINED (symbolP) && ! S_IS_COMMON (symbolP)) { as_bad (_("Ignoring attempt to re-define symbol `%s'."), S_GET_NAME (symbolP)); ignore_rest_of_line (); return; } if (S_GET_VALUE (symbolP) && S_GET_VALUE (symbolP) != (valueT) size) { as_bad (_("Length of .lcomm \"%s\" is already %ld. Not changed to %ld."), S_GET_NAME (symbolP), (long) S_GET_VALUE (symbolP), (long) size); ignore_rest_of_line (); return; } /* allocate_bss: */ old_sec = now_seg; old_subsec = now_subseg; if (align) { /* convert to a power of 2 alignment */ for (align2 = 0; (align & 1) == 0; align >>= 1, ++align2); if (align != 1) { as_bad (_("Common alignment not a power of 2")); ignore_rest_of_line (); return; } } else align2 = 0; record_alignment (bss_section, align2); subseg_set (bss_section, 0); if (align2) frag_align (align2, 0, 0); if (S_GET_SEGMENT (symbolP) == bss_section) symbol_get_frag (symbolP)->fr_symbol = 0; symbol_set_frag (symbolP, frag_now); pfrag = frag_var (rs_org, 1, 1, (relax_substateT) 0, symbolP, size, (char *) 0); *pfrag = 0; S_SET_SIZE (symbolP, size); S_SET_SEGMENT (symbolP, bss_section); subseg_set (old_sec, old_subsec); demand_empty_rest_of_line ();}/* Validate any relocations emitted for -mrelocatable, possibly adding fixups for word relocations in writable segments, so we can adjust them at runtime. */static voidppc_elf_validate_fix (fixp, seg) fixS *fixp; segT seg;{ if (fixp->fx_done || fixp->fx_pcrel) return; switch (shlib) { case SHLIB_NONE: case SHLIB_PIC: return; case SHLIB_MRELOCATABLE: if (fixp->fx_r_type <= BFD_RELOC_UNUSED
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -