/* tc-z80.c -- Assemble code for the Zilog Z80, Z180, EZ80 and ASCII R800
- Copyright (C) 2005-2020 Free Software Foundation, Inc.
+ Copyright (C) 2005-2023 Free Software Foundation, Inc.
Contributed by Arnold Metselaar <arnold_m@operamail.com>
This file is part of GAS, the GNU Assembler.
{"xdcb", INS_ROT_II_LD, 0, 0, "instructions like RL (IX+d),R (DD/FD CB dd oo)" }
};
+
+static int signed_overflow (signed long value, unsigned bitsize);
+static int unsigned_overflow (unsigned long value, unsigned bitsize);
+static int is_overflow (long value, unsigned bitsize);
+
static void
setup_march (const char *name, int *ok, int *err, int *mode)
{
}
void
-z80_md_end (void)
+z80_md_finish (void)
{
int mach_type;
return str_to_double (litP, sizeP);
break;
}
- return ieee_md_atof (type, litP, sizeP, FALSE);
+ return ieee_md_atof (type, litP, sizeP, false);
}
valueT
}
/* Check whether a symbol involves a register. */
-static bfd_boolean
+static bool
contains_register (symbolS *sym)
{
if (sym)
switch (ex->X_op)
{
case O_register:
- return TRUE;
+ return true;
case O_add:
case O_subtract:
if (ex->X_op_symbol && contains_register (ex->X_op_symbol))
- return TRUE;
+ return true;
/* Fall through. */
case O_uminus:
case O_symbol:
if (ex->X_add_symbol && contains_register (ex->X_add_symbol))
- return TRUE;
+ return true;
break;
default:
}
}
- return FALSE;
+ return false;
}
/* Parse general expression, not looking for indexed addressing. */
}
input_line_pointer = (char*) s ;
expression (op);
+ resolve_register (op);
switch (op->X_op)
{
case O_absent:
if (val->X_op == O_constant)
{
int i;
+
+ /* PR 28791:
+ Check for overflow, but ignore values that were generated by bit
+ manipulation operators (eg ~0xe6 and -7). This does mean that
+ manipluated overlarge values will not be reported (eg ~0x1234),
+ but it does help to maintain compatibility with earlier versions
+ of the assembler. */
+ if (! val->X_extrabit
+ && is_overflow (val->X_add_number, size*8))
+ as_warn ( _("%d-bit overflow (%+ld)"), size*8, val->X_add_number);
for (i = 0; i < size; ++i)
p[i] = (char)(val->X_add_number >> (i*8));
return;
if (size <= 2 && val->X_op_symbol)
{
- bfd_boolean simplify = TRUE;
+ bool simplify = true;
int shift = symbol_get_value_expression (val->X_op_symbol)->X_add_number;
if (val->X_op == O_bit_and && shift == (1 << (size*8))-1)
shift = 0;
case 8: r_type = BFD_RELOC_Z80_BYTE1; break;
case 16: r_type = BFD_RELOC_Z80_BYTE2; break;
case 24: r_type = BFD_RELOC_Z80_BYTE3; break;
- default: simplify = FALSE;
+ default: simplify = false;
}
}
else /* if (size == 2) */
{
case 0: r_type = BFD_RELOC_Z80_WORD0; break;
case 16: r_type = BFD_RELOC_Z80_WORD1; break;
- default: simplify = FALSE;
+ case 8:
+ case 24: /* add two byte fixups */
+ val->X_op = O_symbol;
+ val->X_op_symbol = NULL;
+ val->X_add_number = 0;
+ if (shift == 8)
+ {
+ fix_new_exp (frag_now, p++ - frag_now->fr_literal, 1, val, false,
+ BFD_RELOC_Z80_BYTE1);
+ /* prepare to next byte */
+ r_type = BFD_RELOC_Z80_BYTE2;
+ }
+ else
+ r_type = BFD_RELOC_Z80_BYTE3; /* high byte will be 0 */
+ size = 1;
+ simplify = false;
+ break;
+ default: simplify = false;
}
}
}
}
- fix_new_exp (frag_now, p - frag_now->fr_literal, size, val, FALSE, r_type);
+ fix_new_exp (frag_now, p - frag_now->fr_literal, size, val, false, r_type);
}
static void
{
/* For symbols only, constants are stored at begin of function. */
fix_new_exp (frag_now, p - frag_now->fr_literal, 1, val,
- (r_type == BFD_RELOC_8_PCREL) ? TRUE : FALSE, r_type);
+ r_type == BFD_RELOC_8_PCREL, r_type);
}
}
*q = 0x8A;
q = frag_more (2);
- fix_new_exp (frag_now, q - frag_now->fr_literal, 2, &arg, FALSE,
+ fix_new_exp (frag_now, q - frag_now->fr_literal, 2, &arg, false,
BFD_RELOC_Z80_16_BE);
return p;
*q = (ins_ok & INS_GBZ80) ? 0xFA : 0x3A;
emit_word (src);
}
+ else
+ ill_op ();
}
}
psect (arg);
}
+/* Handle the .bss pseudo-op. */
+
+static void
+s_bss (int ignore ATTRIBUTE_UNUSED)
+{
+ subseg_set (bss_section, 0);
+ demand_empty_rest_of_line ();
+}
+
/* Port specific pseudo ops. */
const pseudo_typeS md_pseudo_table[] =
{
{ ".hd64", set_inss, INS_Z180},
{ ".z80", set_inss, INS_Z80},
{ ".z80n", set_inss, INS_Z80N},
+ { "bss", s_bss, 0},
{ "db" , emit_data, 1},
{ "d24", z80_cons, 3},
{ "d32", z80_cons, 4},
input_line_pointer = old_ptr;
}
+static int
+signed_overflow (signed long value, unsigned bitsize)
+{
+ signed long max = (signed long) ((1UL << (bitsize - 1)) - 1);
+ return value < -max - 1 || value > max;
+}
+
+static int
+unsigned_overflow (unsigned long value, unsigned bitsize)
+{
+ return value >> (bitsize - 1) >> 1 != 0;
+}
+
static int
is_overflow (long value, unsigned bitsize)
{
- long fieldmask = (2UL << (bitsize - 1)) - 1;
- long signmask = ~fieldmask;
- long a = value & fieldmask;
- long ss = a & signmask;
- if (ss != 0 && ss != (signmask & fieldmask))
- return 1;
- return 0;
+ if (value < 0)
+ return signed_overflow (value, bitsize);
+ return unsigned_overflow ((unsigned long)value, bitsize);
}
void
{
case BFD_RELOC_8_PCREL:
case BFD_RELOC_Z80_DISP8:
- if (fixP->fx_done && (val < -0x80 || val > 0x7f))
+ if (fixP->fx_done && signed_overflow (val, 8))
as_bad_where (fixP->fx_file, fixP->fx_line,
_("8-bit signed offset out of range (%+ld)"), val);
*p_lit++ = val;
if (fixp->fx_subsy != NULL)
{
- as_bad_where (fixp->fx_file, fixp->fx_line, _("expression too complex"));
+ as_bad_subtract (fixp);
return NULL;
}
#define EXP_MIN -0x10000
#define EXP_MAX 0x10000
static int
-str_to_broken_float (bfd_boolean *signP, bfd_uint64_t *mantissaP, int *expP)
+str_to_broken_float (bool *signP, uint64_t *mantissaP, int *expP)
{
char *p;
- bfd_boolean sign;
- bfd_uint64_t mantissa = 0;
+ bool sign;
+ uint64_t mantissa = 0;
int exponent = 0;
int i;
static const char *
str_to_zeda32(char *litP, int *sizeP)
{
- bfd_uint64_t mantissa;
- bfd_boolean sign;
+ uint64_t mantissa;
+ bool sign;
int exponent;
unsigned i;
static const char *
str_to_float48(char *litP, int *sizeP)
{
- bfd_uint64_t mantissa;
- bfd_boolean sign;
+ uint64_t mantissa;
+ bool sign;
int exponent;
unsigned i;
static const char *
str_to_ieee754_h(char *litP, int *sizeP)
{
- return ieee_md_atof ('h', litP, sizeP, FALSE);
+ return ieee_md_atof ('h', litP, sizeP, false);
}
static const char *
str_to_ieee754_s(char *litP, int *sizeP)
{
- return ieee_md_atof ('s', litP, sizeP, FALSE);
+ return ieee_md_atof ('s', litP, sizeP, false);
}
static const char *
str_to_ieee754_d(char *litP, int *sizeP)
{
- return ieee_md_atof ('d', litP, sizeP, FALSE);
+ return ieee_md_atof ('d', litP, sizeP, false);
}
#ifdef TARGET_USE_CFIPOP