📄 tc-m32r.c
字号:
fragP->fr_opcode[0] |= 0x80; /* Increase known (fixed) size of fragment. */ fragP->fr_fix += 2; /* Create a relocation for it. */ fix_new (fragP, old_fr_fix, 4, fragP->fr_symbol, fragP->fr_offset, 1 /* pcrel */, /* FIXME: Can't use a real BFD reloc here. gas_cgen_md_apply_fix3 can't handle it. */ BFD_RELOC_M32R_26_PCREL); /* Mark this fragment as finished. */ frag_wane (fragP); return fragP->fr_fix - old_fr_fix;#else { const CGEN_INSN *insn; int i; /* Update the recorded insn. Fortunately we don't have to look very far. FIXME: Change this to record in the instruction the next higher relaxable insn to use. */ for (i = 0, insn = fragP->fr_cgen.insn; i < 4; i++, insn++) { if ((strcmp (CGEN_INSN_MNEMONIC (insn), CGEN_INSN_MNEMONIC (fragP->fr_cgen.insn)) == 0) && CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_RELAX)) break; } if (i == 4) abort (); fragP->fr_cgen.insn = insn; return 2; }#endif } return md_relax_table[fragP->fr_subtype].rlx_length;}/* *FRAGP has been relaxed to its final size, and now needs to have the bytes inside it modified to conform to the new size. Called after relaxation is finished. fragP->fr_type == rs_machine_dependent. fragP->fr_subtype is the subtype of what the address relaxed to. */voidmd_convert_frag (abfd, sec, fragP) bfd *abfd; segT sec; fragS *fragP;{ char *opcode; char *displacement; int target_address; int opcode_address; int extension; int addend; opcode = fragP->fr_opcode; /* Address opcode resides at in file space. */ opcode_address = fragP->fr_address + fragP->fr_fix - 2; switch (fragP->fr_subtype) { case 1: extension = 0; displacement = &opcode[1]; break; case 2: opcode[0] |= 0x80; extension = 2; displacement = &opcode[1]; break; case 3: opcode[2] = opcode[0] | 0x80; md_number_to_chars (opcode, PAR_NOP_INSN, 2); opcode_address += 2; extension = 4; displacement = &opcode[3]; break; default: abort (); } if (S_GET_SEGMENT (fragP->fr_symbol) != sec) { /* Symbol must be resolved by linker. */ if (fragP->fr_offset & 3) as_warn (_("Addend to unresolved symbol not on word boundary.")); addend = fragP->fr_offset >> 2; } else { /* Address we want to reach in file space. */ target_address = S_GET_VALUE (fragP->fr_symbol) + fragP->fr_offset; target_address += symbol_get_frag (fragP->fr_symbol)->fr_address; addend = (target_address - (opcode_address & -4)) >> 2; } /* Create a relocation for symbols that must be resolved by the linker. Otherwise output the completed insn. */ if (S_GET_SEGMENT (fragP->fr_symbol) != sec) { assert (fragP->fr_subtype != 1); assert (fragP->fr_cgen.insn != 0); gas_cgen_record_fixup (fragP, /* Offset of branch insn in frag. */ fragP->fr_fix + extension - 4, fragP->fr_cgen.insn, 4 /* Length. */, /* FIXME: quick hack. */#if 0 cgen_operand_lookup_by_num (gas_cgen_cpu_desc, fragP->fr_cgen.opindex),#else cgen_operand_lookup_by_num (gas_cgen_cpu_desc, M32R_OPERAND_DISP24),#endif fragP->fr_cgen.opinfo, fragP->fr_symbol, fragP->fr_offset); }#define SIZE_FROM_RELAX_STATE(n) ((n) == 1 ? 1 : 3) md_number_to_chars (displacement, (valueT) addend, SIZE_FROM_RELAX_STATE (fragP->fr_subtype)); fragP->fr_fix += extension;}/* Functions concerning relocs. *//* The location from which a PC relative jump should be calculated, given a PC relative reloc. */longmd_pcrel_from_section (fixP, sec) fixS *fixP; segT sec;{ if (fixP->fx_addsy != (symbolS *) NULL && (! S_IS_DEFINED (fixP->fx_addsy) || S_GET_SEGMENT (fixP->fx_addsy) != sec)) { /* The symbol is undefined (or is defined but not in this section). Let the linker figure it out. */ return 0; } return (fixP->fx_frag->fr_address + fixP->fx_where) & -4L;}/* Return the bfd reloc type for OPERAND of INSN at fixup FIXP. Returns BFD_RELOC_NONE if no reloc type can be found. *FIXP may be modified if desired. */bfd_reloc_code_real_typemd_cgen_lookup_reloc (insn, operand, fixP) const CGEN_INSN *insn; const CGEN_OPERAND *operand; fixS *fixP;{ switch (operand->type) { case M32R_OPERAND_DISP8: return BFD_RELOC_M32R_10_PCREL; case M32R_OPERAND_DISP16: return BFD_RELOC_M32R_18_PCREL; case M32R_OPERAND_DISP24: return BFD_RELOC_M32R_26_PCREL; case M32R_OPERAND_UIMM24: return BFD_RELOC_M32R_24; case M32R_OPERAND_HI16: case M32R_OPERAND_SLO16: case M32R_OPERAND_ULO16: /* If low/high/shigh/sda was used, it is recorded in `opinfo'. */ if (fixP->fx_cgen.opinfo != 0) return fixP->fx_cgen.opinfo; break; default: /* Avoid -Wall warning. */ break; } return BFD_RELOC_NONE;}/* Record a HI16 reloc for later matching with its LO16 cousin. */static voidm32r_record_hi16 (reloc_type, fixP, seg) int reloc_type; fixS *fixP; segT seg;{ struct m32r_hi_fixup *hi_fixup; assert (reloc_type == BFD_RELOC_M32R_HI16_SLO || reloc_type == BFD_RELOC_M32R_HI16_ULO); hi_fixup = ((struct m32r_hi_fixup *) xmalloc (sizeof (struct m32r_hi_fixup))); hi_fixup->fixp = fixP; hi_fixup->seg = now_seg; hi_fixup->next = m32r_hi_fixup_list; m32r_hi_fixup_list = hi_fixup;}/* Called while parsing an instruction to create a fixup. We need to check for HI16 relocs and queue them up for later sorting. */fixS *m32r_cgen_record_fixup_exp (frag, where, insn, length, operand, opinfo, exp) fragS *frag; int where; const CGEN_INSN *insn; int length; const CGEN_OPERAND *operand; int opinfo; expressionS *exp;{ fixS *fixP = gas_cgen_record_fixup_exp (frag, where, insn, length, operand, opinfo, exp); switch (operand->type) { case M32R_OPERAND_HI16: /* If low/high/shigh/sda was used, it is recorded in `opinfo'. */ if (fixP->fx_cgen.opinfo == BFD_RELOC_M32R_HI16_SLO || fixP->fx_cgen.opinfo == BFD_RELOC_M32R_HI16_ULO) m32r_record_hi16 (fixP->fx_cgen.opinfo, fixP, now_seg); break; default: /* Avoid -Wall warning */ break; } return fixP;}/* Return BFD reloc type from opinfo field in a fixS. It's tricky using fx_r_type in m32r_frob_file because the values are BFD_RELOC_UNUSED + operand number. */#define FX_OPINFO_R_TYPE(f) ((f)->fx_cgen.opinfo)/* Sort any unmatched HI16 relocs so that they immediately precede the corresponding LO16 reloc. This is called before md_apply_fix and tc_gen_reloc. */voidm32r_frob_file (){ struct m32r_hi_fixup *l; for (l = m32r_hi_fixup_list; l != NULL; l = l->next) { segment_info_type *seginfo; int pass; assert (FX_OPINFO_R_TYPE (l->fixp) == BFD_RELOC_M32R_HI16_SLO || FX_OPINFO_R_TYPE (l->fixp) == BFD_RELOC_M32R_HI16_ULO); /* Check quickly whether the next fixup happens to be a matching low. */ if (l->fixp->fx_next != NULL && FX_OPINFO_R_TYPE (l->fixp->fx_next) == BFD_RELOC_M32R_LO16 && l->fixp->fx_addsy == l->fixp->fx_next->fx_addsy && l->fixp->fx_offset == l->fixp->fx_next->fx_offset) continue; /* Look through the fixups for this segment for a matching `low'. When we find one, move the high/shigh just in front of it. We do this in two passes. In the first pass, we try to find a unique `low'. In the second pass, we permit multiple high's relocs for a single `low'. */ seginfo = seg_info (l->seg); for (pass = 0; pass < 2; pass++) { fixS *f; fixS *prev; prev = NULL; for (f = seginfo->fix_root; f != NULL; f = f->fx_next) { /* Check whether this is a `low' fixup which matches l->fixp. */ if (FX_OPINFO_R_TYPE (f) == BFD_RELOC_M32R_LO16 && f->fx_addsy == l->fixp->fx_addsy && f->fx_offset == l->fixp->fx_offset && (pass == 1 || prev == NULL || (FX_OPINFO_R_TYPE (prev) != BFD_RELOC_M32R_HI16_SLO && FX_OPINFO_R_TYPE (prev) != BFD_RELOC_M32R_HI16_ULO) || prev->fx_addsy != f->fx_addsy || prev->fx_offset != f->fx_offset)) { fixS **pf; /* Move l->fixp before f. */ for (pf = &seginfo->fix_root; *pf != l->fixp; pf = & (*pf)->fx_next) assert (*pf != NULL); *pf = l->fixp->fx_next; l->fixp->fx_next = f; if (prev == NULL) seginfo->fix_root = l->fixp; else prev->fx_next = l->fixp; break; } prev = f; } if (f != NULL) break; if (pass == 1 && warn_unmatched_high) as_warn_where (l->fixp->fx_file, l->fixp->fx_line, _("Unmatched high/shigh reloc")); } }}/* See whether we need to force a relocation into the output file. This is used to force out switch and PC relative relocations when relaxing. */intm32r_force_relocation (fix) fixS *fix;{ if (fix->fx_r_type == BFD_RELOC_VTABLE_INHERIT || fix->fx_r_type == BFD_RELOC_VTABLE_ENTRY) return 1; if (! m32r_relax) return 0; return fix->fx_pcrel;}/* Write a value out to the object file, using the appropriate endianness. */voidmd_number_to_chars (buf, val, n) char *buf; valueT val; int n;{ if (target_big_endian) number_to_chars_bigendian (buf, val, n); else number_to_chars_littleendian (buf, val, n);}/* 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. *//* Equal to MAX_PRECISION in atof-ieee.c. */#define MAX_LITTLENUMS 6char *md_atof (type, litP, sizeP) char type; char *litP; int *sizeP;{ int i; int prec; LITTLENUM_TYPE words[MAX_LITTLENUMS]; 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; /* FIXME: Some targets allow other format chars for bigger sizes here. */ 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); if (target_big_endian) { for (i = 0; i < prec; i++) { md_number_to_chars (litP, (valueT) words[i], sizeof (LITTLENUM_TYPE)); litP += sizeof (LITTLENUM_TYPE); } } else { for (i = prec - 1; i >= 0; i--) { md_number_to_chars (litP, (valueT) words[i], sizeof (LITTLENUM_TYPE)); litP += sizeof (LITTLENUM_TYPE); } } return 0;}voidm32r_elf_section_change_hook (){ /* If we have reached the end of a section and we have just emitted a 16 bit insn, then emit a nop to make sure that the section ends on a 32 bit boundary. */ if (prev_insn.insn || seen_relaxable_p) (void) m32r_fill_insn (0);}/* Return true if can adjust the reloc to be relative to its section (such as .data) instead of relative to some symbol. */booleanm32r_fix_adjustable (fixP) fixS *fixP;{ bfd_reloc_code_real_type reloc_type; if ((int) fixP->fx_r_type >= (int) BFD_RELOC_UNUSED) { const CGEN_INSN *insn = NULL; int opindex = (int) fixP->fx_r_type - (int) BFD_RELOC_UNUSED; const CGEN_OPERAND *operand = cgen_operand_lookup_by_num(gas_cgen_cpu_desc, opindex); reloc_type = md_cgen_lookup_reloc (insn, operand, fixP); } else reloc_type = fixP->fx_r_type; if (fixP->fx_addsy == NULL) return 1; /* Prevent all adjustments to global symbols. */ if (S_IS_EXTERN (fixP->fx_addsy)) return 0; if (S_IS_WEAK (fixP->fx_addsy)) return 0; /* We need the symbol name for the VTABLE entries. */ if (reloc_type == BFD_RELOC_VTABLE_INHERIT || reloc_type == BFD_RELOC_VTABLE_ENTRY) return 0; return 1;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -