S12Z: GAS: Allow #_symbol operands as mov source

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.
This commit is contained in:
John Darrington 2019-02-01 17:42:54 +01:00
parent 91bae99160
commit c6f14c0d2c
5 changed files with 119 additions and 39 deletions

View File

@ -1,3 +1,13 @@
2019-01-31 John Darrington <john@darrington.wattle.id.au>
* 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.
2019-01-31 John Darrington <john@darrington.wattle.id.au>
* config/tc-s12z.c (md_apply_fix): Fix incorrect limits.

View File

@ -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;
}
static void
emit_reloc (expressionS *exp, char *f, int size, enum bfd_reloc_code_real reloc)
{
if (exp->X_op != O_absent && exp->X_op != O_constant)
{
fixS *fix = fix_new_exp (frag_now,
f - frag_now->fr_literal,
size,
exp,
FALSE,
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. */
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);
if (exp->X_op != O_absent && exp->X_op != O_constant)
{
fixS *fix = fix_new_exp (frag_now,
f - frag_now->fr_literal,
3,
exp,
FALSE,
BFD_RELOC_S12Z_OPR);
/* 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. */
fix->fx_addnumber = 0x00;
}
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;

View File

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

View File

@ -0,0 +1,5 @@
.extern xxx
mov.p #xxx+3, (0,s)
mov.w #xxx+2, (0,s)
mov.l #xxx+1, (0,s)

View File

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