diff options
author | DJ Delorie <dj@redhat.com> | 2012-05-15 03:04:47 +0000 |
---|---|---|
committer | DJ Delorie <dj@redhat.com> | 2012-05-15 03:04:47 +0000 |
commit | 0e25bcb440a877010123d832576e3290bcef2242 (patch) | |
tree | a2e1a5827cc061d0e4d7b331f3902c39e4000edf /gas/config/tc-rx.c | |
parent | d051b294b998b68119ed6866459a47be0995d9cd (diff) | |
download | gdb-0e25bcb440a877010123d832576e3290bcef2242.zip gdb-0e25bcb440a877010123d832576e3290bcef2242.tar.gz gdb-0e25bcb440a877010123d832576e3290bcef2242.tar.bz2 |
* config/tc-rx.c (rx_fetchalign): Declare.
(md_pseudo_table): Add .fetchalign.
(RX_NBASE_FETCHALIGN): New.
(fetchalign_bytes): New.
(rx_fetchalign): New.
(rx_frag_init): If a "magic" value is found, also init the
machine-specific data.
(md_assemble): Note following opcode size if called for.
(rx_next_opcode): New.
(rx_relax_frag): Support .fetchalign.
(md_convert_frag): Likewise.
* doc/c-rx.texi (RX-Directives): Add .fetchalign.
Diffstat (limited to 'gas/config/tc-rx.c')
-rw-r--r-- | gas/config/tc-rx.c | 99 |
1 files changed, 96 insertions, 3 deletions
diff --git a/gas/config/tc-rx.c b/gas/config/tc-rx.c index 4fa0f67..3db8fe1 100644 --- a/gas/config/tc-rx.c +++ b/gas/config/tc-rx.c @@ -56,6 +56,8 @@ static int rx_num_int_regs = 0; int rx_pid_register; int rx_gp_register; +static void rx_fetchalign (int ignore ATTRIBUTE_UNUSED); + enum options { OPTION_BIG = OPTION_MD_BASE, @@ -600,6 +602,8 @@ const pseudo_typeS md_pseudo_table[] = { "int", cons, 4 }, { "word", cons, 4 }, + { "fetchalign", rx_fetchalign, 0 }, + /* End of list marker. */ { NULL, NULL, 0 } }; @@ -648,9 +652,14 @@ md_begin (void) char * rx_lex_start; char * rx_lex_end; +/* These negative numbers are found in rx_bytesT.n_base for non-opcode + md_frags */ +#define RX_NBASE_FETCHALIGN -1 + typedef struct rx_bytesT { char base[4]; + /* If this is negative, it's a special-purpose frag as per the defines above. */ int n_base; char ops[8]; int n_ops; @@ -678,6 +687,31 @@ typedef struct rx_bytesT } rx_bytesT; static rx_bytesT rx_bytes; +/* We set n_ops to be "size of next opcode" if the next opcode doesn't relax. */ +static rx_bytesT *fetchalign_bytes = NULL; + +static void +rx_fetchalign (int ignore ATTRIBUTE_UNUSED) +{ + char * bytes; + fragS * frag_then; + + memset (& rx_bytes, 0, sizeof (rx_bytes)); + rx_bytes.n_base = RX_NBASE_FETCHALIGN; + + bytes = frag_more (8); + frag_then = frag_now; + frag_variant (rs_machine_dependent, + 0 /* max_chars */, + 0 /* var */, + 0 /* subtype */, + 0 /* symbol */, + 0 /* offset */, + 0 /* opcode */); + frag_then->fr_opcode = bytes; + frag_then->fr_subtype = 0; + fetchalign_bytes = frag_then->tc_frag_data; +} void rx_relax (int type, int pos) @@ -933,7 +967,7 @@ rx_wrap (void) void rx_frag_init (fragS * fragP) { - if (rx_bytes.n_relax || rx_bytes.link_relax) + if (rx_bytes.n_relax || rx_bytes.link_relax || rx_bytes.n_base < 0) { fragP->tc_frag_data = malloc (sizeof (rx_bytesT)); memcpy (fragP->tc_frag_data, & rx_bytes, sizeof (rx_bytesT)); @@ -1049,8 +1083,12 @@ md_assemble (char * str) { bytes = frag_more (rx_bytes.n_base + rx_bytes.n_ops); frag_then = frag_now; + if (fetchalign_bytes) + fetchalign_bytes->n_ops = rx_bytes.n_base + rx_bytes.n_ops; } + fetchalign_bytes = NULL; + APPEND (base, n_base); APPEND (ops, n_ops); @@ -1413,6 +1451,18 @@ md_estimate_size_before_relax (fragS * fragP ATTRIBUTE_UNUSED, segT segment ATTR return delta; } +/* Given a frag FRAGP, return the "next" frag that contains an + opcode. Assumes the next opcode is relaxable, and thus rs_machine_dependent. */ + +static fragS * +rx_next_opcode (fragS *fragP) +{ + do { + fragP = fragP->fr_next; + } while (fragP && fragP->fr_type != rs_machine_dependent); + return fragP; +} + /* Given the new addresses for this relax pass, figure out how big each opcode must be. We store the total number of bytes needed in fr_subtype. The return value is the difference between the size @@ -1437,6 +1487,34 @@ rx_relax_frag (segT segment ATTRIBUTE_UNUSED, fragS * fragP, long stretch) (long) fragP->fr_fix, (long) fragP->fr_var, (long) fragP->fr_offset, fragP->fr_literal, fragP->fr_opcode, fragP->fr_type, fragP->fr_subtype, stretch); + mypc = fragP->fr_address + (fragP->fr_opcode - fragP->fr_literal); + + if (fragP->tc_frag_data->n_base == RX_NBASE_FETCHALIGN) + { + unsigned int next_size; + if (fragP->fr_next == NULL) + return 0; + + next_size = fragP->tc_frag_data->n_ops; + if (next_size == 0) + { + fragS *n = rx_next_opcode (fragP); + next_size = n->fr_subtype; + } + + fragP->fr_subtype = (8-(mypc & 7)) & 7; + tprintf("subtype %u\n", fragP->fr_subtype); + if (fragP->fr_subtype >= next_size) + fragP->fr_subtype = 0; + tprintf ("\033[34m -> mypc %lu next_size %u new %d old %d delta %d (fetchalign)\033[0m\n", + mypc & 7, + next_size, fragP->fr_subtype, oldsize, fragP->fr_subtype-oldsize); + + newsize = fragP->fr_subtype; + + return newsize - oldsize; + } + optype = rx_opcode_type (fragP->fr_opcode); /* In the one case where we have both a disp and imm relaxation, we want @@ -1485,7 +1563,6 @@ rx_relax_frag (segT segment ATTRIBUTE_UNUSED, fragS * fragP, long stretch) return newsize - oldsize; } - mypc = fragP->fr_address + (fragP->fr_opcode - fragP->fr_literal); if (sym_addr > mypc) addr0 += stretch; @@ -1644,13 +1721,29 @@ md_convert_frag (bfd * abfd ATTRIBUTE_UNUSED, { int i; - printf ("lit %08x opc %08x", (int) fragP->fr_literal, (int) fragP->fr_opcode); + printf ("lit 0x%p opc 0x%p", fragP->fr_literal, fragP->fr_opcode); for (i = 0; i < 10; i++) printf (" %02x", (unsigned char) (fragP->fr_opcode[i])); printf ("\n"); } #endif + if (fragP->tc_frag_data->n_base == RX_NBASE_FETCHALIGN) + { + int count = fragP->fr_subtype; + if (count == 0) + ; + else if (count > BIGGEST_NOP) + { + op[0] = 0x2e; + op[1] = count; + } + else if (count > 0) + { + memcpy (op, nops[count], count); + } + } + /* In the one case where we have both a disp and imm relaxation, we want the imm relaxation here. */ ri = 0; |