The value of a bignum expression is held in a single global array. This means
authorNick Clifton <nickc@redhat.com>
Wed, 12 Mar 2014 15:44:09 +0000 (15:44 +0000)
committerNick Clifton <nickc@redhat.com>
Wed, 12 Mar 2014 15:50:49 +0000 (15:50 +0000)
that if multiple bignum values are encountered only the most recent is valid.
If such expressions are cached, eg to be emitted into a literal pool later on
in the assembly, then only one expression - the last - will be correct.  This
patch fixes the problem for the AArch64 target by caching each bignum value
locally.

PR gas/16688
* config/tc-aarch64.c (literal_expression): New structure.
(literal_pool): Replace exp array with literal_expression array.
(add_to_lit_pool): When adding a bignum cache the big value.
(s_ltorg): When emitting a bignum initialise the global bignum
array from the cached value.

* gas/aarch64/litpool.s: New test case.
* gas/aarch64/litpool.d: Expected disassembly.

gas/ChangeLog
gas/config/tc-aarch64.c
gas/testsuite/ChangeLog
gas/testsuite/gas/aarch64/litpool.d [new file with mode: 0644]
gas/testsuite/gas/aarch64/litpool.s [new file with mode: 0644]

index 7bff8d35a544751754e65d3544bef21b41d141fe..6851b8c4bb4b8164094795a35d47855788fd4689 100644 (file)
@@ -1,3 +1,12 @@
+2014-03-12  Nick Clifton  <nickc@redhat.com>
+
+       PR gas/16688
+       * config/tc-aarch64.c (literal_expression): New structure.
+       (literal_pool): Replace exp array with literal_expression array.
+       (add_to_lit_pool): When adding a bignum cache the big value.
+       (s_ltorg): When emitting a bignum initialise the global bignum
+       array from the cached value.
+
 2014-03-12  Alan Modra  <amodra@gmail.com>
 
        * Makefile.in: Regenerate.
index c08e8af856effbb8a8df4fc926a02f569b087809..5c1b938ee724278cfb2e6aa603f39cb4f6e9936e 100644 (file)
@@ -435,9 +435,16 @@ static symbolS *last_label_seen;
    and per-sub-section basis.  */
 
 #define MAX_LITERAL_POOL_SIZE 1024
+typedef struct literal_expression
+{
+  expressionS exp;
+  /* If exp.op == O_big then this bignum holds a copy of the global bignum value.  */
+  LITTLENUM_TYPE * bignum;
+} literal_expression;
+
 typedef struct literal_pool
 {
-  expressionS literals[MAX_LITERAL_POOL_SIZE];
+  literal_expression literals[MAX_LITERAL_POOL_SIZE];
   unsigned int next_free_entry;
   unsigned int id;
   symbolS *symbol;
@@ -1616,17 +1623,19 @@ add_to_lit_pool (expressionS *exp, int size)
   /* Check if this literal value is already in the pool.  */
   for (entry = 0; entry < pool->next_free_entry; entry++)
     {
-      if ((pool->literals[entry].X_op == exp->X_op)
+      expressionS * litexp = & pool->literals[entry].exp;
+
+      if ((litexp->X_op == exp->X_op)
          && (exp->X_op == O_constant)
-         && (pool->literals[entry].X_add_number == exp->X_add_number)
-         && (pool->literals[entry].X_unsigned == exp->X_unsigned))
+         && (litexp->X_add_number == exp->X_add_number)
+         && (litexp->X_unsigned == exp->X_unsigned))
        break;
 
-      if ((pool->literals[entry].X_op == exp->X_op)
+      if ((litexp->X_op == exp->X_op)
          && (exp->X_op == O_symbol)
-         && (pool->literals[entry].X_add_number == exp->X_add_number)
-         && (pool->literals[entry].X_add_symbol == exp->X_add_symbol)
-         && (pool->literals[entry].X_op_symbol == exp->X_op_symbol))
+         && (litexp->X_add_number == exp->X_add_number)
+         && (litexp->X_add_symbol == exp->X_add_symbol)
+         && (litexp->X_op_symbol == exp->X_op_symbol))
        break;
     }
 
@@ -1639,8 +1648,18 @@ add_to_lit_pool (expressionS *exp, int size)
          return FALSE;
        }
 
-      pool->literals[entry] = *exp;
+      pool->literals[entry].exp = *exp;
       pool->next_free_entry += 1;
+      if (exp->X_op == O_big)
+       {
+         /* PR 16688: Bignums are held in a single global array.  We must
+            copy and preserve that value now, before it is overwritten.  */
+         pool->literals[entry].bignum = xmalloc (CHARS_PER_LITTLENUM * exp->X_add_number);
+         memcpy (pool->literals[entry].bignum, generic_bignum,
+                 CHARS_PER_LITTLENUM * exp->X_add_number);
+       }
+      else
+       pool->literals[entry].bignum = NULL;
     }
 
   exp->X_op = O_symbol;
