📄 tc-m32r.c
字号:
gas_cgen_restore_fixups (); /* Write out the first instruction. */ expand_debug_syms (first.debug_sym_link, 1); gas_cgen_finish_insn (first.orig_insn, first.buffer, CGEN_FIELDS_BITSIZE (&first.fields), 0, NULL); } else { as_bad ("'%s': %s", str2, errmsg); return; } /* Set these so m32r_fill_insn can use them. */ prev_seg = now_seg; prev_subseg = now_subseg;}voidmd_assemble (str) char *str;{ m32r_insn insn; char *errmsg; char *str2 = NULL; /* Initialize GAS's cgen interface for a new instruction. */ gas_cgen_init_parse (); /* Look for a parallel instruction seperator. */ if ((str2 = strstr (str, "||")) != NULL) { assemble_two_insns (str, str2, 1); return; } /* Also look for a sequential instruction seperator. */ if ((str2 = strstr (str, "->")) != NULL) { assemble_two_insns (str, str2, 0); return; } insn.debug_sym_link = debug_sym_link; debug_sym_link = (sym_linkS *) 0; insn.insn = m32r_cgen_assemble_insn (gas_cgen_cpu_desc, str, &insn.fields, insn.buffer, & errmsg); if (!insn.insn) { as_bad (errmsg); return; } if (! enable_special && CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_SPECIAL)) { /* xgettext:c-format */ as_bad (_("unknown instruction '%s'"), str); return; } else if (! enable_m32rx && CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_MACH) == (1 << MACH_M32RX)) { /* xgettext:c-format */ as_bad (_("instruction '%s' is for the M32RX only"), str); return; } if (CGEN_INSN_BITSIZE (insn.insn) == 32) { /* 32 bit insns must live on 32 bit boundaries. */ if (prev_insn.insn || seen_relaxable_p) { /* ??? If calling fill_insn too many times turns us into a memory pig, can we call a fn to assemble a nop instead of !seen_relaxable_p? */ fill_insn (0); } expand_debug_syms (insn.debug_sym_link, 2); /* Doesn't really matter what we pass for RELAX_P here. */ gas_cgen_finish_insn (insn.insn, insn.buffer, CGEN_FIELDS_BITSIZE (&insn.fields), 1, NULL); } else { int on_32bit_boundary_p; int swap = false; if (CGEN_INSN_BITSIZE (insn.insn) != 16) abort (); insn.orig_insn = insn.insn; /* If the previous insn was relaxable, then it may be expanded to fill the current 16 bit slot. Emit a NOP here to occupy this slot, so that we can start at optimizing at a 32 bit boundary. */ if (prev_insn.insn && seen_relaxable_p && optimize) fill_insn (0); if (enable_m32rx) { /* Get the indices of the operands of the instruction. FIXME: See assemble_parallel for notes on orig_insn. */ { CGEN_FIELDS tmp_fields; insn.insn = cgen_lookup_get_insn_operands (gas_cgen_cpu_desc, NULL, INSN_VALUE (insn.buffer), NULL, 16, insn.indices, &tmp_fields); } if (insn.insn == NULL) as_fatal (_("internal error: lookup/get operands failed")); } /* Compute whether we're on a 32 bit boundary or not. prev_insn.insn is NULL when we're on a 32 bit boundary. */ on_32bit_boundary_p = prev_insn.insn == NULL; /* Look to see if this instruction can be combined with the previous instruction to make one, parallel, 32 bit instruction. If the previous instruction (potentially) changed the flow of program control, then it cannot be combined with the current instruction. If the current instruction is relaxable, then it might be replaced with a longer version, so we cannot combine it. Also if the output of the previous instruction is used as an input to the current instruction then it cannot be combined. Otherwise call can_make_parallel() with both orderings of the instructions to see if they can be combined. */ if (! on_32bit_boundary_p && enable_m32rx && optimize && CGEN_INSN_ATTR_VALUE (insn.orig_insn, CGEN_INSN_RELAXABLE) == 0 && ! writes_to_pc (&prev_insn) && ! first_writes_to_seconds_operands (&prev_insn, &insn, false)) { if (can_make_parallel (&prev_insn, &insn) == NULL) make_parallel (insn.buffer); else if (can_make_parallel (&insn, &prev_insn) == NULL) swap = true; } expand_debug_syms (insn.debug_sym_link, 1); { int i; finished_insnS fi; /* Ensure each pair of 16 bit insns is in the same frag. */ frag_grow (4); gas_cgen_finish_insn (insn.orig_insn, insn.buffer, CGEN_FIELDS_BITSIZE (&insn.fields), 1 /* relax_p */, &fi); insn.addr = fi.addr; insn.frag = fi.frag; insn.num_fixups = fi.num_fixups; for (i = 0; i < fi.num_fixups; ++i) insn.fixups[i] = fi.fixups[i]; } if (swap) { int i, tmp;#define SWAP_BYTES(a,b) tmp = a; a = b; b = tmp /* Swap the two insns */ SWAP_BYTES (prev_insn.addr[0], insn.addr[0]); SWAP_BYTES (prev_insn.addr[1], insn.addr[1]); target_make_parallel (insn.addr); /* Swap any relaxable frags recorded for the two insns. */ /* FIXME: Clarify. relaxation precludes parallel insns */ if (prev_insn.frag->fr_opcode == prev_insn.addr) prev_insn.frag->fr_opcode = insn.addr; else if (insn.frag->fr_opcode == insn.addr) insn.frag->fr_opcode = prev_insn.addr; /* Update the addresses in any fixups. Note that we don't have to handle the case where each insn is in a different frag as we ensure they're in the same frag above. */ for (i = 0; i < prev_insn.num_fixups; ++i) prev_insn.fixups[i]->fx_where += 2; for (i = 0; i < insn.num_fixups; ++i) insn.fixups[i]->fx_where -= 2; } /* Keep track of whether we've seen a pair of 16 bit insns. prev_insn.insn is NULL when we're on a 32 bit boundary. */ if (on_32bit_boundary_p) prev_insn = insn; else prev_insn.insn = NULL; /* If the insn needs the following one to be on a 32 bit boundary (e.g. subroutine calls), fill this insn's slot. */ if (on_32bit_boundary_p && CGEN_INSN_ATTR_VALUE (insn.orig_insn, CGEN_INSN_FILL_SLOT) != 0) fill_insn (0); /* If this is a relaxable insn (can be replaced with a larger version) mark the fact so that we can emit an alignment directive for a following 32 bit insn if we see one. */ if (CGEN_INSN_ATTR_VALUE (insn.orig_insn, CGEN_INSN_RELAXABLE) != 0) seen_relaxable_p = 1; } /* Set these so m32r_fill_insn can use them. */ prev_seg = now_seg; prev_subseg = now_subseg;}/* The syntax in the manual says constants begin with '#'. We just ignore it. */voidmd_operand (expressionP) expressionS *expressionP;{ if (*input_line_pointer == '#') { input_line_pointer++; expression (expressionP); }}valueTmd_section_align (segment, size) segT segment; valueT size;{ int align = bfd_get_section_alignment (stdoutput, segment); return ((size + (1 << align) - 1) & (-1 << align));}symbolS *md_undefined_symbol (name) char *name;{ return 0;}/* .scomm pseudo-op handler. This is a new pseudo-op to handle putting objects in .scommon. By doing this the linker won't need to do any work, and more importantly it removes the implicit -G arg necessary to correctly link the object file. */static voidm32r_scomm (ignore) int ignore;{ register char *name; register char c; register char *p; offsetT size; register symbolS *symbolP; offsetT align; 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; } /* Skip ','. */ input_line_pointer++; if ((size = get_absolute_expression ()) < 0) { /* xgettext:c-format */ as_warn (_(".SCOMMon length (%ld.) <0! Ignored."), (long) size); ignore_rest_of_line (); return; } /* The third argument to .scomm 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; } } /* Convert to a power of 2 alignment. */ if (align) { for (align2 = 0; (align & 1) == 0; align >>= 1, ++align2) continue; if (align != 1) { as_bad (_("Common alignment not a power of 2")); ignore_rest_of_line (); return; } } else align2 = 0; *p = 0; symbolP = symbol_find_or_make (name); *p = c; if (S_IS_DEFINED (symbolP)) { /* xgettext:c-format */ 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) { /* xgettext:c-format */ as_bad (_("Length of .scomm \"%s\" is already %ld. Not changed to %ld."), S_GET_NAME (symbolP), (long) S_GET_VALUE (symbolP), (long) size); ignore_rest_of_line (); return; } if (symbol_get_obj (symbolP)->local) { segT old_sec = now_seg; int old_subsec = now_subseg; char *pfrag; record_alignment (sbss_section, align2); subseg_set (sbss_section, 0); if (align2) frag_align (align2, 0, 0); if (S_GET_SEGMENT (symbolP) == sbss_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, sbss_section); S_CLEAR_EXTERNAL (symbolP); subseg_set (old_sec, old_subsec); } else { S_SET_VALUE (symbolP, (valueT) size); S_SET_ALIGN (symbolP, align2); S_SET_EXTERNAL (symbolP); S_SET_SEGMENT (symbolP, &scom_section); } demand_empty_rest_of_line ();}/* Interface to relax_segment. *//* FIXME: Build table by hand, get it working, then machine generate. */const relax_typeS md_relax_table[] ={/* The fields are: 1) most positive reach of this state, 2) most negative reach of this state, 3) how many bytes this mode will add to the size of the current frag 4) which index into the table to try if we can't fit into this one. */ /* The first entry must be unused because an `rlx_more' value of zero ends each list. */ {1, 1, 0, 0}, /* The displacement used by GAS is from the end of the 2 byte insn, so we subtract 2 from the following. */ /* 16 bit insn, 8 bit disp -> 10 bit range. This doesn't handle a branch in the right slot at the border: the "& -4" isn't taken into account. It's not important enough to complicate things over it, so we subtract an extra 2 (or + 2 in -ve case). */ {511 - 2 - 2, -512 - 2 + 2, 0, 2 }, /* 32 bit insn, 24 bit disp -> 26 bit range. */ {0x2000000 - 1 - 2, -0x2000000 - 2, 2, 0 }, /* Same thing, but with leading nop for alignment. */ {0x2000000 - 1 - 2, -0x2000000 - 2, 4, 0 }};longm32r_relax_frag (segment, fragP, stretch) segT segment; fragS *fragP; long stretch;{ /* Address of branch insn. */ long address = fragP->fr_address + fragP->fr_fix - 2; long growth = 0; /* Keep 32 bit insns aligned on 32 bit boundaries. */ if (fragP->fr_subtype == 2) { if ((address & 3) != 0) { fragP->fr_subtype = 3; growth = 2; } } else if (fragP->fr_subtype == 3) { if ((address & 3) == 0) { fragP->fr_subtype = 2; growth = -2; } } else { growth = relax_frag (segment, fragP, stretch); /* Long jump on odd halfword boundary? */ if (fragP->fr_subtype == 2 && (address & 3) != 0) { fragP->fr_subtype = 3; growth += 2; } } return growth;}/* Return an initial guess of the length by which a fragment must grow to hold a branch to reach its destination. Also updates fr_type/fr_subtype as necessary. Called just before doing relaxation. Any symbol that is now undefined will not become defined. The guess for fr_var is ACTUALLY the growth beyond fr_fix. Whatever we do to grow fr_fix or fr_var contributes to our returned value. Although it may not be explicit in the frag, pretend fr_var starts with a 0 value. */intmd_estimate_size_before_relax (fragP, segment) fragS *fragP; segT segment;{ /* The only thing we have to handle here are symbols outside of the current segment. They may be undefined or in a different segment in which case linker scripts may place them anywhere. However, we can't finish the fragment here and emit the reloc as insn alignment requirements may move the insn about. */ if (S_GET_SEGMENT (fragP->fr_symbol) != segment) { int old_fr_fix = fragP->fr_fix; /* The symbol is undefined in this segment. Change the relaxation subtype to the max allowable and leave all further handling to md_convert_frag. */ fragP->fr_subtype = 2;#if 0 /* Can't use this, but leave in for illustration. */ /* Change 16 bit insn to 32 bit insn. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -