[4/4] S12Z: GAS: Allow #_symbol operands as mov source

Message ID 20190131180442.31410-4-john@darrington.wattle.id.au
State New
Headers show
Series
  • [1/4] S12Z: GAS: Disallow immediate destination operands
Related show

Commit Message

John Darrington Jan. 31, 2019, 6:04 p.m.
mov.l, mov.p and mov.w (but not mov.b) when called with an immediate source
operand should be accepted a relocatable expression.  This change makes that
possible.

gas/
	* config/tc-s12z.c (lex_imm): Add new argument exp_o.
	(emit_reloc): New function.
	(md_apply_fix): [BFD_RELOC_S12Z_OPR] Recognise that it
	can be either 2 bytes or 3 bytes long.
	* testsuite/gas/s12z/mov-imm-reloc.d: New file.
	* testsuite/gas/s12z/mov-imm-reloc.s: New file.
	* testsuite/gas/s12z/s12z.exp: Add them.
---
 gas/config/tc-s12z.c                   | 114 +++++++++++++++++++++++----------
 gas/testsuite/gas/s12z/mov-imm-reloc.d |  20 ++++++
 gas/testsuite/gas/s12z/mov-imm-reloc.s |   5 ++
 gas/testsuite/gas/s12z/s12z.exp        |   1 +
 4 files changed, 105 insertions(+), 35 deletions(-)
 create mode 100644 gas/testsuite/gas/s12z/mov-imm-reloc.d
 create mode 100644 gas/testsuite/gas/s12z/mov-imm-reloc.s

-- 
2.11.0

Comments

Nick Clifton Feb. 1, 2019, 10:54 a.m. | #1
Hi John,

> gas/

> 	* config/tc-s12z.c (lex_imm): Add new argument exp_o.

> 	(emit_reloc): New function.

> 	(md_apply_fix): [BFD_RELOC_S12Z_OPR] Recognise that it

> 	can be either 2 bytes or 3 bytes long.

> 	* testsuite/gas/s12z/mov-imm-reloc.d: New file.

> 	* testsuite/gas/s12z/mov-imm-reloc.s: New file.

> 	* testsuite/gas/s12z/s12z.exp: Add them.


Approved - please apply.

Cheers
  Nick

Patch

diff --git a/gas/config/tc-s12z.c b/gas/config/tc-s12z.c
index 8b56b685b8..bc1bb5c382 100644
--- a/gas/config/tc-s12z.c
+++ b/gas/config/tc-s12z.c
@@ -227,9 +227,12 @@  lex_expression (expressionS *exp)
   return 0;
 }
 
-/* immediate operand */
+/* Immediate operand.
+   If EXP_O is non-null, then a symbolic expression is permitted,
+   in which case, EXP_O will be populated with the parsed expression.
+ */
 static int
