This is the mail archive of the gdb-patches@sources.redhat.com mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [RFA] H8/300sx port for gas, sim, and opcodes (2/5)


Michael Snyder wrote:
> 
> This is the gas portion of the h8/300sx port.
> It depends on the changes to include/opcode/h8300.h, submitted separately.
> 
> 2003-05-14  Michael Snyder  <msnyder@redhat.com>
>         From Bernd Schmidt  <bernds@redhat.com>
>         and Michael Snyder  <msnyder@redhat.com>
>         and Alexandre Oliva <aoliva@redhat.com>
>         * config/tc-h8300.c: Add insns and addressing modes for h8300sx.
>         * config/tc-h8300.h: Ditto.

Committed.

> 
>   -------------------------------------------------------------------------------
> /* This file is tc-h8300.h
>    Copyright 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996,
>    1997, 1998, 2000, 2002, 2003
>    Free Software Foundation, Inc.
> 
>    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, 59 Temple Place - Suite 330, Boston, MA
>    02111-1307, USA.  */
> 
> #define TC_H8300
> 
> #define TARGET_BYTES_BIG_ENDIAN 1
> 
> #define TARGET_ARCH bfd_arch_h8300
> 
> #ifdef BFD_ASSEMBLER
> /* Fixup debug sections since we will never relax them.  */
> #define TC_LINKRELAX_FIXUP(seg) (seg->flags & SEC_ALLOC)
> #endif
> #ifdef OBJ_ELF
> #define TARGET_FORMAT "elf32-h8300"
> #define LOCAL_LABEL_PREFIX '.'
> #define LOCAL_LABEL(NAME) (NAME[0] == '.' && NAME[1] == 'L')
> #define FAKE_LABEL_NAME ".L0\001"
> #endif
> 
> #if ANSI_PROTOTYPES
> struct fix;
> struct internal_reloc;
> #endif
> 
> #define WORKING_DOT_WORD
> 
> /* This macro translates between an internal fix and a coff reloc type.  */
> #define TC_COFF_FIX2RTYPE(fixP) abort ();
> 
> #define BFD_ARCH bfd_arch_h8300
> #define COFF_MAGIC ( Smode && Nmode ? 0x8304 : Hmode && Nmode ? 0x8303 : Smode ? 0x8302 : Hmode ? 0x8301 : 0x8300)
> #define TC_COUNT_RELOC(x) (1)
> #define IGNORE_NONSTANDARD_ESCAPES
> 
> #define tc_coff_symbol_emit_hook(a) ; /* not used */
> #define TC_RELOC_MANGLE(s,a,b,c) tc_reloc_mangle(a,b,c)
> extern void tc_reloc_mangle
>   PARAMS ((struct fix *, struct internal_reloc *, bfd_vma));
> 
> /* No shared lib support, so we don't need to ensure externally
>    visible symbols can be overridden.  */
> #define EXTERN_FORCE_RELOC 0
> 
> /* Minimum instruction is of 16 bits.  */
> #define DWARF2_LINE_MIN_INSN_LENGTH 2
> 
> #ifdef OBJ_ELF
> /* Provide mappings from the original H8 COFF relocation names to
>    their corresponding BFD relocation names.  This allows us to use
>    most of tc-h8300.c without modifications for both ELF and COFF
>    ports.  */
> #define R_MOV24B1 BFD_RELOC_H8_DIR24A8
> #define R_MOVL1 BFD_RELOC_H8_DIR32A16
> #define R_MOV24B1 BFD_RELOC_H8_DIR24A8
> #define R_MOVL1 BFD_RELOC_H8_DIR32A16
> #define R_RELLONG BFD_RELOC_32
> #define R_MOV16B1 BFD_RELOC_H8_DIR16A8
> #define R_RELWORD BFD_RELOC_16
> #define R_RELBYTE BFD_RELOC_8
> #define R_PCRWORD BFD_RELOC_16_PCREL
> #define R_PCRBYTE BFD_RELOC_8_PCREL
> #define R_JMPL1 BFD_RELOC_H8_DIR24R8
> #define R_MEM_INDIRECT BFD_RELOC_8
> 
> /* We do not want to adjust any relocations to make implementation of
>    linker relaxations easier.  */
> #define tc_fix_adjustable(FIX) 0
> #endif
> 
> #define TC_CONS_RELOC          (Hmode ? R_RELLONG: R_RELWORD)
> 
> #define DO_NOT_STRIP 0
> #define LISTING_HEADER "Renesas H8/300 GAS "
> #define NEED_FX_R_TYPE 1
> #ifndef OBJ_ELF
> #define RELOC_32 1234
> #endif
> 
> extern int Hmode;
> extern int Smode;
> extern int Nmode;
> extern int SXmode;
> 
> #define md_operand(x)
> 
>   -------------------------------------------------------------------------------
> /* tc-h8300.c -- Assemble code for the Renesas H8/300
>    Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 2000,
>    2001, 2002, 2003 Free Software Foundation, Inc.
> 
>    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, 59 Temple Place - Suite 330, Boston, MA
>    02111-1307, USA.  */
> 
> /* Written By Steve Chamberlain <sac@cygnus.com>.  */
> 
> #include <stdio.h>
> #include "as.h"
> #include "subsegs.h"
> #include "bfd.h"
> 
> #ifdef BFD_ASSEMBLER
> #include "dwarf2dbg.h"
> #endif
> 
> #define DEFINE_TABLE
> #define h8_opcodes ops
> #include "opcode/h8300.h"
> #include "safe-ctype.h"
> 
> #ifdef OBJ_ELF
> #include "elf/h8.h"
> #endif
> 
> const char comment_chars[] = ";";
> const char line_comment_chars[] = "#";
> const char line_separator_chars[] = "";
> 
> void cons        PARAMS ((int));
> void sbranch     PARAMS ((int));
> void h8300hmode  PARAMS ((int));
> void h8300smode  PARAMS ((int));
> void h8300hnmode PARAMS ((int));
> void h8300snmode PARAMS ((int));
> void h8300sxmode PARAMS ((int));
> static void pint PARAMS ((int));
> 
> int Hmode;
> int Smode;
> int Nmode;
> int SXmode;
> 
> #define PSIZE (Hmode ? L_32 : L_16)
> #define DMODE (L_16)
> #define DSYMMODE (Hmode ? L_24 : L_16)
> 
> int bsize = L_8;                /* Default branch displacement.  */
> 
> struct h8_instruction
> {
>   int length;
>   int noperands;
>   int idx;
>   int size;
>   const struct h8_opcode *opcode;
> };
> 
> struct h8_instruction *h8_instructions;
> 
> void
> h8300hmode (arg)
>      int arg ATTRIBUTE_UNUSED;
> {
>   Hmode = 1;
>   Smode = 0;
> #ifdef BFD_ASSEMBLER
>   if (!bfd_set_arch_mach (stdoutput, bfd_arch_h8300, bfd_mach_h8300h))
>     as_warn (_("could not set architecture and machine"));
> #endif
> }
> 
> void
> h8300smode (arg)
>      int arg ATTRIBUTE_UNUSED;
> {
>   Smode = 1;
>   Hmode = 1;
> #ifdef BFD_ASSEMBLER
>   if (!bfd_set_arch_mach (stdoutput, bfd_arch_h8300, bfd_mach_h8300s))
>     as_warn (_("could not set architecture and machine"));
> #endif
> }
> 
> void
> h8300hnmode (arg)
>      int arg ATTRIBUTE_UNUSED;
> {
>   Hmode = 1;
>   Smode = 0;
>   Nmode = 1;
> #ifdef BFD_ASSEMBLER
>   if (!bfd_set_arch_mach (stdoutput, bfd_arch_h8300, bfd_mach_h8300hn))
>     as_warn (_("could not set architecture and machine"));
> #endif
> }
> 
> void
> h8300snmode (arg)
>      int arg ATTRIBUTE_UNUSED;
> {
>   Smode = 1;
>   Hmode = 1;
>   Nmode = 1;
> #ifdef BFD_ASSEMBLER
>   if (!bfd_set_arch_mach (stdoutput, bfd_arch_h8300, bfd_mach_h8300sn))
>     as_warn (_("could not set architecture and machine"));
> #endif
> }
> 
> void
> h8300sxmode (arg)
>      int arg ATTRIBUTE_UNUSED;
> {
>   Smode = 1;
>   Hmode = 1;
>   SXmode = 1;
> #ifdef BFD_ASSEMBLER
>   if (!bfd_set_arch_mach (stdoutput, bfd_arch_h8300, bfd_mach_h8300sx))
>     as_warn (_("could not set architecture and machine"));
> #endif
> }
> 
> void
> sbranch (size)
>      int size;
> {
>   bsize = size;
> }
> 
> static void
> pint (arg)
>      int arg ATTRIBUTE_UNUSED;
> {
>   cons (Hmode ? 4 : 2);
> }
> 
> /* This table describes all the machine specific pseudo-ops the assembler
>    has to support.  The fields are:
>    pseudo-op name without dot
>    function to call to execute this pseudo-op
>    Integer arg to pass to the function.  */
> 
> const pseudo_typeS md_pseudo_table[] =
> {
>   {"h8300h",  h8300hmode,  0},
>   {"h8300hn", h8300hnmode, 0},
>   {"h8300s",  h8300smode,  0},
>   {"h8300sn", h8300snmode, 0},
>   {"h8300sx", h8300sxmode, 0},
>   {"sbranch", sbranch, L_8},
>   {"lbranch", sbranch, L_16},
> 
>   {"int", pint, 0},
>   {"data.b", cons, 1},
>   {"data.w", cons, 2},
>   {"data.l", cons, 4},
>   {"form", listing_psize, 0},
>   {"heading", listing_title, 0},
>   {"import",  s_ignore, 0},
>   {"page",    listing_eject, 0},
>   {"program", s_ignore, 0},
>   {0, 0, 0}
> };
> 
> const int md_reloc_size;
> 
> const char EXP_CHARS[] = "eE";
> 
> /* Chars that mean this number is a floating point constant
>    As in 0f12.456
>    or    0d1.2345e12.  */
> const char FLT_CHARS[] = "rRsSfFdDxXpP";
> 
> static struct hash_control *opcode_hash_control;        /* Opcode mnemonics.  */
> 
> /* This function is called once, at assembler startup time.  This
>    should set up all the tables, etc. that the MD part of the assembler
>    needs.  */
> 
> void
> md_begin ()
> {
>   unsigned int nopcodes;
>   struct h8_opcode *p, *p1;
>   struct h8_instruction *pi;
>   char prev_buffer[100];
>   int idx = 0;
> 
> #ifdef BFD_ASSEMBLER
>   if (!bfd_set_arch_mach (stdoutput, bfd_arch_h8300, bfd_mach_h8300))
>     as_warn (_("could not set architecture and machine"));
> #endif
> 
>   opcode_hash_control = hash_new ();
>   prev_buffer[0] = 0;
> 
>   nopcodes = sizeof (h8_opcodes) / sizeof (struct h8_opcode);
> 
>   h8_instructions = (struct h8_instruction *)
>     xmalloc (nopcodes * sizeof (struct h8_instruction));
> 
>   pi = h8_instructions;
>   p1 = h8_opcodes;
>   /* We do a minimum amount of sorting on the opcode table; this is to
>      make it easy to describe the mova instructions without unnecessary
>      code duplication.
>      Sorting only takes place inside blocks of instructions of the form
>      X/Y, so for example mova/b, mova/w and mova/l can be intermixed.  */
>   while (p1)
>     {
>       struct h8_opcode *first_skipped = 0;
>       int len, cmplen = 0;
>       char *src = p1->name;
>       char *dst, *buffer;
> 
>       if (p1->name == 0)
>         break;
>       /* Strip off any . part when inserting the opcode and only enter
>          unique codes into the hash table.  */
>       dst = buffer = malloc (strlen (src) + 1);
>       while (*src)
>         {
>           if (*src == '.')
>             {
>               src++;
>               break;
>             }
>           if (*src == '/')
>             cmplen = src - p1->name + 1;
>           *dst++ = *src++;
>         }
>       *dst = 0;
>       len = dst - buffer;
>       if (cmplen == 0)
>         cmplen = len;
>       hash_insert (opcode_hash_control, buffer, (char *) pi);
>       strcpy (prev_buffer, buffer);
>       idx++;
> 
>       for (p = p1; p->name; p++)
>         {
>           /* A negative TIME is used to indicate that we've added this opcode
>              already.  */
>           if (p->time == -1)
>             continue;
>           if (strncmp (p->name, buffer, cmplen) != 0
>               || (p->name[cmplen] != '\0' && p->name[cmplen] != '.'
>                   && p->name[cmplen - 1] != '/'))
>             {
>               if (first_skipped == 0)
>                 first_skipped = p;
>               break;
>             }
>           if (strncmp (p->name, buffer, len) != 0)
>             {
>               if (first_skipped == 0)
>                 first_skipped = p;
>               continue;
>             }
> 
>           p->time = -1;
>           pi->size = p->name[len] == '.' ? p->name[len + 1] : 0;
>           pi->idx = idx;
> 
>           /* Find the number of operands.  */
>           pi->noperands = 0;
>           while (pi->noperands < 3 && p->args.nib[pi->noperands] != (op_type) E)
>             pi->noperands++;
> 
>           /* Find the length of the opcode in bytes.  */
>           pi->length = 0;
>           while (p->data.nib[pi->length * 2] != (op_type) E)
>             pi->length++;
> 
>           pi->opcode = p;
>           pi++;
>         }
>       p1 = first_skipped;
>     }
> 
>   /* Add entry for the NULL vector terminator.  */
>   pi->length = 0;
>   pi->noperands = 0;
>   pi->idx = 0;
>   pi->size = 0;
>   pi->opcode = 0;
> 
>   linkrelax = 1;
> }
> 
> struct h8_exp
> {
>   char *e_beg;
>   char *e_end;
>   expressionS e_exp;
> };
> 
> struct h8_op
> {
>   op_type mode;
>   unsigned reg;
>   expressionS exp;
> };
> 
> static void clever_message PARAMS ((const struct h8_instruction *, struct h8_op *));
> static void build_bytes    PARAMS ((const struct h8_instruction *, struct h8_op *));
> static void do_a_fix_imm   PARAMS ((int, int, struct h8_op *, int));
> static void check_operand  PARAMS ((struct h8_op *, unsigned int, char *));
> static const struct h8_instruction * get_specific PARAMS ((const struct h8_instruction *, struct h8_op *, int));
> static char * get_operands PARAMS ((unsigned, char *, struct h8_op *));
> static void   get_operand  PARAMS ((char **, struct h8_op *, int));
> static char * skip_colonthing PARAMS ((char *, expressionS *, int *));
> static char * parse_exp PARAMS ((char *, expressionS *));
> static int    parse_reg PARAMS ((char *, op_type *, unsigned *, int));
> char * colonmod24 PARAMS ((struct h8_op *, char *));
> 
> static int constant_fits_width_p PARAMS ((struct h8_op *, unsigned int));
> static int constant_fits_size_p PARAMS ((struct h8_op *, int, int));
> 
> /*
>   parse operands
>   WREG r0,r1,r2,r3,r4,r5,r6,r7,fp,sp
>   r0l,r0h,..r7l,r7h
>   @WREG
>   @WREG+
>   @-WREG
>   #const
>   ccr
> */
> 
> /* Try to parse a reg name.  Return the number of chars consumed.  */
> 
> static int
> parse_reg (src, mode, reg, direction)
>      char *src;
>      op_type *mode;
>      unsigned int *reg;
>      int direction;
> {
>   char *end;
>   int len;
> 
>   /* Cribbed from get_symbol_end.  */
>   if (!is_name_beginner (*src) || *src == '\001')
>     return 0;
>   end = src + 1;
>   while ((is_part_of_name (*end) && *end != '.') || *end == '\001')
>     end++;
>   len = end - src;
> 
>   if (len == 2 && TOLOWER (src[0]) == 's' && TOLOWER (src[1]) == 'p')
>     {
>       *mode = PSIZE | REG | direction;
>       *reg = 7;
>       return len;
>     }
>   if (len == 3 &&
>       TOLOWER (src[0]) == 'c' &&
>       TOLOWER (src[1]) == 'c' &&
>       TOLOWER (src[2]) == 'r')
>     {
>       *mode = CCR;
>       *reg = 0;
>       return len;
>     }
>   if (len == 3 &&
>       TOLOWER (src[0]) == 'e' &&
>       TOLOWER (src[1]) == 'x' &&
>       TOLOWER (src[2]) == 'r')
>     {
>       *mode = EXR;
>       *reg = 1;
>       return len;
>     }
>   if (len == 3 &&
>       TOLOWER (src[0]) == 'v' &&
>       TOLOWER (src[1]) == 'b' &&
>       TOLOWER (src[2]) == 'r')
>     {
>       *mode = VBR;
>       *reg = 6;
>       return len;
>     }
>   if (len == 3 &&
>       TOLOWER (src[0]) == 's' &&
>       TOLOWER (src[1]) == 'b' &&
>       TOLOWER (src[2]) == 'r')
>     {
>       *mode = SBR;
>       *reg = 7;
>       return len;
>     }
>   if (len == 2 && TOLOWER (src[0]) == 'f' && TOLOWER (src[1]) == 'p')
>     {
>       *mode = PSIZE | REG | direction;
>       *reg = 6;
>       return len;
>     }
>   if (len == 3 && TOLOWER (src[0]) == 'e' && TOLOWER (src[1]) == 'r' &&
>       src[2] >= '0' && src[2] <= '7')
>     {
>       *mode = L_32 | REG | direction;
>       *reg = src[2] - '0';
>       if (!Hmode)
>         as_warn (_("Reg not valid for H8/300"));
>       return len;
>     }
>   if (len == 2 && TOLOWER (src[0]) == 'e' && src[1] >= '0' && src[1] <= '7')
>     {
>       *mode = L_16 | REG | direction;
>       *reg = src[1] - '0' + 8;
>       if (!Hmode)
>         as_warn (_("Reg not valid for H8/300"));
>       return len;
>     }
> 
>   if (TOLOWER (src[0]) == 'r')
>     {
>       if (src[1] >= '0' && src[1] <= '7')
>         {
>           if (len == 3 && TOLOWER (src[2]) == 'l')
>             {
>               *mode = L_8 | REG | direction;
>               *reg = (src[1] - '0') + 8;
>               return len;
>             }
>           if (len == 3 && TOLOWER (src[2]) == 'h')
>             {
>               *mode = L_8 | REG | direction;
>               *reg = (src[1] - '0');
>               return len;
>             }
>           if (len == 2)
>             {
>               *mode = L_16 | REG | direction;
>               *reg = (src[1] - '0');
>               return len;
>             }
>         }
>     }
> 
>   return 0;
> }
> 
> static char *
> parse_exp (s, op)
>      char *s;
>      expressionS *op;
> {
>   char *save = input_line_pointer;
>   char *new;
> 
>   input_line_pointer = s;
>   expression (op);
>   if (op->X_op == O_absent)
>     as_bad (_("missing operand"));
>   new = input_line_pointer;
>   input_line_pointer = save;
>   return new;
> }
> 
> static char *
> skip_colonthing (ptr, exp, mode)
>      char *ptr;
>      expressionS *exp ATTRIBUTE_UNUSED;
>      int *mode;
> {
>   if (*ptr == ':')
>     {
>       ptr++;
>       *mode &= ~SIZE;
>       if (ptr[0] == '8' && ! ISDIGIT (ptr[1]))
>         *mode |= L_8;
>       else if (ptr[0] == '2' && ! ISDIGIT (ptr[1]))
>         *mode |= L_2;
>       else if (ptr[0] == '3' && ! ISDIGIT (ptr[1]))
>         *mode |= L_3;
>       else if (ptr[0] == '4' && ! ISDIGIT (ptr[1]))
>         *mode |= L_4;
>       else if (ptr[0] == '5' && ! ISDIGIT (ptr[1]))
>         *mode |= L_5;
>       else if (ptr[0] == '2' && ptr[1] == '4')
>         *mode |= L_24;
>       else if (ptr[0] == '3' && ptr[1] == '2')
>         *mode |= L_32;
>       else if (ptr[0] == '1' && ptr[1] == '6')
>         *mode |= L_16;
>       else
>         as_bad (_("invalid operand size requested"));
> 
>       while (ISDIGIT (*ptr))
>         ptr++;
>     }
>   return ptr;
> }
> 
> /* The many forms of operand:
> 
>    Rn                   Register direct
>    @Rn                  Register indirect
>    @(exp[:16], Rn)      Register indirect with displacement
>    @Rn+
>    @-Rn
>    @aa:8                absolute 8 bit
>    @aa:16               absolute 16 bit
>    @aa                  absolute 16 bit
> 
>    #xx[:size]           immediate data
>    @(exp:[8], pc)       pc rel
>    @@aa[:8]             memory indirect.  */
> 
> char *
> colonmod24 (op, src)
>      struct h8_op *op;
>      char *src;
> {
>   int mode = 0;
>   src = skip_colonthing (src, &op->exp, &mode);
> 
>   if (!mode)
>     {
>       /* Choose a default mode.  */
>       if (op->exp.X_add_number < -32768
>           || op->exp.X_add_number > 32767)
>         {
>           if (Hmode)
>             mode = L_24;
>           else
>             mode = L_16;
>         }
>       else if (op->exp.X_add_symbol
>                || op->exp.X_op_symbol)
>         mode = DSYMMODE;
>       else
>         mode = DMODE;
>     }
> 
>   op->mode |= mode;
>   return src;
> }
> 
> static int
> constant_fits_width_p (operand, width)
>      struct h8_op *operand;
>      unsigned int width;
> {
>   return ((operand->exp.X_add_number & ~width) == 0
>           || (operand->exp.X_add_number | width) == (unsigned)(~0));
> }
> 
> static int
> constant_fits_size_p (operand, size, no_symbols)
>      struct h8_op *operand;
>      int size, no_symbols;
> {
>   offsetT num = operand->exp.X_add_number;
>   if (no_symbols
>       && (operand->exp.X_add_symbol != 0 || operand->exp.X_op_symbol != 0))
>     return 0;
>   switch (size)
>     {
>     case L_2:
>       return (num & ~3) == 0;
>     case L_3:
>       return (num & ~7) == 0;
>     case L_3NZ:
>       return num >= 1 && num < 8;
>     case L_4:
>       return (num & ~15) == 0;
>     case L_5:
>       return num >= 1 && num < 32;
>     case L_8:
>       return (num & ~0xFF) == 0 || ((unsigned)num | 0x7F) == ~0u;
>     case L_8U:
>       return (num & ~0xFF) == 0;
>     case L_16:
>       return (num & ~0xFFFF) == 0 || ((unsigned)num | 0x7FFF) == ~0u;
>     case L_16U:
>       return (num & ~0xFFFF) == 0;
>     case L_32:
>       return 1;
>     default:
>       abort ();
>     }
> }
> 
> static void
> get_operand (ptr, op, direction)
>      char **ptr;
>      struct h8_op *op;
>      int direction;
> {
>   char *src = *ptr;
>   op_type mode;
>   unsigned int num;
>   unsigned int len;
> 
>   op->mode = 0;
> 
>   /* Check for '(' and ')' for instructions ldm and stm.  */
>   if (src[0] == '(' && src[8] == ')')
>     ++ src;
> 
>   /* Gross.  Gross.  ldm and stm have a format not easily handled
>      by get_operand.  We deal with it explicitly here.  */
>   if (TOLOWER (src[0]) == 'e' && TOLOWER (src[1]) == 'r' &&
>       ISDIGIT (src[2]) && src[3] == '-' &&
>       TOLOWER (src[4]) == 'e' && TOLOWER (src[5]) == 'r' && ISDIGIT (src[6]))
>     {
>       int low, high;
> 
>       low = src[2] - '0';
>       high = src[6] - '0';
> 
>       if (high == low)
>         as_bad (_("Invalid register list for ldm/stm\n"));
> 
>       if (high < low)
>         as_bad (_("Invalid register list for ldm/stm\n"));
> 
>       if (high - low > 3)
>         as_bad (_("Invalid register list for ldm/stm)\n"));
> 
>       /* Even sicker.  We encode two registers into op->reg.  One
>          for the low register to save, the other for the high
>          register to save;  we also set the high bit in op->reg
>          so we know this is "very special".  */
>       op->reg = 0x80000000 | (high << 8) | low;
>       op->mode = REG;
>       if (src[7] == ')')
>         *ptr = src + 8;
>       else
>         *ptr = src + 7;
>       return;
>     }
> 
>   len = parse_reg (src, &op->mode, &op->reg, direction);
>   if (len)
>     {
>       src += len;
>       if (*src == '.')
>         {
>           int size = op->mode & SIZE;
>           switch (src[1])
>             {
>             case 'l': case 'L':
>               if (size != L_32)
>                 as_warn (_("mismatch between register and suffix"));
>               op->mode = (op->mode & ~MODE) | LOWREG;
>               break;
>             case 'w': case 'W':
>               if (size != L_32 && size != L_16)
>                 as_warn (_("mismatch between register and suffix"));
>               op->mode = (op->mode & ~MODE) | LOWREG;
>               op->mode = (op->mode & ~SIZE) | L_16;
>               break;
>             case 'b': case 'B':
>               op->mode = (op->mode & ~MODE) | LOWREG;
>               if (size != L_32 && size != L_8)
>                 as_warn (_("mismatch between register and suffix"));
>               op->mode = (op->mode & ~MODE) | LOWREG;
>               op->mode = (op->mode & ~SIZE) | L_8;
>               break;
>             default:
>               as_warn ("invalid suffix after register.");
>               break;
>             }
>           src += 2;
>         }
>       *ptr = src;
>       return;
>     }
> 
>   if (*src == '@')
>     {
>       src++;
>       if (*src == '@')
>         {
>           src++;
>           src = parse_exp (src, &op->exp);
> 
>           src = skip_colonthing (src, &op->exp, &op->mode);
> 
>           *ptr = src;
> 
>           if (op->exp.X_add_number >= 0x100)
>             {
>               int divisor;
> 
>               op->mode = VECIND;
>               /* FIXME : 2?  or 4?  */
>               if (op->exp.X_add_number >= 0x400)
>                 as_bad (_("address too high for vector table jmp/jsr"));
>               else if (op->exp.X_add_number >= 0x200)
>                 divisor = 4;
>               else
>                 divisor = 2;
> 
>               op->exp.X_add_number = op->exp.X_add_number / divisor - 0x80;
>             }
>           else
>             op->mode = MEMIND;
> 
>           return;
>         }
> 
>       if (*src == '-' || *src == '+')
>         {
>           char c = *src;
>           src++;
>           len = parse_reg (src, &mode, &num, direction);
>           if (len == 0)
>             {
>               /* Oops, not a reg after all, must be ordinary exp.  */
>               src--;
>               /* Must be a symbol.  */
>               op->mode = ABS | PSIZE | direction;
>               *ptr = skip_colonthing (parse_exp (src, &op->exp),
>                                       &op->exp, &op->mode);
> 
>               return;
>             }
> 
>           if ((mode & SIZE) != PSIZE)
>             as_bad (_("Wrong size pointer register for architecture."));
>           op->mode = c == '-' ? RDPREDEC : RDPREINC;
>           op->reg = num;
>           *ptr = src + len;
>           return;
>         }
>       if (*src == '(')
>         {
>           src++;
> 
>           /* See if this is @(ERn.x, PC).  */
>           len = parse_reg (src, &mode, &op->reg, direction);
>           if (len != 0 && (mode & MODE) == REG && src[len] == '.')
>             {
>               switch (TOLOWER (src[len + 1]))
>                 {
>                 case 'b':
>                   mode = PCIDXB | direction;
>                   break;
>                 case 'w':
>                   mode = PCIDXW | direction;
>                   break;
>                 case 'l':
>                   mode = PCIDXL | direction;
>                   break;
>                 default:
>                   mode = 0;
>                   break;
>                 }
>               if (mode
>                   && src[len + 2] == ','
>                   && TOLOWER (src[len + 3]) != 'p'
>                   && TOLOWER (src[len + 4]) != 'c'
>                   && src[len + 5] != ')')
>                 {
>                   *ptr = src + len + 6;
>                   op->mode |= mode;
>                   return;
>                 }
>               /* Fall through into disp case - the grammar is somewhat
>                  ambiguous, so we should try whether it's a DISP operand
>                  after all ("ER3.L" might be a poorly named label...).  */
>             }
> 
>           /* Disp.  */
> 
>           /* Start off assuming a 16 bit offset.  */
> 
>           src = parse_exp (src, &op->exp);
> 
>           src = colonmod24 (op, src);
> 
>           if (*src == ')')
>             {
>               src++;
>               op->mode |= ABS | direction;
>               *ptr = src;
>               return;
>             }
> 
>           if (*src != ',')
>             {
>               as_bad (_("expected @(exp, reg16)"));
>               return;
> 
>             }
>           src++;
> 
>           len = parse_reg (src, &mode, &op->reg, direction);
>           if (len == 0 || (mode & MODE) != REG)
>             {
>               as_bad (_("expected @(exp, reg16)"));
>               return;
>             }
>           src += len;
>           if (src[0] == '.')
>             {
>               switch (TOLOWER (src[1]))
>                 {
>                 case 'b':
>                   op->mode |= INDEXB | direction;
>                   break;
>                 case 'w':
>                   op->mode |= INDEXW | direction;
>                   break;
>                 case 'l':
>                   op->mode |= INDEXL | direction;
>                   break;
>                 default:
>                   as_bad (_("expected .L, .W or .B for register in indexed addressing mode"));
>                 }
>               src += 2;
>               op->reg &= 7;
>             }
>           else
>             op->mode |= DISP | direction;
>           src = skip_colonthing (src, &op->exp, &op->mode);
> 
>           if (*src != ')' && '(')
>             {
>               as_bad (_("expected @(exp, reg16)"));
>               return;
>             }
>           *ptr = src + 1;
> 
>           return;
>         }
>       len = parse_reg (src, &mode, &num, direction);
> 
>       if (len)
>         {
>           src += len;
>           if (*src == '+' || *src == '-')
>             {
>               if ((mode & SIZE) != PSIZE)
>                 as_bad (_("Wrong size pointer register for architecture."));
>               op->mode = *src == '+' ? RSPOSTINC : RSPOSTDEC;
>               op->reg = num;
>               src++;
>               *ptr = src;
>               return;
>             }
>           if ((mode & SIZE) != PSIZE)
>             as_bad (_("Wrong size pointer register for architecture."));
> 
>           op->mode = direction | IND | PSIZE;
>           op->reg = num;
>           *ptr = src;
> 
>           return;
>         }
>       else
>         {
>           /* must be a symbol */
> 
>           op->mode = ABS | direction;
>           src = parse_exp (src, &op->exp);
> 
>           *ptr = colonmod24 (op, src);
> 
>           return;
>         }
>     }
> 
>   if (*src == '#')
>     {
>       src++;
>       op->mode = IMM;
>       src = parse_exp (src, &op->exp);
>       *ptr = skip_colonthing (src, &op->exp, &op->mode);
> 
>       return;
>     }
>   else if (strncmp (src, "mach", 4) == 0 ||
>            strncmp (src, "macl", 4) == 0 ||
>            strncmp (src, "MACH", 4) == 0 ||
>            strncmp (src, "MACL", 4) == 0)
>     {
>       op->reg = TOLOWER (src[3]) == 'l';
>       op->mode = MACREG;
>       *ptr = src + 4;
>       return;
>     }
>   else
>     {
>       src = parse_exp (src, &op->exp);
>       /* Trailing ':' size ? */
>       if (*src == ':')
>         {
>           if (src[1] == '1' && src[2] == '6')
>             {
>               op->mode = PCREL | L_16;
>               src += 3;
>             }
>           else if (src[1] == '8')
>             {
>               op->mode = PCREL | L_8;
>               src += 2;
>             }
>           else
>             as_bad (_("expect :8 or :16 here"));
>         }
>       else
>         {
>           int val = op->exp.X_add_number;
> 
>           op->mode = PCREL;
>           if (-128 < val && val < 127)
>             op->mode |= L_8;
>           else
>             op->mode |= L_16;
>         }
> 
>       *ptr = src;
>     }
> }
> 
> static char *
> get_operands (noperands, op_end, operand)
>      unsigned int noperands;
>      char *op_end;
>      struct h8_op *operand;
> {
>   char *ptr = op_end;
> 
>   switch (noperands)
>     {
>     case 0:
>       break;
> 
>     case 1:
>       ptr++;
>       get_operand (&ptr, operand + 0, SRC);
>       if (*ptr == ',')
>         {
>           ptr++;
>           get_operand (&ptr, operand + 1, DST);
>         }
>       break;
> 
>     case 2:
>       ptr++;
>       get_operand (&ptr, operand + 0, SRC);
>       if (*ptr == ',')
>         ptr++;
>       get_operand (&ptr, operand + 1, DST);
>       break;
> 
>     case 3:
>       ptr++;
>       get_operand (&ptr, operand + 0, SRC);
>       if (*ptr == ',')
>         ptr++;
>       get_operand (&ptr, operand + 1, DST);
>       if (*ptr == ',')
>         ptr++;
>       get_operand (&ptr, operand + 2, OP3);
>       break;
> 
>     default:
>       abort ();
>     }
> 
>   return ptr;
> }
> 
> /* MOVA has special requirements.  Rather than adding twice the amount of
>    addressing modes, we simply special case it a bit.  */
> static void
> get_mova_operands (char *op_end, struct h8_op *operand)
> {
>   char *ptr = op_end;
> 
>   if (ptr[1] != '@' || ptr[2] != '(')
>     goto error;
>   ptr += 3;
>   operand[0].mode = 0;
>   ptr = parse_exp (ptr, &operand[0].exp);
>   ptr = colonmod24 (operand + 0, ptr);
> 
>   if (*ptr !=',')
>     goto error;
>   ptr++;
>   get_operand (&ptr, operand + 1, DST);
> 
>   if (*ptr =='.')
>     {
>       ptr++;
>       switch (*ptr++)
>         {
>         case 'b': case 'B':
>           operand[0].mode = (operand[0].mode & ~MODE) | INDEXB;
>           break;
>         case 'w': case 'W':
>           operand[0].mode = (operand[0].mode & ~MODE) | INDEXW;
>           break;
>         case 'l': case 'L':
>           operand[0].mode = (operand[0].mode & ~MODE) | INDEXL;
>           break;
>         default:
>           goto error;
>         }
>     }
>   else if ((operand[1].mode & MODE) == LOWREG)
>     {
>       switch (operand[1].mode & SIZE)
>         {
>         case L_8:
>           operand[0].mode = (operand[0].mode & ~MODE) | INDEXB;
>           break;
>         case L_16:
>           operand[0].mode = (operand[0].mode & ~MODE) | INDEXW;
>           break;
>         case L_32:
>           operand[0].mode = (operand[0].mode & ~MODE) | INDEXL;
>           break;
>         default:
>           goto error;
>         }
>     }
>   else
>     goto error;
> 
>   if (*ptr++ != ')' || *ptr++ != ',')
>     goto error;
>   get_operand (&ptr, operand + 2, OP3);
>   /* See if we can use the short form of MOVA.  */
>   if (((operand[1].mode & MODE) == REG || (operand[1].mode & MODE) == LOWREG)
>       && (operand[2].mode & MODE) == REG
>       && (operand[1].reg & 7) == (operand[2].reg & 7))
>     {
>       operand[1].mode = operand[2].mode = 0;
>       operand[0].reg = operand[2].reg & 7;
>     }
>   return;
> 
>  error:
>   as_bad (_("expected valid addressing mode for mova: \"@(disp, ea.sz),ERn\""));
>   return;
> }
> 
> static void
> get_rtsl_operands (char *ptr, struct h8_op *operand)
> {
>   int mode, num, num2, len, type = 0;
> 
>   ptr++;
>   if (*ptr == '(')
>     {
>       ptr++;
>       type = 1;
>     }
>   len = parse_reg (ptr, &mode, &num, SRC);
>   if (len == 0 || (mode & MODE) != REG)
>     {
>       as_bad (_("expected register"));
>       return;
>     }
>   if (type == 1)
>     {
>       ptr += len;
>       if (*ptr++ != '-')
>         {
>           as_bad (_("expected register list"));
>           return;
>         }
>       len = parse_reg (ptr, &mode, &num2, SRC);
>       if (len == 0 || (mode & MODE) != REG)
>         {
>           as_bad (_("expected register"));
>           return;
>         }
>       ptr += len;
>       if (*ptr++ != ')')
>         {
>           as_bad (_("expected closing paren"));
>           return;
>         }
>       /* CONST_xxx are used as placeholders in the opcode table.  */
>       num = num2 - num;
>       if (num < 1 || num > 3)
>         {
>           as_bad (_("invalid register list"));
>           return;
>         }
>     }
>   else
>     num2 = num, num = 0;
>   operand[0].mode = RS32;
>   operand[1].mode = RD32;
>   operand[0].reg = num;
>   operand[1].reg = num2;
> }
> 
> /* Passed a pointer to a list of opcodes which use different
>    addressing modes, return the opcode which matches the opcodes
>    provided.  */
> 
> static const struct h8_instruction *
> get_specific (instruction, operands, size)
>      const struct h8_instruction *instruction;
>      struct h8_op *operands;
>      int size;
> {
>   const struct h8_instruction *this_try = instruction;
>   const struct h8_instruction *found_other = 0, *found_mismatched = 0;
>   int found = 0;
>   int this_index = instruction->idx;
>   int noperands = 0;
> 
>   /* There's only one ldm/stm and it's easier to just
>      get out quick for them.  */
>   if (OP_KIND (instruction->opcode->how) == O_LDM
>       || OP_KIND (instruction->opcode->how) == O_STM)
>     return this_try;
> 
>   while (noperands < 3 && operands[noperands].mode != 0)
>     noperands++;
> 
>   while (this_index == instruction->idx && !found)
>     {
>       int this_size;
> 
>       found = 1;
>       this_try = instruction++;
>       this_size = this_try->opcode->how & SN;
> 
>       if (this_try->noperands != noperands)
>         found = 0;
>       else if (this_try->noperands > 0)
>         {
>           int i;
> 
>           for (i = 0; i < this_try->noperands && found; i++)
>             {
>               op_type op = this_try->opcode->args.nib[i];
>               int op_mode = op & MODE;
>               int op_size = op & SIZE;
>               int x = operands[i].mode;
>               int x_mode = x & MODE;
>               int x_size = x & SIZE;
> 
>               if (op_mode == LOWREG && (x_mode == REG || x_mode == LOWREG))
>                 {
>                   if ((x_size == L_8 && (operands[i].reg & 8) == 0)
>                       || (x_size == L_16 && (operands[i].reg & 8) == 8))
>                     as_warn (_("can't use high part of register in operand %d"), i);
> 
>                   if (x_size != op_size)
>                     found = 0;
>                 }
>               else if (op_mode == REG)
>                 {
>                   if (x_mode == LOWREG)
>                     x_mode = REG;
>                   if (x_mode != REG)
>                     found = 0;
> 
>                   if (x_size == L_P)
>                     x_size = (Hmode ? L_32 : L_16);
>                   if (op_size == L_P)
>                     op_size = (Hmode ? L_32 : L_16);
> 
>                   /* The size of the reg is v important.  */
>                   if (op_size != x_size)
>                     found = 0;
>                 }
>               else if (op_mode & CTRL)  /* control register */
>                 {
>                   if (!(x_mode & CTRL))
>                     found = 0;
> 
>                   switch (x_mode)
>                     {
>                     case CCR:
>                       if (op_mode != CCR &&
>                           op_mode != CCR_EXR &&
>                           op_mode != CC_EX_VB_SB)
>                         found = 0;
>                       break;
>                     case EXR:
>                       if (op_mode != EXR &&
>                           op_mode != CCR_EXR &&
>                           op_mode != CC_EX_VB_SB)
>                         found = 0;
>                       break;
>                     case MACH:
>                       if (op_mode != MACH &&
>                           op_mode != MACREG)
>                         found = 0;
>                       break;
>                     case MACL:
>                       if (op_mode != MACL &&
>                           op_mode != MACREG)
>                         found = 0;
>                       break;
>                     case VBR:
>                       if (op_mode != VBR &&
>                           op_mode != VBR_SBR &&
>                           op_mode != CC_EX_VB_SB)
>                         found = 0;
>                       break;
>                     case SBR:
>                       if (op_mode != SBR &&
>                           op_mode != VBR_SBR &&
>                           op_mode != CC_EX_VB_SB)
>                         found = 0;
>                       break;
>                     }
>                 }
>               else if ((op & ABSJMP) && (x_mode == ABS || x_mode == PCREL))
>                 {
>                   operands[i].mode &= ~MODE;
>                   operands[i].mode |= ABSJMP;
>                   /* But it may not be 24 bits long.  */
>                   if (x_mode == ABS && !Hmode)
>                     {
>                       operands[i].mode &= ~SIZE;
>                       operands[i].mode |= L_16;
>                     }
>                   if ((operands[i].mode & SIZE) == L_32
>                       && (op_mode & SIZE) != L_32)
>                    found = 0;
>                 }
>               else if (x_mode == IMM && op_mode != IMM)
>                 {
>                   offsetT num = operands[i].exp.X_add_number;
>                   if (op_mode == KBIT || op_mode == DBIT)
>                     /* This is ok if the immediate value is sensible.  */;
>                   else if (op_mode == CONST_2)
>                     found = num == 2;
>                   else if (op_mode == CONST_4)
>                     found = num == 4;
>                   else if (op_mode == CONST_8)
>                     found = num == 8;
>                   else if (op_mode == CONST_16)
>                     found = num == 16;
>                   else
>                     found = 0;
>                 }
>               else if (op_mode == PCREL && op_mode == x_mode)
>                 {
>                   /* movsd only comes in PCREL16 flavour:
>                      If x_size is L_8, promote it.  */
>                   if (OP_KIND (this_try->opcode->how) == O_MOVSD)
>                     if (x_size == L_8)
>                       x_size = L_16;
> 
>                   /* The size of the displacement is important.  */
>                   if (op_size != x_size)
>                     found = 0;
>                 }
>               else if ((op_mode == DISP || op_mode == IMM || op_mode == ABS
>                         || op_mode == INDEXB || op_mode == INDEXW
>                         || op_mode == INDEXL)
>                        && op_mode == x_mode)
>                 {
>                   /* Promote a L_24 to L_32 if it makes us match.  */
>                   if (x_size == L_24 && op_size == L_32)
>                     {
>                       x &= ~SIZE;
>                       x |= x_size = L_32;
>                     }
> 
> #if 0 /* ??? */
>                   /* Promote an L8 to L_16 if it makes us match.  */
>                   if ((op_mode == ABS || op_mode == DISP) && x_size == L_8)
>                     {
>                       if (op_size == L_16)
>                         x_size = L_16;
>                     }
> #endif
> 
>                   if (((x_size == L_16 && op_size == L_16U)
>                        || (x_size == L_3 && op_size == L_3NZ))
>                       /* We're deliberately more permissive for ABS modes.  */
>                       && (op_mode == ABS
>                           || constant_fits_size_p (operands + i, op_size,
>                                                    op & NO_SYMBOLS)))
>                     x_size = op_size;
> 
>                   if (x_size != 0 && op_size != x_size)
>                     found = 0;
>                   else if (x_size == 0
>                            && ! constant_fits_size_p (operands + i, op_size,
>                                                       op & NO_SYMBOLS))
>                     found = 0;
>                 }
>               else if (op_mode != x_mode)
>                 {
>                   found = 0;
>                 }
>             }
>         }
>       if (found)
>         {
>           if ((this_try->opcode->available == AV_H8SX && ! SXmode)
>               || (this_try->opcode->available == AV_H8H && ! Hmode))
>             found = 0, found_other = this_try;
>           else if (this_size != size && (this_size != SN && size != SN))
>             found_mismatched = this_try, found = 0;
> 
>         }
>     }
>   if (found)
>     return this_try;
>   if (found_other)
>     {
>       as_warn (_("Opcode `%s' with these operand types not available in %s mode"),
>                found_other->opcode->name,
>                (! Hmode && ! Smode ? "H8/300"
>                 : SXmode ? "H8sx"
>                 : Smode ? "H8/300S"
>                 : "H8/300H"));
>     }
>   else if (found_mismatched)
>     {
>       as_warn (_("mismatch between opcode size and operand size"));
>       return found_mismatched;
>     }
>   return 0;
> }
> 
> static void
> check_operand (operand, width, string)
>      struct h8_op *operand;
>      unsigned int width;
>      char *string;
> {
>   if (operand->exp.X_add_symbol == 0
>       && operand->exp.X_op_symbol == 0)
>     {
>       /* No symbol involved, let's look at offset, it's dangerous if
>          any of the high bits are not 0 or ff's, find out by oring or
>          anding with the width and seeing if the answer is 0 or all
>          fs.  */
> 
>       if (! constant_fits_width_p (operand, width))
>         {
>           if (width == 255
>               && (operand->exp.X_add_number & 0xff00) == 0xff00)
>             {
>               /* Just ignore this one - which happens when trying to
>                  fit a 16 bit address truncated into an 8 bit address
>                  of something like bset.  */
>             }
>           else if (strcmp (string, "@") == 0
>                    && width == 0xffff
>                    && (operand->exp.X_add_number & 0xff8000) == 0xff8000)
>             {
>               /* Just ignore this one - which happens when trying to
>                  fit a 24 bit address truncated into a 16 bit address
>                  of something like mov.w.  */
>             }
>           else
>             {
>               as_warn (_("operand %s0x%lx out of range."), string,
>                        (unsigned long) operand->exp.X_add_number);
>             }
>         }
>     }
> }
> 
> /* RELAXMODE has one of 3 values:
> 
>    0 Output a "normal" reloc, no relaxing possible for this insn/reloc
> 
>    1 Output a relaxable 24bit absolute mov.w address relocation
>      (may relax into a 16bit absolute address).
> 
>    2 Output a relaxable 16/24 absolute mov.b address relocation
>      (may relax into an 8bit absolute address).  */
> 
> static void
> do_a_fix_imm (offset, nibble, operand, relaxmode)
>      int offset, nibble;
>      struct h8_op *operand;
>      int relaxmode;
> {
>   int idx;
>   int size;
>   int where;
>   char *bytes = frag_now->fr_literal + offset;
> 
>   char *t = ((operand->mode & MODE) == IMM) ? "#" : "@";
> 
>   if (operand->exp.X_add_symbol == 0)
>     {
>       switch (operand->mode & SIZE)
>         {
>         case L_2:
>           check_operand (operand, 0x3, t);
>           bytes[0] |= (operand->exp.X_add_number & 3) << (nibble ? 0 : 4);
>           break;
>         case L_3:
>         case L_3NZ:
>           check_operand (operand, 0x7, t);
>           bytes[0] |= (operand->exp.X_add_number & 7) << (nibble ? 0 : 4);
>           break;
>         case L_4:
>           check_operand (operand, 0xF, t);
>           bytes[0] |= (operand->exp.X_add_number & 15) << (nibble ? 0 : 4);
>           break;
>         case L_5:
>           check_operand (operand, 0x1F, t);
>           bytes[0] |= operand->exp.X_add_number & 31;
>           break;
>         case L_8:
>         case L_8U:
>           check_operand (operand, 0xff, t);
>           bytes[0] |= operand->exp.X_add_number;
>           break;
>         case L_16:
>         case L_16U:
>           check_operand (operand, 0xffff, t);
>           bytes[0] |= operand->exp.X_add_number >> 8;
>           bytes[1] |= operand->exp.X_add_number >> 0;
>           break;
>         case L_24:
>           check_operand (operand, 0xffffff, t);
>           bytes[0] |= operand->exp.X_add_number >> 16;
>           bytes[1] |= operand->exp.X_add_number >> 8;
>           bytes[2] |= operand->exp.X_add_number >> 0;
>           break;
> 
>         case L_32:
>           /* This should be done with bfd.  */
>           bytes[0] |= operand->exp.X_add_number >> 24;
>           bytes[1] |= operand->exp.X_add_number >> 16;
>           bytes[2] |= operand->exp.X_add_number >> 8;
>           bytes[3] |= operand->exp.X_add_number >> 0;
>           if (relaxmode != 0)
>             {
>               idx = (relaxmode == 2) ? R_MOV24B1 : R_MOVL1;
>               fix_new_exp (frag_now, offset, 4, &operand->exp, 0, idx);
>             }
>           break;
>         }
>     }
>   else
>     {
>       switch (operand->mode & SIZE)
>         {
>         case L_24:
>         case L_32:
>           size = 4;
>           where = (operand->mode & SIZE) == L_24 ? -1 : 0;
>           if (relaxmode == 2)
>             idx = R_MOV24B1;
>           else if (relaxmode == 1)
>             idx = R_MOVL1;
>           else
>             idx = R_RELLONG;
>           break;
>         default:
>           as_bad (_("Can't work out size of operand.\n"));
>         case L_16:
>         case L_16U:
>           size = 2;
>           where = 0;
>           if (relaxmode == 2)
>             idx = R_MOV16B1;
>           else
>             idx = R_RELWORD;
>           operand->exp.X_add_number =
>             ((operand->exp.X_add_number & 0xffff) ^ 0x8000) - 0x8000;
>           operand->exp.X_add_number |= (bytes[0] << 8) | bytes[1];
>           break;
>         case L_8:
>           size = 1;
>           where = 0;
>           idx = R_RELBYTE;
>           operand->exp.X_add_number =
>             ((operand->exp.X_add_number & 0xff) ^ 0x80) - 0x80;
>           operand->exp.X_add_number |= bytes[0];
>         }
> 
>       fix_new_exp (frag_now,
>                    offset + where,
>                    size,
>                    &operand->exp,
>                    0,
>                    idx);
>     }
> }
> 
> /* Now we know what sort of opcodes it is, let's build the bytes.  */
> 
> static void
> build_bytes (this_try, operand)
>      const struct h8_instruction *this_try;
>      struct h8_op *operand;
> {
>   int i;
>   char *output = frag_more (this_try->length);
>   op_type *nibble_ptr = this_try->opcode->data.nib;
>   op_type c;
>   unsigned int nibble_count = 0;
>   int op_at[3];
>   int nib = 0;
>   int movb = 0;
>   char asnibbles[100];
>   char *p = asnibbles;
>   int high, low;
> 
>   if (!(this_try->opcode->available == AV_H8 || Hmode))
>     as_warn (_("Opcode `%s' with these operand types not available in H8/300 mode"),
>              this_try->opcode->name);
> 
>   while (*nibble_ptr != (op_type) E)
>     {
>       int d;
> 
>       nib = 0;
>       c = *nibble_ptr++;
> 
>       d = (c & OP3) == OP3 ? 2 : (c & DST) == DST ? 1 : 0;
> 
>       if (c < 16)
>         nib = c;
>       else
>         {
>           int c2 = c & MODE;
> 
>           if (c2 == REG || c2 == LOWREG
>               || c2 == IND || c2 == PREINC || c2 == PREDEC
>               || c2 == POSTINC || c2 == POSTDEC)
>             {
>               nib = operand[d].reg;
>               if (c2 == LOWREG)
>                 nib &= 7;
>             }
> 
>           else if (c & CTRL)    /* Control reg operand.  */
>             nib = operand[d].reg;
> 
>           else if ((c & DISPREG) == (DISPREG))
>             {
>               nib = operand[d].reg;
>             }
>           else if (c2 == ABS)
>             {
>               operand[d].mode = c;
>               op_at[d] = nibble_count;
>               nib = 0;
>             }
>           else if (c2 == IMM || c2 == PCREL || c2 == ABS
>                    || (c & ABSJMP) || c2 == DISP)
>             {
>               operand[d].mode = c;
>               op_at[d] = nibble_count;
>               nib = 0;
>             }
>           else if ((c & IGNORE) || (c & DATA))
>             nib = 0;
> 
>           else if (c2 == DBIT)
>             {
>               switch (operand[0].exp.X_add_number)
>                 {
>                 case 1:
>                   nib = c;
>                   break;
>                 case 2:
>                   nib = 0x8 | c;
>                   break;
>                 default:
>                   as_bad (_("Need #1 or #2 here"));
>                 }
>             }
>           else if (c2 == KBIT)
>             {
>               switch (operand[0].exp.X_add_number)
>                 {
>                 case 1:
>                   nib = 0;
>                   break;
>                 case 2:
>                   nib = 8;
>                   break;
>                 case 4:
>                   if (!Hmode)
>                     as_warn (_("#4 not valid on H8/300."));
>                   nib = 9;
>                   break;
> 
>                 default:
>                   as_bad (_("Need #1 or #2 here"));
>                   break;
>                 }
>               /* Stop it making a fix.  */
>               operand[0].mode = 0;
>             }
> 
>           if (c & MEMRELAX)
>             operand[d].mode |= MEMRELAX;
> 
>           if (c & B31)
>             nib |= 0x8;
> 
>           if (c & B21)
>             nib |= 0x4;
> 
>           if (c & B11)
>             nib |= 0x2;
> 
>           if (c & B01)
>             nib |= 0x1;
> 
>           if (c2 == MACREG)
>             {
>               if (operand[0].mode == MACREG)
>                 /* stmac has mac[hl] as the first operand.  */
>                 nib = 2 + operand[0].reg;
>               else
>                 /* ldmac has mac[hl] as the second operand.  */
>                 nib = 2 + operand[1].reg;
>             }
>         }
>       nibble_count++;
> 
>       *p++ = nib;
>     }
> 
>   /* Disgusting.  Why, oh why didn't someone ask us for advice
>      on the assembler format.  */
>   if (OP_KIND (this_try->opcode->how) == O_LDM)
>     {
>       high = (operand[1].reg >> 8) & 0xf;
>       low  = (operand[1].reg) & 0xf;
>       asnibbles[2] = high - low;
>       asnibbles[7] = high;
>     }
>   else if (OP_KIND (this_try->opcode->how) == O_STM)
>     {
>       high = (operand[0].reg >> 8) & 0xf;
>       low  = (operand[0].reg) & 0xf;
>       asnibbles[2] = high - low;
>       asnibbles[7] = low;
>     }
> 
>   for (i = 0; i < this_try->length; i++)
>     output[i] = (asnibbles[i * 2] << 4) | asnibbles[i * 2 + 1];
> 
>   /* Note if this is a movb instruction -- there's a special relaxation
>      which only applies to them.  */
>   if (this_try->opcode->how == O (O_MOV, SB))
>     movb = 1;
> 
>   /* Output any fixes.  */
>   for (i = 0; i < this_try->noperands; i++)
>     {
>       int x = operand[i].mode;
>       int x_mode = x & MODE;
> 
>       if (x_mode == IMM || x_mode == DISP)
>         do_a_fix_imm (output - frag_now->fr_literal + op_at[i] / 2,
>                       op_at[i] & 1, operand + i, (x & MEMRELAX) != 0);
> 
>       else if (x_mode == ABS)
>         do_a_fix_imm (output - frag_now->fr_literal + op_at[i] / 2,
>                       op_at[i] & 1, operand + i,
>                       (x & MEMRELAX) ? movb + 1 : 0);
> 
>       else if (x_mode == PCREL)
>         {
>           int size16 = (x & SIZE) == L_16;
>           int size = size16 ? 2 : 1;
>           int type = size16 ? R_PCRWORD : R_PCRBYTE;
>           fixS *fixP;
> 
>           check_operand (operand + i, size16 ? 0x7fff : 0x7f, "@");
> 
>           if (operand[i].exp.X_add_number & 1)
>             as_warn (_("branch operand has odd offset (%lx)\n"),
>                      (unsigned long) operand->exp.X_add_number);
> #ifndef OBJ_ELF
>           /* The COFF port has always been off by one, changing it
>              now would be an incompatible change, so we leave it as-is.
> 
>              We don't want to do this for ELF as we want to be
>              compatible with the proposed ELF format from Hitachi.  */
>           operand[i].exp.X_add_number -= 1;
> #endif
>           if (size16)
>             {
>               operand[i].exp.X_add_number =
>                 ((operand[i].exp.X_add_number & 0xffff) ^ 0x8000) - 0x8000;
>             }
>           else
>             {
>               operand[i].exp.X_add_number =
>                 ((operand[i].exp.X_add_number & 0xff) ^ 0x80) - 0x80;
>             }
> 
>           /* For BRA/S.  */
>           if (! size16)
>             operand[i].exp.X_add_number |= output[op_at[i] / 2];
> 
>           fixP = fix_new_exp (frag_now,
>                               output - frag_now->fr_literal + op_at[i] / 2,
>                               size,
>                               &operand[i].exp,
>                               1,
>                               type);
>           fixP->fx_signed = 1;
>         }
>       else if (x_mode == MEMIND)
>         {
>           check_operand (operand + i, 0xff, "@@");
>           fix_new_exp (frag_now,
>                        output - frag_now->fr_literal + 1,
>                        1,
>                        &operand[i].exp,
>                        0,
>                        R_MEM_INDIRECT);
>         }
>       else if (x_mode == VECIND)
>         {
>           check_operand (operand + i, 0x7f, "@@");
>           /* FIXME: approximating the effect of "B31" here...
>              This is very hackish, and ought to be done a better way.  */
>           operand[i].exp.X_add_number |= 0x80;
>           fix_new_exp (frag_now,
>                        output - frag_now->fr_literal + 1,
>                        1,
>                        &operand[i].exp,
>                        0,
>                        R_MEM_INDIRECT);
>         }
>       else if (x & ABSJMP)
>         {
>           int where = 0;
>           bfd_reloc_code_real_type reloc_type = R_JMPL1;
> 
> #ifdef OBJ_ELF
>           /* To be compatible with the proposed H8 ELF format, we
>              want the relocation's offset to point to the first byte
>              that will be modified, not to the start of the instruction.  */
> 
>           if ((operand->mode & SIZE) == L_32)
>             {
>               where = 2;
>               reloc_type = R_RELLONG;
>             }
>           else
>             where = 1;
> #endif
> 
>           /* This jmp may be a jump or a branch.  */
> 
>           check_operand (operand + i,
>                          SXmode ? 0xffffffff : Hmode ? 0xffffff : 0xffff,
>                          "@");
> 
>           if (operand[i].exp.X_add_number & 1)
>             as_warn (_("branch operand has odd offset (%lx)\n"),
>                      (unsigned long) operand->exp.X_add_number);
> 
>           if (!Hmode)
>             operand[i].exp.X_add_number =
>               ((operand[i].exp.X_add_number & 0xffff) ^ 0x8000) - 0x8000;
>           fix_new_exp (frag_now,
>                        output - frag_now->fr_literal + where,
>                        4,
>                        &operand[i].exp,
>                        0,
>                        reloc_type);
>         }
>     }
> }
> 
> /* Try to give an intelligent error message for common and simple to
>    detect errors.  */
> 
> static void
> clever_message (instruction, operand)
>      const struct h8_instruction *instruction;
>      struct h8_op *operand;
> {
>   /* Find out if there was more than one possible opcode.  */
> 
>   if ((instruction + 1)->idx != instruction->idx)
>     {
>       int argn;
> 
>       /* Only one opcode of this flavour, try to guess which operand
>          didn't match.  */
>       for (argn = 0; argn < instruction->noperands; argn++)
>         {
>           switch (instruction->opcode->args.nib[argn])
>             {
>             case RD16:
>               if (operand[argn].mode != RD16)
>                 {
>                   as_bad (_("destination operand must be 16 bit register"));
>                   return;
> 
>                 }
>               break;
> 
>             case RS8:
>               if (operand[argn].mode != RS8)
>                 {
>                   as_bad (_("source operand must be 8 bit register"));
>                   return;
>                 }
>               break;
> 
>             case ABS16DST:
>               if (operand[argn].mode != ABS16DST)
>                 {
>                   as_bad (_("destination operand must be 16bit absolute address"));
>                   return;
>                 }
>               break;
>             case RD8:
>               if (operand[argn].mode != RD8)
>                 {
>                   as_bad (_("destination operand must be 8 bit register"));
>                   return;
>                 }
>               break;
> 
>             case ABS16SRC:
>               if (operand[argn].mode != ABS16SRC)
>                 {
>                   as_bad (_("source operand must be 16bit absolute address"));
>                   return;
>                 }
>               break;
> 
>             }
>         }
>     }
>   as_bad (_("invalid operands"));
> }
> 
> /* This is the guts of the machine-dependent assembler.  STR points to
>    a machine dependent instruction.  This function is supposed to emit
>    the frags/bytes it assembles.  */
> 
> void
> md_assemble (str)
>      char *str;
> {
>   char *op_start;
>   char *op_end;
>   struct h8_op operand[3];
>   const struct h8_instruction *instruction;
>   const struct h8_instruction *prev_instruction;
> 
>   char *dot = 0;
>   char c;
>   int size, i;
> 
>   /* Drop leading whitespace.  */
>   while (*str == ' ')
>     str++;
> 
>   /* Find the op code end.  */
>   for (op_start = op_end = str;
>        *op_end != 0 && *op_end != ' ';
>        op_end++)
>     {
>       if (*op_end == '.')
>         {
>           dot = op_end + 1;
>           *op_end = 0;
>           op_end += 2;
>           break;
>         }
>     }
> 
>   if (op_end == op_start)
>     {
>       as_bad (_("can't find opcode "));
>     }
>   c = *op_end;
> 
>   *op_end = 0;
> 
>   instruction = (const struct h8_instruction *)
>     hash_find (opcode_hash_control, op_start);
> 
>   if (instruction == NULL)
>     {
>       as_bad (_("unknown opcode"));
>       return;
>     }
> 
>   /* We used to set input_line_pointer to the result of get_operands,
>      but that is wrong.  Our caller assumes we don't change it.  */
> 
>   operand[0].mode = 0;
>   operand[1].mode = 0;
>   operand[2].mode = 0;
> 
>   if (OP_KIND (instruction->opcode->how) == O_MOVAB
>       || OP_KIND (instruction->opcode->how) == O_MOVAW
>       || OP_KIND (instruction->opcode->how) == O_MOVAL)
>     get_mova_operands (op_end, operand);
>   else if (OP_KIND (instruction->opcode->how) == O_RTEL
>            || OP_KIND (instruction->opcode->how) == O_RTSL)
>     get_rtsl_operands (op_end, operand);
>   else
>     get_operands (instruction->noperands, op_end, operand);
> 
>   *op_end = c;
>   prev_instruction = instruction;
> 
>   size = SN;
>   if (dot)
>     {
>       switch (*dot)
>         {
>         case 'b':
>           size = SB;
>           break;
> 
>         case 'w':
>           size = SW;
>           break;
> 
>         case 'l':
>           size = SL;
>           break;
>         }
>     }
>   instruction = get_specific (instruction, operand, size);
> 
>   if (instruction == 0)
>     {
>       /* Couldn't find an opcode which matched the operands.  */
>       char *where = frag_more (2);
> 
>       where[0] = 0x0;
>       where[1] = 0x0;
>       clever_message (prev_instruction, operand);
> 
>       return;
>     }
> 
>   /* This is the earliest point at which we can do this:
>      any DISP2 operands need to be fixed-up according to
>      the size of the operation.  */
>   /* MOVA is a whole different set of rules...  */
>   if (OP_KIND (instruction->opcode->how) == O_MOVAB ||
>       OP_KIND (instruction->opcode->how) == O_MOVAW ||
>       OP_KIND (instruction->opcode->how) == O_MOVAL)
>     {
>       if ((operand[1].mode & MODE) == DISP &&
>           (operand[1].mode & SIZE) == L_2)
>         switch (operand[0].mode & MODE) {
>         case INDEXB:
>         default:
>           break;
>         case INDEXW:
>           if (operand[1].exp.X_add_number % 2)
>             as_warn (_("operand/size mis-match"));
>           operand[1].exp.X_add_number /= 2;
>           break;
>         case INDEXL:
>           if (operand[1].exp.X_add_number % 4)
>             as_warn (_("operand/size mis-match"));
>           operand[1].exp.X_add_number /= 4;
>           break;
>         }
>     }
>   else
>     {
>       for (i = 0; i < instruction->noperands; i++)
>         if ((operand[i].mode & MODE) == DISP &&
>             (operand[i].mode & SIZE) == L_2)
>           switch (size) {
>           case SN:
>           case SB:
>           default:
>             break;
>           case SW:
>             if (operand[i].exp.X_add_number % 2)
>               as_warn (_("operand/size mis-match"));
>             operand[i].exp.X_add_number /= 2;
>             break;
>           case SL:
>             if (operand[i].exp.X_add_number % 4)
>               as_warn (_("operand/size mis-match"));
>             operand[i].exp.X_add_number /= 4;
>             break;
>           }
>     }
> 
>   build_bytes (instruction, operand);
> 
> #ifdef BFD_ASSEMBLER
>   dwarf2_emit_insn (instruction->length);
> #endif
> }
> 
> #ifndef BFD_ASSEMBLER
> void
> tc_crawl_symbol_chain (headers)
>      object_headers *headers ATTRIBUTE_UNUSED;
> {
>   printf (_("call to tc_crawl_symbol_chain \n"));
> }
> #endif
> 
> symbolS *
> md_undefined_symbol (name)
>      char *name ATTRIBUTE_UNUSED;
> {
>   return 0;
> }
> 
> #ifndef BFD_ASSEMBLER
> void
> tc_headers_hook (headers)
>      object_headers *headers ATTRIBUTE_UNUSED;
> {
>   printf (_("call to tc_headers_hook \n"));
> }
> #endif
> 
> /* Various routines to kill one day */
> /* Equal to MAX_PRECISION in atof-ieee.c */
> #define MAX_LITTLENUMS 6
> 
> /* Turn a string in input_line_pointer into a floating point constant
>    of type TYPE, and store the appropriate bytes in *LITP.  The number
>    of LITTLENUMS emitted is stored in *SIZEP.  An error message is
>    returned, or NULL on OK.  */
> 
> char *
> md_atof (type, litP, sizeP)
>      char type;
>      char *litP;
>      int *sizeP;
> {
>   int prec;
>   LITTLENUM_TYPE words[MAX_LITTLENUMS];
>   LITTLENUM_TYPE *wordP;
>   char *t;
> 
>   switch (type)
>     {
>     case 'f':
>     case 'F':
>     case 's':
>     case 'S':
>       prec = 2;
>       break;
> 
>     case 'd':
>     case 'D':
>     case 'r':
>     case 'R':
>       prec = 4;
>       break;
> 
>     case 'x':
>     case 'X':
>       prec = 6;
>       break;
> 
>     case 'p':
>     case 'P':
>       prec = 6;
>       break;
> 
>     default:
>       *sizeP = 0;
>       return _("Bad call to MD_ATOF()");
>     }
>   t = atof_ieee (input_line_pointer, type, words);
>   if (t)
>     input_line_pointer = t;
> 
>   *sizeP = prec * sizeof (LITTLENUM_TYPE);
>   for (wordP = words; prec--;)
>     {
>       md_number_to_chars (litP, (long) (*wordP++), sizeof (LITTLENUM_TYPE));
>       litP += sizeof (LITTLENUM_TYPE);
>     }
>   return 0;
> }
> 
> const char *md_shortopts = "";
> struct option md_longopts[] = {
>   {NULL, no_argument, NULL, 0}
> };
> 
> size_t md_longopts_size = sizeof (md_longopts);
> 
> int
> md_parse_option (c, arg)
>      int c ATTRIBUTE_UNUSED;
>      char *arg ATTRIBUTE_UNUSED;
> {
>   return 0;
> }
> 
> void
> md_show_usage (stream)
>      FILE *stream ATTRIBUTE_UNUSED;
> {
> }
> 
> void tc_aout_fix_to_chars PARAMS ((void));
> 
> void
> tc_aout_fix_to_chars ()
> {
>   printf (_("call to tc_aout_fix_to_chars \n"));
>   abort ();
> }
> 
> void
> md_convert_frag (headers, seg, fragP)
> #ifdef BFD_ASSEMBLER
>      bfd *headers ATTRIBUTE_UNUSED;
> #else
>      object_headers *headers ATTRIBUTE_UNUSED;
> #endif
>      segT seg ATTRIBUTE_UNUSED;
>      fragS *fragP ATTRIBUTE_UNUSED;
> {
>   printf (_("call to md_convert_frag \n"));
>   abort ();
> }
> 
> #ifdef BFD_ASSEMBLER
> valueT
> md_section_align (segment, size)
>      segT segment;
>      valueT size;
> {
>   int align = bfd_get_section_alignment (stdoutput, segment);
>   return ((size + (1 << align) - 1) & (-1 << align));
> }
> #else
> valueT
> md_section_align (seg, size)
>      segT seg;
>      valueT size;
> {
>   return ((size + (1 << section_alignment[(int) seg]) - 1)
>           & (-1 << section_alignment[(int) seg]));
> }
> #endif
> 
> void
> md_apply_fix3 (fixP, valP, seg)
>      fixS *fixP;
>      valueT *valP;
>      segT seg ATTRIBUTE_UNUSED;
> {
>   char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
>   long val = *valP;
> 
>   switch (fixP->fx_size)
>     {
>     case 1:
>       *buf++ = val;
>       break;
>     case 2:
>       *buf++ = (val >> 8);
>       *buf++ = val;
>       break;
>     case 4:
>       *buf++ = (val >> 24);
>       *buf++ = (val >> 16);
>       *buf++ = (val >> 8);
>       *buf++ = val;
>       break;
>     default:
>       abort ();
>     }
> 
>   if (fixP->fx_addsy == NULL && fixP->fx_pcrel == 0)
>     fixP->fx_done = 1;
> }
> 
> int
> md_estimate_size_before_relax (fragP, segment_type)
>      register fragS *fragP ATTRIBUTE_UNUSED;
>      register segT segment_type ATTRIBUTE_UNUSED;
> {
>   printf (_("call tomd_estimate_size_before_relax \n"));
>   abort ();
> }
> 
> /* Put number into target byte order.  */
> void
> md_number_to_chars (ptr, use, nbytes)
>      char *ptr;
>      valueT use;
>      int nbytes;
> {
>   number_to_chars_bigendian (ptr, use, nbytes);
> }
> 
> long
> md_pcrel_from (fixP)
>      fixS *fixP ATTRIBUTE_UNUSED;
> {
>   abort ();
> }
> 
> #ifndef BFD_ASSEMBLER
> void
> tc_reloc_mangle (fix_ptr, intr, base)
>      fixS *fix_ptr;
>      struct internal_reloc *intr;
>      bfd_vma base;
> 
> {
>   symbolS *symbol_ptr;
> 
>   symbol_ptr = fix_ptr->fx_addsy;
> 
>   /* If this relocation is attached to a symbol then it's ok
>      to output it.  */
>   if (fix_ptr->fx_r_type == TC_CONS_RELOC)
>     {
>       /* cons likes to create reloc32's whatever the size of the reloc..
>        */
>       switch (fix_ptr->fx_size)
>         {
>         case 4:
>           intr->r_type = R_RELLONG;
>           break;
>         case 2:
>           intr->r_type = R_RELWORD;
>           break;
>         case 1:
>           intr->r_type = R_RELBYTE;
>           break;
>         default:
>           abort ();
>         }
>     }
>   else
>     {
>       intr->r_type = fix_ptr->fx_r_type;
>     }
> 
>   intr->r_vaddr = fix_ptr->fx_frag->fr_address + fix_ptr->fx_where + base;
>   intr->r_offset = fix_ptr->fx_offset;
> 
>   if (symbol_ptr)
>     {
>       if (symbol_ptr->sy_number != -1)
>         intr->r_symndx = symbol_ptr->sy_number;
>       else
>         {
>           symbolS *segsym;
> 
>           /* This case arises when a reference is made to `.'.  */
>           segsym = seg_info (S_GET_SEGMENT (symbol_ptr))->dot;
>           if (segsym == NULL)
>             intr->r_symndx = -1;
>           else
>             {
>               intr->r_symndx = segsym->sy_number;
>               intr->r_offset += S_GET_VALUE (symbol_ptr);
>             }
>         }
>     }
>   else
>     intr->r_symndx = -1;
> }
> #else /* BFD_ASSEMBLER */
> arelent *
> tc_gen_reloc (section, fixp)
>      asection *section ATTRIBUTE_UNUSED;
>      fixS *fixp;
> {
>   arelent *rel;
>   bfd_reloc_code_real_type r_type;
> 
>   if (fixp->fx_addsy && fixp->fx_subsy)
>     {
>       if ((S_GET_SEGMENT (fixp->fx_addsy) != S_GET_SEGMENT (fixp->fx_subsy))
>           || S_GET_SEGMENT (fixp->fx_addsy) == undefined_section)
>         {
>           as_bad_where (fixp->fx_file, fixp->fx_line,
>                         "Difference of symbols in different sections is not supported");
>           return NULL;
>         }
>     }
> 
>   rel = (arelent *) xmalloc (sizeof (arelent));
>   rel->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
>   *rel->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
>   rel->address = fixp->fx_frag->fr_address + fixp->fx_where;
>   rel->addend = fixp->fx_offset;
> 
>   r_type = fixp->fx_r_type;
> 
> #define DEBUG 0
> #if DEBUG
>   fprintf (stderr, "%s\n", bfd_get_reloc_code_name (r_type));
>   fflush(stderr);
> #endif
>   rel->howto = bfd_reloc_type_lookup (stdoutput, r_type);
>   if (rel->howto == NULL)
>     {
>       as_bad_where (fixp->fx_file, fixp->fx_line,
>                     _("Cannot represent relocation type %s"),
>                     bfd_get_reloc_code_name (r_type));
>       return NULL;
>     }
> 
>   return rel;
> }
> #endif


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]