From 55d9b4c146716a683d9fea769e5f4106eadb30fc Mon Sep 17 00:00:00 2001 From: Nick Clifton Date: Wed, 12 Mar 2014 15:44:09 +0000 Subject: [PATCH] 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. --- gas/ChangeLog | 9 ++++++ gas/config/tc-aarch64.c | 61 +++++++++++++++++++++++++++++-------- gas/testsuite/ChangeLog | 6 ++++ gas/testsuite/gas/aarch64/litpool.d | 30 ++++++++++++++++++ gas/testsuite/gas/aarch64/litpool.s | 7 +++++ 5 files changed, 101 insertions(+), 12 deletions(-) create mode 100644 gas/testsuite/gas/aarch64/litpool.d create mode 100644 gas/testsuite/gas/aarch64/litpool.s 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 + + 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 * 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 + + PR gas/16688 + * gas/aarch64/litpool.s: New test case. + * gas/aarch64/litpool.d: Expected disassembly. + 2014-03-05 Alan Modra 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 -- 2.7.4