-lex_imm (long *v)
+lex_imm (long *v, expressionS *exp_o)
 {
   char *ilp = input_line_pointer;
 
@@ -242,7 +245,12 @@  lex_imm (long *v)
     goto fail;
 
   if (exp.X_op != O_constant)
-    goto fail;
+    {
+      if (!exp_o)
+        as_bad (_("A non-constant expression is not permitted here"));
+      else
+        *exp_o = exp;
+    }
 
   *v = exp.X_add_number;
   return 1;
@@ -258,7 +266,7 @@  static int
 lex_imm_e4 (long *val)
 {
   char *ilp = input_line_pointer;
-  if ((lex_imm (val)))
+  if ((lex_imm (val, NULL)))
     {
       if ((*val == -1) || (*val > 0 && *val <= 15))
 	{
@@ -731,26 +739,35 @@  no_operands (const struct instruction *insn)
   return 1;
 }
 
-/* Emit the code for an OPR address mode operand */
-static char *
-emit_opr (char *f, const uint8_t *buffer, int n_bytes, expressionS *exp)
+
+static void
+emit_reloc (expressionS *exp, char *f, int size, enum bfd_reloc_code_real reloc)
 {
-  int i;
-  number_to_chars_bigendian (f++, buffer[0], 1);
   if (exp->X_op != O_absent && exp->X_op != O_constant)
     {
       fixS *fix = fix_new_exp (frag_now,
 			       f - frag_now->fr_literal,
-			       3,
+			       size,
 			       exp,
 			       FALSE,
-			       BFD_RELOC_S12Z_OPR);
+                               reloc);
       /* Some third party tools seem to use the lower bits
-	of this addend for flags.   They don't get added
-	to the final location.   The purpose of these flags
-	is not known.  We simply set it to zero.  */
+         of this addend for flags.   They don't get added
+         to the final location.   The purpose of these flags
+         is not known.  We simply set it to zero.  */
       fix->fx_addnumber = 0x00;
     }
+}
+
+/* Emit the code for an OPR address mode operand */
+static char *
+emit_opr (char *f, const uint8_t *buffer, int n_bytes, expressionS *exp)
+{
+  int i;
+  number_to_chars_bigendian (f++, buffer[0], 1);
+
+  emit_reloc (exp, f, 3, BFD_RELOC_S12Z_OPR);
+
   for (i = 1; i < n_bytes; ++i)
     number_to_chars_bigendian (f++,  buffer[i], 1);
 
@@ -1037,7 +1054,7 @@  mul_reg_reg_imm (const struct instruction *insn)
     goto fail;
 
   long imm;
-  if (!lex_imm (&imm))
+  if (!lex_imm (&imm, NULL))
     goto fail;
 
 
@@ -1349,7 +1366,7 @@  static int
 imm8 (const struct instruction *insn)
 {
   long imm;
-  if (! lex_imm (&imm))
+  if (! lex_imm (&imm, NULL))
     return 0;
   if (imm > 127 || imm < -128)
     {
@@ -1374,7 +1391,7 @@  reg_imm (const struct instruction *insn, int allowed_reg)
       if (!lex_force_match (','))
 	goto fail;
       long imm;
-      if (! lex_imm (&imm))
+      if (! lex_imm (&imm, NULL))
 	goto fail;
 
       short size = registers[reg].bytes;
@@ -1417,7 +1434,7 @@  static int
 trap_imm (const struct instruction *insn ATTRIBUTE_UNUSED)
 {
   long imm = -1;
-  if (! lex_imm (&imm))
+  if (! lex_imm (&imm, NULL))
     goto fail;
 
   if (imm < 0x92 || imm > 0xFF ||
@@ -1619,7 +1636,19 @@  imm_opr  (const struct instruction *insn)
 {
   char *ilp = input_line_pointer;
   long imm;
-  if (!lex_imm (&imm))
+  expressionS exp0;
+  int size = size_from_suffix (insn, 0);
+  exp0.X_op = O_absent;
+
+  /* Note:  The ternary expression below means that "MOV.x #symbol,
+     mem-expr"  is accepted when x is a member of {'w', 'p', 'l'} but
+     not when it is 'b'.
+     The Freescale assembler accepts "MOV.b #symbol, mem-expr" but
+     produces obviously incorrect code.    Since such an instruction
+     would require an 8-bit reloc (which we don't have) and some
+     non-optimal kludges in the OPR encoding, it seems sensible that
+     such instructions should be rejected.  */
+  if (!lex_imm (&imm, size > 1 ? &exp0 : NULL))
     goto fail;
 
   if (!lex_match (','))
@@ -1627,19 +1656,20 @@  imm_opr  (const struct instruction *insn)
 
   uint8_t buffer[4];
   int n_bytes;
-  expressionS exp;
-  if (!lex_opr (buffer, &n_bytes, &exp, false))
+  expressionS exp1;
+  if (!lex_opr (buffer, &n_bytes, &exp1, false))
     goto fail;
 
-  int size = size_from_suffix (insn, 0);
   char *f = s12z_new_insn (1 + n_bytes + size);
   number_to_chars_bigendian (f++, insn->opc, 1);
 
+  emit_reloc (&exp0, f, size, size == 4 ? BFD_RELOC_32 : BFD_RELOC_S12Z_OPR);
+
   int i;
   for (i = 0; i < size; ++i)
     number_to_chars_bigendian (f++, imm >> (CHAR_BIT * (size - i - 1)), 1);
 
-  emit_opr (f, buffer, n_bytes, &exp);
+  emit_opr (f, buffer, n_bytes, &exp1);
 
   return 1;
 
@@ -1771,7 +1801,7 @@  lex_shift_reg_imm1  (const struct instruction *insn, short type, short dir)
     goto fail;
 
   long imm = -1;
-  if (!lex_imm (&imm))
+  if (!lex_imm (&imm, NULL))
     goto fail;
 
   if (imm != 1 && imm != 2)
@@ -1847,7 +1877,7 @@  lex_shift_reg  (const struct instruction *insn, short type, short dir)
 
       return 1;
     }
-  else if (lex_imm (&imm))
+  else if (lex_imm (&imm, NULL))
     {
       if (imm < 0 || imm > 31)
 	{
@@ -1942,7 +1972,7 @@  shift_two_operand  (const struct instruction *insn)
     goto fail;
 
   long imm = -1;
-  if (!lex_imm (&imm))
+  if (!lex_imm (&imm, NULL))
     goto fail;
 
   if (imm != 1 && imm != 2)
@@ -1999,7 +2029,7 @@  shift_opr_imm  (const struct instruction *insn)
   expressionS exp2;
   long imm;
   bool immediate = false;
-  if (lex_imm (&imm))
+  if (lex_imm (&imm, NULL))
     {
       immediate = true;
     }
@@ -2087,7 +2117,7 @@  bm_regd_imm  (const struct instruction *insn)
     goto fail;
 
   long imm;
-  if (!lex_imm (&imm))
+  if (!lex_imm (&imm, NULL))
     goto fail;
 
 
@@ -2162,7 +2192,7 @@  bm_opr_imm  (const struct instruction *insn)
 
 
   long imm;
-  if (!lex_imm (&imm))
+  if (!lex_imm (&imm, NULL))
     goto fail;
 
   int size = size_from_suffix (insn, 0);
@@ -2255,7 +2285,7 @@  bf_reg_opr_imm  (const struct instruction *insn, short ie)
     goto fail;
 
   long width;
-  if (!lex_imm (&width))
+  if (!lex_imm (&width, NULL))
     goto fail;
 
   if (width < 0 || width > 31)
@@ -2324,7 +2354,7 @@  bf_opr_reg_imm  (const struct instruction *insn, short ie)
     goto fail;
 
   long width;
-  if (!lex_imm (&width))
+  if (!lex_imm (&width, NULL))
     goto fail;
 
   if (width < 0 || width > 31)
@@ -2392,7 +2422,7 @@  bf_reg_reg_imm  (const struct instruction *insn, short ie)
     goto fail;
 
   long width;
-  if (!lex_imm (&width))
+  if (!lex_imm (&width, NULL))
     goto fail;
 
   if (width < 0 || width > 31)
@@ -2909,7 +2939,7 @@  test_br_opr_imm_rel  (const struct instruction *insn)
     goto fail;
 
   long imm;
-  if (!lex_imm (&imm))
+  if (!lex_imm (&imm, NULL))
     goto fail;
 
   if (imm < 0 || imm > 31)
@@ -2962,7 +2992,7 @@  test_br_reg_imm_rel  (const struct instruction *insn)
     goto fail;
 
   long imm;
-  if (!lex_imm (&imm))
+  if (!lex_imm (&imm, NULL))
     goto fail;
 
   if (imm < 0 || imm > 31)
@@ -3846,9 +3876,23 @@  md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
       bfd_putb16 ((bfd_vma) value, (unsigned char *) where);
       break;
     case BFD_RELOC_24:
-    case BFD_RELOC_S12Z_OPR:
       bfd_putb24 ((bfd_vma) value, (unsigned char *) where);
       break;
+    case BFD_RELOC_S12Z_OPR:
+      {
+        switch (fixP->fx_size)
+          {
+          case 3:
+            bfd_putb24 ((bfd_vma) value, (unsigned char *) where);
+            break;
+          case 2:
+            bfd_putb16 ((bfd_vma) value, (unsigned char *) where);
+            break;
+          default:
+            abort ();
+          }
+      }
+      break;
     case BFD_RELOC_32:
       bfd_putb32 ((bfd_vma) value, (unsigned char *) where);
       break;
diff --git a/gas/testsuite/gas/s12z/mov-imm-reloc.d b/gas/testsuite/gas/s12z/mov-imm-reloc.d
new file mode 100644
index 0000000000..76048ec96b
--- /dev/null
+++ b/gas/testsuite/gas/s12z/mov-imm-reloc.d
@@ -0,0 +1,20 @@ 
+#objdump: -d -r
+#name:    MOV instructions involving immediate operands which are relocatable expressions
+#source:  mov-imm-reloc.s
+
+
+.*:     file format elf32-s12z
+
+
+Disassembly of section .text:
+
+00000000 <.text>:
+   0:	0e 00 00 03 	mov.p #3, \(0,s\)
+   4:	60 
+			1: R_S12Z_OPR	xxx
+   5:	0d 00 02 60 	mov.w #2, \(0,s\)
+			6: R_S12Z_OPR	xxx
+   9:	0f 00 00 00 	mov.l #1, \(0,s\)
+   d:	01 60 
+			a: R_S12Z_EXT32	xxx
+
diff --git a/gas/testsuite/gas/s12z/mov-imm-reloc.s b/gas/testsuite/gas/s12z/mov-imm-reloc.s
new file mode 100644
index 0000000000..ec9f7affd0
--- /dev/null
+++ b/gas/testsuite/gas/s12z/mov-imm-reloc.s
@@ -0,0 +1,5 @@ 
+	.extern xxx
+
+	mov.p #xxx+3, (0,s)
+	mov.w #xxx+2, (0,s)
+	mov.l #xxx+1, (0,s)
diff --git a/gas/testsuite/gas/s12z/s12z.exp b/gas/testsuite/gas/s12z/s12z.exp
index d9746d3d91..612fda765b 100644
--- a/gas/testsuite/gas/s12z/s12z.exp
+++ b/gas/testsuite/gas/s12z/s12z.exp
@@ -75,6 +75,7 @@  run_dump_test mac
 run_dump_test min-max
 run_dump_test mod
 run_dump_test mov
+run_dump_test mov-imm-reloc
 run_dump_test p2-mul
 run_dump_test mul-imm
 run_dump_test mul-opr-opr