* [PATCH 2/4] S12Z: GAS: Issue warning if TFR/EXG have identical source and destination.
2019-01-31 18:04 [PATCH 1/4] S12Z: GAS: Disallow immediate destination operands John Darrington
@ 2019-01-31 18:04 ` John Darrington
2019-02-01 10:51 ` Nick Clifton
2019-01-31 18:04 ` [PATCH 4/4] S12Z: GAS: Allow #_symbol operands as mov source John Darrington
` (2 subsequent siblings)
3 siblings, 1 reply; 9+ messages in thread
From: John Darrington @ 2019-01-31 18:04 UTC (permalink / raw)
To: binutils; +Cc: John Darrington
It is permissible for the source and destination operands of TFR and EXG to be
the same register. However it is a pointless instruction and anyone writing it
has probably made a mistake. This change emits a warning if such an instruction
is encountered.
gas/
* config/tc-s12z.c (tfr): Emit warning if operands are the same.
* testsuite/gas/s12z/exg.d: New test case.
* testsuite/gas/s12z/exg.l: New file.
---
gas/config/tc-s12z.c | 2 ++
gas/testsuite/gas/s12z/exg.d | 1 +
gas/testsuite/gas/s12z/exg.l | 2 ++
3 files changed, 5 insertions(+)
create mode 100644 gas/testsuite/gas/s12z/exg.l
diff --git a/gas/config/tc-s12z.c b/gas/config/tc-s12z.c
index 2bd536aca3..a0131490ba 100644
--- a/gas/config/tc-s12z.c
+++ b/gas/config/tc-s12z.c
@@ -1328,6 +1328,8 @@ tfr (const struct instruction *insn)
&& (registers[reg2].bytes <= registers[reg1].bytes))
as_warn (_("Source register for %s is no larger than the destination register"),
insn->name);
+ else if (reg1 == reg2)
+ as_warn (_("The destination and source registers are identical"));
char *f = s12z_new_insn (1 + insn->page);
if (insn->page == 2)
diff --git a/gas/testsuite/gas/s12z/exg.d b/gas/testsuite/gas/s12z/exg.d
index 54cf268620..e9af154e82 100644
--- a/gas/testsuite/gas/s12z/exg.d
+++ b/gas/testsuite/gas/s12z/exg.d
@@ -1,6 +1,7 @@
#objdump: -d
#name:
#source: exg.s
+#warning_output: exg.l
.*: file format elf32-s12z
diff --git a/gas/testsuite/gas/s12z/exg.l b/gas/testsuite/gas/s12z/exg.l
new file mode 100644
index 0000000000..018d8f90df
--- /dev/null
+++ b/gas/testsuite/gas/s12z/exg.l
@@ -0,0 +1,2 @@
+.*: Assembler messages:
+.*:2: Warning: The destination and source registers are identical
--
2.11.0
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 1/4] S12Z: GAS: Disallow immediate destination operands
@ 2019-01-31 18:04 John Darrington
2019-01-31 18:04 ` [PATCH 2/4] S12Z: GAS: Issue warning if TFR/EXG have identical source and destination John Darrington
` (3 more replies)
0 siblings, 4 replies; 9+ messages in thread
From: John Darrington @ 2019-01-31 18:04 UTC (permalink / raw)
To: binutils; +Cc: John Darrington
The assembler permitted instructions which attempted to assign to an immediate
operand. Bizarrely there is a valid machine code for such operations (although
the documentation says it's "inappropriate"). This change causes such attempts
to fail with an error message.
gas/
* config/tc-s12z.c (lex_opr): Add a parameter to indicate whether
immediate mode operands should be permitted.
* testsuite/s12z/imm-dest.d: New file.
* testsuite/s12z/imm-dest.l: New file.
* testsuite/s12z/imm-dest.s: New file.
* testsuite/s12z/s12z.exp: Add them.
---
gas/config/tc-s12z.c | 94 ++++++++++++++++++++++++---------------
gas/testsuite/gas/s12z/imm-dest.d | 4 ++
gas/testsuite/gas/s12z/imm-dest.l | 25 +++++++++++
gas/testsuite/gas/s12z/imm-dest.s | 9 ++++
gas/testsuite/gas/s12z/s12z.exp | 2 +
5 files changed, 98 insertions(+), 36 deletions(-)
create mode 100644 gas/testsuite/gas/s12z/imm-dest.d
create mode 100644 gas/testsuite/gas/s12z/imm-dest.l
create mode 100644 gas/testsuite/gas/s12z/imm-dest.s
diff --git a/gas/config/tc-s12z.c b/gas/config/tc-s12z.c
index e62f3833f1..2bd536aca3 100644
--- a/gas/config/tc-s12z.c
+++ b/gas/config/tc-s12z.c
@@ -348,7 +348,8 @@ lex_force_match (char x)
}
static int
-lex_opr (uint8_t *buffer, int *n_bytes, expressionS *exp)
+lex_opr (uint8_t *buffer, int *n_bytes, expressionS *exp,
+ bool immediate_ok)
{
char *ilp = input_line_pointer;
uint8_t *xb = buffer;
@@ -359,6 +360,11 @@ lex_opr (uint8_t *buffer, int *n_bytes, expressionS *exp)
*xb = 0;
if (lex_imm_e4 (&imm))
{
+ if (!immediate_ok)
+ {
+ as_bad (_("An immediate value in a source operand is inappropriate"));
+ return 0;
+ }
if (imm > 0)
*xb = imm;
else
@@ -766,7 +772,7 @@ opr (const struct instruction *insn)
uint8_t buffer[4];
int n_bytes;
expressionS exp;
- if (lex_opr (buffer, &n_bytes, &exp))
+ if (lex_opr (buffer, &n_bytes, &exp, false))
{
/* Large constant direct values are more efficiently encoded as ext24 mode.
Otherwise a decision has to be deferred to a relax. */
@@ -1094,7 +1100,7 @@ mul_reg_reg_opr (const struct instruction *insn)
uint8_t buffer[4];
int n_bytes;
expressionS exp;
- if (!lex_opr (buffer, &n_bytes, &exp))
+ if (!lex_opr (buffer, &n_bytes, &exp, true))
goto fail;
int size = size_from_suffix (insn, 0);
@@ -1149,7 +1155,7 @@ mul_reg_opr_opr (const struct instruction *insn)
uint8_t buffer1[4];
int n_bytes1;
expressionS exp1;
- if (!lex_opr (buffer1, &n_bytes1, &exp1))
+ if (!lex_opr (buffer1, &n_bytes1, &exp1, false))
goto fail;
if (!lex_match (','))
@@ -1158,7 +1164,7 @@ mul_reg_opr_opr (const struct instruction *insn)
uint8_t buffer2[4];
int n_bytes2;
expressionS exp2;
- if (!lex_opr (buffer2, &n_bytes2, &exp2))
+ if (!lex_opr (buffer2, &n_bytes2, &exp2, false))
goto fail;
int size1 = size_from_suffix (insn, 0);
@@ -1519,7 +1525,8 @@ regd6_regy_regx (const struct instruction *insn)
}
static int
-reg_opr (const struct instruction *insn, int allowed_regs)
+reg_opr (const struct instruction *insn, int allowed_regs,
+ bool immediate_ok)
{
char *ilp = input_line_pointer;
int reg;
@@ -1531,7 +1538,7 @@ reg_opr (const struct instruction *insn, int allowed_regs)
uint8_t buffer[4];
int n_bytes;
expressionS exp;
- if (lex_opr (buffer, &n_bytes, &exp))
+ if (lex_opr (buffer, &n_bytes, &exp, immediate_ok))
{
/* Large constant direct values are more efficiently encoded as ext24 mode.
Otherwise a decision has to be deferred to a relax. */
@@ -1572,22 +1579,37 @@ reg_opr (const struct instruction *insn, int allowed_regs)
static int
-regdxy_opr (const struct instruction *insn)
+regdxy_opr_dest (const struct instruction *insn)
{
- return reg_opr (insn, REG_BIT_Dn | REG_BIT_XY);
+ return reg_opr (insn, REG_BIT_Dn | REG_BIT_XY, false);
}
static int
+regdxy_opr_src (const struct instruction *insn)
+{
+ return reg_opr (insn, REG_BIT_Dn | REG_BIT_XY, true);
+}
+
+
+static int
regd_opr (const struct instruction *insn)
{
- return reg_opr (insn, REG_BIT_Dn);
+ return reg_opr (insn, REG_BIT_Dn, true);
}
+/* OP0: S; OP1: destination OPR */
+static int
+regs_opr_dest (const struct instruction *insn)
+{
+ return reg_opr (insn, 0x1U << REG_S, false);
+}
+
+/* OP0: S; OP1: source OPR */
static int
-regs_opr (const struct instruction *insn)
+regs_opr_src (const struct instruction *insn)
{
- return reg_opr (insn, 0x1U << REG_S);
+ return reg_opr (insn, 0x1U << REG_S, true);
}
static int
@@ -1604,7 +1626,7 @@ imm_opr (const struct instruction *insn)
uint8_t buffer[4];
int n_bytes;
expressionS exp;
- if (!lex_opr (buffer, &n_bytes, &exp))
+ if (!lex_opr (buffer, &n_bytes, &exp, false))
goto fail;
int size = size_from_suffix (insn, 0);
@@ -1633,7 +1655,7 @@ opr_opr (const struct instruction *insn)
uint8_t buffer1[4];
int n_bytes1;
expressionS exp1;
- if (!lex_opr (buffer1, &n_bytes1, &exp1))
+ if (!lex_opr (buffer1, &n_bytes1, &exp1, false))
goto fail;
@@ -1643,7 +1665,7 @@ opr_opr (const struct instruction *insn)
uint8_t buffer2[4];
int n_bytes2;
expressionS exp2;
- if (!lex_opr (buffer2, &n_bytes2, &exp2))
+ if (!lex_opr (buffer2, &n_bytes2, &exp2, false))
goto fail;
char *f = s12z_new_insn (1 + n_bytes1 + n_bytes2);
@@ -1673,7 +1695,7 @@ reg67sxy_opr (const struct instruction *insn)
uint8_t buffer[4];
int n_bytes;
expressionS exp;
- if (!lex_opr (buffer, &n_bytes, &exp))
+ if (!lex_opr (buffer, &n_bytes, &exp, false))
return 0;
char *f = s12z_new_insn (1 + n_bytes);
@@ -1689,7 +1711,7 @@ rotate (const struct instruction *insn, short dir)
uint8_t buffer[4];
int n_bytes;
expressionS exp;
- if (lex_opr (buffer, &n_bytes, &exp))
+ if (lex_opr (buffer, &n_bytes, &exp, false))
{
char *f = s12z_new_insn (n_bytes + 2);
number_to_chars_bigendian (f++, insn->opc, 1);
@@ -1760,7 +1782,7 @@ lex_shift_reg_imm1 (const struct instruction *insn, short type, short dir)
int n_bytes;
expressionS exp;
- if (!lex_opr (buffer, &n_bytes, &exp))
+ if (!lex_opr (buffer, &n_bytes, &exp, false))
goto fail;
gas_assert (n_bytes == 1);
@@ -1911,7 +1933,7 @@ shift_two_operand (const struct instruction *insn)
uint8_t buffer[4];
int n_opr_bytes;
expressionS exp;
- if (!lex_opr (buffer, &n_opr_bytes, &exp))
+ if (!lex_opr (buffer, &n_opr_bytes, &exp, false))
goto fail;
if (!lex_match (','))
@@ -1963,7 +1985,7 @@ shift_opr_imm (const struct instruction *insn)
int n_opr_bytes1;
expressionS exp1;
- if (!lex_opr (buffer1, &n_opr_bytes1, &exp1))
+ if (!lex_opr (buffer1, &n_opr_bytes1, &exp1, false))
goto fail;
n_bytes += n_opr_bytes1;
@@ -1979,7 +2001,7 @@ shift_opr_imm (const struct instruction *insn)
{
immediate = true;
}
- else if (!lex_opr (buffer2, &n_opr_bytes2, &exp2))
+ else if (!lex_opr (buffer2, &n_opr_bytes2, &exp2, false))
goto fail;
uint8_t sb = 0x20;
@@ -2091,7 +2113,7 @@ bm_opr_reg (const struct instruction *insn)
int n_opr_bytes;
expressionS exp;
- if (!lex_opr (buffer, &n_opr_bytes, &exp))
+ if (!lex_opr (buffer, &n_opr_bytes, &exp, false))
goto fail;
if (!lex_match (','))
@@ -2130,7 +2152,7 @@ bm_opr_imm (const struct instruction *insn)
int n_opr_bytes;
expressionS exp;
- if (!lex_opr (buffer, &n_opr_bytes, &exp))
+ if (!lex_opr (buffer, &n_opr_bytes, &exp, false))
goto fail;
if (!lex_match (','))
@@ -2224,7 +2246,7 @@ bf_reg_opr_imm (const struct instruction *insn, short ie)
int n_bytes;
expressionS exp;
- if (!lex_opr (buffer, &n_bytes, &exp))
+ if (!lex_opr (buffer, &n_bytes, &exp, false))
goto fail;
if (!lex_match (','))
@@ -2286,7 +2308,7 @@ bf_opr_reg_imm (const struct instruction *insn, short ie)
uint8_t buffer[4];
int n_bytes;
expressionS exp;
- if (!lex_opr (buffer, &n_bytes, &exp))
+ if (!lex_opr (buffer, &n_bytes, &exp, false))
goto fail;
if (!lex_match (','))
@@ -2463,7 +2485,7 @@ bf_opr_reg_reg (const struct instruction *insn, short ie)
uint8_t buffer[4];
int n_bytes;
expressionS exp;
- if (!lex_opr (buffer, &n_bytes, &exp))
+ if (!lex_opr (buffer, &n_bytes, &exp, false))
goto fail;
if (!lex_match (','))
@@ -2523,7 +2545,7 @@ bf_reg_opr_reg (const struct instruction *insn, short ie)
uint8_t buffer[4];
int n_bytes;
expressionS exp;
- if (!lex_opr (buffer, &n_bytes, &exp))
+ if (!lex_opr (buffer, &n_bytes, &exp, false))
goto fail;
if (!lex_match (','))
@@ -2714,7 +2736,7 @@ tb_opr_rel (const struct instruction *insn)
uint8_t buffer[4];
int n_bytes;
expressionS exp;
- if (!lex_opr (buffer, &n_bytes, &exp))
+ if (!lex_opr (buffer, &n_bytes, &exp, false))
goto fail;
if (!lex_match (','))
@@ -2829,7 +2851,7 @@ test_br_opr_reg_rel (const struct instruction *insn)
uint8_t buffer[4];
int n_bytes;
expressionS exp;
- if (!lex_opr (buffer, &n_bytes, &exp))
+ if (!lex_opr (buffer, &n_bytes, &exp, false))
goto fail;
if (!lex_match (','))
@@ -2878,7 +2900,7 @@ test_br_opr_imm_rel (const struct instruction *insn)
uint8_t buffer[4];
int n_bytes;
expressionS exp;
- if (!lex_opr (buffer, &n_bytes, &exp))
+ if (!lex_opr (buffer, &n_bytes, &exp, false))
goto fail;
if (!lex_match (','))
@@ -3238,7 +3260,7 @@ static const struct instruction opcodes[] = {
{"tfr", 1, 0x9e, tfr, 0},
{"zex", 1, 0x9e, tfr, 0},
- {"ld", 1, 0xa0, regdxy_opr, 0xb0},
+ {"ld", 1, 0xa0, regdxy_opr_src, 0xb0},
{"jmp", 1, 0xaa, opr, 0xba},
{"jsr", 1, 0xab, opr, 0xbb},
@@ -3246,7 +3268,7 @@ static const struct instruction opcodes[] = {
{"exg", 1, 0xae, tfr, 0},
{"sex", 1, 0xae, tfr, 0},
- {"st", 1, 0xc0, regdxy_opr, 0xd0},
+ {"st", 1, 0xc0, regdxy_opr_dest, 0xd0},
{"andcc", 1, 0xce, imm8, 0},
{"orcc", 1, 0xde, imm8, 0},
@@ -3305,7 +3327,7 @@ static const struct instruction opcodes[] = {
{"btgl.l", 1, 0xee, bm_opr_reg, 0},
{"cmp", 1, 0xe0, regdxy_imm, 0},
- {"cmp", 1, 0xf0, regdxy_opr, 0},
+ {"cmp", 1, 0xf0, regdxy_opr_src, 0},
{"cmp", 1, 0xfc, regx_regy, 0},
{"sub", 1, 0xfd, regd6_regx_regy, 0},
@@ -3316,13 +3338,13 @@ static const struct instruction opcodes[] = {
/* Page 2 */
/* The -10 below is a kludge. The opcode is in fact 0x00 */
- {"ld", 2, -10, regs_opr, 0},
+ {"ld", 2, -10, regs_opr_src, 0},
/* The -9 below is a kludge. The opcode is in fact 0x01 */
- {"st", 2, -9, regs_opr, 0},
+ {"st", 2, -9, regs_opr_dest, 0},
/* The -8 below is a kludge. The opcode is in fact 0x02 */
- {"cmp", 2, -8, regs_opr, 0},
+ {"cmp", 2, -8, regs_opr_src, 0},
/* The -7 below is a kludge. The opcode is in fact 0x03 */
{"ld", 2, -7, regs_imm, 0},
diff --git a/gas/testsuite/gas/s12z/imm-dest.d b/gas/testsuite/gas/s12z/imm-dest.d
new file mode 100644
index 0000000000..37c4ed79e9
--- /dev/null
+++ b/gas/testsuite/gas/s12z/imm-dest.d
@@ -0,0 +1,4 @@
+# Check that opr destinations which are short immediates fail with an error
+#name: invalid immediate destination operands
+#source: imm-dest.s
+#error_output: imm-dest.l
diff --git a/gas/testsuite/gas/s12z/imm-dest.l b/gas/testsuite/gas/s12z/imm-dest.l
new file mode 100644
index 0000000000..14d614d93e
--- /dev/null
+++ b/gas/testsuite/gas/s12z/imm-dest.l
@@ -0,0 +1,25 @@
+.*: Assembler messages:
+.*:2: Error: An immediate value in a source operand is inappropriate
+.*:2: Error: Invalid instruction: "st d0,#2"
+.*:2: Error: First invalid token: "d0,#2"
+.*:3: Error: An immediate value in a source operand is inappropriate
+.*:3: Error: Invalid instruction: "st s,#4"
+.*:3: Error: First invalid token: ""
+.*:4: Error: An immediate value in a source operand is inappropriate
+.*:4: Error: Invalid instruction: "mov.b d0,#4"
+.*:4: Error: First invalid token: ""
+.*:5: Error: An immediate value in a source operand is inappropriate
+.*:5: Error: Invalid instruction: "inc.b #1"
+.*:5: Error: First invalid token: "\(null\)"
+.*:6: Error: An immediate value in a source operand is inappropriate
+.*:6: Error: Invalid instruction: "dec.b #12"
+.*:6: Error: First invalid token: "\(null\)"
+.*:7: Error: An immediate value in a source operand is inappropriate
+.*:7: Error: Invalid instruction: "com.w #1"
+.*:7: Error: First invalid token: "\(null\)"
+.*:8: Error: An immediate value in a source operand is inappropriate
+.*:8: Error: Invalid instruction: "neg.l #-1"
+.*:8: Error: First invalid token: "\(null\)"
+.*:9: Error: An immediate value in a source operand is inappropriate
+.*:9: Error: Invalid instruction: "ror.b #3"
+.*:9: Error: First invalid token: "\(null\)"
diff --git a/gas/testsuite/gas/s12z/imm-dest.s b/gas/testsuite/gas/s12z/imm-dest.s
new file mode 100644
index 0000000000..136326816a
--- /dev/null
+++ b/gas/testsuite/gas/s12z/imm-dest.s
@@ -0,0 +1,9 @@
+;;; All these are invalid instructions and should provoke an error
+ st d0, #2
+ st s, #4
+ mov.b d0, #4
+ inc.b #1
+ dec.b #12
+ com.w #1
+ neg.l #-1
+ ror.b #3
diff --git a/gas/testsuite/gas/s12z/s12z.exp b/gas/testsuite/gas/s12z/s12z.exp
index 76d0931593..a6546d76ac 100644
--- a/gas/testsuite/gas/s12z/s12z.exp
+++ b/gas/testsuite/gas/s12z/s12z.exp
@@ -132,3 +132,5 @@ run_dump_test ld-large-direct
run_dump_test ld-small-direct
run_dump_test st-large-direct
run_dump_test st-small-direct
+
+run_dump_test imm-dest
--
2.11.0
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 4/4] S12Z: GAS: Allow #_symbol operands as mov source
2019-01-31 18:04 [PATCH 1/4] S12Z: GAS: Disallow immediate destination operands John Darrington
2019-01-31 18:04 ` [PATCH 2/4] S12Z: GAS: Issue warning if TFR/EXG have identical source and destination John Darrington
@ 2019-01-31 18:04 ` John Darrington
2019-02-01 10:54 ` Nick Clifton
2019-01-31 18:04 ` [PATCH 3/4] S12Z: GAS: Fix incorrect range test for 16-bit PC relative offsets John Darrington
2019-02-01 10:49 ` [PATCH 1/4] S12Z: GAS: Disallow immediate destination operands Nick Clifton
3 siblings, 1 reply; 9+ messages in thread
From: John Darrington @ 2019-01-31 18:04 UTC (permalink / raw)
To: binutils; +Cc: John Darrington
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.
---
gas/config/tc-s12z.c | 114 +++++++++++++++++++++++----------
gas/testsuite/gas/s12z/mov-imm-reloc.d | 20 ++++++
gas/testsuite/gas/s12z/mov-imm-reloc.s | 5 ++
gas/testsuite/gas/s12z/s12z.exp | 1 +
4 files changed, 105 insertions(+), 35 deletions(-)
create mode 100644 gas/testsuite/gas/s12z/mov-imm-reloc.d
create mode 100644 gas/testsuite/gas/s12z/mov-imm-reloc.s
diff --git a/gas/config/tc-s12z.c b/gas/config/tc-s12z.c
index 8b56b685b8..bc1bb5c382 100644
--- a/gas/config/tc-s12z.c
+++ b/gas/config/tc-s12z.c
@@ -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;
}
-/* Emit the code for an OPR address mode operand */
-static char *
-emit_opr (char *f, const uint8_t *buffer, int n_bytes, expressionS *exp)
+
+static void
+emit_reloc (expressionS *exp, char *f, int size, enum bfd_reloc_code_real reloc)
{
- 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,
+ size,
exp,
FALSE,
- BFD_RELOC_S12Z_OPR);
+ 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. */
+ 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);
+
+ 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;
diff --git a/gas/testsuite/gas/s12z/mov-imm-reloc.d b/gas/testsuite/gas/s12z/mov-imm-reloc.d
new file mode 100644
index 0000000000..76048ec96b
--- /dev/null
+++ b/gas/testsuite/gas/s12z/mov-imm-reloc.d
@@ -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
+
diff --git a/gas/testsuite/gas/s12z/mov-imm-reloc.s b/gas/testsuite/gas/s12z/mov-imm-reloc.s
new file mode 100644
index 0000000000..ec9f7affd0
--- /dev/null
+++ b/gas/testsuite/gas/s12z/mov-imm-reloc.s
@@ -0,0 +1,5 @@
+ .extern xxx
+
+ mov.p #xxx+3, (0,s)
+ mov.w #xxx+2, (0,s)
+ mov.l #xxx+1, (0,s)
diff --git a/gas/testsuite/gas/s12z/s12z.exp b/gas/testsuite/gas/s12z/s12z.exp
index d9746d3d91..612fda765b 100644
--- a/gas/testsuite/gas/s12z/s12z.exp
+++ b/gas/testsuite/gas/s12z/s12z.exp
@@ -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
--
2.11.0
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 3/4] S12Z: GAS: Fix incorrect range test for 16-bit PC relative offsets.
2019-01-31 18:04 [PATCH 1/4] S12Z: GAS: Disallow immediate destination operands John Darrington
2019-01-31 18:04 ` [PATCH 2/4] S12Z: GAS: Issue warning if TFR/EXG have identical source and destination John Darrington
2019-01-31 18:04 ` [PATCH 4/4] S12Z: GAS: Allow #_symbol operands as mov source John Darrington
@ 2019-01-31 18:04 ` John Darrington
2019-02-01 10:51 ` Nick Clifton
2019-02-01 10:49 ` [PATCH 1/4] S12Z: GAS: Disallow immediate destination operands Nick Clifton
3 siblings, 1 reply; 9+ messages in thread
From: John Darrington @ 2019-01-31 18:04 UTC (permalink / raw)
To: binutils; +Cc: John Darrington
The limits for PC relative offsets were incorrect. This change fixes
them and adds some tests.
gas/
* config/tc-s12z.c (md_apply_fix): Fix incorrect limits.
* testsuite/gas/s12z/pc-rel-bad.d: New file.
* testsuite/gas/s12z/pc-rel-bad.l: New file.
* testsuite/gas/s12z/pc-rel-bad.s: New file.
* testsuite/gas/s12z/pc-rel-good.d: New file.
* testsuite/gas/s12z/pc-rel-good.s: New file.
* testsuite/gas/s12z/s12z.exp: Add them.
---
gas/config/tc-s12z.c | 2 +-
gas/testsuite/gas/s12z/pc-rel-bad.d | 9 +++++++++
gas/testsuite/gas/s12z/pc-rel-bad.l | 3 +++
gas/testsuite/gas/s12z/pc-rel-bad.s | 8 ++++++++
gas/testsuite/gas/s12z/pc-rel-good.d | 24 ++++++++++++++++++++++++
gas/testsuite/gas/s12z/pc-rel-good.s | 6 ++++++
gas/testsuite/gas/s12z/s12z.exp | 2 ++
7 files changed, 53 insertions(+), 1 deletion(-)
create mode 100644 gas/testsuite/gas/s12z/pc-rel-bad.d
create mode 100644 gas/testsuite/gas/s12z/pc-rel-bad.l
create mode 100644 gas/testsuite/gas/s12z/pc-rel-bad.s
create mode 100644 gas/testsuite/gas/s12z/pc-rel-good.d
create mode 100644 gas/testsuite/gas/s12z/pc-rel-good.s
diff --git a/gas/config/tc-s12z.c b/gas/config/tc-s12z.c
index a0131490ba..8b56b685b8 100644
--- a/gas/config/tc-s12z.c
+++ b/gas/config/tc-s12z.c
@@ -3853,7 +3853,7 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
bfd_putb32 ((bfd_vma) value, (unsigned char *) where);
break;
case BFD_RELOC_16_PCREL:
- if (value < -0x8000 || value > 0x7FFF)
+ if (value < -0x4000 || value > 0x3FFF)
as_bad_where (fixP->fx_file, fixP->fx_line,
_("Value out of 16-bit range."));
diff --git a/gas/testsuite/gas/s12z/pc-rel-bad.d b/gas/testsuite/gas/s12z/pc-rel-bad.d
new file mode 100644
index 0000000000..ae01a7fa63
--- /dev/null
+++ b/gas/testsuite/gas/s12z/pc-rel-bad.d
@@ -0,0 +1,9 @@
+#objdump: -d -r -t
+#name: PC relative branches which are out of range.
+#source: pc-rel-bad.s
+#error_output: pc-rel-bad.l
+
+.*: file format elf32-s12z
+
+
+Disassembly of section .text:
diff --git a/gas/testsuite/gas/s12z/pc-rel-bad.l b/gas/testsuite/gas/s12z/pc-rel-bad.l
new file mode 100644
index 0000000000..e3d63c3c09
--- /dev/null
+++ b/gas/testsuite/gas/s12z/pc-rel-bad.l
@@ -0,0 +1,3 @@
+.*: Assembler messages:
+.*:4: Error: Value out of 16-bit range.
+.*:8: Error: Value out of 16-bit range.
diff --git a/gas/testsuite/gas/s12z/pc-rel-bad.s b/gas/testsuite/gas/s12z/pc-rel-bad.s
new file mode 100644
index 0000000000..a79b4d6244
--- /dev/null
+++ b/gas/testsuite/gas/s12z/pc-rel-bad.s
@@ -0,0 +1,8 @@
+
+;;; Both the BNE instructions should fail
+;;; because the destination is out of range.
+ bne .label
+ .fill 0x3FFD, 1, 0 ; 0x3FFF minus 3 (the length of the BNE insn)
+.label:
+ .fill 0x4001, 1, 0
+ bne .label
diff --git a/gas/testsuite/gas/s12z/pc-rel-good.d b/gas/testsuite/gas/s12z/pc-rel-good.d
new file mode 100644
index 0000000000..acc7e6301c
--- /dev/null
+++ b/gas/testsuite/gas/s12z/pc-rel-good.d
@@ -0,0 +1,24 @@
+#objdump: -d -r -t
+#name: PC relative branches (close to the limit)
+#source: pc-rel-good.s
+
+
+.*: file format elf32-s12z
+
+SYMBOL TABLE:
+00000000 l d .text 00000000 .text
+00000000 l d .data 00000000 .data
+00000000 l d .bss 00000000 .bss
+00003fff l .text 00000000 .label
+
+
+
+Disassembly of section .text:
+
+00000000 <.label-0x3fff>:
+ 0: 26 bf ff bne .label
+ ...
+
+00003fff <.label>:
+ ...
+ 7fff: 26 c0 00 bne .label
diff --git a/gas/testsuite/gas/s12z/pc-rel-good.s b/gas/testsuite/gas/s12z/pc-rel-good.s
new file mode 100644
index 0000000000..f64d1975da
--- /dev/null
+++ b/gas/testsuite/gas/s12z/pc-rel-good.s
@@ -0,0 +1,6 @@
+
+ bne .label
+ .fill 0x3FFC, 1, 0
+.label:
+ .fill 0x4000, 1, 0
+ bne .label
diff --git a/gas/testsuite/gas/s12z/s12z.exp b/gas/testsuite/gas/s12z/s12z.exp
index a6546d76ac..d9746d3d91 100644
--- a/gas/testsuite/gas/s12z/s12z.exp
+++ b/gas/testsuite/gas/s12z/s12z.exp
@@ -90,6 +90,8 @@ run_dump_test opr-idx3-reg
run_dump_test opr-idx3-xysp-24
run_dump_test or-imm
run_dump_test or-opr
+run_dump_test pc-rel-bad
+run_dump_test pc-rel-good
run_dump_test page2-inh
run_dump_test psh-pul
run_dump_test qmul
--
2.11.0
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 1/4] S12Z: GAS: Disallow immediate destination operands
2019-01-31 18:04 [PATCH 1/4] S12Z: GAS: Disallow immediate destination operands John Darrington
` (2 preceding siblings ...)
2019-01-31 18:04 ` [PATCH 3/4] S12Z: GAS: Fix incorrect range test for 16-bit PC relative offsets John Darrington
@ 2019-02-01 10:49 ` Nick Clifton
2019-02-01 12:51 ` John Darrington
3 siblings, 1 reply; 9+ messages in thread
From: Nick Clifton @ 2019-02-01 10:49 UTC (permalink / raw)
To: John Darrington, binutils
Hi John,
> gas/
>
> * config/tc-s12z.c (lex_opr): Add a parameter to indicate whether
> immediate mode operands should be permitted.
> * testsuite/s12z/imm-dest.d: New file.
> * testsuite/s12z/imm-dest.l: New file.
> * testsuite/s12z/imm-dest.s: New file.
> * testsuite/s12z/s12z.exp: Add them.
Approved - please apply - but I do have one question:
> static int
> -lex_opr (uint8_t *buffer, int *n_bytes, expressionS *exp)
> +lex_opr (uint8_t *buffer, int *n_bytes, expressionS *exp,
> + bool immediate_ok)
> {
Why does this function return an int instead of a bfd_boolean ?
> static int
> -reg_opr (const struct instruction *insn, int allowed_regs)
> +reg_opr (const struct instruction *insn, int allowed_regs,
> + bool immediate_ok)
> {
In fact ... it seems that there are a whole bunch of functions
in tc-s12z.c that ought to be returning booleans. Just an idea
for a clean-up patch...
Cheers
Nick
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 2/4] S12Z: GAS: Issue warning if TFR/EXG have identical source and destination.
2019-01-31 18:04 ` [PATCH 2/4] S12Z: GAS: Issue warning if TFR/EXG have identical source and destination John Darrington
@ 2019-02-01 10:51 ` Nick Clifton
0 siblings, 0 replies; 9+ messages in thread
From: Nick Clifton @ 2019-02-01 10:51 UTC (permalink / raw)
To: John Darrington, binutils
Hi John,
> It is permissible for the source and destination operands of TFR and EXG to be
> the same register. However it is a pointless instruction and anyone writing it
> has probably made a mistake.
I don't suppose that the ISA designers intended that this sort of instruction be
treated as a NOP, with the idea that in future ISA extensions they might be given
new semantics ?
> gas/
> * config/tc-s12z.c (tfr): Emit warning if operands are the same.
> * testsuite/gas/s12z/exg.d: New test case.
> * testsuite/gas/s12z/exg.l: New file.
Approved - please apply.
Cheers
Nick
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 3/4] S12Z: GAS: Fix incorrect range test for 16-bit PC relative offsets.
2019-01-31 18:04 ` [PATCH 3/4] S12Z: GAS: Fix incorrect range test for 16-bit PC relative offsets John Darrington
@ 2019-02-01 10:51 ` Nick Clifton
0 siblings, 0 replies; 9+ messages in thread
From: Nick Clifton @ 2019-02-01 10:51 UTC (permalink / raw)
To: John Darrington, binutils
Hi John,
> gas/
> * config/tc-s12z.c (md_apply_fix): Fix incorrect limits.
> * testsuite/gas/s12z/pc-rel-bad.d: New file.
> * testsuite/gas/s12z/pc-rel-bad.l: New file.
> * testsuite/gas/s12z/pc-rel-bad.s: New file.
> * testsuite/gas/s12z/pc-rel-good.d: New file.
> * testsuite/gas/s12z/pc-rel-good.s: New file.
> * testsuite/gas/s12z/s12z.exp: Add them.
Approved - please apply.
Cheers
Nick
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 4/4] S12Z: GAS: Allow #_symbol operands as mov source
2019-01-31 18:04 ` [PATCH 4/4] S12Z: GAS: Allow #_symbol operands as mov source John Darrington
@ 2019-02-01 10:54 ` Nick Clifton
0 siblings, 0 replies; 9+ messages in thread
From: Nick Clifton @ 2019-02-01 10:54 UTC (permalink / raw)
To: John Darrington, binutils
Hi John,
> 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.
Approved - please apply.
Cheers
Nick
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 1/4] S12Z: GAS: Disallow immediate destination operands
2019-02-01 10:49 ` [PATCH 1/4] S12Z: GAS: Disallow immediate destination operands Nick Clifton
@ 2019-02-01 12:51 ` John Darrington
0 siblings, 0 replies; 9+ messages in thread
From: John Darrington @ 2019-02-01 12:51 UTC (permalink / raw)
To: Nick Clifton; +Cc: John Darrington, binutils
On Fri, Feb 01, 2019 at 10:48:57AM +0000, Nick Clifton wrote:
Why does this function return an int instead of a bfd_boolean ?
> static int
> -reg_opr (const struct instruction *insn, int allowed_regs)
> +reg_opr (const struct instruction *insn, int allowed_regs,
> + bool immediate_ok)
> {
In fact ... it seems that there are a whole bunch of functions
in tc-s12z.c that ought to be returning booleans. Just an idea
for a clean-up patch...
You're right. I'll prepare such a patch in the next few days.
J'
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2019-02-01 12:51 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-01-31 18:04 [PATCH 1/4] S12Z: GAS: Disallow immediate destination operands John Darrington
2019-01-31 18:04 ` [PATCH 2/4] S12Z: GAS: Issue warning if TFR/EXG have identical source and destination John Darrington
2019-02-01 10:51 ` Nick Clifton
2019-01-31 18:04 ` [PATCH 4/4] S12Z: GAS: Allow #_symbol operands as mov source John Darrington
2019-02-01 10:54 ` Nick Clifton
2019-01-31 18:04 ` [PATCH 3/4] S12Z: GAS: Fix incorrect range test for 16-bit PC relative offsets John Darrington
2019-02-01 10:51 ` Nick Clifton
2019-02-01 10:49 ` [PATCH 1/4] S12Z: GAS: Disallow immediate destination operands Nick Clifton
2019-02-01 12:51 ` John Darrington
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).