summaryrefslogtreecommitdiff
path: root/gas/config/tc-rx.c
diff options
context:
space:
mode:
Diffstat (limited to 'gas/config/tc-rx.c')
-rw-r--r--gas/config/tc-rx.c2394
1 files changed, 2394 insertions, 0 deletions
diff --git a/gas/config/tc-rx.c b/gas/config/tc-rx.c
new file mode 100644
index 00000000000..f6353210f18
--- /dev/null
+++ b/gas/config/tc-rx.c
@@ -0,0 +1,2394 @@
+/* tc-rx.c -- Assembler for the Renesas RX
+ Copyright 2008, 2009
+ Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to the Free
+ Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
+ 02110-1301, USA. */
+
+#include "as.h"
+#include "struc-symbol.h"
+#include "obstack.h"
+#include "safe-ctype.h"
+#include "dwarf2dbg.h"
+#include "libbfd.h"
+#include "elf/common.h"
+#include "elf/rx.h"
+#include "rx-defs.h"
+#include "filenames.h"
+#include "listing.h"
+#include "sb.h"
+#include "macro.h"
+
+#define RX_OPCODE_BIG_ENDIAN 0
+
+const char comment_chars[] = ";";
+/* Note that input_file.c hand checks for '#' at the beginning of the
+ first line of the input file. This is because the compiler outputs
+ #NO_APP at the beginning of its output. */
+const char line_comment_chars[] = "#";
+const char line_separator_chars[] = "!";
+
+const char EXP_CHARS[] = "eE";
+const char FLT_CHARS[] = "dD";
+
+/* ELF flags to set in the output file header. */
+static int elf_flags = 0;
+
+bfd_boolean rx_use_conventional_section_names = FALSE;
+static bfd_boolean rx_use_small_data_limit = FALSE;
+
+enum options
+{
+ OPTION_BIG = OPTION_MD_BASE,
+ OPTION_LITTLE,
+ OPTION_32BIT_DOUBLES,
+ OPTION_64BIT_DOUBLES,
+ OPTION_CONVENTIONAL_SECTION_NAMES,
+ OPTION_RENESAS_SECTION_NAMES,
+ OPTION_SMALL_DATA_LIMIT,
+ OPTION_RELAX
+};
+
+#define RX_SHORTOPTS ""
+const char * md_shortopts = RX_SHORTOPTS;
+
+/* Assembler options. */
+struct option md_longopts[] =
+{
+ {"mbig-endian-data", no_argument, NULL, OPTION_BIG},
+ {"mlittle-endian-data", no_argument, NULL, OPTION_LITTLE},
+ /* The next two switches are here because the
+ generic parts of the linker testsuite uses them. */
+ {"EB", no_argument, NULL, OPTION_BIG},
+ {"EL", no_argument, NULL, OPTION_LITTLE},
+ {"m32bit-doubles", no_argument, NULL, OPTION_32BIT_DOUBLES},
+ {"m64bit-doubles", no_argument, NULL, OPTION_64BIT_DOUBLES},
+ /* This option is here mainly for the binutils testsuites,
+ as many of their tests assume conventional section naming. */
+ {"muse-conventional-section-names", no_argument, NULL, OPTION_CONVENTIONAL_SECTION_NAMES},
+ {"muse-renesas-section-names", no_argument, NULL, OPTION_RENESAS_SECTION_NAMES},
+ {"msmall-data-limit", no_argument, NULL, OPTION_SMALL_DATA_LIMIT},
+ {"relax", no_argument, NULL, OPTION_RELAX},
+ {NULL, no_argument, NULL, 0}
+};
+size_t md_longopts_size = sizeof (md_longopts);
+
+int
+md_parse_option (int c ATTRIBUTE_UNUSED, char * arg ATTRIBUTE_UNUSED)
+{
+ switch (c)
+ {
+ case OPTION_BIG:
+ target_big_endian = 1;
+ return 1;
+
+ case OPTION_LITTLE:
+ target_big_endian = 0;
+ return 1;
+
+ case OPTION_32BIT_DOUBLES:
+ elf_flags &= ~ E_FLAG_RX_64BIT_DOUBLES;
+ return 1;
+
+ case OPTION_64BIT_DOUBLES:
+ elf_flags |= E_FLAG_RX_64BIT_DOUBLES;
+ return 1;
+
+ case OPTION_CONVENTIONAL_SECTION_NAMES:
+ rx_use_conventional_section_names = TRUE;
+ return 1;
+
+ case OPTION_RENESAS_SECTION_NAMES:
+ rx_use_conventional_section_names = FALSE;
+ return 1;
+
+ case OPTION_SMALL_DATA_LIMIT:
+ rx_use_small_data_limit = TRUE;
+ return 1;
+
+ case OPTION_RELAX:
+ linkrelax = 1;
+ return 1;
+ }
+ return 0;
+}
+
+void
+md_show_usage (FILE * stream)
+{
+ fprintf (stream, _(" RX specific command line options:\n"));
+ fprintf (stream, _(" --mbig-endian-data\n"));
+ fprintf (stream, _(" --mlittle-endian-data [default]\n"));
+ fprintf (stream, _(" --m32bit-doubles [default]\n"));
+ fprintf (stream, _(" --m64bit-doubles\n"));
+ fprintf (stream, _(" --muse-conventional-section-names\n"));
+ fprintf (stream, _(" --muse-renesas-section-names [default]\n"));
+ fprintf (stream, _(" --msmall-data-limit\n"));
+}
+
+static void
+s_bss (int ignore ATTRIBUTE_UNUSED)
+{
+ int temp;
+
+ temp = get_absolute_expression ();
+ subseg_set (bss_section, (subsegT) temp);
+ demand_empty_rest_of_line ();
+}
+
+static void
+rx_float_cons (int ignore ATTRIBUTE_UNUSED)
+{
+ if (elf_flags & E_FLAG_RX_64BIT_DOUBLES)
+ return float_cons ('d');
+ return float_cons ('f');
+}
+
+static char *
+rx_strcasestr (const char *string, const char *sub)
+{
+ int subl;
+ int strl;
+
+ if (!sub || !sub[0])
+ return (char *)string;
+
+ subl = strlen (sub);
+ strl = strlen (string);
+
+ while (strl >= subl)
+ {
+ /* strncasecmp is in libiberty. */
+ if (strncasecmp (string, sub, subl) == 0)
+ return (char *)string;
+
+ string ++;
+ strl --;
+ }
+ return NULL;
+}
+
+static void
+rx_include (int ignore)
+{
+ FILE * try;
+ char * path;
+ char * filename;
+ char * current_filename;
+ char * eof;
+ char * p;
+ char * d;
+ char * f;
+ char end_char;
+ size_t len;
+
+ /* The RX version of the .INCLUDE pseudo-op does not
+ have to have the filename inside double quotes. */
+ SKIP_WHITESPACE ();
+ if (*input_line_pointer == '"')
+ {
+ /* Treat as the normal GAS .include pseudo-op. */
+ s_include (ignore);
+ return;
+ }
+
+ /* Get the filename. Spaces are allowed, NUL characters are not. */
+ filename = input_line_pointer;
+ eof = find_end_of_line (filename, FALSE);
+ input_line_pointer = eof;
+
+ while (eof >= filename && (* eof == ' ' || * eof == '\n'))
+ -- eof;
+ end_char = *(++ eof);
+ * eof = 0;
+ if (eof == filename)
+ {
+ as_bad (_("no filename following .INCLUDE pseudo-op"));
+ * eof = end_char;
+ return;
+ }
+
+ as_where (& current_filename, NULL);
+ f = (char *) xmalloc (strlen (current_filename) + strlen (filename) + 1);
+
+ /* Check the filename. If [@]..FILE[@] is found then replace
+ this with the current assembler source filename, stripped
+ of any directory prefixes or extensions. */
+ if ((p = rx_strcasestr (filename, "..file")) != NULL)
+ {
+ char * c;
+
+ len = 6; /* strlen ("..file"); */
+
+ if (p > filename && p[-1] == '@')
+ -- p, ++len;
+
+ if (p[len] == '@')
+ len ++;
+
+ for (d = c = current_filename; *c; c++)
+ if (IS_DIR_SEPARATOR (* c))
+ d = c + 1;
+ for (c = d; *c; c++)
+ if (*c == '.')
+ break;
+
+ sprintf (f, "%.*s%.*s%.*s", (int) (p - filename), filename,
+ (int) (c - d), d,
+ (int) (strlen (filename) - ((p + len) - filename)),
+ p + len);
+ }
+ else
+ strcpy (f, filename);
+
+ /* RX .INCLUDE semantics say that 'filename' is located by:
+
+ 1. If filename is absolute, just try that. Otherwise...
+
+ 2. If the current source file includes a directory component
+ then prepend that to the filename and try. Otherwise...
+
+ 3. Try any directories specified by the -I command line
+ option(s).
+
+ 4 .Try a directory specifed by the INC100 environment variable. */
+
+ if (IS_ABSOLUTE_PATH (f))
+ try = fopen (path = f, FOPEN_RT);
+ else
+ {
+ char * env = getenv ("INC100");
+
+ try = NULL;
+
+ len = strlen (current_filename);
+ if ((size_t) include_dir_maxlen > len)
+ len = include_dir_maxlen;
+ if (env && strlen (env) > len)
+ len = strlen (env);
+
+ path = (char *) xmalloc (strlen (f) + len + 5);
+
+ if (current_filename != NULL)
+ {
+ for (d = NULL, p = current_filename; *p; p++)
+ if (IS_DIR_SEPARATOR (* p))
+ d = p;
+
+ if (d != NULL)
+ {
+ sprintf (path, "%.*s/%s", (int) (d - current_filename), current_filename,
+ f);
+ try = fopen (path, FOPEN_RT);
+ }
+ }
+
+ if (try == NULL)
+ {
+ int i;
+
+ for (i = 0; i < include_dir_count; i++)
+ {
+ sprintf (path, "%s/%s", include_dirs[i], f);
+ if ((try = fopen (path, FOPEN_RT)) != NULL)
+ break;
+ }
+ }
+
+ if (try == NULL && env != NULL)
+ {
+ sprintf (path, "%s/%s", env, f);
+ try = fopen (path, FOPEN_RT);
+ }
+
+ free (f);
+ }
+
+ if (try == NULL)
+ {
+ as_bad (_("unable to locate include file: %s"), filename);
+ free (path);
+ }
+ else
+ {
+ fclose (try);
+ register_dependency (path);
+ input_scrub_insert_file (path);
+ }
+
+ * eof = end_char;
+}
+
+static void
+parse_rx_section (char * name)
+{
+ asection * sec;
+ int type;
+ int attr = SHF_ALLOC | SHF_EXECINSTR;
+ int align = 2;
+ char end_char;
+
+ do
+ {
+ char * p;
+
+ SKIP_WHITESPACE ();
+ for (p = input_line_pointer; *p && strchr ("\n\t, =", *p) == NULL; p++)
+ ;
+ end_char = *p;
+ *p = 0;
+
+ if (strcasecmp (input_line_pointer, "ALIGN") == 0)
+ {
+ *p = end_char;
+
+ if (end_char == ' ')
+ while (ISSPACE (*p))
+ p++;
+
+ if (*p == '=')
+ {
+ ++ p;
+ while (ISSPACE (*p))
+ p++;
+ switch (*p)
+ {
+ case '2': align = 2; break;
+ case '4': align = 4; break;
+ case '8': align = 8; break;
+ default:
+ as_bad (_("unrecognised alignment value in .SECTION directive: %s"), p);
+ ignore_rest_of_line ();
+ return;
+ }
+ ++ p;
+ }
+
+ end_char = *p;
+ }
+ else if (strcasecmp (input_line_pointer, "CODE") == 0)
+ attr = SHF_ALLOC | SHF_EXECINSTR;
+ else if (strcasecmp (input_line_pointer, "DATA") == 0)
+ attr = SHF_ALLOC | SHF_WRITE;
+ else if (strcasecmp (input_line_pointer, "ROMDATA") == 0)
+ attr = SHF_ALLOC;
+ else
+ {
+ as_bad (_("unknown parameter following .SECTION directive: %s"),
+ input_line_pointer);
+
+ *p = end_char;
+ input_line_pointer = p + 1;
+ ignore_rest_of_line ();
+ return;
+ }
+
+ *p = end_char;
+ input_line_pointer = p + 1;
+ }
+ while (end_char != '\n' && end_char != 0);
+
+ if ((sec = bfd_get_section_by_name (stdoutput, name)) == NULL)
+ {
+ if (strcmp (name, "B") && strcmp (name, "B_1") && strcmp (name, "B_2"))
+ type = SHT_NULL;
+ else
+ type = SHT_NOBITS;
+
+ obj_elf_change_section (name, type, attr, 0, NULL, FALSE, FALSE);
+ }
+ else /* Try not to redefine a section, especially B_1. */
+ {
+ int flags = sec->flags;
+
+ type = elf_section_type (sec);
+
+ attr = ((flags & SEC_READONLY) ? 0 : SHF_WRITE)
+ | ((flags & SEC_ALLOC) ? SHF_ALLOC : 0)
+ | ((flags & SEC_CODE) ? SHF_EXECINSTR : 0)
+ | ((flags & SEC_MERGE) ? SHF_MERGE : 0)
+ | ((flags & SEC_STRINGS) ? SHF_STRINGS : 0)
+ | ((flags & SEC_THREAD_LOCAL) ? SHF_TLS : 0);
+
+ obj_elf_change_section (name, type, attr, 0, NULL, FALSE, FALSE);
+ }
+
+ bfd_set_section_alignment (stdoutput, now_seg, align);
+}
+
+static void
+rx_section (int ignore)
+{
+ char * p;
+
+ /* The as100 assembler supports a different syntax for the .section
+ pseudo-op. So check for it and handle it here if necessary. */
+ SKIP_WHITESPACE ();
+
+ /* Peek past the section name to see if arguments follow. */
+ for (p = input_line_pointer; *p; p++)
+ if (*p == ',' || *p == '\n')
+ break;
+
+ if (*p == ',')
+ {
+ int len = p - input_line_pointer;
+
+ while (ISSPACE (*++p))
+ ;
+
+ if (*p != '"' && *p != '#')
+ {
+ char * name = (char *) xmalloc (len + 1);
+
+ strncpy (name, input_line_pointer, len);
+ name[len] = 0;
+
+ input_line_pointer = p;
+ parse_rx_section (name);
+ return;
+ }
+ }
+
+ obj_elf_section (ignore);
+}
+
+static void
+rx_list (int ignore ATTRIBUTE_UNUSED)
+{
+ SKIP_WHITESPACE ();
+
+ if (strncasecmp (input_line_pointer, "OFF", 3))
+ listing_list (0);
+ else if (strncasecmp (input_line_pointer, "ON", 2))
+ listing_list (1);
+ else
+ as_warn (_("expecting either ON or OFF after .list"));
+}
+
+/* Like the .rept pseudo op, but supports the
+ use of ..MACREP inside the repeated region. */
+
+static void
+rx_rept (int ignore ATTRIBUTE_UNUSED)
+{
+ int count = get_absolute_expression ();
+
+ do_repeat_with_expander (count, "MREPEAT", "ENDR", "..MACREP");
+}
+
+/* Like cons() accept that strings are allowed. */
+
+static void
+rx_cons (int size)
+{
+ SKIP_WHITESPACE ();
+
+ if (* input_line_pointer == '"')
+ stringer (8+0);
+ else
+ cons (size);
+}
+
+static void
+rx_nop (int ignore ATTRIBUTE_UNUSED)
+{
+ ignore_rest_of_line ();
+}
+
+static void
+rx_unimp (int idx)
+{
+ as_warn (_("The \".%s\" pseudo-op is not implemented\n"),
+ md_pseudo_table[idx].poc_name);
+ ignore_rest_of_line ();
+}
+
+/* The target specific pseudo-ops which we support. */
+const pseudo_typeS md_pseudo_table[] =
+{
+ /* These are unimplemented. They're listed first so that we can use
+ the poc_value as the index into this array, to get the name of
+ the pseudo. So, keep these (1) first, and (2) in order, with (3)
+ the poc_value's in sequence. */
+ { "btglb", rx_unimp, 0 },
+ { "call", rx_unimp, 1 },
+ { "einsf", rx_unimp, 2 },
+ { "fb", rx_unimp, 3 },
+ { "fbsym", rx_unimp, 4 },
+ { "id", rx_unimp, 5 },
+ { "initsct", rx_unimp, 6 },
+ { "insf", rx_unimp, 7 },
+ { "instr", rx_unimp, 8 },
+ { "lbba", rx_unimp, 9 },
+ { "len", rx_unimp, 10 },
+ { "optj", rx_unimp, 11 },
+ { "rvector", rx_unimp, 12 },
+ { "sb", rx_unimp, 13 },
+ { "sbbit", rx_unimp, 14 },
+ { "sbsym", rx_unimp, 15 },
+ { "sbsym16", rx_unimp, 16 },
+
+ /* These are the do-nothing pseudos. */
+ { "stk", rx_nop, 0 },
+ /* The manual documents ".stk" but the compiler emits ".stack". */
+ { "stack", rx_nop, 0 },
+
+ /* Theae are Renesas as100 assembler pseudo-ops that we do support. */
+ { "addr", rx_cons, 3 },
+ { "align", s_align_bytes, 2 },
+ { "byte", rx_cons, 1 },
+ { "fixed", float_cons, 'f' },
+ { "form", listing_psize, 0 },
+ { "glb", s_globl, 0 },
+ { "include", rx_include, 0 },
+ { "list", rx_list, 0 },
+ { "lword", rx_cons, 4 },
+ { "mrepeat", rx_rept, 0 },
+ { "section", rx_section, 0 },
+
+ /* FIXME: The following pseudo-ops place their values (and associated
+ label if present) in the data section, regardless of whatever
+ section we are currently in. At the moment this code does not
+ implement that part of the semantics. */
+ { "blka", s_space, 3 },
+ { "blkb", s_space, 1 },
+ { "blkd", s_space, 8 },
+ { "blkf", s_space, 4 },
+ { "blkl", s_space, 4 },
+ { "blkw", s_space, 2 },
+
+ /* Our "standard" pseudos. */
+ { "double", rx_float_cons, 0 },
+ { "bss", s_bss, 0 },
+ { "3byte", cons, 3 },
+ { "int", cons, 4 },
+ { "word", cons, 4 },
+
+ /* End of list marker. */
+ { NULL, NULL, 0 }
+};
+
+static asymbol * gp_symbol;
+
+void
+md_begin (void)
+{
+ if (rx_use_small_data_limit)
+ /* Make the __gp symbol now rather
+ than after the symbol table is frozen. We only do this
+ when supporting small data limits because otherwise we
+ pollute the symbol table. */
+ gp_symbol = symbol_get_bfdsym (symbol_find_or_make ("__gp"));
+}
+
+char * rx_lex_start;
+char * rx_lex_end;
+
+typedef struct rx_bytesT
+{
+ char base[4];
+ int n_base;
+ char ops[8];
+ int n_ops;
+ struct
+ {
+ expressionS exp;
+ char offset;
+ char nbits;
+ char type; /* RXREL_*. */
+ int reloc;
+ fixS * fixP;
+ } fixups[2];
+ int n_fixups;
+ struct
+ {
+ char type;
+ char field_pos;
+ char val_ofs;
+ } relax[2];
+ int n_relax;
+ int link_relax;
+ fixS *link_relax_fixP;
+} rx_bytesT;
+
+static rx_bytesT rx_bytes;
+
+void
+rx_relax (int type, int pos)
+{
+ rx_bytes.relax[rx_bytes.n_relax].type = type;
+ rx_bytes.relax[rx_bytes.n_relax].field_pos = pos;
+ rx_bytes.relax[rx_bytes.n_relax].val_ofs = rx_bytes.n_base + rx_bytes.n_ops;
+ rx_bytes.n_relax ++;
+}
+
+void
+rx_linkrelax_dsp (int pos)
+{
+ switch (pos)
+ {
+ case 4:
+ rx_bytes.link_relax |= RX_RELAXA_DSP4;
+ break;
+ case 6:
+ rx_bytes.link_relax |= RX_RELAXA_DSP6;
+ break;
+ case 14:
+ rx_bytes.link_relax |= RX_RELAXA_DSP14;
+ break;
+ }
+}
+
+void
+rx_linkrelax_imm (int pos)
+{
+ switch (pos)
+ {
+ case 6:
+ rx_bytes.link_relax |= RX_RELAXA_IMM6;
+ break;
+ case 12:
+ rx_bytes.link_relax |= RX_RELAXA_IMM12;
+ break;
+ }
+}
+
+void
+rx_linkrelax_branch (void)
+{
+ rx_bytes.link_relax |= RX_RELAXA_BRA;
+}
+
+static void
+rx_fixup (expressionS exp, int offsetbits, int nbits, int type)
+{
+ rx_bytes.fixups[rx_bytes.n_fixups].exp = exp;
+ rx_bytes.fixups[rx_bytes.n_fixups].offset = offsetbits;
+ rx_bytes.fixups[rx_bytes.n_fixups].nbits = nbits;
+ rx_bytes.fixups[rx_bytes.n_fixups].type = type;
+ rx_bytes.fixups[rx_bytes.n_fixups].reloc = exp.X_md;
+ rx_bytes.n_fixups ++;
+}
+
+#define rx_field_fixup(exp, offset, nbits, type) \
+ rx_fixup (exp, offset, nbits, type)
+
+#define rx_op_fixup(exp, offset, nbits, type) \
+ rx_fixup (exp, offset + 8 * rx_bytes.n_base, nbits, type)
+
+void
+rx_base1 (int b1)
+{
+ rx_bytes.base[0] = b1;
+ rx_bytes.n_base = 1;
+}
+
+void
+rx_base2 (int b1, int b2)
+{
+ rx_bytes.base[0] = b1;
+ rx_bytes.base[1] = b2;
+ rx_bytes.n_base = 2;
+}
+
+void
+rx_base3 (int b1, int b2, int b3)
+{
+ rx_bytes.base[0] = b1;
+ rx_bytes.base[1] = b2;
+ rx_bytes.base[2] = b3;
+ rx_bytes.n_base = 3;
+}
+
+void
+rx_base4 (int b1, int b2, int b3, int b4)
+{
+ rx_bytes.base[0] = b1;
+ rx_bytes.base[1] = b2;
+ rx_bytes.base[2] = b3;
+ rx_bytes.base[3] = b4;
+ rx_bytes.n_base = 4;
+}
+
+/* This gets complicated when the field spans bytes, because fields
+ are numbered from the MSB of the first byte as zero, and bits are
+ stored LSB towards the LSB of the byte. Thus, a simple four-bit
+ insertion of 12 at position 4 of 0x00 yields: 0x0b. A three-bit
+ insertion of b'MXL at position 7 is like this:
+
+ - - - - - - - - - - - - - - - -
+ M X L */
+
+void
+rx_field (int val, int pos, int sz)
+{
+ int valm;
+ int bytep, bitp;
+
+ if (sz > 0)
+ {
+ if (val < 0 || val >= (1 << sz))
+ as_bad (_("Value %d doesn't fit in unsigned %d-bit field"), val, sz);
+ }
+ else
+ {
+ sz = - sz;
+ if (val < -(1 << (sz - 1)) || val >= (1 << (sz - 1)))
+ as_bad (_("Value %d doesn't fit in signed %d-bit field"), val, sz);
+ }
+
+ /* This code points at 'M' in the above example. */
+ bytep = pos / 8;
+ bitp = pos % 8;
+
+ while (bitp + sz > 8)
+ {
+ int ssz = 8 - bitp;
+ int svalm;
+
+ svalm = val >> (sz - ssz);
+ svalm = svalm & ((1 << ssz) - 1);
+ svalm = svalm << (8 - bitp - ssz);
+ gas_assert (bytep < rx_bytes.n_base);
+ rx_bytes.base[bytep] |= svalm;
+
+ bitp = 0;
+ sz -= ssz;
+ bytep ++;
+ }
+ valm = val & ((1 << sz) - 1);
+ valm = valm << (8 - bitp - sz);
+ gas_assert (bytep < rx_bytes.n_base);
+ rx_bytes.base[bytep] |= valm;
+}
+
+/* Special case of the above, for 3-bit displacements of 2..9. */
+
+void
+rx_disp3 (expressionS exp, int pos)
+{
+ rx_field_fixup (exp, pos, 3, RXREL_PCREL);
+}
+
+/* Special case of the above, for split 5-bit displacements. Assumes
+ the displacement has been checked with rx_disp5op. */
+/* ---- -432 1--- 0--- */
+
+void
+rx_field5s (expressionS exp)
+{
+ int val;
+
+ val = exp.X_add_number;
+ rx_bytes.base[0] |= val >> 2;
+ rx_bytes.base[1] |= (val << 6) & 0x80;
+ rx_bytes.base[1] |= (val << 3) & 0x08;
+}
+
+/* ---- ---- 4--- 3210 */
+
+void
+rx_field5s2 (expressionS exp)
+{
+ int val;
+
+ val = exp.X_add_number;
+ rx_bytes.base[1] |= (val << 3) & 0x80;
+ rx_bytes.base[1] |= (val ) & 0x0f;
+}
+
+#define OP(x) rx_bytes.ops[rx_bytes.n_ops++] = (x)
+
+#define F_PRECISION 2
+
+void
+rx_op (expressionS exp, int nbytes, int type)
+{
+ int v = 0;
+
+ if ((exp.X_op == O_constant || exp.X_op == O_big)
+ && type != RXREL_PCREL)
+ {
+ if (exp.X_op == O_big && exp.X_add_number <= 0)
+ {
+ LITTLENUM_TYPE w[2];
+ char * ip = rx_bytes.ops + rx_bytes.n_ops;
+
+ gen_to_words (w, F_PRECISION, 8);
+#if RX_OPCODE_BIG_ENDIAN
+ ip[0] = w[0] >> 8;
+ ip[1] = w[0];
+ ip[2] = w[1] >> 8;
+ ip[3] = w[1];
+#else
+ ip[3] = w[0] >> 8;
+ ip[2] = w[0];
+ ip[1] = w[1] >> 8;
+ ip[0] = w[1];
+#endif
+ rx_bytes.n_ops += 4;
+ }
+ else
+ {
+ v = exp.X_add_number;
+ while (nbytes)
+ {
+#if RX_OPCODE_BIG_ENDIAN
+ OP ((v >> (8 * (nbytes - 1))) & 0xff);
+#else
+ OP (v & 0xff);
+ v >>= 8;
+#endif
+ nbytes --;
+ }
+ }
+ }
+ else
+ {
+ rx_op_fixup (exp, rx_bytes.n_ops * 8, nbytes * 8, type);
+ memset (rx_bytes.ops + rx_bytes.n_ops, 0, nbytes);
+ rx_bytes.n_ops += nbytes;
+ }
+}
+
+int
+rx_wrap (void)
+{
+ return 0;
+}
+
+#define APPEND(B, N_B) \
+ if (rx_bytes.N_B) \
+ { \
+ memcpy (bytes + idx, rx_bytes.B, rx_bytes.N_B); \
+ idx += rx_bytes.N_B; \
+ }
+
+void
+rx_frag_init (fragS * fragP)
+{
+ if (rx_bytes.n_relax || rx_bytes.link_relax)
+ {
+ fragP->tc_frag_data = malloc (sizeof (rx_bytesT));
+ memcpy (fragP->tc_frag_data, & rx_bytes, sizeof (rx_bytesT));
+ }
+ else
+ fragP->tc_frag_data = 0;
+}
+
+/* Handle the as100's version of the .equ pseudo-op. It has the syntax:
+ <symbol_name> .equ <expression> */
+
+static void
+rx_equ (char * name, char * expr)
+{
+ char saved_name_end_char;
+ char * name_end;
+ char * saved_ilp;
+
+ while (ISSPACE (* name))
+ name ++;
+
+ for (name_end = name + 1; *name_end; name_end ++)
+ if (! ISALNUM (* name_end))
+ break;
+
+ saved_name_end_char = * name_end;
+ * name_end = 0;
+
+ saved_ilp = input_line_pointer;
+ input_line_pointer = expr;
+
+ equals (name, 1);
+
+ input_line_pointer = saved_ilp;
+ * name_end = saved_name_end_char;
+}
+
+/* Look for Renesas as100 pseudo-ops that occur after a symbol name
+ rather than at the start of a line. (eg .EQU or .DEFINE). If one
+ is found, process it and return TRUE otherwise return FALSE. */
+
+static bfd_boolean
+scan_for_infix_rx_pseudo_ops (char * str)
+{
+ char * p;
+ char * pseudo_op;
+ char * dot = strchr (str, '.');
+
+ if (dot == NULL || dot == str)
+ return FALSE;
+
+ /* A real pseudo-op must be preceeded by whitespace. */
+ if (dot[-1] != ' ' && dot[-1] != '\t')
+ return FALSE;
+
+ pseudo_op = dot + 1;
+
+ if (!ISALNUM (* pseudo_op))
+ return FALSE;
+
+ for (p = pseudo_op + 1; ISALNUM (* p); p++)
+ ;
+
+ if (strncasecmp ("EQU", pseudo_op, p - pseudo_op) == 0)
+ rx_equ (str, p);
+ else if (strncasecmp ("DEFINE", pseudo_op, p - pseudo_op) == 0)
+ as_warn (_("The .DEFINE pseudo-op is not implemented"));
+ else if (strncasecmp ("MACRO", pseudo_op, p - pseudo_op) == 0)
+ as_warn (_("The .MACRO pseudo-op is not implemented"));
+ else if (strncasecmp ("BTEQU", pseudo_op, p - pseudo_op) == 0)
+ as_warn (_("The .BTEQU pseudo-op is not implemented."));
+ else
+ return FALSE;
+
+ return TRUE;
+}
+
+void
+md_assemble (char * str)
+{
+ char * bytes;
+ int idx = 0;
+ int i, rel;
+ fragS * frag_then = frag_now;
+ expressionS *exp;
+
+ memset (& rx_bytes, 0, sizeof (rx_bytes));
+
+ rx_lex_init (str, str + strlen (str));
+ if (scan_for_infix_rx_pseudo_ops (str))
+ return;
+ rx_parse ();
+
+ /* This simplifies the relaxation code. */
+ if (rx_bytes.n_relax || rx_bytes.link_relax)
+ {
+ /* We do it this way because we want the frag to have the
+ rx_bytes in it, which we initialize above. */
+ bytes = frag_more (12);
+ 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_fix += rx_bytes.n_base + rx_bytes.n_ops;
+ frag_then->fr_subtype = rx_bytes.n_base + rx_bytes.n_ops;
+ }
+ else
+ {
+ bytes = frag_more (rx_bytes.n_base + rx_bytes.n_ops);
+ frag_then = frag_now;
+ }
+
+ APPEND (base, n_base);
+ APPEND (ops, n_ops);
+
+ if (rx_bytes.link_relax && rx_bytes.n_fixups)
+ {
+ fixS * f;
+
+ f = fix_new (frag_then,
+ (char *) bytes - frag_then->fr_literal,
+ 0,
+ abs_section_sym,
+ rx_bytes.link_relax | rx_bytes.n_fixups,
+ 0,
+ BFD_RELOC_RX_RELAX);
+ frag_then->tc_frag_data->link_relax_fixP = f;
+ }
+
+ for (i = 0; i < rx_bytes.n_fixups; i ++)
+ {
+ /* index: [nbytes][type] */
+ static int reloc_map[5][4] =
+ {
+ { 0, 0, 0, BFD_RELOC_RX_DIR3U_PCREL },
+ { BFD_RELOC_8, BFD_RELOC_RX_8U, BFD_RELOC_RX_NEG8, BFD_RELOC_8_PCREL },
+ { BFD_RELOC_RX_16_OP, BFD_RELOC_RX_16U, BFD_RELOC_RX_NEG16, BFD_RELOC_16_PCREL },
+ { BFD_RELOC_RX_24_OP, BFD_RELOC_RX_24U, BFD_RELOC_RX_NEG24, BFD_RELOC_24_PCREL },
+ { BFD_RELOC_RX_32_OP, BFD_RELOC_32, BFD_RELOC_RX_NEG32, BFD_RELOC_32_PCREL },
+ };
+ fixS * f;
+
+ idx = rx_bytes.fixups[i].offset / 8;
+ rel = reloc_map [rx_bytes.fixups[i].nbits / 8][(int) rx_bytes.fixups[i].type];
+
+ if (rx_bytes.fixups[i].reloc)
+ rel = rx_bytes.fixups[i].reloc;
+
+ if (frag_then->tc_frag_data)
+ exp = & frag_then->tc_frag_data->fixups[i].exp;
+ else
+ exp = & rx_bytes.fixups[i].exp;
+
+ f = fix_new_exp (frag_then,
+ (char *) bytes + idx - frag_then->fr_literal,
+ rx_bytes.fixups[i].nbits / 8,
+ exp,
+ rx_bytes.fixups[i].type == RXREL_PCREL ? 1 : 0,
+ rel);
+ if (frag_then->tc_frag_data)
+ frag_then->tc_frag_data->fixups[i].fixP = f;
+ }
+
+ dwarf2_emit_insn (idx);
+}
+
+void
+rx_md_end (void)
+{
+}
+
+/* Write a value out to the object file, using the appropriate endianness. */
+
+void
+md_number_to_chars (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);
+}
+
+static struct
+{
+ char * fname;
+ int reloc;
+}
+reloc_functions[] =
+{
+ { "gp", BFD_RELOC_GPREL16 },
+ { 0, 0 }
+};
+
+void
+md_operand (expressionS * exp ATTRIBUTE_UNUSED)
+{
+ int reloc = 0;
+ int i;
+
+ for (i = 0; reloc_functions[i].fname; i++)
+ {
+ int flen = strlen (reloc_functions[i].fname);
+
+ if (input_line_pointer[0] == '%'
+ && strncasecmp (input_line_pointer + 1, reloc_functions[i].fname, flen) == 0
+ && input_line_pointer[flen + 1] == '(')
+ {
+ reloc = reloc_functions[i].reloc;
+ input_line_pointer += flen + 2;
+ break;
+ }
+ }
+ if (reloc == 0)
+ return;
+
+ expression (exp);
+ if (* input_line_pointer == ')')
+ input_line_pointer ++;
+
+ exp->X_md = reloc;
+}
+
+valueT
+md_section_align (segT segment, valueT size)
+{
+ int align = bfd_get_section_alignment (stdoutput, segment);
+ return ((size + (1 << align) - 1) & (-1 << align));
+}
+
+/* When relaxing, we need to output a reloc for any .align directive
+ so that we can retain this alignment as we adjust opcode sizes. */
+void
+rx_handle_align (fragS * frag)
+{
+ if (linkrelax
+ && (frag->fr_type == rs_align
+ || frag->fr_type == rs_align_code)
+ && frag->fr_address + frag->fr_fix > 0
+ && frag->fr_offset > 0
+ && now_seg != bss_section)
+ {
+ fix_new (frag, frag->fr_fix, 0,
+ &abs_symbol, RX_RELAXA_ALIGN + frag->fr_offset,
+ 0, BFD_RELOC_RX_RELAX);
+ /* For the purposes of relaxation, this relocation is attached
+ to the byte *after* the alignment - i.e. the byte that must
+ remain aligned. */
+ fix_new (frag->fr_next, 0, 0,
+ &abs_symbol, RX_RELAXA_ELIGN + frag->fr_offset,
+ 0, BFD_RELOC_RX_RELAX);
+ }
+}
+
+char *
+md_atof (int type, char * litP, int * sizeP)
+{
+ return ieee_md_atof (type, litP, sizeP, target_big_endian);
+}
+
+symbolS *
+md_undefined_symbol (char * name ATTRIBUTE_UNUSED)
+{
+ return NULL;
+}
+
+/*----------------------------------------------------------------------*/
+/* To recap: we estimate everything based on md_estimate_size, then
+ adjust based on rx_relax_frag. When it all settles, we call
+ md_convert frag to update the bytes. The relaxation types and
+ relocations are in fragP->tc_frag_data, which is a copy of that
+ rx_bytes.
+
+ Our scheme is as follows: fr_fix has the size of the smallest
+ opcode (like BRA.S). We store the number of total bytes we need in
+ fr_subtype. When we're done relaxing, we use fr_subtype and the
+ existing opcode bytes to figure out what actual opcode we need to
+ put in there. If the fixup isn't resolvable now, we use the
+ maximal size. */
+
+#define TRACE_RELAX 0
+#define tprintf if (TRACE_RELAX) printf
+
+typedef enum
+{
+ OT_other,
+ OT_bra,
+ OT_beq,
+ OT_bne,
+ OT_bsr,
+ OT_bcc
+} op_type_T;
+
+/* We're looking for these types of relaxations:
+
+ BRA.S 00001dsp
+ BRA.B 00101110 dspppppp
+ BRA.W 00111000 dspppppp pppppppp
+ BRA.A 00000100 dspppppp pppppppp pppppppp
+
+ BEQ.S 00010dsp
+ BEQ.B 00100000 dspppppp
+ BEQ.W 00111010 dspppppp pppppppp
+
+ BNE.S 00011dsp
+ BNE.B 00100001 dspppppp
+ BNE.W 00111011 dspppppp pppppppp
+
+ BSR.W 00111001 dspppppp pppppppp
+ BSR.A 00000101 dspppppp pppppppp pppppppp
+
+ Bcc.B 0010cond dspppppp
+
+ Additionally, we can synthesize longer conditional branches using
+ pairs of opcodes, one with an inverted conditional (flip LSB):
+
+ Bcc.W 0010ncnd 00000110 00111000 dspppppp pppppppp
+ Bcc.A 0010ncnd 00000111 00000100 dspppppp pppppppp pppppppp
+ BEQ.A 00011100 00000100 dspppppp pppppppp pppppppp
+ BNE.A 00010100 00000100 dspppppp pppppppp pppppppp */
+
+/* Given the opcode bytes at OP, figure out which opcode it is and
+ return the type of opcode. We use this to re-encode the opcode as
+ a different size later. */
+
+static op_type_T
+rx_opcode_type (char * op)
+{
+ unsigned char b = (unsigned char) op[0];
+
+ switch (b & 0xf8)
+ {
+ case 0x08: return OT_bra;
+ case 0x10: return OT_beq;
+ case 0x18: return OT_bne;
+ }
+
+ switch (b)
+ {
+ case 0x2e: return OT_bra;
+ case 0x38: return OT_bra;
+ case 0x04: return OT_bra;
+
+ case 0x20: return OT_beq;
+ case 0x3a: return OT_beq;
+
+ case 0x21: return OT_bne;
+ case 0x3b: return OT_bne;
+
+ case 0x39: return OT_bsr;
+ case 0x05: return OT_bsr;
+ }
+
+ if ((b & 0xf0) == 0x20)
+ return OT_bcc;
+
+ return OT_other;
+}
+
+/* Returns zero if *addrP has the target address. Else returns nonzero
+ if we cannot compute the target address yet. */
+
+static int
+rx_frag_fix_value (fragS * fragP,
+ segT segment,
+ int which,
+ addressT * addrP,
+ int need_diff,
+ addressT * sym_addr)
+{
+ addressT addr = 0;
+ rx_bytesT * b = fragP->tc_frag_data;
+ expressionS * exp = & b->fixups[which].exp;
+
+ if (need_diff && exp->X_op != O_subtract)
+ return 1;
+
+ if (exp->X_add_symbol)
+ {
+ if (S_FORCE_RELOC (exp->X_add_symbol, 1))
+ return 1;
+ if (S_GET_SEGMENT (exp->X_add_symbol) != segment)
+ return 1;
+ addr += S_GET_VALUE (exp->X_add_symbol);
+ }
+
+ if (exp->X_op_symbol)
+ {
+ if (exp->X_op != O_subtract)
+ return 1;
+ if (S_FORCE_RELOC (exp->X_op_symbol, 1))
+ return 1;
+ if (S_GET_SEGMENT (exp->X_op_symbol) != segment)
+ return 1;
+ addr -= S_GET_VALUE (exp->X_op_symbol);
+ }
+ if (sym_addr)
+ * sym_addr = addr;
+ addr += exp->X_add_number;
+ * addrP = addr;
+ return 0;
+}
+
+/* Estimate how big the opcode is after this relax pass. The return
+ value is the difference between fr_fix and the actual size. We
+ compute the total size in rx_relax_frag and store it in fr_subtype,
+ sowe only need to subtract fx_fix and return it. */
+
+int
+md_estimate_size_before_relax (fragS * fragP ATTRIBUTE_UNUSED, segT segment ATTRIBUTE_UNUSED)
+{
+ int opfixsize;
+ int delta;
+
+ tprintf ("\033[32m est frag: addr %08lx fix %ld var %ld ofs %ld lit %p opc %p type %d sub %d\033[0m\n",
+ fragP->fr_address + (fragP->fr_opcode - fragP->fr_literal),
+ fragP->fr_fix, fragP->fr_var, fragP->fr_offset,
+ fragP->fr_literal, fragP->fr_opcode, fragP->fr_type, fragP->fr_subtype);
+
+ /* This is the size of the opcode that's accounted for in fr_fix. */
+ opfixsize = fragP->fr_fix - (fragP->fr_opcode - fragP->fr_literal);
+ /* This is the size of the opcode that isn't. */
+ delta = (fragP->fr_subtype - opfixsize);
+
+ tprintf (" -> opfixsize %d delta %d\n", opfixsize, delta);
+ return delta;
+}
+
+/* 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
+ after the last pass and the size after this pass, so we use the old
+ fr_subtype to calculate the difference. */
+
+int
+rx_relax_frag (segT segment ATTRIBUTE_UNUSED, fragS * fragP, long stretch)
+{
+ addressT addr0, sym_addr;
+ addressT mypc;
+ int disp;
+ int oldsize = fragP->fr_subtype;
+ int newsize = oldsize;
+ op_type_T optype;
+ /* Index of relaxation we care about. */
+ int ri;
+
+ tprintf ("\033[36mrelax frag: addr %08lx fix %ld var %ld ofs %ld lit %p opc %p type %d sub %d str %ld\033[0m\n",
+ fragP->fr_address + (fragP->fr_opcode - fragP->fr_literal),
+ fragP->fr_fix, fragP->fr_var, fragP->fr_offset,
+ fragP->fr_literal, fragP->fr_opcode, fragP->fr_type, fragP->fr_subtype, stretch);
+
+ optype = rx_opcode_type (fragP->fr_opcode);
+
+ /* In the one case where we have both a disp and imm relaxation, we want
+ the imm relaxation here. */
+ ri = 0;
+ if (fragP->tc_frag_data->n_relax > 1
+ && fragP->tc_frag_data->relax[0].type == RX_RELAX_DISP)
+ ri = 1;
+
+ /* Try to get the target address. */
+ if (rx_frag_fix_value (fragP, segment, ri, & addr0,
+ fragP->tc_frag_data->relax[ri].type != RX_RELAX_BRANCH,
+ & sym_addr))
+ {
+ /* If we don't, we must use the maximum size for the linker.
+ Note that we don't use synthetically expanded conditionals
+ for this. */
+ switch (fragP->tc_frag_data->relax[ri].type)
+ {
+ case RX_RELAX_BRANCH:
+ switch (optype)
+ {
+ case OT_bra:
+ case OT_bsr:
+ newsize = 4;
+ break;
+ case OT_beq:
+ case OT_bne:
+ newsize = 3;
+ break;
+ case OT_bcc:
+ newsize = 2;
+ break;
+ case OT_other:
+ newsize = oldsize;
+ break;
+ }
+ break;
+
+ case RX_RELAX_IMM:
+ newsize = fragP->tc_frag_data->relax[ri].val_ofs + 4;
+ break;
+ }
+ fragP->fr_subtype = newsize;
+ tprintf (" -> new %d old %d delta %d (external)\n", newsize, oldsize, newsize-oldsize);
+ return newsize - oldsize;
+ }
+
+ mypc = fragP->fr_address + (fragP->fr_opcode - fragP->fr_literal);
+ if (sym_addr > mypc)
+ addr0 += stretch;
+
+ switch (fragP->tc_frag_data->relax[ri].type)
+ {
+ case RX_RELAX_BRANCH:
+ tprintf ("branch, addr %08lx pc %08lx disp %ld\n", addr0, mypc, addr0-mypc);
+ disp = (int) addr0 - (int) mypc;
+
+ switch (optype)
+ {
+ case OT_bcc:
+ if (disp >= -128 && (disp - (oldsize-2)) <= 127)
+ /* bcc.b */
+ newsize = 2;
+ else if (disp >= -32768 && (disp - (oldsize-5)) <= 32767)
+ /* bncc.b/bra.w */
+ newsize = 5;
+ else
+ /* bncc.b/bra.a */
+ newsize = 6;
+ break;
+
+ case OT_beq:
+ case OT_bne:
+ if ((disp - (oldsize-1)) >= 3 && (disp - (oldsize-1)) <= 10 && !linkrelax)
+ /* beq.s */
+ newsize = 1;
+ else if (disp >= -128 && (disp - (oldsize-2)) <= 127)
+ /* beq.b */
+ newsize = 2;
+ else if (disp >= -32768 && (disp - (oldsize-3)) <= 32767)
+ /* beq.w */
+ newsize = 3;
+ else
+ /* bne.s/bra.a */
+ newsize = 5;
+ break;
+
+ case OT_bra:
+ case OT_bsr:
+ if ((disp - (oldsize-1)) >= 3 && (disp - (oldsize-1)) <= 10 && !linkrelax)
+ /* bra.s */
+ newsize = 1;
+ else if (disp >= -128 && (disp - (oldsize-2)) <= 127)
+ /* bra.b */
+ newsize = 2;
+ else if (disp >= -32768 && (disp - (oldsize-3)) <= 32767)
+ /* bra.w */
+ newsize = 3;
+ else
+ /* bra.a */
+ newsize = 4;
+ break;
+
+ case OT_other:
+ break;
+ }
+ tprintf (" - newsize %d\n", newsize);
+ break;
+
+ case RX_RELAX_IMM:
+ tprintf ("other, addr %08lx pc %08lx LI %d OF %d\n", addr0, mypc,
+ fragP->tc_frag_data->relax[ri].field_pos,
+ fragP->tc_frag_data->relax[ri].val_ofs);
+
+ newsize = fragP->tc_frag_data->relax[ri].val_ofs;
+
+ if ((long) addr0 >= -128 && (long) addr0 <= 127)
+ newsize += 1;
+ else if ((long) addr0 >= -32768 && (long) addr0 <= 32767)
+ newsize += 2;
+ else if ((long) addr0 >= -8388608 && (long) addr0 <= 8388607)
+ newsize += 3;
+ else
+ newsize += 4;
+ break;
+
+ default:
+ break;
+ }
+
+ if (fragP->tc_frag_data->relax[ri].type == RX_RELAX_BRANCH)
+ switch (optype)
+ {
+ case OT_bra:
+ case OT_bcc:
+ case OT_beq:
+ case OT_bne:
+ break;
+ case OT_bsr:
+ if (newsize < 3)
+ newsize = 3;
+ break;
+ case OT_other:
+ break;
+ }
+
+ fragP->fr_subtype = newsize;
+ tprintf (" -> new %d old %d delta %d\n", newsize, oldsize, newsize-oldsize);
+ return newsize - oldsize;
+}
+
+/* This lets us test for the opcode type and the desired size in a
+ switch statement. */
+#define OPCODE(type,size) ((type) * 16 + (size))
+
+/* Given the opcode stored in fr_opcode and the number of bytes we
+ think we need, encode a new opcode. We stored a pointer to the
+ fixup for this opcode in the tc_frag_data structure. If we can do
+ the fixup here, we change the relocation type to "none" (we test
+ for that in tc_gen_reloc) else we change it to the right type for
+ the new (biggest) opcode. */
+
+void
+md_convert_frag (bfd * abfd ATTRIBUTE_UNUSED,
+ segT segment ATTRIBUTE_UNUSED,
+ fragS * fragP ATTRIBUTE_UNUSED)
+{
+ rx_bytesT * rxb = fragP->tc_frag_data;
+ addressT addr0, mypc;
+ int disp;
+ int reloc_type, reloc_adjust;
+ char * op = fragP->fr_opcode;
+ int keep_reloc = 0;
+ int ri;
+ int fi = (rxb->n_fixups > 1) ? 1 : 0;
+ fixS * fix = rxb->fixups[fi].fixP;
+
+ tprintf ("\033[31mconvrt frag: addr %08lx fix %ld var %ld ofs %ld lit %p opc %p type %d sub %d\033[0m\n",
+ fragP->fr_address + (fragP->fr_opcode - fragP->fr_literal),
+ fragP->fr_fix, fragP->fr_var, fragP->fr_offset,
+ fragP->fr_literal, fragP->fr_opcode, fragP->fr_type, fragP->fr_subtype);
+
+#if TRACE_RELAX
+ {
+ int i;
+
+ printf ("lit %08x opc %08x", (int) fragP->fr_literal, (int) fragP->fr_opcode);
+ for (i = 0; i < 10; i++)
+ printf (" %02x", (unsigned char) (fragP->fr_opcode[i]));
+ printf ("\n");
+ }
+#endif
+
+ /* In the one case where we have both a disp and imm relaxation, we want
+ the imm relaxation here. */
+ ri = 0;
+ if (fragP->tc_frag_data->n_relax > 1
+ && fragP->tc_frag_data->relax[0].type == RX_RELAX_DISP)
+ ri = 1;
+
+ /* Try to get the target address. If we fail here, we just use the
+ largest format. */
+ if (rx_frag_fix_value (fragP, segment, 0, & addr0,
+ fragP->tc_frag_data->relax[ri].type != RX_RELAX_BRANCH, 0))
+ keep_reloc = 1;
+
+ if (linkrelax)
+ keep_reloc = 1;
+
+ /* We used a new frag for this opcode, so the opcode address should
+ be the frag address. */
+ mypc = fragP->fr_address + (fragP->fr_opcode - fragP->fr_literal);
+ disp = (int) addr0 - (int) mypc;
+
+ reloc_type = BFD_RELOC_NONE;
+ reloc_adjust = 0;
+
+ tprintf ("convert, op is %d, disp %d (%lx-%lx)\n", rx_opcode_type (fragP->fr_opcode), disp, addr0, mypc);
+ switch (fragP->tc_frag_data->relax[ri].type)
+ {
+ case RX_RELAX_BRANCH:
+ switch (OPCODE (rx_opcode_type (fragP->fr_opcode), fragP->fr_subtype))
+ {
+ case OPCODE (OT_bra, 1): /* BRA.S - no change. */
+ op[0] = 0x08 + (disp & 7);
+ break;
+ case OPCODE (OT_bra, 2): /* BRA.B - 8 bit. */
+ op[0] = 0x2e;
+ op[1] = disp;
+ reloc_type = keep_reloc ? BFD_RELOC_8_PCREL : BFD_RELOC_NONE;
+ reloc_adjust = 1;
+ break;
+ case OPCODE (OT_bra, 3): /* BRA.W - 16 bit. */
+ op[0] = 0x38;
+#if RX_OPCODE_BIG_ENDIAN
+ op[1] = (disp >> 8) & 0xff;
+ op[2] = disp;
+#else
+ op[2] = (disp >> 8) & 0xff;
+ op[1] = disp;
+#endif
+ reloc_adjust = 1;
+ reloc_type = keep_reloc ? BFD_RELOC_16_PCREL : BFD_RELOC_NONE;
+ break;
+ case OPCODE (OT_bra, 4): /* BRA.A - 24 bit. */
+ op[0] = 0x04;
+#if RX_OPCODE_BIG_ENDIAN
+ op[1] = (disp >> 16) & 0xff;
+ op[2] = (disp >> 8) & 0xff;
+ op[3] = disp;
+#else
+ op[3] = (disp >> 16) & 0xff;
+ op[2] = (disp >> 8) & 0xff;
+ op[1] = disp;
+#endif
+ reloc_type = keep_reloc ? BFD_RELOC_24_PCREL : BFD_RELOC_NONE;
+ reloc_adjust = 1;
+ break;
+
+ case OPCODE (OT_beq, 1): /* BEQ.S - no change. */
+ op[0] = 0x10 + (disp & 7);
+ break;
+ case OPCODE (OT_beq, 2): /* BEQ.B - 8 bit. */
+ op[0] = 0x20;
+ op[1] = disp;
+ reloc_adjust = 1;
+ reloc_type = keep_reloc ? BFD_RELOC_8_PCREL : BFD_RELOC_NONE;
+ break;
+ case OPCODE (OT_beq, 3): /* BEQ.W - 16 bit. */
+ op[0] = 0x3a;
+#if RX_OPCODE_BIG_ENDIAN
+ op[1] = (disp >> 8) & 0xff;
+ op[2] = disp;
+#else
+ op[2] = (disp >> 8) & 0xff;
+ op[1] = disp;
+#endif
+ reloc_type = keep_reloc ? BFD_RELOC_16_PCREL : BFD_RELOC_NONE;
+ reloc_adjust = 1;
+ break;
+ case OPCODE (OT_beq, 5): /* BEQ.A - synthetic. */
+ op[0] = 0x1e; /* bne.s .+4. */
+ op[1] = 0x04; /* bra.a dsp:24. */
+ disp -= 1;
+#if RX_OPCODE_BIG_ENDIAN
+ op[2] = (disp >> 16) & 0xff;
+ op[3] = (disp >> 8) & 0xff;
+ op[4] = disp;
+#else
+ op[4] = (disp >> 16) & 0xff;
+ op[3] = (disp >> 8) & 0xff;
+ op[2] = disp;
+#endif
+ reloc_type = keep_reloc ? BFD_RELOC_24_PCREL : BFD_RELOC_NONE;
+ reloc_adjust = 2;
+ break;
+
+ case OPCODE (OT_bne, 1): /* BNE.S - no change. */
+ op[0] = 0x18 + (disp & 7);
+ break;
+ case OPCODE (OT_bne, 2): /* BNE.B - 8 bit. */
+ op[0] = 0x21;
+ op[1] = disp;
+ reloc_adjust = 1;
+ reloc_type = keep_reloc ? BFD_RELOC_8_PCREL : BFD_RELOC_NONE;
+ break;
+ case OPCODE (OT_bne, 3): /* BNE.W - 16 bit. */
+ op[0] = 0x3b;
+#if RX_OPCODE_BIG_ENDIAN
+ op[1] = (disp >> 8) & 0xff;
+ op[2] = disp;
+#else
+ op[2] = (disp >> 8) & 0xff;
+ op[1] = disp;
+#endif
+ reloc_type = keep_reloc ? BFD_RELOC_16_PCREL : BFD_RELOC_NONE;
+ reloc_adjust = 1;
+ break;
+ case OPCODE (OT_bne, 5): /* BNE.A - synthetic. */
+ op[0] = 0x15; /* beq.s .+4. */
+ op[1] = 0x04; /* bra.a dsp:24. */
+ disp -= 1;
+#if RX_OPCODE_BIG_ENDIAN
+ op[2] = (disp >> 16) & 0xff;
+ op[3] = (disp >> 8) & 0xff;
+ op[4] = disp;
+#else
+ op[4] = (disp >> 16) & 0xff;
+ op[3] = (disp >> 8) & 0xff;
+ op[2] = disp;
+#endif
+ reloc_type = keep_reloc ? BFD_RELOC_24_PCREL : BFD_RELOC_NONE;
+ reloc_adjust = 2;
+ break;
+
+ case OPCODE (OT_bsr, 3): /* BSR.W - 16 bit. */
+ op[0] = 0x39;
+#if RX_OPCODE_BIG_ENDIAN
+ op[1] = (disp >> 8) & 0xff;
+ op[2] = disp;
+#else
+ op[2] = (disp >> 8) & 0xff;
+ op[1] = disp;
+#endif
+ reloc_type = keep_reloc ? BFD_RELOC_16_PCREL : BFD_RELOC_NONE;
+ reloc_adjust = 0;
+ break;
+ case OPCODE (OT_bsr, 4): /* BSR.A - 24 bit. */
+ op[0] = 0x05;
+#if RX_OPCODE_BIG_ENDIAN
+ op[1] = (disp >> 16) & 0xff;
+ op[2] = (disp >> 8) & 0xff;
+ op[3] = disp;
+#else
+ op[3] = (disp >> 16) & 0xff;
+ op[2] = (disp >> 8) & 0xff;
+ op[1] = disp;
+#endif
+ reloc_type = keep_reloc ? BFD_RELOC_24_PCREL : BFD_RELOC_NONE;
+ reloc_adjust = 0;
+ break;
+
+ case OPCODE (OT_bcc, 2): /* Bcond.B - 8 bit. */
+ op[1] = disp;
+ reloc_type = keep_reloc ? BFD_RELOC_8_PCREL : BFD_RELOC_NONE;
+ break;
+ case OPCODE (OT_bcc, 5): /* Bcond.W - synthetic. */
+ op[0] ^= 1; /* Invert condition. */
+ op[1] = 5; /* Displacement. */
+ op[2] = 0x38;
+ disp -= 2;
+#if RX_OPCODE_BIG_ENDIAN
+ op[3] = (disp >> 8) & 0xff;
+ op[4] = disp;
+#else
+ op[4] = (disp >> 8) & 0xff;
+ op[3] = disp;
+#endif
+ reloc_type = keep_reloc ? BFD_RELOC_16_PCREL : BFD_RELOC_NONE;
+ reloc_adjust = 2;
+ break;
+ case OPCODE (OT_bcc, 6): /* Bcond.S - synthetic. */
+ op[0] ^= 1; /* Invert condition. */
+ op[1] = 6; /* Displacement. */
+ op[2] = 0x04;
+ disp -= 2;
+#if RX_OPCODE_BIG_ENDIAN
+ op[3] = (disp >> 16) & 0xff;
+ op[4] = (disp >> 8) & 0xff;
+ op[5] = disp;
+#else
+ op[5] = (disp >> 16) & 0xff;
+ op[4] = (disp >> 8) & 0xff;
+ op[3] = disp;
+#endif
+ reloc_type = keep_reloc ? BFD_RELOC_24_PCREL : BFD_RELOC_NONE;
+ reloc_adjust = 2;
+ break;
+
+ default:
+ /* These are opcodes we'll relax in th linker, later. */
+ if (rxb->n_fixups)
+ reloc_type = rxb->fixups[ri].fixP->fx_r_type;
+ break;
+ }
+ break;
+
+ case RX_RELAX_IMM:
+ {
+ int nbytes = fragP->fr_subtype - fragP->tc_frag_data->relax[ri].val_ofs;
+ int li;
+ char * imm = op + fragP->tc_frag_data->relax[ri].val_ofs;
+
+ switch (nbytes)
+ {
+ case 1:
+ li = 1;
+ imm[0] = addr0;
+ reloc_type = BFD_RELOC_8;
+ break;
+ case 2:
+ li = 2;
+#if RX_OPCODE_BIG_ENDIAN
+ imm[1] = addr0;
+ imm[0] = addr0 >> 8;
+#else
+ imm[0] = addr0;
+ imm[1] = addr0 >> 8;
+#endif
+ reloc_type = BFD_RELOC_RX_16_OP;
+ break;
+ case 3:
+ li = 3;
+#if RX_OPCODE_BIG_ENDIAN
+ imm[2] = addr0;
+ imm[1] = addr0 >> 8;
+ imm[0] = addr0 >> 16;
+#else
+ imm[0] = addr0;
+ imm[1] = addr0 >> 8;
+ imm[2] = addr0 >> 16;
+#endif
+ reloc_type = BFD_RELOC_RX_24_OP;
+ break;
+ case 4:
+ li = 0;
+#if RX_OPCODE_BIG_ENDIAN
+ imm[3] = addr0;
+ imm[2] = addr0 >> 8;
+ imm[1] = addr0 >> 16;
+ imm[0] = addr0 >> 24;
+#else
+ imm[0] = addr0;
+ imm[1] = addr0 >> 8;
+ imm[2] = addr0 >> 16;
+ imm[3] = addr0 >> 24;
+#endif
+ reloc_type = BFD_RELOC_RX_32_OP;
+ break;
+ default:
+ as_bad (_("invalid immediate size"));
+ li = -1;
+ }
+
+ switch (fragP->tc_frag_data->relax[ri].field_pos)
+ {
+ case 6:
+ op[0] &= 0xfc;
+ op[0] |= li;
+ break;
+ case 12:
+ op[1] &= 0xf3;
+ op[1] |= li << 2;
+ break;
+ case 20:
+ op[2] &= 0xf3;
+ op[2] |= li << 2;
+ break;
+ default:
+ as_bad (_("invalid immediate field position"));
+ }
+ }
+ break;
+
+ default:
+ if (rxb->n_fixups)
+ {
+ reloc_type = fix->fx_r_type;
+ reloc_adjust = 0;
+ }
+ break;
+ }
+
+ if (rxb->n_fixups)
+ {
+
+ fix->fx_r_type = reloc_type;
+ fix->fx_where += reloc_adjust;
+ switch (reloc_type)
+ {
+ case BFD_RELOC_NONE:
+ fix->fx_size = 0;
+ break;
+ case BFD_RELOC_8:
+ fix->fx_size = 1;
+ break;
+ case BFD_RELOC_16_PCREL:
+ case BFD_RELOC_RX_16_OP:
+ fix->fx_size = 2;
+ break;
+ case BFD_RELOC_24_PCREL:
+ case BFD_RELOC_RX_24_OP:
+ fix->fx_size = 3;
+ break;
+ case BFD_RELOC_RX_32_OP:
+ fix->fx_size = 4;
+ break;
+ }
+ }
+
+ fragP->fr_fix = fragP->fr_subtype + (fragP->fr_opcode - fragP->fr_literal);
+ tprintf ("fragP->fr_fix now %ld (%d + (%p - %p)\n", fragP->fr_fix,
+ fragP->fr_subtype, fragP->fr_opcode, fragP->fr_literal);
+ fragP->fr_var = 0;
+
+ if (fragP->fr_next != NULL
+ && ((offsetT) (fragP->fr_next->fr_address - fragP->fr_address)
+ != fragP->fr_fix))
+ as_bad (_("bad frag at %p : fix %ld addr %ld %ld \n"), fragP,
+ fragP->fr_fix, fragP->fr_address, fragP->fr_next->fr_address);
+}
+
+#undef OPCODE
+
+int
+rx_validate_fix_sub (struct fix * f)
+{
+ /* We permit the subtraction of two symbols as a 32-bit relocation. */
+ if (f->fx_r_type == BFD_RELOC_RX_DIFF
+ && ! f->fx_pcrel
+ && f->fx_size == 4)
+ return 1;
+ return 0;
+}
+
+long
+md_pcrel_from_section (fixS * fixP, segT sec)
+{
+ long rv;
+
+ if (fixP->fx_addsy != 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;
+
+ rv = fixP->fx_frag->fr_address + fixP->fx_where;
+ switch (fixP->fx_r_type)
+ {
+ case BFD_RELOC_RX_DIR3U_PCREL:
+ return rv;
+ default:
+ return rv - 1;
+ }
+}
+
+void
+rx_cons_fix_new (fragS * frag,
+ int where,
+ int size,
+ expressionS * exp)
+{
+ bfd_reloc_code_real_type type;
+
+ switch (size)
+ {
+ case 1:
+ type = BFD_RELOC_8;
+ break;
+ case 2:
+ type = BFD_RELOC_16;
+ break;
+ case 3:
+ type = BFD_RELOC_24;
+ break;
+ case 4:
+ type = BFD_RELOC_32;
+ break;
+ default:
+ as_bad (_("unsupported constant size %d\n"), size);
+ return;
+ }
+
+ if (exp->X_op == O_subtract && exp->X_op_symbol)
+ {
+ if (size != 4 && size != 2 && size != 1)
+ as_bad (_("difference of two symbols only supported with .long, .short, or .byte"));
+ else
+ type = BFD_RELOC_RX_DIFF;
+ }
+
+ fix_new_exp (frag, where, (int) size, exp, 0, type);
+}
+
+void
+md_apply_fix (struct fix * f ATTRIBUTE_UNUSED,
+ valueT * t ATTRIBUTE_UNUSED,
+ segT s ATTRIBUTE_UNUSED)
+{
+ /* Instruction bytes are always little endian. */
+ char * op;
+ unsigned long val;
+
+ if (f->fx_addsy && S_FORCE_RELOC (f->fx_addsy, 1))
+ return;
+ if (f->fx_subsy && S_FORCE_RELOC (f->fx_subsy, 1))
+ return;
+
+#define OP2(x) op[target_big_endian ? 1-x : x]
+#define OP3(x) op[target_big_endian ? 2-x : x]
+#define OP4(x) op[target_big_endian ? 3-x : x]
+
+ op = f->fx_frag->fr_literal + f->fx_where;
+ val = (unsigned long) * t;
+
+ /* Opcode words are always the same endian. Data words are either
+ big or little endian. */
+
+ switch (f->fx_r_type)
+ {
+ case BFD_RELOC_NONE:
+ break;
+
+ case BFD_RELOC_RX_RELAX:
+ f->fx_done = 1;
+ break;
+
+ case BFD_RELOC_RX_DIR3U_PCREL:
+ if (val < 3 || val > 10)
+ as_bad_where (f->fx_file, f->fx_line,
+ _("jump not 3..10 bytes away (is %d)"), (int) val);
+ op[0] &= 0xf8;
+ op[0] |= val & 0x07;
+ break;
+
+ case BFD_RELOC_8:
+ case BFD_RELOC_8_PCREL:
+ case BFD_RELOC_RX_8U:
+ op[0] = val;
+ break;
+
+ case BFD_RELOC_16:
+ OP2(1) = val & 0xff;
+ OP2(0) = (val >> 8) & 0xff;
+ break;
+
+ case BFD_RELOC_16_PCREL:
+ case BFD_RELOC_RX_16_OP:
+ case BFD_RELOC_RX_16U:
+#if RX_OPCODE_BIG_ENDIAN
+ op[1] = val & 0xff;
+ op[0] = (val >> 8) & 0xff;
+#else
+ op[0] = val & 0xff;
+ op[1] = (val >> 8) & 0xff;
+#endif
+ break;
+
+ case BFD_RELOC_24:
+ OP3(0) = val & 0xff;
+ OP3(1) = (val >> 8) & 0xff;
+ OP3(2) = (val >> 16) & 0xff;
+ break;
+
+ case BFD_RELOC_24_PCREL:
+ case BFD_RELOC_RX_24_OP:
+ case BFD_RELOC_RX_24U:
+#if RX_OPCODE_BIG_ENDIAN
+ op[2] = val & 0xff;
+ op[1] = (val >> 8) & 0xff;
+ op[0] = (val >> 16) & 0xff;
+#else
+ op[0] = val & 0xff;
+ op[1] = (val >> 8) & 0xff;
+ op[2] = (val >> 16) & 0xff;
+#endif
+ break;
+
+ case BFD_RELOC_RX_DIFF:
+ switch (f->fx_size)
+ {
+ case 1:
+ op[0] = val & 0xff;
+ break;
+ case 2:
+ OP2(0) = val & 0xff;
+ OP2(1) = (val >> 8) & 0xff;
+ break;
+ case 4:
+ OP4(0) = val & 0xff;
+ OP4(1) = (val >> 8) & 0xff;
+ OP4(2) = (val >> 16) & 0xff;
+ OP4(3) = (val >> 24) & 0xff;
+ break;
+ }
+ break;
+
+ case BFD_RELOC_32:
+ OP4(0) = val & 0xff;
+ OP4(1) = (val >> 8) & 0xff;
+ OP4(2) = (val >> 16) & 0xff;
+ OP4(3) = (val >> 24) & 0xff;
+ break;
+
+ case BFD_RELOC_RX_32_OP:
+#if RX_OPCODE_BIG_ENDIAN
+ op[3] = val & 0xff;
+ op[2] = (val >> 8) & 0xff;
+ op[1] = (val >> 16) & 0xff;
+ op[0] = (val >> 24) & 0xff;
+#else
+ op[0] = val & 0xff;
+ op[1] = (val >> 8) & 0xff;
+ op[2] = (val >> 16) & 0xff;
+ op[3] = (val >> 24) & 0xff;
+#endif
+ break;
+
+ case BFD_RELOC_RX_NEG8:
+ op[0] = - val;
+ break;
+
+ case BFD_RELOC_RX_NEG16:
+ val = -val;
+#if RX_OPCODE_BIG_ENDIAN
+ op[1] = val & 0xff;
+ op[0] = (val >> 8) & 0xff;
+#else
+ op[0] = val & 0xff;
+ op[1] = (val >> 8) & 0xff;
+#endif
+ break;
+
+ case BFD_RELOC_RX_NEG24:
+ val = -val;
+#if RX_OPCODE_BIG_ENDIAN
+ op[2] = val & 0xff;
+ op[1] = (val >> 8) & 0xff;
+ op[0] = (val >> 16) & 0xff;
+#else
+ op[0] = val & 0xff;
+ op[1] = (val >> 8) & 0xff;
+ op[2] = (val >> 16) & 0xff;
+#endif
+ break;
+
+ case BFD_RELOC_RX_NEG32:
+ val = -val;
+#if RX_OPCODE_BIG_ENDIAN
+ op[3] = val & 0xff;
+ op[2] = (val >> 8) & 0xff;
+ op[1] = (val >> 16) & 0xff;
+ op[0] = (val >> 24) & 0xff;
+#else
+ op[0] = val & 0xff;
+ op[1] = (val >> 8) & 0xff;
+ op[2] = (val >> 16) & 0xff;
+ op[3] = (val >> 24) & 0xff;
+#endif
+ break;
+
+ case BFD_RELOC_RX_GPRELL:
+ val >>= 1;
+ case BFD_RELOC_RX_GPRELW:
+ val >>= 1;
+ case BFD_RELOC_RX_GPRELB:
+#if RX_OPCODE_BIG_ENDIAN
+ op[1] = val & 0xff;
+ op[0] = (val >> 8) & 0xff;
+#else
+ op[0] = val & 0xff;
+ op[1] = (val >> 8) & 0xff;
+#endif
+ break;
+
+ default:
+ as_bad (_("Unknown reloc in md_apply_fix: %s"),
+ bfd_get_reloc_code_name (f->fx_r_type));
+ break;
+ }
+
+ if (f->fx_addsy == NULL)
+ f->fx_done = 1;
+}
+
+arelent **
+tc_gen_reloc (asection * seg ATTRIBUTE_UNUSED, fixS * fixp)
+{
+ static arelent * reloc[5];
+
+ if (fixp->fx_r_type == BFD_RELOC_NONE)
+ {
+ reloc[0] = NULL;
+ return reloc;
+ }
+
+ if (fixp->fx_subsy
+ && S_GET_SEGMENT (fixp->fx_subsy) == absolute_section)
+ {
+ fixp->fx_offset -= S_GET_VALUE (fixp->fx_subsy);
+ fixp->fx_subsy = NULL;
+ }
+
+ reloc[0] = (arelent *) xmalloc (sizeof (arelent));
+ reloc[0]->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
+ * reloc[0]->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
+ reloc[0]->address = fixp->fx_frag->fr_address + fixp->fx_where;
+ reloc[0]->addend = fixp->fx_offset;
+
+ /* Certain BFD relocations cannot be translated directly into
+ a single (non-Red Hat) RX relocation, but instead need
+ multiple RX relocations - handle them here. */
+ switch (fixp->fx_r_type)
+ {
+ case BFD_RELOC_RX_DIFF:
+ reloc[0]->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_RX_SYM);
+
+ reloc[1] = (arelent *) xmalloc (sizeof (arelent));
+ reloc[1]->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
+ * reloc[1]->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_subsy);
+ reloc[1]->address = fixp->fx_frag->fr_address + fixp->fx_where;
+ reloc[1]->addend = 0;
+ reloc[1]->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_RX_SYM);
+
+ reloc[2] = (arelent *) xmalloc (sizeof (arelent));
+ reloc[2]->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_RX_OP_SUBTRACT);
+ reloc[2]->addend = 0;
+ reloc[2]->sym_ptr_ptr = reloc[1]->sym_ptr_ptr;
+ reloc[2]->address = fixp->fx_frag->fr_address + fixp->fx_where;
+
+ reloc[3] = (arelent *) xmalloc (sizeof (arelent));
+ switch (fixp->fx_size)
+ {
+ case 1:
+ reloc[3]->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_RX_ABS8);
+ break;
+ case 2:
+ reloc[3]->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_RX_ABS16);
+ break;
+ case 4:
+ reloc[3]->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_RX_ABS32);
+ break;
+ }
+ reloc[3]->addend = 0;
+ reloc[3]->sym_ptr_ptr = reloc[1]->sym_ptr_ptr;
+ reloc[3]->address = fixp->fx_frag->fr_address + fixp->fx_where;
+
+ reloc[4] = NULL;
+ break;
+
+ case BFD_RELOC_RX_GPRELL:
+ reloc[0]->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_RX_SYM);
+
+ reloc[1] = (arelent *) xmalloc (sizeof (arelent));
+ reloc[1]->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
+ if (gp_symbol == NULL)
+ {
+ if (symbol_table_frozen)
+ {
+ symbolS * gp;
+
+ gp = symbol_find ("__gp");
+ if (gp == NULL)
+ as_bad (("unable to create __gp symbol: please re-assemble with the -msmall-data-limit option specified"));
+ else
+ gp_symbol = symbol_get_bfdsym (gp);
+ }
+ else
+ gp_symbol = symbol_get_bfdsym (symbol_find_or_make ("__gp"));
+ }
+ * reloc[1]->sym_ptr_ptr = gp_symbol;
+ reloc[1]->address = fixp->fx_frag->fr_address + fixp->fx_where;
+ reloc[1]->addend = 0;
+ reloc[1]->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_RX_SYM);
+
+ reloc[2] = (arelent *) xmalloc (sizeof (arelent));
+ reloc[2]->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_RX_OP_SUBTRACT);
+ reloc[2]->addend = 0;
+ reloc[2]->sym_ptr_ptr = reloc[1]->sym_ptr_ptr;
+ reloc[2]->address = fixp->fx_frag->fr_address + fixp->fx_where;
+
+ reloc[3] = (arelent *) xmalloc (sizeof (arelent));
+ reloc[3]->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_RX_ABS16UL);
+ reloc[3]->addend = 0;
+ reloc[3]->sym_ptr_ptr = reloc[1]->sym_ptr_ptr;
+ reloc[3]->address = fixp->fx_frag->fr_address + fixp->fx_where;
+
+ reloc[4] = NULL;
+ break;
+
+ case BFD_RELOC_RX_GPRELW:
+ reloc[0]->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_RX_SYM);
+
+ reloc[1] = (arelent *) xmalloc (sizeof (arelent));
+ reloc[1]->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
+ if (gp_symbol == NULL)
+ {
+ if (symbol_table_frozen)
+ {
+ symbolS * gp;
+
+ gp = symbol_find ("__gp");
+ if (gp == NULL)
+ as_bad (("unable to create __gp symbol: please re-assemble with the -msmall-data-limit option specified"));
+ else
+ gp_symbol = symbol_get_bfdsym (gp);
+ }
+ else
+ gp_symbol = symbol_get_bfdsym (symbol_find_or_make ("__gp"));
+ }
+ * reloc[1]->sym_ptr_ptr = gp_symbol;
+ reloc[1]->address = fixp->fx_frag->fr_address + fixp->fx_where;
+ reloc[1]->addend = 0;
+ reloc[1]->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_RX_SYM);
+
+ reloc[2] = (arelent *) xmalloc (sizeof (arelent));
+ reloc[2]->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_RX_OP_SUBTRACT);
+ reloc[2]->addend = 0;
+ reloc[2]->sym_ptr_ptr = reloc[1]->sym_ptr_ptr;
+ reloc[2]->address = fixp->fx_frag->fr_address + fixp->fx_where;
+
+ reloc[3] = (arelent *) xmalloc (sizeof (arelent));
+ reloc[3]->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_RX_ABS16UW);
+ reloc[3]->addend = 0;
+ reloc[3]->sym_ptr_ptr = reloc[1]->sym_ptr_ptr;
+ reloc[3]->address = fixp->fx_frag->fr_address + fixp->fx_where;
+
+ reloc[4] = NULL;
+ break;
+
+ case BFD_RELOC_RX_GPRELB:
+ reloc[0]->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_RX_SYM);
+
+ reloc[1] = (arelent *) xmalloc (sizeof (arelent));
+ reloc[1]->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
+ if (gp_symbol == NULL)
+ {
+ if (symbol_table_frozen)
+ {
+ symbolS * gp;
+
+ gp = symbol_find ("__gp");
+ if (gp == NULL)
+ as_bad (("unable to create __gp symbol: please re-assemble with the -msmall-data-limit option specified"));
+ else
+ gp_symbol = symbol_get_bfdsym (gp);
+ }
+ else
+ gp_symbol = symbol_get_bfdsym (symbol_find_or_make ("__gp"));
+ }
+ * reloc[1]->sym_ptr_ptr = gp_symbol;
+ reloc[1]->address = fixp->fx_frag->fr_address + fixp->fx_where;
+ reloc[1]->addend = 0;
+ reloc[1]->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_RX_SYM);
+
+ reloc[2] = (arelent *) xmalloc (sizeof (arelent));
+ reloc[2]->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_RX_OP_SUBTRACT);
+ reloc[2]->addend = 0;
+ reloc[2]->sym_ptr_ptr = reloc[1]->sym_ptr_ptr;
+ reloc[2]->address = fixp->fx_frag->fr_address + fixp->fx_where;
+
+ reloc[3] = (arelent *) xmalloc (sizeof (arelent));
+ reloc[3]->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_RX_ABS16U);
+ reloc[3]->addend = 0;
+ reloc[3]->sym_ptr_ptr = reloc[1]->sym_ptr_ptr;
+ reloc[3]->address = fixp->fx_frag->fr_address + fixp->fx_where;
+
+ reloc[4] = NULL;
+ break;
+
+ default:
+ reloc[0]->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type);
+ reloc[1] = NULL;
+ break;
+ }
+
+ return reloc;
+}
+
+/* Set the ELF specific flags. */
+
+void
+rx_elf_final_processing (void)
+{
+ elf_elfheader (stdoutput)->e_flags |= elf_flags;
+}
+
+/* Scan the current input line for occurances of Renesas
+ local labels and replace them with the GAS version. */
+
+void
+rx_start_line (void)
+{
+ int in_double_quote = 0;
+ int in_single_quote = 0;
+ int done = 0;
+ char * p = input_line_pointer;
+
+ /* Scan the line looking for question marks. Skip past quote enclosed regions. */
+ do
+ {
+ switch (*p)
+ {
+ case '\n':
+ case 0:
+ done = 1;
+ break;
+
+ case '"':
+ in_double_quote = ! in_double_quote;
+ break;
+
+ case '\'':
+ in_single_quote = ! in_single_quote;
+ break;
+
+ case '?':
+ if (in_double_quote || in_single_quote)
+ break;
+
+ if (p[1] == ':')
+ *p = '1';
+ else if (p[1] == '+')
+ {
+ p[0] = '1';
+ p[1] = 'f';
+ }
+ else if (p[1] == '-')
+ {
+ p[0] = '1';
+ p[1] = 'b';
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ p ++;
+ }
+ while (! done);
+}