diff options
Diffstat (limited to 'binutils-2.17/gas/config/tc-z80.c')
-rw-r--r-- | binutils-2.17/gas/config/tc-z80.c | 2035 |
1 files changed, 0 insertions, 2035 deletions
diff --git a/binutils-2.17/gas/config/tc-z80.c b/binutils-2.17/gas/config/tc-z80.c deleted file mode 100644 index 413e336a..00000000 --- a/binutils-2.17/gas/config/tc-z80.c +++ /dev/null @@ -1,2035 +0,0 @@ -/* tc-z80.c -- Assemble code for the Zilog Z80 and ASCII R800 - Copyright 2005 Free Software Foundation, Inc. - Contributed by Arnold Metselaar <arnold_m@operamail.com> - - This file is part of GAS, the GNU Assembler. - - GAS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - GAS is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with GAS; see the file COPYING. If not, write to the Free - Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA - 02110-1301, USA. */ - -#include "as.h" -#include "listing.h" -#include "bfd.h" -#include "safe-ctype.h" -#include "subsegs.h" -#include "symbols.h" -#include "libiberty.h" - -/* Exported constants. */ -const char comment_chars[] = ";\0"; -const char line_comment_chars[] = "#;\0"; -const char line_separator_chars[] = "\0"; -const char EXP_CHARS[] = "eE\0"; -const char FLT_CHARS[] = "RrFf\0"; - -/* For machine specific options. */ -const char * md_shortopts = ""; /* None yet. */ - -enum options -{ - OPTION_MACH_Z80 = OPTION_MD_BASE, - OPTION_MACH_R800, - OPTION_MACH_IUD, - OPTION_MACH_WUD, - OPTION_MACH_FUD, - OPTION_MACH_IUP, - OPTION_MACH_WUP, - OPTION_MACH_FUP -}; - -#define INS_Z80 1 -#define INS_UNDOC 2 -#define INS_UNPORT 4 -#define INS_R800 8 - -struct option md_longopts[] = -{ - { "z80", no_argument, NULL, OPTION_MACH_Z80}, - { "r800", no_argument, NULL, OPTION_MACH_R800}, - { "ignore-undocumented-instructions", no_argument, NULL, OPTION_MACH_IUD }, - { "Wnud", no_argument, NULL, OPTION_MACH_IUD }, - { "warn-undocumented-instructions", no_argument, NULL, OPTION_MACH_WUD }, - { "Wud", no_argument, NULL, OPTION_MACH_WUD }, - { "forbid-undocumented-instructions", no_argument, NULL, OPTION_MACH_FUD }, - { "Fud", no_argument, NULL, OPTION_MACH_FUD }, - { "ignore-unportable-instructions", no_argument, NULL, OPTION_MACH_IUP }, - { "Wnup", no_argument, NULL, OPTION_MACH_IUP }, - { "warn-unportable-instructions", no_argument, NULL, OPTION_MACH_WUP }, - { "Wup", no_argument, NULL, OPTION_MACH_WUP }, - { "forbid-unportable-instructions", no_argument, NULL, OPTION_MACH_FUP }, - { "Fup", no_argument, NULL, OPTION_MACH_FUP }, - - { NULL, no_argument, NULL, 0 } -} ; - -size_t md_longopts_size = sizeof (md_longopts); - -extern int coff_flags; -/* Instruction classes that silently assembled. */ -static int ins_ok = INS_Z80 | INS_UNDOC; -/* Instruction classes that generate errors. */ -static int ins_err = INS_R800; -/* Instruction classes actually used, determines machine type. */ -static int ins_used = INS_Z80; - -int -md_parse_option (int c, char* arg ATTRIBUTE_UNUSED) -{ - switch (c) - { - default: - return 0; - case OPTION_MACH_Z80: - ins_ok &= ~INS_R800; - ins_err |= INS_R800; - break; - case OPTION_MACH_R800: - ins_ok = INS_Z80 | INS_UNDOC | INS_R800; - ins_err = INS_UNPORT; - break; - case OPTION_MACH_IUD: - ins_ok |= INS_UNDOC; - ins_err &= ~INS_UNDOC; - break; - case OPTION_MACH_IUP: - ins_ok |= INS_UNDOC | INS_UNPORT; - ins_err &= ~(INS_UNDOC | INS_UNPORT); - break; - case OPTION_MACH_WUD: - if ((ins_ok & INS_R800) == 0) - { - ins_ok &= ~(INS_UNDOC|INS_UNPORT); - ins_err &= ~INS_UNDOC; - } - break; - case OPTION_MACH_WUP: - ins_ok &= ~INS_UNPORT; - ins_err &= ~(INS_UNDOC|INS_UNPORT); - break; - case OPTION_MACH_FUD: - if ((ins_ok & INS_R800) == 0) - { - ins_ok &= (INS_UNDOC | INS_UNPORT); - ins_err |= INS_UNDOC | INS_UNPORT; - } - break; - case OPTION_MACH_FUP: - ins_ok &= ~INS_UNPORT; - ins_err |= INS_UNPORT; - break; - } - - return 1; -} - -void -md_show_usage (FILE * f) -{ - fprintf (f, "\n\ -CPU model/instruction set options:\n\ -\n\ - -z80\t\t assemble for Z80\n\ - -ignore-undocumented-instructions\n\ - -Wnud\n\ -\tsilently assemble undocumented Z80-instructions that work on R800\n\ - -ignore-unportable-instructions\n\ - -Wnup\n\ -\tsilently assemble all undocumented Z80-instructions\n\ - -warn-undocumented-instructions\n\ - -Wud\n\ -\tissue warnings for undocumented Z80-instructions that work on R800\n\ - -warn-unportable-instructions\n\ - -Wup\n\ -\tissue warnings for other undocumented Z80-instructions\n\ - -forbid-undocumented-instructions\n\ - -Fud\n\ -\ttreat all undocumented z80-instructions as errors\n\ - -forbid-unportable-instructions\n\ - -Fup\n\ -\ttreat undocumented z80-instructions that do not work on R800 as errors\n\ - -r800\t assemble for R800\n\n\ -Default: -z80 -ignore-undocument-instructions -warn-unportable-instructions.\n"); -} - -static symbolS * zero; - -void -md_begin (void) -{ - expressionS nul; - char * p; - - p = input_line_pointer; - input_line_pointer = "0"; - nul.X_md=0; - expression (& nul); - input_line_pointer = p; - zero = make_expr_symbol (& nul); - /* We do not use relaxation (yet). */ - linkrelax = 0; -} - -void -z80_md_end (void) -{ - int mach_type; - - if (ins_used & (INS_UNPORT | INS_R800)) - ins_used |= INS_UNDOC; - - switch (ins_used) - { - case INS_Z80: - mach_type = bfd_mach_z80strict; - break; - case INS_Z80|INS_UNDOC: - mach_type = bfd_mach_z80; - break; - case INS_Z80|INS_UNDOC|INS_UNPORT: - mach_type = bfd_mach_z80full; - break; - case INS_Z80|INS_UNDOC|INS_R800: - mach_type = bfd_mach_r800; - break; - default: - mach_type = 0; - } - - bfd_set_arch_mach (stdoutput, TARGET_ARCH, mach_type); -} - -static const char * -skip_space (const char *s) -{ - while (*s == ' ' || *s == '\t') - ++s; - return s; -} - -/* A non-zero return-value causes a continue in the - function read_a_source_file () in ../read.c. */ -int -z80_start_line_hook (void) -{ - char *p, quote; - char buf[4]; - - /* Convert one character constants. */ - for (p = input_line_pointer; *p && *p != '\n'; ++p) - { - switch (*p) - { - case '\'': - if (p[1] != 0 && p[1] != '\'' && p[2] == '\'') - { - snprintf (buf, 4, "%3d", (unsigned char)p[1]); - *p++ = buf[0]; - *p++ = buf[1]; - *p++ = buf[2]; - break; - } - case '"': - for (quote = *p++; quote != *p && '\n' != *p; ++p) - /* No escapes. */ ; - if (quote != *p) - { - as_bad (_("-- unterminated string")); - ignore_rest_of_line (); - return 1; - } - break; - } - } - /* Check for <label>[:] [.](EQU|DEFL) <value>. */ - if (is_name_beginner (*input_line_pointer)) - { - char c, *rest, *line_start; - int len; - symbolS * symbolP; - - line_start = input_line_pointer; - LISTING_NEWLINE (); - if (ignore_input ()) - return 0; - - c = get_symbol_end (); - rest = input_line_pointer + 1; - - if (*rest == ':') - ++rest; - if (*rest == ' ' || *rest == '\t') - ++rest; - if (*rest == '.') - ++rest; - if (strncasecmp (rest, "EQU", 3) == 0) - len = 3; - else if (strncasecmp (rest, "DEFL", 4) == 0) - len = 4; - else - len = 0; - if (len && (rest[len] == ' ' || rest[len] == '\t')) - { - /* Handle assignment here. */ - input_line_pointer = rest + len; - if (line_start[-1] == '\n') - bump_line_counters (); - /* Most Z80 assemblers require the first definition of a - label to use "EQU" and redefinitions to have "DEFL". */ - if (len == 3 && (symbolP = symbol_find (line_start)) != NULL) - { - if (S_IS_DEFINED (symbolP) || symbol_equated_p (symbolP)) - as_bad (_("symbol `%s' is already defined"), line_start); - } - equals (line_start, 1); - return 1; - } - else - { - /* Restore line and pointer. */ - *input_line_pointer = c; - input_line_pointer = line_start; - } - } - return 0; -} - -symbolS * -md_undefined_symbol (char *name ATTRIBUTE_UNUSED) -{ - return NULL; -} - -char * -md_atof (int type ATTRIBUTE_UNUSED, char *litP ATTRIBUTE_UNUSED, - int *sizeP ATTRIBUTE_UNUSED) -{ - return _("floating point numbers are not implemented"); -} - -valueT -md_section_align (segT seg ATTRIBUTE_UNUSED, valueT size) -{ - return size; -} - -long -md_pcrel_from (fixS * fixp) -{ - return fixp->fx_where + - fixp->fx_frag->fr_address + 1; -} - -typedef const char * (asfunc)(char, char, const char*); - -typedef struct _table_t -{ - char* name; - char prefix; - char opcode; - asfunc * fp; -} table_t; - -/* Compares the key for structs that start with a char * to the key. */ -static int -key_cmp (const void * a, const void * b) -{ - const char *str_a, *str_b; - - str_a = *((const char**)a); - str_b = *((const char**)b); - return strcmp (str_a, str_b); -} - -#define BUFLEN 8 /* Large enough for any keyword. */ - -char buf[BUFLEN]; -const char *key = buf; - -#define R_STACKABLE (0x80) -#define R_ARITH (0x40) -#define R_IX (0x20) -#define R_IY (0x10) -#define R_INDEX (R_IX | R_IY) - -#define REG_A (7) -#define REG_B (0) -#define REG_C (1) -#define REG_D (2) -#define REG_E (3) -#define REG_H (4) -#define REG_L (5) -#define REG_F (6 | 8) -#define REG_I (9) -#define REG_R (10) - -#define REG_AF (3 | R_STACKABLE) -#define REG_BC (0 | R_STACKABLE | R_ARITH) -#define REG_DE (1 | R_STACKABLE | R_ARITH) -#define REG_HL (2 | R_STACKABLE | R_ARITH) -#define REG_SP (3 | R_ARITH) - -static const struct reg_entry -{ - char* name; - int number; -} regtable[] = -{ - {"a", REG_A }, - {"af", REG_AF }, - {"b", REG_B }, - {"bc", REG_BC }, - {"c", REG_C }, - {"d", REG_D }, - {"de", REG_DE }, - {"e", REG_E }, - {"f", REG_F }, - {"h", REG_H }, - {"hl", REG_HL }, - {"i", REG_I }, - {"ix", REG_HL | R_IX }, - {"ixh",REG_H | R_IX }, - {"ixl",REG_L | R_IX }, - {"iy", REG_HL | R_IY }, - {"iyh",REG_H | R_IY }, - {"iyl",REG_L | R_IY }, - {"l", REG_L }, - {"r", REG_R }, - {"sp", REG_SP }, -} ; - -/* Prevent an error on a line from also generating - a "junk at end of line" error message. */ -static char err_flag; - -static void -error (const char * message) -{ - as_bad (message); - err_flag = 1; -} - -static void -ill_op (void) -{ - error (_("illegal operand")); -} - -static void -wrong_mach (int ins_type) -{ - const char *p; - - switch (ins_type) - { - case INS_UNDOC: - p = "undocumented instruction"; - break; - case INS_UNPORT: - p = "instruction does not work on R800"; - break; - case INS_R800: - p = "instruction only works R800"; - break; - default: - p = 0; /* Not reachable. */ - } - - if (ins_type & ins_err) - error (_(p)); - else - as_warn (_(p)); -} - -static void -check_mach (int ins_type) -{ - if ((ins_type & ins_ok) == 0) - wrong_mach (ins_type); - ins_used |= ins_type; -} - -/* Check whether an expression is indirect. */ -static int -is_indir (const char *s) -{ - char quote; - const char *p; - int indir, depth; - - /* Indirection is indicated with parentheses. */ - indir = (*s == '('); - - for (p = s, depth = 0; *p && *p != ','; ++p) - { - switch (*p) - { - case '"': - case '\'': - for (quote = *p++; quote != *p && *p != '\n'; ++p) - if (*p == '\\' && p[1]) - ++p; - break; - case '(': - ++ depth; - break; - case ')': - -- depth; - if (depth == 0) - { - p = skip_space (p + 1); - if (*p && *p != ',') - indir = 0; - --p; - } - if (depth < 0) - error (_("mismatched parentheses")); - break; - } - } - - if (depth != 0) - error (_("mismatched parentheses")); - - return indir; -} - -/* Parse general expression. */ -static const char * -parse_exp2 (const char *s, expressionS *op, segT *pseg) -{ - const char *p; - int indir; - int i; - const struct reg_entry * regp; - expressionS offset; - - p = skip_space (s); - op->X_md = indir = is_indir (p); - if (indir) - p = skip_space (p + 1); - - for (i = 0; i < BUFLEN; ++i) - { - if (!ISALPHA (p[i])) /* Register names consist of letters only. */ - break; - buf[i] = TOLOWER (p[i]); - } - - if ((i < BUFLEN) && ((p[i] == 0) || (strchr (")+-, \t", p[i])))) - { - buf[i] = 0; - regp = bsearch (& key, regtable, ARRAY_SIZE (regtable), - sizeof (regtable[0]), key_cmp); - if (regp) - { - *pseg = reg_section; - op->X_add_symbol = op->X_op_symbol = 0; - op->X_add_number = regp->number; - op->X_op = O_register; - p += strlen (regp->name); - p = skip_space (p); - if (indir) - { - if (*p == ')') - ++p; - if ((regp->number & R_INDEX) && (regp->number & R_ARITH)) - { - op->X_op = O_md1; - - if ((*p == '+') || (*p == '-')) - { - input_line_pointer = (char*) p; - expression (& offset); - p = skip_space (input_line_pointer); - if (*p != ')') - error (_("bad offset expression syntax")); - else - ++ p; - op->X_add_symbol = make_expr_symbol (& offset); - return p; - } - - /* We treat (i[xy]) as (i[xy]+0), which is how it will - end up anyway, unless we're processing jp (i[xy]). */ - op->X_add_symbol = zero; - } - } - p = skip_space (p); - - if ((*p == 0) || (*p == ',')) - return p; - } - } - /* Not an argument involving a register; use the generic parser. */ - input_line_pointer = (char*) s ; - *pseg = expression (op); - if (op->X_op == O_absent) - error (_("missing operand")); - if (op->X_op == O_illegal) - error (_("bad expression syntax")); - return input_line_pointer; -} - -static const char * -parse_exp (const char *s, expressionS *op) -{ - segT dummy; - return parse_exp2 (s, op, & dummy); -} - -/* Condition codes, including some synonyms provided by HiTech zas. */ -static const struct reg_entry cc_tab[] = -{ - { "age", 6 << 3 }, - { "alt", 7 << 3 }, - { "c", 3 << 3 }, - { "di", 4 << 3 }, - { "ei", 5 << 3 }, - { "lge", 2 << 3 }, - { "llt", 3 << 3 }, - { "m", 7 << 3 }, - { "nc", 2 << 3 }, - { "nz", 0 << 3 }, - { "p", 6 << 3 }, - { "pe", 5 << 3 }, - { "po", 4 << 3 }, - { "z", 1 << 3 }, -} ; - -/* Parse condition code. */ -static const char * -parse_cc (const char *s, char * op) -{ - const char *p; - int i; - struct reg_entry * cc_p; - - for (i = 0; i < BUFLEN; ++i) - { - if (!ISALPHA (s[i])) /* Condition codes consist of letters only. */ - break; - buf[i] = TOLOWER (s[i]); - } - - if ((i < BUFLEN) - && ((s[i] == 0) || (s[i] == ','))) - { - buf[i] = 0; - cc_p = bsearch (&key, cc_tab, ARRAY_SIZE (cc_tab), - sizeof (cc_tab[0]), key_cmp); - } - else - cc_p = NULL; - - if (cc_p) - { - *op = cc_p->number; - p = s + i; - } - else - p = NULL; - - return p; -} - -static const char * -emit_insn (char prefix, char opcode, const char * args) -{ - char *p; - - if (prefix) - { - p = frag_more (2); - *p++ = prefix; - } - else - p = frag_more (1); - *p = opcode; - return args; -} - -void z80_cons_fix_new (fragS *frag_p, int offset, int nbytes, expressionS *exp) -{ - bfd_reloc_code_real_type r[4] = - { - BFD_RELOC_8, - BFD_RELOC_16, - BFD_RELOC_24, - BFD_RELOC_32 - }; - - if (nbytes < 1 || nbytes > 4) - { - as_bad (_("unsupported BFD relocation size %u"), nbytes); - } - else - { - fix_new_exp (frag_p, offset, nbytes, exp, 0, r[nbytes-1]); - } -} - -static void -emit_byte (expressionS * val, bfd_reloc_code_real_type r_type) -{ - char *p; - int lo, hi; - fixS * fixp; - - p = frag_more (1); - *p = val->X_add_number; - if ((r_type == BFD_RELOC_8_PCREL) && (val->X_op == O_constant)) - { - as_bad(_("cannot make a relative jump to an absolute location")); - } - else if (val->X_op == O_constant) - { - lo = -128; - hi = (BFD_RELOC_8 == r_type) ? 255 : 127; - - if ((val->X_add_number < lo) || (val->X_add_number > hi)) - { - if (r_type == BFD_RELOC_Z80_DISP8) - as_bad (_("offset too large")); - else - as_warn (_("overflow")); - } - } - else - { - fixp = fix_new_exp (frag_now, p - frag_now->fr_literal, 1, val, - (r_type == BFD_RELOC_8_PCREL) ? TRUE : FALSE, r_type); - /* FIXME : Process constant offsets immediately. */ - } -} - -static void -emit_word (expressionS * val) -{ - char *p; - - p = frag_more (2); - if ( (val->X_op == O_register) - || (val->X_op == O_md1)) - ill_op (); - else - { - *p = val->X_add_number; - p[1] = (val->X_add_number>>8); - if (val->X_op != O_constant) - fix_new_exp (frag_now, p - frag_now->fr_literal, 2, - val, FALSE, BFD_RELOC_16); - } -} - -static void -emit_mx (char prefix, char opcode, int shift, expressionS * arg) - /* The operand m may be r, (hl), (ix+d), (iy+d), - if 0 == prefix m may also be ixl, ixh, iyl, iyh. */ -{ - char *q; - int rnum; - - rnum = arg->X_add_number; - switch (arg->X_op) - { - case O_register: - if (arg->X_md) - { - if (rnum != REG_HL) - { - ill_op (); - break; - } - else - rnum = 6; - } - else - { - if ((prefix == 0) && (rnum & R_INDEX)) - { - prefix = (rnum & R_IX) ? 0xDD : 0xFD; - check_mach (INS_UNDOC); - rnum &= ~R_INDEX; - } - if (rnum > 7) - { - ill_op (); - break; - } - } - q = frag_more (prefix ? 2 : 1); - if (prefix) - * q ++ = prefix; - * q ++ = opcode + (rnum << shift); - break; - case O_md1: - q = frag_more (2); - *q++ = (rnum & R_IX) ? 0xDD : 0xFD; - *q = (prefix) ? prefix : (opcode + (6 << shift)); - emit_byte (symbol_get_value_expression (arg->X_add_symbol), - BFD_RELOC_Z80_DISP8); - if (prefix) - { - q = frag_more (1); - *q = opcode+(6<<shift); - } - break; - default: - abort (); - } -} - -/* The operand m may be r, (hl), (ix+d), (iy+d), - if 0 = prefix m may also be ixl, ixh, iyl, iyh. */ -static const char * -emit_m (char prefix, char opcode, const char *args) -{ - expressionS arg_m; - const char *p; - - p = parse_exp (args, &arg_m); - switch (arg_m.X_op) - { - case O_md1: - case O_register: - emit_mx (prefix, opcode, 0, &arg_m); - break; - default: - ill_op (); - } - return p; -} - -/* The operand m may be as above or one of the undocumented - combinations (ix+d),r and (iy+d),r (if unportable instructions - are allowed). */ -static const char * -emit_mr (char prefix, char opcode, const char *args) -{ - expressionS arg_m, arg_r; - const char *p; - - p = parse_exp (args, & arg_m); - - switch (arg_m.X_op) - { - case O_md1: - if (*p == ',') - { - p = parse_exp (p + 1, & arg_r); - - if ((arg_r.X_md == 0) - && (arg_r.X_op == O_register) - && (arg_r.X_add_number < 8)) - opcode += arg_r.X_add_number-6; /* Emit_mx () will add 6. */ - else - { - ill_op (); - break; - } - check_mach (INS_UNPORT); - } - case O_register: - emit_mx (prefix, opcode, 0, & arg_m); - break; - default: - ill_op (); - } - return p; -} - -static void -emit_sx (char prefix, char opcode, expressionS * arg_p) -{ - char *q; - - switch (arg_p->X_op) - { - case O_register: - case O_md1: - emit_mx (prefix, opcode, 0, arg_p); - break; - default: - if (arg_p->X_md) - ill_op (); - else - { - q = frag_more (prefix ? 2 : 1); - if (prefix) - *q++ = prefix; - *q = opcode ^ 0x46; - emit_byte (arg_p, BFD_RELOC_8); - } - } -} - -/* The operand s may be r, (hl), (ix+d), (iy+d), n. */ -static const char * -emit_s (char prefix, char opcode, const char *args) -{ - expressionS arg_s; - const char *p; - - p = parse_exp (args, & arg_s); - emit_sx (prefix, opcode, & arg_s); - return p; -} - -static const char * -emit_call (char prefix ATTRIBUTE_UNUSED, char opcode, const char * args) -{ - expressionS addr; - const char *p; char *q; - - p = parse_exp (args, &addr); - if (addr.X_md) - ill_op (); - else - { - q = frag_more (1); - *q = opcode; - emit_word (& addr); - } - return p; -} - -/* Operand may be rr, r, (hl), (ix+d), (iy+d). */ -static const char * -emit_incdec (char prefix, char opcode, const char * args) -{ - expressionS operand; - int rnum; - const char *p; char *q; - - p = parse_exp (args, &operand); - rnum = operand.X_add_number; - if ((! operand.X_md) - && (operand.X_op == O_register) - && (R_ARITH&rnum)) - { - q = frag_more ((rnum & R_INDEX) ? 2 : 1); - if (rnum & R_INDEX) - *q++ = (rnum & R_IX) ? 0xDD : 0xFD; - *q = prefix + ((rnum & 3) << 4); - } - else - { - if ((operand.X_op == O_md1) || (operand.X_op == O_register)) - emit_mx (0, opcode, 3, & operand); - else - ill_op (); - } - return p; -} - -static const char * -emit_jr (char prefix ATTRIBUTE_UNUSED, char opcode, const char * args) -{ - expressionS addr; - const char *p; - char *q; - - p = parse_exp (args, &addr); - if (addr.X_md) - ill_op (); - else - { - q = frag_more (1); - *q = opcode; - emit_byte (&addr, BFD_RELOC_8_PCREL); - } - return p; -} - -static const char * -emit_jp (char prefix, char opcode, const char * args) -{ - expressionS addr; - const char *p; - char *q; - int rnum; - - p = parse_exp (args, & addr); - if (addr.X_md) - { - rnum = addr.X_add_number; - if ((addr.X_op == O_register && (rnum & ~R_INDEX) == REG_HL) - /* An operand (i[xy]) would have been rewritten to (i[xy]+0) - in parse_exp (). */ - || (addr.X_op == O_md1 && addr.X_add_symbol == zero)) - { - q = frag_more ((rnum & R_INDEX) ? 2 : 1); - if (rnum & R_INDEX) - *q++ = (rnum & R_IX) ? 0xDD : 0xFD; - *q = prefix; - } - else - ill_op (); - } - else - { - q = frag_more (1); - *q = opcode; - emit_word (& addr); - } - return p; -} - -static const char * -emit_im (char prefix, char opcode, const char * args) -{ - expressionS mode; - const char *p; - char *q; - - p = parse_exp (args, & mode); - if (mode.X_md || (mode.X_op != O_constant)) - ill_op (); - else - switch (mode.X_add_number) - { - case 1: - case 2: - ++mode.X_add_number; - /* Fall through. */ - case 0: - q = frag_more (2); - *q++ = prefix; - *q = opcode + 8*mode.X_add_number; - break; - default: - ill_op (); - } - return p; -} - -static const char * -emit_pop (char prefix ATTRIBUTE_UNUSED, char opcode, const char * args) -{ - expressionS regp; - const char *p; - char *q; - - p = parse_exp (args, & regp); - if ((!regp.X_md) - && (regp.X_op == O_register) - && (regp.X_add_number & R_STACKABLE)) - { - int rnum; - - rnum = regp.X_add_number; - if (rnum&R_INDEX) - { - q = frag_more (2); - *q++ = (rnum&R_IX)?0xDD:0xFD; - } - else - q = frag_more (1); - *q = opcode + ((rnum & 3) << 4); - } - else - ill_op (); - - return p; -} - -static const char * -emit_retcc (char prefix ATTRIBUTE_UNUSED, char opcode, const char * args) -{ - char cc, *q; - const char *p; - - p = parse_cc (args, &cc); - q = frag_more (1); - if (p) - *q = opcode + cc; - else - *q = prefix; - return p ? p : args; -} - -static const char * -emit_adc (char prefix, char opcode, const char * args) -{ - expressionS term; - int rnum; - const char *p; - char *q; - - p = parse_exp (args, &term); - if (*p++ != ',') - { - error (_("bad intruction syntax")); - return p; - } - - if ((term.X_md) || (term.X_op != O_register)) - ill_op (); - else - switch (term.X_add_number) - { - case REG_A: - p = emit_s (0, prefix, p); - break; - case REG_HL: - p = parse_exp (p, &term); - if ((!term.X_md) && (term.X_op == O_register)) - { - rnum = term.X_add_number; - if (R_ARITH == (rnum & (R_ARITH | R_INDEX))) - { - q = frag_more (2); - *q++ = 0xED; - *q = opcode + ((rnum & 3) << 4); - break; - } - } - /* Fall through. */ - default: - ill_op (); - } - return p; -} - -static const char * -emit_add (char prefix, char opcode, const char * args) -{ - expressionS term; - int lhs, rhs; - const char *p; - char *q; - - p = parse_exp (args, &term); - if (*p++ != ',') - { - error (_("bad intruction syntax")); - return p; - } - - if ((term.X_md) || (term.X_op != O_register)) - ill_op (); - else - switch (term.X_add_number & ~R_INDEX) - { - case REG_A: - p = emit_s (0, prefix, p); - break; - case REG_HL: - lhs = term.X_add_number; - p = parse_exp (p, &term); - if ((!term.X_md) && (term.X_op == O_register)) - { - rhs = term.X_add_number; - if ((rhs & R_ARITH) - && ((rhs == lhs) || ((rhs & ~R_INDEX) != REG_HL))) - { - q = frag_more ((lhs & R_INDEX) ? 2 : 1); - if (lhs & R_INDEX) - *q++ = (lhs & R_IX) ? 0xDD : 0xFD; - *q = opcode + ((rhs & 3) << 4); - break; - } - } - /* Fall through. */ - default: - ill_op (); - } - return p; -} - -static const char * -emit_bit (char prefix, char opcode, const char * args) -{ - expressionS b; - int bn; - const char *p; - - p = parse_exp (args, &b); - if (*p++ != ',') - error (_("bad intruction syntax")); - - bn = b.X_add_number; - if ((!b.X_md) - && (b.X_op == O_constant) - && (0 <= bn) - && (bn < 8)) - { - if (opcode == 0x40) - /* Bit : no optional third operand. */ - p = emit_m (prefix, opcode + (bn << 3), p); - else - /* Set, res : resulting byte can be copied to register. */ - p = emit_mr (prefix, opcode + (bn << 3), p); - } - else - ill_op (); - return p; -} - -static const char * -emit_jpcc (char prefix, char opcode, const char * args) -{ - char cc; - const char *p; - - p = parse_cc (args, & cc); - if (p && *p++ == ',') - p = emit_call (0, opcode + cc, p); - else - p = (prefix == (char)0xC3) - ? emit_jp (0xE9, prefix, args) - : emit_call (0, prefix, args); - return p; -} - -static const char * -emit_jrcc (char prefix, char opcode, const char * args) -{ - char cc; - const char *p; - - p = parse_cc (args, &cc); - if (p && *p++ == ',') - { - if (cc > (3 << 3)) - error (_("condition code invalid for jr")); - else - p = emit_jr (0, opcode + cc, p); - } - else - p = emit_jr (0, prefix, args); - - return p; -} - -static const char * -emit_ex (char prefix_in ATTRIBUTE_UNUSED, - char opcode_in ATTRIBUTE_UNUSED, const char * args) -{ - expressionS op; - const char * p; - char prefix, opcode; - - p = parse_exp (args, &op); - p = skip_space (p); - if (*p++ != ',') - { - error (_("bad instruction syntax")); - return p; - } - - prefix = opcode = 0; - if (op.X_op == O_register) - switch (op.X_add_number | (op.X_md ? 0x8000 : 0)) - { - case REG_AF: - if (TOLOWER (*p++) == 'a' && TOLOWER (*p++) == 'f') - { - /* The scrubber changes '\'' to '`' in this context. */ - if (*p == '`') - ++p; - opcode = 0x08; - } - break; - case REG_DE: - if (TOLOWER (*p++) == 'h' && TOLOWER (*p++) == 'l') - opcode = 0xEB; - break; - case REG_SP|0x8000: - p = parse_exp (p, & op); - if (op.X_op == O_register - && op.X_md == 0 - && (op.X_add_number & ~R_INDEX) == REG_HL) - { - opcode = 0xE3; - if (R_INDEX & op.X_add_number) - prefix = (R_IX & op.X_add_number) ? 0xDD : 0xFD; - } - break; - } - if (opcode) - emit_insn (prefix, opcode, p); - else - ill_op (); - - return p; -} - -static const char * -emit_in (char prefix ATTRIBUTE_UNUSED, char opcode ATTRIBUTE_UNUSED, - const char * args) -{ - expressionS reg, port; - const char *p; - char *q; - - p = parse_exp (args, ®); - if (*p++ != ',') - { - error (_("bad intruction syntax")); - return p; - } - - p = parse_exp (p, &port); - if (reg.X_md == 0 - && reg.X_op == O_register - && (reg.X_add_number <= 7 || reg.X_add_number == REG_F) - && (port.X_md)) - { - if (port.X_op != O_md1 && port.X_op != O_register) - { - if (REG_A == reg.X_add_number) - { - q = frag_more (1); - *q = 0xDB; - emit_byte (&port, BFD_RELOC_8); - } - else - ill_op (); - } - else - { - if (port.X_add_number == REG_C) - { - if (reg.X_add_number == REG_F) - check_mach (INS_UNDOC); - else - { - q = frag_more (2); - *q++ = 0xED; - *q = 0x40|((reg.X_add_number&7)<<3); - } - } - else - ill_op (); - } - } - else - ill_op (); - return p; -} - -static const char * -emit_out (char prefix ATTRIBUTE_UNUSED, char opcode ATTRIBUTE_UNUSED, - const char * args) -{ - expressionS reg, port; - const char *p; - char *q; - - p = parse_exp (args, & port); - if (*p++ != ',') - { - error (_("bad intruction syntax")); - return p; - } - p = parse_exp (p, ®); - if (!port.X_md) - { ill_op (); return p; } - /* Allow "out (c), 0" as unportable instruction. */ - if (reg.X_op == O_constant && reg.X_add_number == 0) - { - check_mach (INS_UNPORT); - reg.X_op = O_register; - reg.X_add_number = 6; - } - if (reg.X_md - || reg.X_op != O_register - || reg.X_add_number > 7) - ill_op (); - else - if (port.X_op != O_register && port.X_op != O_md1) - { - if (REG_A == reg.X_add_number) - { - q = frag_more (1); - *q = 0xD3; - emit_byte (&port, BFD_RELOC_8); - } - else - ill_op (); - } - else - { - if (REG_C == port.X_add_number) - { - q = frag_more (2); - *q++ = 0xED; - *q = 0x41 | (reg.X_add_number << 3); - } - else - ill_op (); - } - return p; -} - -static const char * -emit_rst (char prefix ATTRIBUTE_UNUSED, char opcode, const char * args) -{ - expressionS addr; - const char *p; - char *q; - - p = parse_exp (args, &addr); - if (addr.X_op != O_constant) - { - error ("rst needs constant address"); - return p; - } - - if (addr.X_add_number & ~(7 << 3)) - ill_op (); - else - { - q = frag_more (1); - *q = opcode + (addr.X_add_number & (7 << 3)); - } - return p; -} - -static void -emit_ldxhl (char prefix, char opcode, expressionS *src, expressionS *d) -{ - char *q; - - if (src->X_md) - ill_op (); - else - { - if (src->X_op == O_register) - { - if (src->X_add_number>7) - ill_op (); - if (prefix) - { - q = frag_more (2); - *q++ = prefix; - } - else - q = frag_more (1); - *q = opcode + src->X_add_number; - if (d) - emit_byte (d, BFD_RELOC_Z80_DISP8); - } - else - { - if (prefix) - { - q = frag_more (2); - *q++ = prefix; - } - else - q = frag_more (1); - *q = opcode^0x46; - if (d) - emit_byte (d, BFD_RELOC_Z80_DISP8); - emit_byte (src, BFD_RELOC_8); - } - } -} - -static void -emit_ldreg (int dest, expressionS * src) -{ - char *q; - int rnum; - - switch (dest) - { - /* 8 Bit ld group: */ - case REG_I: - case REG_R: - if (src->X_md == 0 && src->X_op == O_register && src->X_add_number == REG_A) - { - q = frag_more (2); - *q++ = 0xED; - *q = (dest == REG_I) ? 0x47 : 0x4F; - } - else - ill_op (); - break; - - case REG_A: - if ((src->X_md) && src->X_op != O_register && src->X_op != O_md1) - { - q = frag_more (1); - *q = 0x3A; - emit_word (src); - break; - } - - if ((src->X_md) - && src->X_op == O_register - && (src->X_add_number == REG_BC || src->X_add_number == REG_DE)) - { - q = frag_more (1); - *q = 0x0A + ((dest & 1) << 4); - break; - } - - if ((!src->X_md) - && src->X_op == O_register - && (src->X_add_number == REG_R || src->X_add_number == REG_I)) - { - q = frag_more (2); - *q++ = 0xED; - *q = (src->X_add_number == REG_I) ? 0x57 : 0x5F; - break; - } - /* Fall through. */ - case REG_B: - case REG_C: - case REG_D: - case REG_E: - emit_sx (0, 0x40 + (dest << 3), src); - break; - - case REG_H: - case REG_L: - if ((src->X_md == 0) - && (src->X_op == O_register) - && (src->X_add_number & R_INDEX)) - ill_op (); - else - emit_sx (0, 0x40 + (dest << 3), src); - break; - - case R_IX | REG_H: - case R_IX | REG_L: - case R_IY | REG_H: - case R_IY | REG_L: - if (src->X_md) - { - ill_op (); - break; - } - check_mach (INS_UNDOC); - if (src-> X_op == O_register) - { - rnum = src->X_add_number; - if ((rnum & ~R_INDEX) < 8 - && ((rnum & R_INDEX) == (dest & R_INDEX) - || ( (rnum & ~R_INDEX) != REG_H - && (rnum & ~R_INDEX) != REG_L))) - { - q = frag_more (2); - *q++ = (dest & R_IX) ? 0xDD : 0xFD; - *q = 0x40 + ((dest & 0x07) << 3) + (rnum & 7); - } - else - ill_op (); - } - else - { - q = frag_more (2); - *q++ = (dest & R_IX) ? 0xDD : 0xFD; - *q = 0x06 + ((dest & 0x07) << 3); - emit_byte (src, BFD_RELOC_8); - } - break; - - /* 16 Bit ld group: */ - case REG_SP: - if (src->X_md == 0 - && src->X_op == O_register - && REG_HL == (src->X_add_number &~ R_INDEX)) - { - q = frag_more ((src->X_add_number & R_INDEX) ? 2 : 1); - if (src->X_add_number & R_INDEX) - *q++ = (src->X_add_number & R_IX) ? 0xDD : 0xFD; - *q = 0xF9; - break; - } - /* Fall through. */ - case REG_BC: - case REG_DE: - if (src->X_op == O_register || src->X_op == O_md1) - ill_op (); - q = frag_more (src->X_md ? 2 : 1); - if (src->X_md) - { - *q++ = 0xED; - *q = 0x4B + ((dest & 3) << 4); - } - else - *q = 0x01 + ((dest & 3) << 4); - emit_word (src); - break; - - case REG_HL: - case REG_HL | R_IX: - case REG_HL | R_IY: - if (src->X_op == O_register || src->X_op == O_md1) - ill_op (); - q = frag_more ((dest & R_INDEX) ? 2 : 1); - if (dest & R_INDEX) - * q ++ = (dest & R_IX) ? 0xDD : 0xFD; - *q = (src->X_md) ? 0x2A : 0x21; - emit_word (src); - break; - - case REG_AF: - case REG_F: - ill_op (); - break; - - default: - abort (); - } -} - -static const char * -emit_ld (char prefix_in ATTRIBUTE_UNUSED, char opcode_in ATTRIBUTE_UNUSED, - const char * args) -{ - expressionS dst, src; - const char *p; - char *q; - char prefix, opcode; - - p = parse_exp (args, &dst); - if (*p++ != ',') - error (_("bad intruction syntax")); - p = parse_exp (p, &src); - - switch (dst.X_op) - { - case O_md1: - emit_ldxhl ((dst.X_add_number & R_IX) ? 0xDD : 0xFD, 0x70, - &src, symbol_get_value_expression (dst.X_add_symbol)); - break; - - case O_register: - if (dst.X_md) - { - switch (dst.X_add_number) - { - case REG_BC: - case REG_DE: - if (src.X_md == 0 && src.X_op == O_register && src.X_add_number == REG_A) - { - q = frag_more (1); - *q = 0x02 + ( (dst.X_add_number & 1) << 4); - } - else - ill_op (); - break; - case REG_HL: - emit_ldxhl (0, 0x70, &src, NULL); - break; - default: - ill_op (); - } - } - else - emit_ldreg (dst.X_add_number, &src); - break; - - default: - if (src.X_md != 0 || src.X_op != O_register) - ill_op (); - prefix = opcode = 0; - switch (src.X_add_number) - { - case REG_A: - opcode = 0x32; break; - case REG_BC: case REG_DE: case REG_SP: - prefix = 0xED; opcode = 0x43 + ((src.X_add_number&3)<<4); break; - case REG_HL: - opcode = 0x22; break; - case REG_HL|R_IX: - prefix = 0xDD; opcode = 0x22; break; - case REG_HL|R_IY: - prefix = 0xFD; opcode = 0x22; break; - } - if (opcode) - { - q = frag_more (prefix?2:1); - if (prefix) - *q++ = prefix; - *q = opcode; - emit_word (&dst); - } - else - ill_op (); - } - return p; -} - -static void -emit_data (int size ATTRIBUTE_UNUSED) -{ - const char *p, *q; - char *u, quote; - int cnt; - expressionS exp; - - if (is_it_end_of_statement ()) - { - demand_empty_rest_of_line (); - return; - } - p = skip_space (input_line_pointer); - - do - { - if (*p == '\"' || *p == '\'') - { - for (quote = *p, q = ++p, cnt = 0; *p && quote != *p; ++p, ++cnt) - ; - u = frag_more (cnt); - memcpy (u, q, cnt); - if (!*p) - as_warn (_("unterminated string")); - else - p = skip_space (p+1); - } - else - { - p = parse_exp (p, &exp); - if (exp.X_op == O_md1 || exp.X_op == O_register) - { - ill_op (); - break; - } - if (exp.X_md) - as_warn (_("parentheses ignored")); - emit_byte (&exp, BFD_RELOC_8); - p = skip_space (p); - } - } - while (*p++ == ',') ; - input_line_pointer = (char *)(p-1); -} - -static const char * -emit_mulub (char prefix ATTRIBUTE_UNUSED, char opcode, const char * args) -{ - const char *p; - - p = skip_space (args); - if (TOLOWER (*p++) != 'a' || *p++ != ',') - ill_op (); - else - { - char *q, reg; - - reg = TOLOWER (*p++); - switch (reg) - { - case 'b': - case 'c': - case 'd': - case 'e': - check_mach (INS_R800); - if (!*skip_space (p)) - { - q = frag_more (2); - *q++ = prefix; - *q = opcode + ((reg - 'b') << 3); - break; - } - default: - ill_op (); - } - } - return p; -} - -static const char * -emit_muluw (char prefix ATTRIBUTE_UNUSED, char opcode, const char * args) -{ - const char *p; - - p = skip_space (args); - if (TOLOWER (*p++) != 'h' || TOLOWER (*p++) != 'l' || *p++ != ',') - ill_op (); - else - { - expressionS reg; - char *q; - - p = parse_exp (p, & reg); - - if ((!reg.X_md) && reg.X_op == O_register) - switch (reg.X_add_number) - { - case REG_BC: - case REG_SP: - check_mach (INS_R800); - q = frag_more (2); - *q++ = prefix; - *q = opcode + ((reg.X_add_number & 3) << 4); - break; - default: - ill_op (); - } - } - return p; -} - -/* Port specific pseudo ops. */ -const pseudo_typeS md_pseudo_table[] = -{ - { "db" , emit_data, 1}, - { "d24", cons, 3}, - { "d32", cons, 4}, - { "def24", cons, 3}, - { "def32", cons, 4}, - { "defb", emit_data, 1}, - { "defs", s_space, 1}, /* Synonym for ds on some assemblers. */ - { "defw", cons, 2}, - { "ds", s_space, 1}, /* Fill with bytes rather than words. */ - { "dw", cons, 2}, - { "psect", obj_coff_section, 0}, /* TODO: Translate attributes. */ - { "set", 0, 0}, /* Real instruction on z80. */ - { NULL, 0, 0 } -} ; - -static table_t instab[] = -{ - { "adc", 0x88, 0x4A, emit_adc }, - { "add", 0x80, 0x09, emit_add }, - { "and", 0x00, 0xA0, emit_s }, - { "bit", 0xCB, 0x40, emit_bit }, - { "call", 0xCD, 0xC4, emit_jpcc }, - { "ccf", 0x00, 0x3F, emit_insn }, - { "cp", 0x00, 0xB8, emit_s }, - { "cpd", 0xED, 0xA9, emit_insn }, - { "cpdr", 0xED, 0xB9, emit_insn }, - { "cpi", 0xED, 0xA1, emit_insn }, - { "cpir", 0xED, 0xB1, emit_insn }, - { "cpl", 0x00, 0x2F, emit_insn }, - { "daa", 0x00, 0x27, emit_insn }, - { "dec", 0x0B, 0x05, emit_incdec }, - { "di", 0x00, 0xF3, emit_insn }, - { "djnz", 0x00, 0x10, emit_jr }, - { "ei", 0x00, 0xFB, emit_insn }, - { "ex", 0x00, 0x00, emit_ex}, - { "exx", 0x00, 0xD9, emit_insn }, - { "halt", 0x00, 0x76, emit_insn }, - { "im", 0xED, 0x46, emit_im }, - { "in", 0x00, 0x00, emit_in }, - { "inc", 0x03, 0x04, emit_incdec }, - { "ind", 0xED, 0xAA, emit_insn }, - { "indr", 0xED, 0xBA, emit_insn }, - { "ini", 0xED, 0xA2, emit_insn }, - { "inir", 0xED, 0xB2, emit_insn }, - { "jp", 0xC3, 0xC2, emit_jpcc }, - { "jr", 0x18, 0x20, emit_jrcc }, - { "ld", 0x00, 0x00, emit_ld }, - { "ldd", 0xED, 0xA8, emit_insn }, - { "lddr", 0xED, 0xB8, emit_insn }, - { "ldi", 0xED, 0xA0, emit_insn }, - { "ldir", 0xED, 0xB0, emit_insn }, - { "mulub", 0xED, 0xC5, emit_mulub }, /* R800 only. */ - { "muluw", 0xED, 0xC3, emit_muluw }, /* R800 only. */ - { "neg", 0xed, 0x44, emit_insn }, - { "nop", 0x00, 0x00, emit_insn }, - { "or", 0x00, 0xB0, emit_s }, - { "otdr", 0xED, 0xBB, emit_insn }, - { "otir", 0xED, 0xB3, emit_insn }, - { "out", 0x00, 0x00, emit_out }, - { "outd", 0xED, 0xAB, emit_insn }, - { "outi", 0xED, 0xA3, emit_insn }, - { "pop", 0x00, 0xC1, emit_pop }, - { "push", 0x00, 0xC5, emit_pop }, - { "res", 0xCB, 0x80, emit_bit }, - { "ret", 0xC9, 0xC0, emit_retcc }, - { "reti", 0xED, 0x4D, emit_insn }, - { "retn", 0xED, 0x45, emit_insn }, - { "rl", 0xCB, 0x10, emit_mr }, - { "rla", 0x00, 0x17, emit_insn }, - { "rlc", 0xCB, 0x00, emit_mr }, - { "rlca", 0x00, 0x07, emit_insn }, - { "rld", 0xED, 0x6F, emit_insn }, - { "rr", 0xCB, 0x18, emit_mr }, - { "rra", 0x00, 0x1F, emit_insn }, - { "rrc", 0xCB, 0x08, emit_mr }, - { "rrca", 0x00, 0x0F, emit_insn }, - { "rrd", 0xED, 0x67, emit_insn }, - { "rst", 0x00, 0xC7, emit_rst}, - { "sbc", 0x98, 0x42, emit_adc }, - { "scf", 0x00, 0x37, emit_insn }, - { "set", 0xCB, 0xC0, emit_bit }, - { "sla", 0xCB, 0x20, emit_mr }, - { "sli", 0xCB, 0x30, emit_mr }, - { "sll", 0xCB, 0x30, emit_mr }, - { "sra", 0xCB, 0x28, emit_mr }, - { "srl", 0xCB, 0x38, emit_mr }, - { "sub", 0x00, 0x90, emit_s }, - { "xor", 0x00, 0xA8, emit_s }, -} ; - -void -md_assemble (char* str) -{ - const char *p; - char * old_ptr; - int i; - table_t *insp; - - err_flag = 0; - old_ptr = input_line_pointer; - p = skip_space (str); - for (i = 0; (i < BUFLEN) && (ISALPHA (*p));) - buf[i++] = TOLOWER (*p++); - - if (i == BUFLEN) - { - buf[BUFLEN-3] = buf[BUFLEN-2] = '.'; /* Mark opcode as abbreviated. */ - buf[BUFLEN-1] = 0; - as_bad (_("Unknown instruction '%s'"), buf); - } - else if ((*p) && (!ISSPACE (*p))) - as_bad (_("syntax error")); - else - { - buf[i] = 0; - p = skip_space (p); - key = buf; - - insp = bsearch (&key, instab, ARRAY_SIZE (instab), - sizeof (instab[0]), key_cmp); - if (!insp) - as_bad (_("Unknown instruction '%s'"), buf); - else - { - p = insp->fp (insp->prefix, insp->opcode, p); - p = skip_space (p); - if ((!err_flag) && *p) - as_bad (_("junk at end of line, first unrecognized character is `%c'"), - *p); - } - } - input_line_pointer = old_ptr; -} - -void -md_apply_fix (fixS * fixP, valueT* valP, segT seg ATTRIBUTE_UNUSED) -{ - long val = * (long *) valP; - char *buf = fixP->fx_where + fixP->fx_frag->fr_literal; - - switch (fixP->fx_r_type) - { - case BFD_RELOC_8_PCREL: - if (fixP->fx_addsy) - { - fixP->fx_no_overflow = 1; - fixP->fx_done = 0; - } - else - { - fixP->fx_no_overflow = (-128 <= val && val < 128); - if (!fixP->fx_no_overflow) - as_bad_where (fixP->fx_file, fixP->fx_line, - _("relative jump out of range")); - *buf++ = val; - fixP->fx_done = 1; - } - break; - - case BFD_RELOC_Z80_DISP8: - if (fixP->fx_addsy) - { - fixP->fx_no_overflow = 1; - fixP->fx_done = 0; - } - else - { - fixP->fx_no_overflow = (-128 <= val && val < 128); - if (!fixP->fx_no_overflow) - as_bad_where (fixP->fx_file, fixP->fx_line, - _("index offset out of range")); - *buf++ = val; - fixP->fx_done = 1; - } - break; - - case BFD_RELOC_8: - if (val > 255 || val < -128) - as_warn_where (fixP->fx_file, fixP->fx_line, _("overflow")); - *buf++ = val; - fixP->fx_no_overflow = 1; - if (fixP->fx_addsy == NULL) - fixP->fx_done = 1; - break; - - case BFD_RELOC_16: - *buf++ = val; - *buf++ = (val >> 8); - fixP->fx_no_overflow = 1; - if (fixP->fx_addsy == NULL) - fixP->fx_done = 1; - break; - - case BFD_RELOC_24: /* Def24 may produce this. */ - *buf++ = val; - *buf++ = (val >> 8); - *buf++ = (val >> 16); - fixP->fx_no_overflow = 1; - if (fixP->fx_addsy == NULL) - fixP->fx_done = 1; - break; - - case BFD_RELOC_32: /* Def32 and .long may produce this. */ - *buf++ = val; - *buf++ = (val >> 8); - *buf++ = (val >> 16); - *buf++ = (val >> 24); - if (fixP->fx_addsy == NULL) - fixP->fx_done = 1; - break; - - default: - printf (_("md_apply_fix: unknown r_type 0x%x\n"), fixP->fx_r_type); - abort (); - } -} - -/* GAS will call this to generate a reloc. GAS will pass the - resulting reloc to `bfd_install_relocation'. This currently works - poorly, as `bfd_install_relocation' often does the wrong thing, and - instances of `tc_gen_reloc' have been written to work around the - problems, which in turns makes it difficult to fix - `bfd_install_relocation'. */ - -/* If while processing a fixup, a reloc really - needs to be created then it is done here. */ - -arelent * -tc_gen_reloc (asection *seg ATTRIBUTE_UNUSED , fixS *fixp) -{ - arelent *reloc; - - if (! bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type)) - { - as_bad_where (fixp->fx_file, fixp->fx_line, - _("reloc %d not supported by object file format"), - (int) fixp->fx_r_type); - return NULL; - } - - reloc = xmalloc (sizeof (arelent)); - reloc->sym_ptr_ptr = xmalloc (sizeof (asymbol *)); - *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy); - reloc->address = fixp->fx_frag->fr_address + fixp->fx_where; - reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type); - reloc->addend = fixp->fx_offset; - - return reloc; -} - |