From c6f14c0d2ca4d68308f967c446277789047a980a Mon Sep 17 00:00:00 2001 From: John Darrington Date: Fri, 1 Feb 2019 17:42:54 +0100 Subject: [PATCH] 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. --- gas/ChangeLog | 10 +++ 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 + 5 files changed, 115 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/ChangeLog b/gas/ChangeLog index a02430d..0259667 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,5 +1,15 @@ 2019-01-31 John Darrington + * 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 + * 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. diff --git a/gas/config/tc-s12z.c b/gas/config/tc-s12z.c index 8b56b68..bc1bb5c 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 0000000..76048ec --- /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 0000000..ec9f7af --- /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 d9746d3..612fda7 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.7.4