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.
This commit is contained in:
Nick Clifton 2014-03-12 15:44:09 +00:00
parent 646f441776
commit 55d9b4c146
5 changed files with 101 additions and 12 deletions

View 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.

View 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);

View 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.

View File

@ -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

View File

@ -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