@@ -1734,8 +1753,26 @@ s_ltorg (int ignored ATTRIBUTE_UNUSED)
       symbol_table_insert (pool->symbol);
 
       for (entry = 0; entry < pool->next_free_entry; entry++)
-       /* First output the expression in the instruction to the pool.  */
-       emit_expr (&(pool->literals[entry]), size);     /* .word|.xword  */
+       {
+         expressionS * exp = & pool->literals[entry].exp;
+
+         if (exp->X_op == O_big)
+           {
+             /* PR 16688: Restore the global bignum value.  */
+             gas_assert (pool->literals[entry].bignum != NULL);
+             memcpy (generic_bignum, pool->literals[entry].bignum,
+                     CHARS_PER_LITTLENUM * exp->X_add_number);
+           }
+
+         /* First output the expression in the instruction to the pool.  */
+         emit_expr (exp, size);        /* .word|.xword  */
+
+         if (exp->X_op == O_big)
+           {
+             free (pool->literals[entry].bignum);
+             pool->literals[entry].bignum = NULL;
+           }
+       }
 
       /* Mark the pool as empty.  */
       pool->next_free_entry = 0;
@@ -2815,7 +2852,7 @@ parse_shifter_operand_reloc (char **str, aarch64_opnd_info *operand,
       if (**str == '\0')
        return TRUE;
 
-      /* Otherwise, we have a shifted reloc modifier, so rewind to 
+      /* Otherwise, we have a shifted reloc modifier, so rewind to
          recover the variable name and continue parsing for the shifter.  */
       *str = p;
       return parse_shifter_operand_imm (str, operand, mode);
index f89155ab0702f24d764669b0a9e77a56eaa70dd6..9e87cc02aa5bfd6edfea3c988e99eadd9a836f32 100644 (file)
@@ -1,3 +1,9 @@
+2014-03-12  Nick Clifton  <nickc@redhat.com>
+
+       PR gas/16688
+       * gas/aarch64/litpool.s: New test case.
+       * gas/aarch64/litpool.d: Expected disassembly.
+
 2014-03-05  Alan Modra  <amodra@gmail.com>
 
        Update copyright years.
diff --git a/gas/testsuite/gas/aarch64/litpool.d b/gas/testsuite/gas/aarch64/litpool.d
new file mode 100644 (file)
index 0000000..bc5f6c0
--- /dev/null
@@ -0,0 +1,30 @@
+#objdump: -d
+#name: AArch64 Bignums in Literal Pool (PR 16688)
+# This test is only valid on ELF based ports.
+#not-target: *-*-*coff *-*-pe *-*-wince *-*-*aout* *-*-netbsd *-*-riscix*
+
+.*: +file format.*aarch64.*
+
+Disassembly of section \.text:
+
+00+00 <.*>:
+   0:  9c000080        ldr     q0, 10 <\.text\+0x10>
+   4:  9c0000e1        ldr     q1, 20 <\.text\+0x20>
+   8:  9c000142        ldr     q2, 30 <\.text\+0x30>
+   c:  9c0001a3        ldr     q3, 40 <\.text\+0x40>
+  10:  00000000        .word   0x00000000
+  14:  5a827999        .word   0x5a827999
+  18:  5a827999        .word   0x5a827999
+  1c:  5a827999        .word   0x5a827999
+  20:  6ed9eba1        .word   0x6ed9eba1
+  24:  6ed9eba1        .word   0x6ed9eba1
+  28:  6ed9eba1        .word   0x6ed9eba1
+  2c:  6ed9eba1        .word   0x6ed9eba1
+  30:  11223344        .word   0x11223344
+  34:  8f1bbcdc        .word   0x8f1bbcdc
+  38:  8f1bbcdc        .word   0x8f1bbcdc
+  3c:  8f1bbcdc        .word   0x8f1bbcdc
+  40:  ca62c1d6        .word   0xca62c1d6
+  44:  ca62c1d6        .word   0xca62c1d6
+  48:  ca62c1d6        .word   0xca62c1d6
+  4c:  ca62c1d6        .word   0xca62c1d6
diff --git a/gas/testsuite/gas/aarch64/litpool.s b/gas/testsuite/gas/aarch64/litpool.s
new file mode 100644 (file)
index 0000000..d13e91f
--- /dev/null
@@ -0,0 +1,7 @@
+# Based on PR 16688 this test checks that bignums are correctly added to the literal pool
+       .text
+
+       ldr q0, =0x5a8279995a8279995a82799900000000
+       ldr q1, =0x6ed9eba16ed9eba16ed9eba16ed9eba1
+       ldr q2, =0x8f1bbcdc8f1bbcdc8f1bbcdc11223344
+       ldr q3, =0xca62c1d6ca62c1d6ca62c1d6ca62c1d6