@@ -68,6 +68,7 @@ extern int rx_parse (void);
extern int rx_wrap (void);
extern void rx_note_string_insn_use (void);
extern void rx_post (char);
+extern bool rx_fix_adjustable (fixS *fixP);
extern char * rx_lex_start;
extern char * rx_lex_end;
@@ -1934,8 +1934,12 @@ displacement (expressionS exp, int msize)
valueT val;
int vshift = 0;
- if (exp.X_op == O_symbol
- && exp.X_md)
+ /* "foo - bar[Rn]" case, use dsp16[Rn] addressing. */
+ if (exp.X_op == O_subtract)
+ exp.X_md = BFD_RELOC_RX_DIFF;
+
+ if (((exp.X_op == O_symbol || exp.X_op == O_PIC_reloc) && exp.X_md) ||
+ (exp.X_op == O_subtract))
{
switch (exp.X_md)
{
@@ -1954,6 +1958,14 @@ displacement (expressionS exp, int msize)
}
O2 (exp);
return 2;
+ case BFD_RELOC_16_GOT_PCREL:
+ exp.X_md = BFD_RELOC_RX_GOT;
+ O2 (exp);
+ return 2;
+ case BFD_RELOC_RX_GOTFUNCDESC:
+ exp.X_md = BFD_RELOC_RX_GOTFUNCDESC;
+ O2 (exp);
+ return 2;
}
}
@@ -40,13 +40,16 @@ const char line_separator_chars[] = "!";
const char EXP_CHARS[] = "eE";
const char FLT_CHARS[] = "dD";
+
+/* Whether --fdpic was given. */
+static bool fdpic = false;
#ifndef TE_LINUX
bool rx_use_conventional_section_names = false;
static int elf_flags = E_FLAG_RX_ABI;
#else
bool rx_use_conventional_section_names = true;
-static int elf_flags;
+static int elf_flags = 0;
#endif
static bool rx_use_small_data_limit = false;
@@ -75,6 +78,7 @@ enum options
OPTION_USES_RX_ABI,
OPTION_CPU,
OPTION_DISALLOW_STRING_INSNS,
+ OPTION_FDPIC,
};
#define RX_SHORTOPTS ""
@@ -103,6 +107,7 @@ const struct option md_longopts[] =
{"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},
+ {"fdpic", no_argument, NULL, OPTION_FDPIC},
{NULL, no_argument, NULL, 0}
};
const size_t md_longopts_size = sizeof (md_longopts);
@@ -198,6 +203,9 @@ md_parse_option (int c ATTRIBUTE_UNUSED, const char * arg ATTRIBUTE_UNUSED)
case OPTION_DISALLOW_STRING_INSNS:
elf_flags |= E_FLAG_RX_SINSNS_SET | E_FLAG_RX_SINSNS_NO;
return 1;
+ case OPTION_FDPIC:
+ fdpic = true;
+ return 1;
}
return 0;
@@ -218,7 +226,8 @@ md_show_usage (FILE * stream)
fprintf (stream, _(" --mpid\n"));
fprintf (stream, _(" --mint-register=<value>\n"));
fprintf (stream, _(" --mcpu=<rx100|rx200|rx600|rx610|rxv2|rxv3|rxv3-dfpu>\n"));
- fprintf (stream, _(" --mno-allow-string-insns"));
+ fprintf (stream, _(" --mno-allow-string-insns\n"));
+ fprintf (stream, _(" --fdpic"));
}
static void
@@ -1120,6 +1129,97 @@ scan_for_infix_rx_pseudo_ops (char * str)
return true;
}
+inline static char *
+rx_end_of_match (char *cont, const char *what)
+{
+ int len = strlen (what);
+
+ if (strncasecmp (cont, what, strlen (what)) == 0
+ && ! is_part_of_name (cont[len]))
+ return cont + len;
+
+ return NULL;
+}
+
+#ifdef TE_LINUX
+int
+rx_parse_name (char const *name, expressionS *exprP,
+ enum expr_mode mode, char *nextcharP)
+{
+ char *next = input_line_pointer;
+ char *next_end;
+ int reloc_type;
+ segT segment;
+
+ static const struct suffix_list {
+ const char *name;
+ int reloc;
+ } suffixes[] = {
+ { "GOTOFFFUNCDESC", BFD_RELOC_RX_GOTOFFFUNCDESC },
+ { "GOTFUNCDESC", BFD_RELOC_RX_GOTFUNCDESC },
+ { "GOTOFF", BFD_RELOC_32_GOTOFF },
+ { "FUNCDESC", BFD_RELOC_RX_FUNCDESC },
+ { "GOT", BFD_RELOC_16_GOT_PCREL },
+ { "PLT", BFD_RELOC_32_PLT_PCREL },
+ { NULL, -1 },
+ };
+ const struct suffix_list *s;
+
+ if (!fdpic)
+ return 0;
+
+ exprP->X_op_symbol = NULL;
+ exprP->X_add_symbol = symbol_find_or_make (name);
+
+ if (*nextcharP != '@')
+ goto no_suffix;
+ for (s = suffixes; s->name != NULL; s++)
+ {
+ if ((next_end = rx_end_of_match (next + 1, s->name)))
+ {
+ reloc_type = s->reloc;
+ break;
+ }
+ }
+ if (s->name == NULL)
+ goto no_suffix;
+
+ *input_line_pointer = *nextcharP;
+ input_line_pointer = next_end;
+ *nextcharP = *input_line_pointer;
+ *input_line_pointer = '\0';
+
+ exprP->X_op = O_PIC_reloc;
+ exprP->X_add_number = 0;
+ exprP->X_md = reloc_type;
+ return 1;
+
+ no_suffix:
+ /* If we have an absolute symbol or a reg, then we know its
+ value now. */
+ segment = S_GET_SEGMENT (exprP->X_add_symbol);
+ if (mode != expr_defer && segment == absolute_section)
+ {
+ exprP->X_op = O_constant;
+ exprP->X_add_number = S_GET_VALUE (exprP->X_add_symbol);
+ exprP->X_add_symbol = NULL;
+ }
+ else if (mode != expr_defer && segment == reg_section)
+ {
+ exprP->X_op = O_register;
+ exprP->X_add_number = S_GET_VALUE (exprP->X_add_symbol);
+ exprP->X_add_symbol = NULL;
+ }
+ else
+ {
+ exprP->X_op = O_symbol;
+ exprP->X_add_number = 0;
+ }
+
+ return 1;
+}
+#endif
+
void
md_assemble (char * str)
{
@@ -1168,7 +1268,9 @@ md_assemble (char * str)
APPEND (ops, n_ops);
APPEND (post, n_post);
- if (rx_bytes.link_relax && rx_bytes.n_fixups)
+#ifdef TE_LINUX
+ if (rx_bytes.link_relax && rx_bytes.n_fixups &&
+ rx_bytes.fixups[0].exp.X_op != O_PIC_reloc)
{
fixS * f;
@@ -1181,6 +1283,7 @@ md_assemble (char * str)
BFD_RELOC_RX_RELAX);
frag_then->tc_frag_data->link_relax_fixP = f;
}
+#endif
for (i = 0; i < rx_bytes.n_fixups; i ++)
{
@@ -1206,12 +1309,41 @@ md_assemble (char * str)
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);
+#ifdef TE_LINUX
+ if (exp->X_op == O_PIC_reloc
+ && exp->X_md != BFD_RELOC_RX_GOT
+ && exp->X_md != BFD_RELOC_RX_GOTFUNCDESC)
+ {
+ exp->X_op = O_symbol;
+ f = fix_new_exp (frag_then,
+ (char *) bytes + idx - frag_then->fr_literal,
+ 4,
+ exp,
+ 0,
+ exp->X_md);
+ }
+ else if (exp->X_op == O_PIC_reloc &&
+ (exp->X_md == BFD_RELOC_RX_GOT
+ || exp->X_md == BFD_RELOC_RX_GOTFUNCDESC))
+ {
+ exp->X_op = O_symbol;
+ f = fix_new_exp (frag_then,
+ (char *) bytes + idx - frag_then->fr_literal,
+ 2,
+ exp,
+ 0,
+ exp->X_md);
+ }
+ else
+#endif
+ {
+ 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;
}
@@ -1788,7 +1920,7 @@ md_convert_frag (bfd * abfd ATTRIBUTE_UNUSED,
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",
+ tprintf ("\033[31mconvert frag: addr %08lx fix %ld var %ld ofs %ld lit %p opc %p type %d sub %d\033[0m\n",
(unsigned long) (fragP->fr_address
+ (fragP->fr_opcode - fragP->fr_literal)),
(long) fragP->fr_fix, (long) fragP->fr_var, (long) fragP->fr_offset,
@@ -1895,7 +2027,14 @@ md_convert_frag (bfd * abfd ATTRIBUTE_UNUSED,
op[2] = (disp >> 8) & 0xff;
op[1] = disp;
#endif
- reloc_type = keep_reloc ? BFD_RELOC_24_PCREL : BFD_RELOC_NONE;
+ if (fragP->tc_frag_data->fixups->exp.X_md != BFD_RELOC_32_PLT_PCREL)
+ {
+ reloc_type = keep_reloc ? BFD_RELOC_24_PCREL : BFD_RELOC_NONE;
+ }
+ else
+ {
+ reloc_type = BFD_RELOC_32_PLT_PCREL;
+ }
reloc_adjust = 1;
break;
@@ -1998,7 +2137,14 @@ md_convert_frag (bfd * abfd ATTRIBUTE_UNUSED,
op[2] = (disp >> 8) & 0xff;
op[1] = disp;
#endif
- reloc_type = keep_reloc ? BFD_RELOC_24_PCREL : BFD_RELOC_NONE;
+ if (fragP->tc_frag_data->fixups->exp.X_md != BFD_RELOC_32_PLT_PCREL)
+ {
+ reloc_type = keep_reloc ? BFD_RELOC_24_PCREL : BFD_RELOC_NONE;
+ }
+ else
+ {
+ reloc_type = BFD_RELOC_32_PLT_PCREL;
+ }
reloc_adjust = 0;
break;
@@ -2053,6 +2199,23 @@ md_convert_frag (bfd * abfd ATTRIBUTE_UNUSED,
int li;
char * imm = op + fragP->tc_frag_data->relax[ri].val_ofs;
+ if (rxb->fixups[fi].exp.X_op == O_symbol)
+ {
+#ifdef TE_LINUX
+ switch(rxb->fixups[fi].exp.X_md)
+ {
+ case BFD_RELOC_16_GOT_PCREL:
+ reloc_type = BFD_RELOC_RX_GOT;
+ break;
+ case BFD_RELOC_32_GOTOFF:
+ case BFD_RELOC_RX_GOTFUNCDESC:
+ case BFD_RELOC_RX_GOTOFFFUNCDESC:
+ case BFD_RELOC_RX_FUNCDESC:
+ reloc_type = rxb->fixups[fi].exp.X_md;
+ break;
+ }
+#endif
+ }
switch (nbytes)
{
case 1:
@@ -2097,7 +2260,27 @@ md_convert_frag (bfd * abfd ATTRIBUTE_UNUSED,
imm[2] = addr0 >> 16;
imm[3] = addr0 >> 24;
#endif
- reloc_type = BFD_RELOC_RX_32_OP;
+#ifdef TE_LINUX
+ if (rxb->fixups[fi].exp.X_op == O_symbol)
+ {
+ switch(rxb->fixups[fi].exp.X_md)
+ {
+ case BFD_RELOC_16_GOT_PCREL:
+ reloc_type = BFD_RELOC_RX_GOT;
+ break;
+ case BFD_RELOC_32_GOTOFF:
+ case BFD_RELOC_RX_GOTFUNCDESC:
+ case BFD_RELOC_RX_GOTOFFFUNCDESC:
+ case BFD_RELOC_RX_FUNCDESC:
+ reloc_type = rxb->fixups[fi].exp.X_md;
+ break;
+ default:
+ reloc_type = BFD_RELOC_RX_32_OP;
+ }
+ }
+ else
+#endif
+ reloc_type = BFD_RELOC_RX_32_OP;
break;
default:
as_bad (_("invalid immediate size"));
@@ -2152,6 +2335,9 @@ md_convert_frag (bfd * abfd ATTRIBUTE_UNUSED,
break;
case BFD_RELOC_24_PCREL:
case BFD_RELOC_RX_24_OP:
+#ifdef TE_LINUX
+ case BFD_RELOC_32_PLT_PCREL:
+#endif
fix->fx_size = 3;
break;
case BFD_RELOC_RX_32_OP:
@@ -2220,6 +2406,9 @@ rx_cons_fix_new (fragS * frag,
expressionS * exp,
bfd_reloc_code_real_type type)
{
+
+ type = BFD_RELOC_UNUSED;
+
switch (size)
{
case 1:
@@ -2247,6 +2436,13 @@ rx_cons_fix_new (fragS * frag,
type = BFD_RELOC_RX_DIFF;
}
+#ifdef TE_LINUX
+ if (exp->X_op == O_PIC_reloc)
+ {
+ type = BFD_RELOC_RX_FUNCDESC;
+ exp->X_op = O_symbol;
+ }
+#endif
fix_new_exp (frag, where, size, exp, 0, type);
}
@@ -2433,6 +2629,21 @@ md_apply_fix (struct fix *f,
#endif
break;
+#ifdef TE_LINUX
+ case BFD_RELOC_RX_GOT:
+ case BFD_RELOC_RX_GOTFUNCDESC:
+ f->fx_no_overflow = 1;
+ op[0] = op[1] = 0;
+ break;
+ case BFD_RELOC_RX_GOTOFFFUNCDESC:
+ case BFD_RELOC_RX_FUNCDESC:
+ case BFD_RELOC_32_PLT_PCREL:
+ case BFD_RELOC_32_GOTOFF:
+ /* This field fill in ld */
+ op[0] = op[1] = op[2] = op[3] = 0;
+ break;
+#endif
+
default:
as_bad (_("Unknown reloc in md_apply_fix: %s"),
bfd_get_reloc_code_name (f->fx_r_type));
@@ -2681,12 +2892,44 @@ rx_note_string_insn_use (void)
elf_flags |= E_FLAG_RX_SINSNS_SET | E_FLAG_RX_SINSNS_YES;
}
+#ifdef TE_LINUX
+int
+rx_force_relocation (fixS *fix)
+{
+ /* Make sure some relocations get emitted. */
+ if (fix->fx_r_type == BFD_RELOC_RX_GOT
+ || fix->fx_r_type == BFD_RELOC_RX_GOTOFF
+ || fix->fx_r_type == BFD_RELOC_RX_GOTFUNCDESC
+ || fix->fx_r_type == BFD_RELOC_RX_GOTOFFFUNCDESC
+ || generic_force_reloc (fix))
+ return 1;
+ return 0;
+}
+
+bool
+rx_fix_adjustable (fixS *fixP)
+{
+ if (fixP->fx_r_type == BFD_RELOC_32_PLT_PCREL
+ || fixP->fx_r_type == BFD_RELOC_16_GOT_PCREL
+ || fixP->fx_r_type == BFD_RELOC_RX_GOT
+ || fixP->fx_r_type == BFD_RELOC_32_GOTOFF
+ || fixP->fx_r_type == BFD_RELOC_RX_GOTFUNCDESC
+ || fixP->fx_r_type == BFD_RELOC_RX_GOTOFFFUNCDESC
+ || fixP->fx_r_type == BFD_RELOC_RX_FUNCDESC)
+ return false;
+ return true;
+}
+#endif
+
/* Set the ELF specific flags. */
void
rx_elf_final_processing (void)
{
elf_elfheader (stdoutput)->e_flags |= elf_flags;
+
+ if (fdpic)
+ elf_elfheader (stdoutput)->e_flags |= EF_RX_FDPIC;
}
/* Scan the current input line for occurrences of Renesas
@@ -75,12 +75,28 @@ extern void rx_frag_init (fragS *);
rx_validate_fix_sub (FIX)
extern int rx_validate_fix_sub (struct fix *);
+#ifdef TE_LINUX
+#define md_parse_name(name, exprP, mode, nextcharP) \
+ rx_parse_name ((name), (exprP), (mode), (nextcharP))
+int rx_parse_name (char const *, expressionS *,
+ enum expr_mode, char *);
+/* We need to force out some relocations when relaxing. */
+#define TC_FORCE_RELOCATION(fix) rx_force_relocation (fix)
+extern int rx_force_relocation (struct fix *);
+#endif
#define TC_CONS_FIX_NEW(FRAG, WHERE, NBYTES, EXP, RELOC) \
rx_cons_fix_new (FRAG, WHERE, NBYTES, EXP, RELOC)
extern void rx_cons_fix_new (fragS *, int, int, expressionS *,
bfd_reloc_code_real_type);
-#define tc_fix_adjustable(x) 0
+/* This is used to construct expressions out of @GOTOFF, @PLT and @GOT
+ symbols. The relocation type is stored in X_md. */
+#define O_PIC_reloc O_md1
+
+#ifdef TE_LINUX
+#define tc_fix_adjustable(x) rx_fix_adjustable(x)
+extern bool rx_fix_adjustable (struct fix *);
+#endif
#define md_do_align(n, fill, len, max, around) \
if ((n) \
@@ -528,3 +528,6 @@ Disassembly of section .*:
[0-9a-f]+: fd 2e 0f mov.l \[-r0\], r15
[0-9a-f]+: fd 2e f0 mov.l \[-r15\], r0
[0-9a-f]+: fd 2e ff mov.l \[-r15\], r15
+ [0-9a-f]+: ce 00 04 00 mov.b 4\[r0\], r0
+ [0-9a-f]+: de 00 02 00 mov.w 4\[r0\], r0
+ [0-9a-f]+: ee 00 01 00 mov.l 4\[r0\], r0
@@ -31,3 +31,10 @@
mov{bwl} [{reg}+],{reg}
mov{bwl} {reg},[-{reg}]
mov{bwl} [-{reg}],{reg}
+
+1: mov.B 2f - 1b[r0], r0
+2:
+1: mov.W 2f - 1b[r0], r0
+2:
+1: mov.L 2f - 1b[r0], r0
+2: