📄 tc-d30v.c
字号:
/* Turn an expression into a symbol for later resolution. */ if (X_op != O_absent && X_op != O_constant && X_op != O_symbol && X_op != O_register && X_op != O_big) { symbolS *sym = make_expr_symbol (&myops[j]); myops[j].X_op = X_op = O_symbol; myops[j].X_add_symbol = sym; myops[j].X_add_number = num = 0; } if (fm->form >= LONG) { /* If we're testing for a LONG format, either fits. */ if (X_op != O_constant && X_op != O_symbol) match = 0; } else if (fm->form < LONG && ((fsize == FORCE_SHORT && X_op == O_symbol) || (fm->form == SHORT_D2 && j == 0))) match = 1; /* This is the tricky part. Will the constant or symbol fit into the space in the current format? */ else if (X_op == O_constant) { if (check_range (num, bits, flags)) match = 0; } else if (X_op == O_symbol && S_IS_DEFINED (myops[j].X_add_symbol) && S_GET_SEGMENT (myops[j].X_add_symbol) == now_seg && opcode->reloc_flag == RELOC_PCREL) { /* If the symbol is defined, see if the value will fit into the form we're considering. */ fragS *f; long value; /* Calculate the current address by running through the previous frags and adding our current offset. */ value = 0; for (f = frchain_now->frch_root; f; f = f->fr_next) value += f->fr_fix + f->fr_offset; value = (S_GET_VALUE (myops[j].X_add_symbol) - value - (obstack_next_free (&frchain_now->frch_obstack) - frag_now->fr_literal)); if (check_range (value, bits, flags)) match = 0; } else match = 0; } }#if 0 printf ("through the loop: match=%d\n", match);#endif /* We're only done if the operands matched so far AND there are no more to check. */ if (match && myops[j].X_op == 0) { /* Final check - issue a warning if an odd numbered register is used as the first register in an instruction that reads or writes 2 registers. */ for (j = 0; fm->operands[j]; j++) if (myops[j].X_op == O_register && (myops[j].X_add_number & 1) && (d30v_operand_table[fm->operands[j]].flags & OPERAND_2REG)) as_warn (_("Odd numbered register used as target of multi-register instruction")); return fm; } fm = (struct d30v_format *) &d30v_format_table[++k]; }#if 0 printf ("trying another format: i=%d\n", i);#endif } return NULL;}/* If while processing a fixup, a reloc really needs to be created, then it is done here. */arelent *tc_gen_reloc (seg, fixp) asection *seg; fixS *fixp;{ arelent *reloc; 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; reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type); if (reloc->howto == (reloc_howto_type *) NULL) { as_bad_where (fixp->fx_file, fixp->fx_line, _("reloc %d not supported by object file format"), (int) fixp->fx_r_type); return NULL; } reloc->addend = fixp->fx_addnumber; return reloc;}intmd_estimate_size_before_relax (fragp, seg) fragS *fragp; asection *seg;{ abort (); return 0;}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))) return 0; return fixp->fx_frag->fr_address + fixp->fx_where;}intmd_apply_fix3 (fixp, valuep, seg) fixS *fixp; valueT *valuep; segT seg;{ char *where; unsigned long insn, insn2; long value; if (fixp->fx_addsy == (symbolS *) NULL) { value = *valuep; fixp->fx_done = 1; } else if (fixp->fx_pcrel) value = *valuep; else { value = fixp->fx_offset; if (fixp->fx_subsy != (symbolS *) NULL) { if (S_GET_SEGMENT (fixp->fx_subsy) == absolute_section) value -= S_GET_VALUE (fixp->fx_subsy); else { /* We don't actually support subtracting a symbol. */ as_bad_where (fixp->fx_file, fixp->fx_line, _("expression too complex")); } } } /* Fetch the instruction, insert the fully resolved operand value, and stuff the instruction back again. */ where = fixp->fx_frag->fr_literal + fixp->fx_where; insn = bfd_getb32 ((unsigned char *) where); switch (fixp->fx_r_type) { case BFD_RELOC_8: /* Check for a bad .byte directive. */ if (fixp->fx_addsy != NULL) as_bad (_("line %d: unable to place address of symbol '%s' into a byte"), fixp->fx_line, S_GET_NAME (fixp->fx_addsy)); else if (((unsigned)value) > 0xff) as_bad (_("line %d: unable to place value %x into a byte"), fixp->fx_line, value); else *(unsigned char *) where = value; break; case BFD_RELOC_16: /* Check for a bad .short directive. */ if (fixp->fx_addsy != NULL) as_bad (_("line %d: unable to place address of symbol '%s' into a short"), fixp->fx_line, S_GET_NAME (fixp->fx_addsy)); else if (((unsigned)value) > 0xffff) as_bad (_("line %d: unable to place value %x into a short"), fixp->fx_line, value); else bfd_putb16 ((bfd_vma) value, (unsigned char *) where); break; case BFD_RELOC_64: /* Check for a bad .quad directive. */ if (fixp->fx_addsy != NULL) as_bad (_("line %d: unable to place address of symbol '%s' into a quad"), fixp->fx_line, S_GET_NAME (fixp->fx_addsy)); else { bfd_putb32 ((bfd_vma) value, (unsigned char *) where); bfd_putb32 (0, ((unsigned char *) where) + 4); } break; case BFD_RELOC_D30V_6: check_size (value, 6, fixp->fx_file, fixp->fx_line); insn |= value & 0x3F; bfd_putb32 ((bfd_vma) insn, (unsigned char *) where); break; case BFD_RELOC_D30V_9_PCREL: if (fixp->fx_where & 0x7) { if (fixp->fx_done) value += 4; else fixp->fx_r_type = BFD_RELOC_D30V_9_PCREL_R; } check_size (value, 9, fixp->fx_file, fixp->fx_line); insn |= ((value >> 3) & 0x3F) << 12; bfd_putb32 ((bfd_vma) insn, (unsigned char *) where); break; case BFD_RELOC_D30V_15: check_size (value, 15, fixp->fx_file, fixp->fx_line); insn |= (value >> 3) & 0xFFF; bfd_putb32 ((bfd_vma) insn, (unsigned char *) where); break; case BFD_RELOC_D30V_15_PCREL: if (fixp->fx_where & 0x7) { if (fixp->fx_done) value += 4; else fixp->fx_r_type = BFD_RELOC_D30V_15_PCREL_R; } check_size (value, 15, fixp->fx_file, fixp->fx_line); insn |= (value >> 3) & 0xFFF; bfd_putb32 ((bfd_vma) insn, (unsigned char *) where); break; case BFD_RELOC_D30V_21: check_size (value, 21, fixp->fx_file, fixp->fx_line); insn |= (value >> 3) & 0x3FFFF; bfd_putb32 ((bfd_vma) insn, (unsigned char *) where); break; case BFD_RELOC_D30V_21_PCREL: if (fixp->fx_where & 0x7) { if (fixp->fx_done) value += 4; else fixp->fx_r_type = BFD_RELOC_D30V_21_PCREL_R; } check_size (value, 21, fixp->fx_file, fixp->fx_line); insn |= (value >> 3) & 0x3FFFF; bfd_putb32 ((bfd_vma) insn, (unsigned char *) where); break; case BFD_RELOC_D30V_32: insn2 = bfd_getb32 ((unsigned char *) where + 4); insn |= (value >> 26) & 0x3F; /* Top 6 bits. */ insn2 |= ((value & 0x03FC0000) << 2); /* Next 8 bits. */ insn2 |= value & 0x0003FFFF; /* Bottom 18 bits. */ bfd_putb32 ((bfd_vma) insn, (unsigned char *) where); bfd_putb32 ((bfd_vma) insn2, (unsigned char *) where + 4); break; case BFD_RELOC_D30V_32_PCREL: insn2 = bfd_getb32 ((unsigned char *) where + 4); insn |= (value >> 26) & 0x3F; /* Top 6 bits. */ insn2 |= ((value & 0x03FC0000) << 2); /* Next 8 bits. */ insn2 |= value & 0x0003FFFF; /* Bottom 18 bits. */ bfd_putb32 ((bfd_vma) insn, (unsigned char *) where); bfd_putb32 ((bfd_vma) insn2, (unsigned char *) where + 4); break; case BFD_RELOC_32: bfd_putb32 ((bfd_vma) value, (unsigned char *) where); break; default: as_bad (_("line %d: unknown relocation type: 0x%x"), fixp->fx_line, fixp->fx_r_type); } return 0;}/* Called after the assembler has finished parsing the input file or after a label is defined. Because the D30V assembler sometimes saves short instructions to see if it can package them with the next instruction, there may be a short instruction that still needs written. */intd30v_cleanup (use_sequential) int use_sequential;{ segT seg; subsegT subseg; if (prev_insn != -1) { seg = now_seg; subseg = now_subseg; subseg_set (prev_seg, prev_subseg); write_1_short (&prev_opcode, (long) prev_insn, fixups->next, use_sequential); subseg_set (seg, subseg); prev_insn = -1; if (use_sequential) prev_mul32_p = false; } return 1;}static voidd30v_number_to_chars (buf, value, n) char *buf; /* Return 'nbytes' of chars here. */ long long value; /* The value of the bits. */ int n; /* Number of bytes in the output. */{ while (n--) { buf[n] = value & 0xff; value >>= 8; }}/* This function is called at the start of every line. It checks to see if the first character is a '.', which indicates the start of a pseudo-op. If it is, then write out any unwritten instructions. */voidd30v_start_line (){ char *c = input_line_pointer; while (isspace (*c)) c++; if (*c == '.') d30v_cleanup (false);}static voidcheck_size (value, bits, file, line) long value; int bits; char *file; int line;{ int tmp, max; if (value < 0) tmp = ~value; else tmp = value; max = (1 << (bits - 1)) - 1; if (tmp > max) as_bad_where (file, line, _("value too large to fit in %d bits"), bits); return;}/* d30v_frob_label() is called when after a label is recognized. */voidd30v_frob_label (lab) symbolS *lab;{ /* Emit any pending instructions. */ d30v_cleanup (false); /* Update the label's address with the current output pointer. */ symbol_set_frag (lab, frag_now); S_SET_VALUE (lab, (valueT) frag_now_fix ()); /* Record this label for future adjustment after we find out what kind of data it references, and the required alignment therewith. */ d30v_last_label = lab;}/* Hook into cons for capturing alignment changes. */voidd30v_cons_align (size) int size;{ int log_size; log_size = 0; while ((size >>= 1) != 0) ++log_size; if (d30v_current_align < log_size) d30v_align (log_size, (char *) NULL, NULL); else if (d30v_current_align > log_size) d30v_current_align = log_size; d30v_last_label = NULL;}/* Called internally to handle all alignment needs. This takes care of eliding calls to frag_align if'n the cached current alignment says we've already got it, as well as taking care of the auto-aligning labels wrt code. */static voidd30v_align (n, pfill, label) int n; char *pfill; symbolS *label;{ /* The front end is prone to changing segments out from under us temporarily when -g is in effect. */ int switched_seg_p = (d30v_current_align_seg != now_seg); /* Do not assume that if 'd30v_current_align >= n' and '! switched_seg_p' that it is safe to avoid performing this alignement request. The alignment of the current frag can be changed under our feet, for example by a .ascii directive in the source code. cf testsuite/gas/d30v/reloc.s */ d30v_cleanup (false); if (pfill == NULL) { if (n > 2 && (bfd_get_section_flags (stdoutput, now_seg) & SEC_CODE) != 0) { static char const nop[4] = { 0x00, 0xf0, 0x00, 0x00 }; /* First, make sure we're on a four-byte boundary, in case someone has been putting .byte values the text section. */ if (d30v_current_align < 2 || switched_seg_p) frag_align (2, 0, 0); frag_align_pattern (n, nop, sizeof nop, 0); } else frag_align (n, 0, 0); } else frag_align (n, *pfill, 0); if (!switched_seg_p) d30v_current_align = n; if (label != NULL) { symbolS *sym; int label_seen = false; struct frag *old_frag; valueT old_value; valueT new_value; assert (S_GET_SEGMENT (label) == now_seg); old_frag = symbol_get_frag (label); old_value = S_GET_VALUE (label); new_value = (valueT) frag_now_fix (); /* It is possible to have more than one label at a particular address, especially if debugging is enabled, so we must take care to adjust all the labels at this address in this fragment. To save time we search from the end of the symbol list, backwards, since the symbols we are interested in are almost certainly the ones that were most recently added. Also to save time we stop searching once we have seen at least one matching label, and we encounter a label that is no longer in the target fragment. Note, this search is guaranteed to find at least one match when sym == label, so no special case code is necessary. */ for (sym = symbol_lastP; sym != NULL; sym = symbol_previous (sym)) { if (symbol_get_frag (sym) == old_frag && S_GET_VALUE (sym) == old_value) { label_seen = true; symbol_set_frag (sym, frag_now); S_SET_VALUE (sym, new_value); } else if (label_seen && symbol_get_frag (sym) != old_frag) break; } } record_alignment (now_seg, n);}/* Handle the .align pseudo-op. This aligns to a power of two. We hook here to latch the current alignment. */static voids_d30v_align (ignore) int ignore;{ int align; char fill, *pfill = NULL; long max_alignment = 15; align = get_absolute_expression (); if (align > max_alignment) { align = max_alignment; as_warn (_("Alignment too large: %d assumed"), align); } else if (align < 0) { as_warn (_("Alignment negative: 0 assumed")); align = 0; } if (*input_line_pointer == ',') { input_line_pointer++; fill = get_absolute_expression (); pfill = &fill; } d30v_last_label = NULL; d30v_align (align, pfill, NULL); demand_empty_rest_of_line ();}/* Handle the .text pseudo-op. This is like the usual one, but it clears the saved last label and resets known alignment. */static voids_d30v_text (i) int i;{ s_text (i); d30v_last_label = NULL; d30v_current_align = 0; d30v_current_align_seg = now_seg;}/* Handle the .data pseudo-op. This is like the usual one, but it clears the saved last label and resets known alignment. */static voids_d30v_data (i) int i;{ s_data (i); d30v_last_label = NULL; d30v_current_align = 0; d30v_current_align_seg = now_seg;}/* Handle the .section pseudo-op. This is like the usual one, but it clears the saved last label and resets known alignment. */static voids_d30v_section (ignore) int ignore;{ obj_elf_section (ignore); d30v_last_label = NULL; d30v_current_align = 0; d30v_current_align_seg = now_seg;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -