mirror of
https://github.com/espressif/binutils-gdb.git
synced 2025-06-28 15:18:37 +08:00
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:
@ -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.
|
||||||
|
@ -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;
|
||||||
|
20
gas/testsuite/gas/s12z/mov-imm-reloc.d
Normal file
20
gas/testsuite/gas/s12z/mov-imm-reloc.d
Normal 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
|
||||||
|
|
5
gas/testsuite/gas/s12z/mov-imm-reloc.s
Normal file
5
gas/testsuite/gas/s12z/mov-imm-reloc.s
Normal 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)
|
@ -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
|
||||||
|
Reference in New Issue
Block a user