[RFC PATCH v3 2/4] RX: gas rx-linux target FDPIC support

Yoshinori Sato <[email protected]>
Newsgroups gmane.comp.gnu.binutils
Message-ID <[email protected]>
        * config/rx-parse.y
	(displacement): Fix expression displacement.
	(displacement): Add PIC relocation.
        * config/tc-rx.c
        (fdpic): New. in fdpic mode.
        (options): Add OPTION_FDPIC.
        (md_longopts): Add "--fdpic".
        (md_parse_option): Likewise.
        (md_show_usage): Likewise.
        (rx_end_of_match): New. Lookup relocation type helper.
        (rx_parse_name): New. parse symbol relocation type.
        (md_assemble): PIC relocation support.
        (md_convert_flag): Likewise.
        (md_cons_fix_new): Likewise.
        (md_apply_fix): Likewise.
        (rx_force_relocation): New.
	(rx_fix_adjustable): New.
	(rx_elf_final_processing): set EF_RX_FDPIC flag for fdpic output.
        * config/tc-rx.h
        (md_parse_name): New.
        (TC_FORCE_RELOCATION): New.
        (O_PIC_reloc): New.
        (tc_fix_adjustable): New.
	* config/rx-defs.h
	(rx_fix_adjustable): New prototype.
	* testsuite/gas/rx/mov.d: Add expression displacement case.
	* testsuite/gas/rx/mov.sm: Likewise.

Signed-off-by: Yoshinori Sato <[email protected]>
---
 gas/config/rx-defs.h        |   1 +
 gas/config/rx-parse.y       |  16 ++-
 gas/config/tc-rx.c          | 269 ++++++++++++++++++++++++++++++++++--
 gas/config/tc-rx.h          |  18 ++-
 gas/testsuite/gas/rx/mov.d  |   3 +
 gas/testsuite/gas/rx/mov.sm |   7 +
 6 files changed, 298 insertions(+), 16 deletions(-)

diff --git a/gas/config/rx-defs.h b/gas/config/rx-defs.h
index 8fa708df311..d57abfeae96 100644
--- a/gas/config/rx-defs.h
+++ b/gas/config/rx-defs.h
@@ -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;
diff --git a/gas/config/rx-parse.y b/gas/config/rx-parse.y
index 4d657b5df67..224c7ba208b 100644
--- a/gas/config/rx-parse.y
+++ b/gas/config/rx-parse.y
@@ -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;
 	}
     }
 
diff --git a/gas/config/tc-rx.c b/gas/config/tc-rx.c
index 794f64a54f4..9dd14af4c1a 100644
--- a/gas/config/tc-rx.c
+++ b/gas/config/tc-rx.c
@@ -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
diff --git a/gas/config/tc-rx.h b/gas/config/tc-rx.h
index 8a37b36275d..72e176eb7b7 100644
--- a/gas/config/tc-rx.h
+++ b/gas/config/tc-rx.h
@@ -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)								\
diff --git a/gas/testsuite/gas/rx/mov.d b/gas/testsuite/gas/rx/mov.d
index 276b6d9d898..4c5d2389746 100644
--- a/gas/testsuite/gas/rx/mov.d
+++ b/gas/testsuite/gas/rx/mov.d
@@ -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
diff --git a/gas/testsuite/gas/rx/mov.sm b/gas/testsuite/gas/rx/mov.sm
index 8bebbf5908a..03bec4a7bc1 100644
--- a/gas/testsuite/gas/rx/mov.sm
+++ b/gas/testsuite/gas/rx/mov.sm
@@ -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:
-- 
2.47.3
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.