aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Clifton <nickc@redhat.com>2014-03-12 15:44:09 +0000
committerNick Clifton <nickc@redhat.com>2014-03-12 15:50:49 +0000
commit55d9b4c146716a683d9fea769e5f4106eadb30fc (patch)
tree31d561ee0aa081ccd638955342aece052073d99f
parent646f4417760ab12c0d955dabf821d8737d94335a (diff)
downloadfsf-binutils-gdb-55d9b4c146716a683d9fea769e5f4106eadb30fc.zip
fsf-binutils-gdb-55d9b4c146716a683d9fea769e5f4106eadb30fc.tar.gz
fsf-binutils-gdb-55d9b4c146716a683d9fea769e5f4106eadb30fc.tar.bz2
The value of a bignum expression is held in a single global array. This means
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.
-rw-r--r--gas/ChangeLog9
-rw-r--r--gas/config/tc-aarch64.c61
-rw-r--r--gas/testsuite/ChangeLog6
-rw-r--r--gas/testsuite/gas/aarch64/litpool.d30
-rw-r--r--gas/testsuite/gas/aarch64/litpool.s7
5 files changed, 101 insertions, 12 deletions
diff --git a/gas/ChangeLog b/gas/ChangeLog
index 7bff8d3..6851b8c 100644
--- a/gas/ChangeLog
+++ b/gas/ChangeLog
@@ -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.
diff --git a/gas/config/tc-aarch64.c b/gas/config/tc-aarch64.c
index c08e8af..5c1b938 100644
--- a/gas/config/tc-aarch64.c
+++ b/gas/config/tc-aarch64.c
@@ -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);
diff --git a/gas/testsuite/ChangeLog b/gas/testsuite/ChangeLog
index f89155a..9e87cc0 100644
--- a/gas/testsuite/ChangeLog
+++ b/gas/testsuite/ChangeLog
@@ -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
index 0000000..bc5f6c0
--- /dev/null
+++ b/gas/testsuite/gas/aarch64/litpool.d
@@ -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
index 0000000..d13e91f
--- /dev/null
+++ b/gas/testsuite/gas/aarch64/litpool.s
@@ -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