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

View File

@ -227,9 +227,12 @@ lex_expression (expressionS *exp)
return 0; 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 static int
lex_imm (long *v) lex_imm (long *v, expressionS *exp_o)
{ {
char *ilp = input_line_pointer; char *ilp = input_line_pointer;
@ -242,7 +245,12 @@ lex_imm (long *v)
goto fail; goto fail;
if (exp.X_op != O_constant) 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; *v = exp.X_add_number;
return 1; return 1;
@ -258,7 +266,7 @@ static int
lex_imm_e4 (long *val) lex_imm_e4 (long *val)
{ {
char *ilp = input_line_pointer; char *ilp = input_line_pointer;
if ((lex_imm (val))) if ((lex_imm (val, NULL)))
{ {
if ((*val == -1) || (*val > 0 && *val <= 15)) if ((*val == -1) || (*val > 0 && *val <= 15))
{ {
@ -731,26 +739,35 @@ no_operands (const struct instruction *insn)
return 1; 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 */ /* Emit the code for an OPR address mode operand */
static char * static char *
emit_opr (char *f, const uint8_t *buffer, int n_bytes, expressionS *exp) emit_opr (char *f, const uint8_t *buffer, int n_bytes, expressionS *exp)
{ {
int i; int i;
number_to_chars_bigendian (f++, buffer[0], 1); number_to_chars_bigendian (f++, buffer[0], 1);
if (exp->X_op != O_absent && exp->X_op != O_constant)
{ emit_reloc (exp, f, 3, BFD_RELOC_S12Z_OPR);
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;
}
for (i = 1; i < n_bytes; ++i) for (i = 1; i < n_bytes; ++i)
number_to_chars_bigendian (f++, buffer[i], 1); number_to_chars_bigendian (f++, buffer[i], 1);
@ -1037,7 +1054,7 @@ mul_reg_reg_imm (const struct instruction *insn)
goto fail; goto fail;
long imm; long imm;
if (!lex_imm (&imm)) if (!lex_imm (&imm, NULL))
goto fail; goto fail;
@ -1349,7 +1366,7 @@ static int
imm8 (const struct instruction *insn) imm8 (const struct instruction *insn)
{ {
long imm; long imm;
if (! lex_imm (&imm)) if (! lex_imm (&imm, NULL))
return 0; return 0;
if (imm > 127 || imm < -128) if (imm > 127 || imm < -128)
{ {
@ -1374,7 +1391,7 @@ reg_imm (const struct instruction *insn, int allowed_reg)
if (!lex_force_match (',')) if (!lex_force_match (','))
goto fail; goto fail;
long imm; long imm;
if (! lex_imm (&imm)) if (! lex_imm (&imm, NULL))
goto fail; goto fail;
short size = registers[reg].bytes; short size = registers[reg].bytes;
@ -1417,7 +1434,7 @@ static int
trap_imm (const struct instruction *insn ATTRIBUTE_UNUSED) trap_imm (const struct instruction *insn ATTRIBUTE_UNUSED)
{ {
long imm = -1; long imm = -1;
if (! lex_imm (&imm)) if (! lex_imm (&imm, NULL))
goto fail; goto fail;
if (imm < 0x92 || imm > 0xFF || if (imm < 0x92 || imm > 0xFF ||
@ -1619,7 +1636,19 @@ imm_opr (const struct instruction *insn)
{ {
char *ilp = input_line_pointer; char *ilp = input_line_pointer;
long imm; 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; goto fail;
if (!lex_match (',')) if (!lex_match (','))
@ -1627,19 +1656,20 @@ imm_opr (const struct instruction *insn)
uint8_t buffer[4]; uint8_t buffer[4];
int n_bytes; int n_bytes;
expressionS exp; expressionS exp1;
if (!lex_opr (buffer, &n_bytes, &exp, false)) if (!lex_opr (buffer, &n_bytes, &exp1, false))
goto fail; goto fail;
int size = size_from_suffix (insn, 0);
char *f = s12z_new_insn (1 + n_bytes + size); char *f = s12z_new_insn (1 + n_bytes + size);
number_to_chars_bigendian (f++, insn->opc, 1); number_to_chars_bigendian (f++, insn->opc, 1);
emit_reloc (&exp0, f, size, size == 4 ? BFD_RELOC_32 : BFD_RELOC_S12Z_OPR);
int i; int i;
for (i = 0; i < size; ++i) for (i = 0; i < size; ++i)
number_to_chars_bigendian (f++, imm >> (CHAR_BIT * (size - i - 1)), 1); 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; return 1;
@ -1771,7 +1801,7 @@ lex_shift_reg_imm1 (const struct instruction *insn, short type, short dir)
goto fail; goto fail;
long imm = -1; long imm = -1;
if (!lex_imm (&imm)) if (!lex_imm (&imm, NULL))
goto fail; goto fail;
if (imm != 1 && imm != 2) if (imm != 1 && imm != 2)
@ -1847,7 +1877,7 @@ lex_shift_reg (const struct instruction *insn, short type, short dir)
return 1; return 1;
} }
else if (lex_imm (&imm)) else if (lex_imm (&imm, NULL))
{ {
if (imm < 0 || imm > 31) if (imm < 0 || imm > 31)
{ {
@ -1942,7 +1972,7 @@ shift_two_operand (const struct instruction *insn)
goto fail; goto fail;
long imm = -1; long imm = -1;
if (!lex_imm (&imm)) if (!lex_imm (&imm, NULL))
goto fail; goto fail;
if (imm != 1 && imm != 2) if (imm != 1 && imm != 2)
@ -1999,7 +2029,7 @@ shift_opr_imm (const struct instruction *insn)
expressionS exp2; expressionS exp2;
long imm; long imm;
bool immediate = false; bool immediate = false;
if (lex_imm (&imm)) if (lex_imm (&imm, NULL))
{ {
immediate = true; immediate = true;
} }
@ -2087,7 +2117,7 @@ bm_regd_imm (const struct instruction *insn)
goto fail; goto fail;
long imm; long imm;
if (!lex_imm (&imm)) if (!lex_imm (&imm, NULL))
goto fail; goto fail;
@ -2162,7 +2192,7 @@ bm_opr_imm (const struct instruction *insn)
long imm; long imm;
if (!lex_imm (&imm)) if (!lex_imm (&imm, NULL))
goto fail; goto fail;
int size = size_from_suffix (insn, 0); int size = size_from_suffix (insn, 0);
@ -2255,7 +2285,7 @@ bf_reg_opr_imm (const struct instruction *insn, short ie)
goto fail; goto fail;
long width; long width;
if (!lex_imm (&width)) if (!lex_imm (&width, NULL))
goto fail; goto fail;
if (width < 0 || width > 31) if (width < 0 || width > 31)
@ -2324,7 +2354,7 @@ bf_opr_reg_imm (const struct instruction *insn, short ie)
goto fail; goto fail;
long width; long width;
if (!lex_imm (&width)) if (!lex_imm (&width, NULL))
goto fail; goto fail;
if (width < 0 || width > 31) if (width < 0 || width > 31)
@ -2392,7 +2422,7 @@ bf_reg_reg_imm (const struct instruction *insn, short ie)
goto fail; goto fail;
long width; long width;
if (!lex_imm (&width)) if (!lex_imm (&width, NULL))
goto fail; goto fail;
if (width < 0 || width > 31) if (width < 0 || width > 31)
@ -2909,7 +2939,7 @@ test_br_opr_imm_rel (const struct instruction *insn)
goto fail; goto fail;
long imm; long imm;
if (!lex_imm (&imm)) if (!lex_imm (&imm, NULL))
goto fail; goto fail;
if (imm < 0 || imm > 31) if (imm < 0 || imm > 31)
@ -2962,7 +2992,7 @@ test_br_reg_imm_rel (const struct instruction *insn)
goto fail; goto fail;
long imm; long imm;
if (!lex_imm (&imm)) if (!lex_imm (&imm, NULL))
goto fail; goto fail;
if (imm < 0 || imm > 31) 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); bfd_putb16 ((bfd_vma) value, (unsigned char *) where);
break; break;
case BFD_RELOC_24: case BFD_RELOC_24:
case BFD_RELOC_S12Z_OPR:
bfd_putb24 ((bfd_vma) value, (unsigned char *) where); bfd_putb24 ((bfd_vma) value, (unsigned char *) where);
break; 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: case BFD_RELOC_32:
bfd_putb32 ((bfd_vma) value, (unsigned char *) where); bfd_putb32 ((bfd_vma) value, (unsigned char *) where);
break; 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 min-max
run_dump_test mod run_dump_test mod
run_dump_test mov run_dump_test mov
run_dump_test mov-imm-reloc
run_dump_test p2-mul run_dump_test p2-mul
run_dump_test mul-imm run_dump_test mul-imm
run_dump_test mul-opr-opr run_dump_test mul-opr-opr