/* tc-rx.c -- Assembler for the Renesas RX
- Copyright 2008, 2009
- Free Software Foundation, Inc.
+ Copyright (C) 2008-2017 Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
#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"
const char FLT_CHARS[] = "dD";
\f
/* ELF flags to set in the output file header. */
-static int elf_flags = 0;
+static int elf_flags = E_FLAG_RX_ABI;
bfd_boolean rx_use_conventional_section_names = FALSE;
static bfd_boolean rx_use_small_data_limit = FALSE;
+static bfd_boolean rx_pid_mode = FALSE;
+static int rx_num_int_regs = 0;
+int rx_pid_register;
+int rx_gp_register;
+
+enum rx_cpu_types rx_cpu = RX600;
+
+static void rx_fetchalign (int ignore ATTRIBUTE_UNUSED);
+
enum options
{
OPTION_BIG = OPTION_MD_BASE,
OPTION_CONVENTIONAL_SECTION_NAMES,
OPTION_RENESAS_SECTION_NAMES,
OPTION_SMALL_DATA_LIMIT,
- OPTION_RELAX
+ OPTION_RELAX,
+ OPTION_PID,
+ OPTION_INT_REGS,
+ OPTION_USES_GCC_ABI,
+ OPTION_USES_RX_ABI,
+ OPTION_CPU,
+ OPTION_DISALLOW_STRING_INSNS,
};
#define RX_SHORTOPTS ""
{"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},
+ {"mpid", no_argument, NULL, OPTION_PID},
+ {"mint-register", required_argument, NULL, OPTION_INT_REGS},
+ {"mgcc-abi", no_argument, NULL, OPTION_USES_GCC_ABI},
+ {"mrx-abi", no_argument, NULL, OPTION_USES_RX_ABI},
+ {"mcpu", required_argument, NULL, OPTION_CPU},
+ {"mno-allow-string-insns", no_argument, NULL, OPTION_DISALLOW_STRING_INSNS},
{NULL, no_argument, NULL, 0}
};
size_t md_longopts_size = sizeof (md_longopts);
+struct cpu_type
+{
+ const char *cpu_name;
+ enum rx_cpu_types type;
+};
+
+struct cpu_type cpu_type_list[] =
+{
+ {"rx100",RX100},
+ {"rx200",RX200},
+ {"rx600",RX600},
+ {"rx610",RX610},
+ {"rxv2",RXV2}
+};
+
int
-md_parse_option (int c ATTRIBUTE_UNUSED, char * arg ATTRIBUTE_UNUSED)
+md_parse_option (int c ATTRIBUTE_UNUSED, const char * arg ATTRIBUTE_UNUSED)
{
switch (c)
{
case OPTION_RELAX:
linkrelax = 1;
return 1;
+
+ case OPTION_PID:
+ rx_pid_mode = TRUE;
+ elf_flags |= E_FLAG_RX_PID;
+ return 1;
+
+ case OPTION_INT_REGS:
+ rx_num_int_regs = atoi (optarg);
+ return 1;
+
+ case OPTION_USES_GCC_ABI:
+ elf_flags &= ~ E_FLAG_RX_ABI;
+ return 1;
+
+ case OPTION_USES_RX_ABI:
+ elf_flags |= E_FLAG_RX_ABI;
+ return 1;
+
+ case OPTION_CPU:
+ {
+ unsigned int i;
+ for (i = 0; i < ARRAY_SIZE (cpu_type_list); i++)
+ {
+ if (strcasecmp (arg, cpu_type_list[i].cpu_name) == 0)
+ {
+ rx_cpu = cpu_type_list[i].type;
+ if (rx_cpu == RXV2)
+ elf_flags |= E_FLAG_RX_V2;
+ return 1;
+ }
+ }
+ as_warn (_("unrecognised RX CPU type %s"), arg);
+ break;
+ }
+
+ case OPTION_DISALLOW_STRING_INSNS:
+ elf_flags |= E_FLAG_RX_SINSNS_SET | E_FLAG_RX_SINSNS_NO;
+ return 1;
}
+
return 0;
}
fprintf (stream, _(" --muse-conventional-section-names\n"));
fprintf (stream, _(" --muse-renesas-section-names [default]\n"));
fprintf (stream, _(" --msmall-data-limit\n"));
+ fprintf (stream, _(" --mrelax\n"));
+ fprintf (stream, _(" --mpid\n"));
+ fprintf (stream, _(" --mint-register=<value>\n"));
+ fprintf (stream, _(" --mcpu=<rx100|rx200|rx600|rx610|rxv2>\n"));
+ fprintf (stream, _(" --mno-allow-string-insns"));
}
static void
FILE * try;
char * path;
char * filename;
- char * current_filename;
- char * eof;
- char * p;
- char * d;
+ const char * current_filename;
+ char * last_char;
+ const char * p;
+ const char * d;
char * f;
char end_char;
size_t len;
/* 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)
+ last_char = find_end_of_line (filename, FALSE);
+ input_line_pointer = last_char;
+
+ while (last_char >= filename && (* last_char == ' ' || * last_char == '\n'))
+ -- last_char;
+ end_char = *(++ last_char);
+ * last_char = 0;
+ if (last_char == filename)
{
as_bad (_("no filename following .INCLUDE pseudo-op"));
- * eof = end_char;
+ * last_char = end_char;
return;
}
- as_where (& current_filename, NULL);
- f = (char *) xmalloc (strlen (current_filename) + strlen (filename) + 1);
+ current_filename = as_where (NULL);
+ f = XNEWVEC (char, 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;
+ const char * c;
len = 6; /* strlen ("..file"); */
3. Try any directories specified by the -I command line
option(s).
- 4 .Try a directory specifed by the INC100 environment variable. */
+ 4 .Try a directory specified by the INC100 environment variable. */
if (IS_ABSOLUTE_PATH (f))
try = fopen (path = f, FOPEN_RT);
if (env && strlen (env) > len)
len = strlen (env);
- path = (char *) xmalloc (strlen (f) + len + 5);
+ path = XNEWVEC (char, strlen (f) + len + 5);
if (current_filename != NULL)
{
input_scrub_insert_file (path);
}
- * eof = end_char;
+ * last_char = end_char;
}
static void
asection * sec;
int type;
int attr = SHF_ALLOC | SHF_EXECINSTR;
- int align = 2;
+ int align = 1;
char end_char;
do
p++;
switch (*p)
{
- case '2': align = 2; break;
- case '4': align = 4; break;
- case '8': align = 8; break;
+ case '2': align = 1; break;
+ case '4': align = 2; break;
+ case '8': align = 3; break;
default:
as_bad (_("unrecognised alignment value in .SECTION directive: %s"), p);
ignore_rest_of_line ();
else
type = SHT_NOBITS;
- obj_elf_change_section (name, type, attr, 0, NULL, FALSE, FALSE);
+ obj_elf_change_section (name, type, 0, attr, 0, NULL, FALSE, FALSE);
}
else /* Try not to redefine a section, especially B_1. */
{
| ((flags & SEC_STRINGS) ? SHF_STRINGS : 0)
| ((flags & SEC_THREAD_LOCAL) ? SHF_TLS : 0);
- obj_elf_change_section (name, type, attr, 0, NULL, FALSE, FALSE);
+ obj_elf_change_section (name, type, 0, attr, 0, NULL, FALSE, FALSE);
}
bfd_set_section_alignment (stdoutput, now_seg, align);
if (*p != '"' && *p != '#')
{
- char * name = (char *) xmalloc (len + 1);
-
- strncpy (name, input_line_pointer, len);
- name[len] = 0;
+ char *name = xmemdup0 (input_line_pointer, len);
input_line_pointer = p;
parse_rx_section (name);
/* The manual documents ".stk" but the compiler emits ".stack". */
{ "stack", rx_nop, 0 },
- /* Theae are Renesas as100 assembler pseudo-ops that we do support. */
+ /* These are Renesas as100 assembler pseudo-ops that we do support. */
{ "addr", rx_cons, 3 },
{ "align", s_align_bytes, 2 },
{ "byte", rx_cons, 1 },
{ "int", cons, 4 },
{ "word", cons, 4 },
+ { "fetchalign", rx_fetchalign, 0 },
+
/* End of list marker. */
{ NULL, NULL, 0 }
};
static asymbol * gp_symbol;
+static asymbol * rx_pid_symbol;
+
+static symbolS * rx_pidreg_symbol;
+static symbolS * rx_gpreg_symbol;
void
md_begin (void)
{
+ /* Make the __gp and __pid_base symbols 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. */
+
+ /* The meta-registers %pidreg and %gpreg depend on what other
+ options are specified. The __rx_*_defined symbols exist so we
+ can .ifdef asm code based on what options were passed to gas,
+ without needing a preprocessor */
+
+ if (rx_pid_mode)
+ {
+ rx_pid_register = 13 - rx_num_int_regs;
+ rx_pid_symbol = symbol_get_bfdsym (symbol_find_or_make ("__pid_base"));
+ rx_pidreg_symbol = symbol_find_or_make ("__rx_pidreg_defined");
+ S_SET_VALUE (rx_pidreg_symbol, rx_pid_register);
+ S_SET_SEGMENT (rx_pidreg_symbol, absolute_section);
+ }
+
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"));
+ {
+ if (rx_pid_mode)
+ rx_gp_register = rx_pid_register - 1;
+ else
+ rx_gp_register = 13 - rx_num_int_regs;
+ gp_symbol = symbol_get_bfdsym (symbol_find_or_make ("__gp"));
+ rx_gpreg_symbol = symbol_find_or_make ("__rx_gpreg_defined");
+ S_SET_VALUE (rx_gpreg_symbol, rx_gp_register);
+ S_SET_SEGMENT (rx_gpreg_symbol, absolute_section);
+ }
}
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;
int n_relax;
int link_relax;
fixS *link_relax_fixP;
+ char times_grown;
+ char times_shrank;
} 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)
void
rx_op (expressionS exp, int nbytes, int type)
{
- int v = 0;
+ offsetT 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)
+ if (exp.X_op == O_big)
{
- LITTLENUM_TYPE w[2];
- char * ip = rx_bytes.ops + rx_bytes.n_ops;
+ if (exp.X_add_number == -1)
+ {
+ LITTLENUM_TYPE w[2];
+ char * ip = rx_bytes.ops + rx_bytes.n_ops;
- gen_to_words (w, F_PRECISION, 8);
+ 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];
+ 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];
+ ip[3] = w[0] >> 8;
+ ip[2] = w[0];
+ ip[1] = w[1] >> 8;
+ ip[0] = w[1];
#endif
- rx_bytes.n_ops += 4;
+ rx_bytes.n_ops += 4;
+ return;
+ }
+
+ v = ((generic_bignum[1] & LITTLENUM_MASK) << LITTLENUM_NUMBER_OF_BITS)
+ | (generic_bignum[0] & LITTLENUM_MASK);
+
}
else
+ v = exp.X_add_number;
+
+ while (nbytes)
{
- v = exp.X_add_number;
- while (nbytes)
- {
#if RX_OPCODE_BIG_ENDIAN
- OP ((v >> (8 * (nbytes - 1))) & 0xff);
+ OP ((v >> (8 * (nbytes - 1))) & 0xff);
#else
- OP (v & 0xff);
- v >>= 8;
+ OP (v & 0xff);
+ v >>= 8;
#endif
- nbytes --;
- }
+ nbytes --;
}
}
else
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));
+ fragP->tc_frag_data = XNEW (rx_bytesT);
memcpy (fragP->tc_frag_data, & rx_bytes, sizeof (rx_bytesT));
}
else
<symbol_name> .equ <expression> */
static void
-rx_equ (char * name, char * expr)
+rx_equ (char * name, char * expression)
{
char saved_name_end_char;
char * name_end;
* name_end = 0;
saved_ilp = input_line_pointer;
- input_line_pointer = expr;
+ input_line_pointer = expression;
equals (name, 1);
if (dot == NULL || dot == str)
return FALSE;
- /* A real pseudo-op must be preceeded by whitespace. */
+ /* A real pseudo-op must be preceded by whitespace. */
if (dot[-1] != ' ' && dot[-1] != '\t')
return FALSE;
{
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);
static struct
{
- char * fname;
+ const char * fname;
int reloc;
}
reloc_functions[] =
md_section_align (segT segment, valueT size)
{
int align = bfd_get_section_alignment (stdoutput, segment);
- return ((size + (1 << align) - 1) & (-1 << align));
+ return ((size + (1 << align) - 1) & -(1 << align));
}
+ /* NOP - 1 cycle */
+static unsigned char nop_1[] = { 0x03};
+ /* MOV.L R0,R0 - 1 cycle */
+static unsigned char nop_2[] = { 0xef, 0x00};
+ /* MAX R0,R0 - 1 cycle */
+static unsigned char nop_3[] = { 0xfc, 0x13, 0x00 };
+ /* MUL #1,R0 - 1 cycle */
+static unsigned char nop_4[] = { 0x76, 0x10, 0x01, 0x00 };
+ /* MUL #1,R0 - 1 cycle */
+static unsigned char nop_5[] = { 0x77, 0x10, 0x01, 0x00, 0x00 };
+ /* MUL #1,R0 - 1 cycle */
+static unsigned char nop_6[] = { 0x74, 0x10, 0x01, 0x00, 0x00, 0x00 };
+ /* MAX 0x80000000,R0 - 1 cycle */
+static unsigned char nop_7[] = { 0xFD, 0x70, 0x40, 0x00, 0x00, 0x00, 0x80 };
+
+static unsigned char *nops[] = { NULL, nop_1, nop_2, nop_3, nop_4, nop_5, nop_6, nop_7 };
+#define BIGGEST_NOP 7
+
/* 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 handling an alignment frag, use an optimal NOP pattern.
+ Only do this if a fill value has not already been provided.
+ FIXME: This test fails if the provided fill value is zero. */
+ if ((frag->fr_type == rs_align
+ || frag->fr_type == rs_align_code)
+ && subseg_text_p (now_seg))
+ {
+ int count = (frag->fr_next->fr_address
+ - frag->fr_address
+ - frag->fr_fix);
+ unsigned char *base = (unsigned char *)frag->fr_literal + frag->fr_fix;
+
+ if (* base == 0)
+ {
+ if (count > BIGGEST_NOP)
+ {
+ base[0] = 0x2e;
+ base[1] = count;
+ frag->fr_var = 2;
+ }
+ else if (count > 0)
+ {
+ memcpy (base, nops[count], count);
+ frag->fr_var = count;
+ }
+ }
+ }
+
if (linkrelax
&& (frag->fr_type == rs_align
|| frag->fr_type == rs_align_code)
}
}
-char *
+const char *
md_atof (int type, char * litP, int * sizeP)
{
return ieee_md_atof (type, litP, sizeP, target_big_endian);
/* 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. */
+ so we only need to subtract fx_fix and return it. */
int
md_estimate_size_before_relax (fragS * fragP ATTRIBUTE_UNUSED, segT segment ATTRIBUTE_UNUSED)
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,
+ (unsigned long) (fragP->fr_address
+ + (fragP->fr_opcode - fragP->fr_literal)),
+ (long) fragP->fr_fix, (long) fragP->fr_var, (long) 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. */
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
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,
+ (unsigned long) (fragP->fr_address
+ + (fragP->fr_opcode - fragP->fr_literal)),
+ (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",
+ (unsigned long) (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
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);
+ tprintf ("branch, addr %08lx pc %08lx disp %ld\n",
+ (unsigned long) addr0, (unsigned long) mypc,
+ (long) (addr0 - mypc));
disp = (int) addr0 - (int) mypc;
switch (optype)
break;
case RX_RELAX_IMM:
- tprintf ("other, addr %08lx pc %08lx LI %d OF %d\n", addr0, mypc,
+ tprintf ("other, addr %08lx pc %08lx LI %d OF %d\n",
+ (unsigned long) addr0, (unsigned long) mypc,
fragP->tc_frag_data->relax[ri].field_pos,
fragP->tc_frag_data->relax[ri].val_ofs);
break;
}
+ /* This prevents infinite loops in align-heavy sources. */
+ if (newsize < oldsize)
+ {
+ if (fragP->tc_frag_data->times_shrank > 10
+ && fragP->tc_frag_data->times_grown > 10)
+ newsize = oldsize;
+ if (fragP->tc_frag_data->times_shrank < 20)
+ fragP->tc_frag_data->times_shrank ++;
+ }
+ else if (newsize > oldsize)
+ {
+ if (fragP->tc_frag_data->times_grown < 20)
+ fragP->tc_frag_data->times_grown ++;
+ }
+
fragP->fr_subtype = newsize;
tprintf (" -> new %d old %d delta %d\n", newsize, oldsize, newsize-oldsize);
return newsize - oldsize;
rx_bytesT * rxb = fragP->tc_frag_data;
addressT addr0, mypc;
int disp;
- int reloc_type, reloc_adjust;
+ int reloc_adjust;
+ bfd_reloc_code_real_type reloc_type;
char * op = fragP->fr_opcode;
int keep_reloc = 0;
int ri;
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);
+ (unsigned long) (fragP->fr_address
+ + (fragP->fr_opcode - fragP->fr_literal)),
+ (long) fragP->fr_fix, (long) fragP->fr_var, (long) 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);
+ 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;
&& fragP->tc_frag_data->relax[0].type == RX_RELAX_DISP)
ri = 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);
+
/* 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;
+ {
+ /* We don't know the target address. */
+ keep_reloc = 1;
+ addr0 = 0;
+ disp = 0;
+ }
+ else
+ {
+ /* We know the target address, and it's in addr0. */
+ disp = (int) addr0 - (int) mypc;
+ }
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);
+ tprintf ("convert, op is %d, disp %d (%lx-%lx)\n",
+ rx_opcode_type (fragP->fr_opcode), disp,
+ (unsigned long) addr0, (unsigned long) mypc);
switch (fragP->tc_frag_data->relax[ri].type)
{
case RX_RELAX_BRANCH:
reloc_adjust = 1;
break;
case OPCODE (OT_beq, 5): /* BEQ.A - synthetic. */
- op[0] = 0x1e; /* bne.s .+4. */
+ op[0] = 0x1d; /* bne.s .+5. */
op[1] = 0x04; /* bra.a dsp:24. */
disp -= 1;
#if RX_OPCODE_BIG_ENDIAN
reloc_adjust = 1;
break;
case OPCODE (OT_bne, 5): /* BNE.A - synthetic. */
- op[0] = 0x15; /* beq.s .+4. */
+ op[0] = 0x15; /* beq.s .+5. */
op[1] = 0x04; /* bra.a dsp:24. */
disp -= 1;
#if RX_OPCODE_BIG_ENDIAN
case BFD_RELOC_RX_32_OP:
fix->fx_size = 4;
break;
+ default:
+ 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,
+ tprintf ("fragP->fr_fix now %ld (%d + (%p - %p)\n", (long) fragP->fr_fix,
fragP->fr_subtype, fragP->fr_opcode, fragP->fr_literal);
fragP->fr_var = 0;
&& ((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);
+ (long) fragP->fr_fix,
+ (long) fragP->fr_address, (long) 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. */
+ /* We permit the subtraction of two symbols in a few cases. */
+ /* mov #sym1-sym2, R3 */
+ if (f->fx_r_type == BFD_RELOC_RX_32_OP)
+ return 1;
+ /* .long sym1-sym2 */
if (f->fx_r_type == BFD_RELOC_RX_DIFF
&& ! f->fx_pcrel
- && f->fx_size == 4)
+ && (f->fx_size == 4 || f->fx_size == 2 || f->fx_size == 1))
return 1;
return 0;
}
rx_cons_fix_new (fragS * frag,
int where,
int size,
- expressionS * exp)
+ expressionS * exp,
+ bfd_reloc_code_real_type type)
{
- bfd_reloc_code_real_type type;
-
switch (size)
{
case 1:
case BFD_RELOC_RX_GPRELL:
val >>= 1;
+ /* Fall through. */
case BFD_RELOC_RX_GPRELW:
val >>= 1;
+ /* Fall through. */
case BFD_RELOC_RX_GPRELB:
#if RX_OPCODE_BIG_ENDIAN
op[1] = val & 0xff;
}
arelent **
-tc_gen_reloc (asection * seg ATTRIBUTE_UNUSED, fixS * fixp)
+tc_gen_reloc (asection * sec ATTRIBUTE_UNUSED, fixS * fixp)
{
static arelent * reloc[5];
+ bfd_boolean is_opcode = FALSE;
if (fixp->fx_r_type == BFD_RELOC_NONE)
{
fixp->fx_subsy = NULL;
}
- reloc[0] = (arelent *) xmalloc (sizeof (arelent));
- reloc[0]->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
+ reloc[0] = XNEW (arelent);
+ reloc[0]->sym_ptr_ptr = XNEW (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;
+ if (fixp->fx_r_type == BFD_RELOC_RX_32_OP
+ && fixp->fx_subsy)
+ {
+ fixp->fx_r_type = BFD_RELOC_RX_DIFF;
+ is_opcode = TRUE;
+ }
+ else if (sec)
+ is_opcode = sec->flags & SEC_CODE;
+
/* Certain BFD relocations cannot be translated directly into
a single (non-Red Hat) RX relocation, but instead need
multiple RX relocations - handle them here. */
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] = XNEW (arelent);
+ reloc[1]->sym_ptr_ptr = XNEW (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] = XNEW (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] = XNEW (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);
+ if (!is_opcode && target_big_endian)
+ reloc[3]->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_RX_ABS16_REV);
+ else if (is_opcode)
+ reloc[3]->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_RX_ABS16UL);
+ else
+ 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);
+ if (!is_opcode && target_big_endian)
+ reloc[3]->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_RX_ABS32_REV);
+ else
+ reloc[3]->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_RX_ABS32);
break;
}
reloc[3]->addend = 0;
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 *));
+ reloc[1] = XNEW (arelent);
+ reloc[1]->sym_ptr_ptr = XNEW (asymbol *);
if (gp_symbol == NULL)
{
if (symbol_table_frozen)
reloc[1]->addend = 0;
reloc[1]->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_RX_SYM);
- reloc[2] = (arelent *) xmalloc (sizeof (arelent));
+ reloc[2] = XNEW (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] = XNEW (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;
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 *));
+ reloc[1] = XNEW (arelent);
+ reloc[1]->sym_ptr_ptr = XNEW (asymbol *);
if (gp_symbol == NULL)
{
if (symbol_table_frozen)
reloc[1]->addend = 0;
reloc[1]->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_RX_SYM);
- reloc[2] = (arelent *) xmalloc (sizeof (arelent));
+ reloc[2] = XNEW (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] = XNEW (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;
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 *));
+ reloc[1] = XNEW (arelent);
+ reloc[1]->sym_ptr_ptr = XNEW (asymbol *);
if (gp_symbol == NULL)
{
if (symbol_table_frozen)
reloc[1]->addend = 0;
reloc[1]->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_RX_SYM);
- reloc[2] = (arelent *) xmalloc (sizeof (arelent));
+ reloc[2] = XNEW (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] = XNEW (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[4] = NULL;
break;
+ case BFD_RELOC_RX_NEG32:
+ reloc[0]->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_RX_SYM);
+
+ reloc[1] = XNEW (arelent);
+ reloc[1]->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_RX_OP_NEG);
+ reloc[1]->addend = 0;
+ reloc[1]->sym_ptr_ptr = reloc[0]->sym_ptr_ptr;
+ reloc[1]->address = fixp->fx_frag->fr_address + fixp->fx_where;
+
+ reloc[2] = XNEW (arelent);
+ reloc[2]->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_RX_ABS32);
+ reloc[2]->addend = 0;
+ reloc[2]->sym_ptr_ptr = reloc[0]->sym_ptr_ptr;
+ reloc[2]->address = fixp->fx_frag->fr_address + fixp->fx_where;
+
+ reloc[3] = NULL;
+ break;
+
default:
reloc[0]->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type);
reloc[1] = NULL;
return reloc;
}
+void
+rx_note_string_insn_use (void)
+{
+ if ((elf_flags & E_FLAG_RX_SINSNS_MASK) == (E_FLAG_RX_SINSNS_SET | E_FLAG_RX_SINSNS_NO))
+ as_bad (_("Use of an RX string instruction detected in a file being assembled without string instruction support"));
+ elf_flags |= E_FLAG_RX_SINSNS_SET | E_FLAG_RX_SINSNS_YES;
+}
+
/* Set the ELF specific flags. */
void
elf_elfheader (stdoutput)->e_flags |= elf_flags;
}
-/* Scan the current input line for occurances of Renesas
+/* Scan the current input line for occurrences of Renesas
local labels and replace them with the GAS version. */
void