OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-old/] [binutils-2.18.50/] [gas/] [config/] [tc-hppa.c] - Diff between revs 156 and 816

Go to most recent revision | Only display areas with differences | Details | Blame | View Log

Rev 156 Rev 816
/* tc-hppa.c -- Assemble for the PA
/* tc-hppa.c -- Assemble for the PA
   Copyright 1989, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
   Copyright 1989, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
   2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
   2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
 
 
   This file is part of GAS, the GNU Assembler.
   This file is part of GAS, the GNU Assembler.
 
 
   GAS is free software; you can redistribute it and/or modify
   GAS is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 3, or (at your option)
   the Free Software Foundation; either version 3, or (at your option)
   any later version.
   any later version.
 
 
   GAS is distributed in the hope that it will be useful,
   GAS is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
   GNU General Public License for more details.
 
 
   You should have received a copy of the GNU General Public License
   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
   along with GAS; see the file COPYING.  If not, write to the Free
   Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
   Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
   02110-1301, USA.  */
   02110-1301, USA.  */
 
 
/* HP PA-RISC support was contributed by the Center for Software Science
/* HP PA-RISC support was contributed by the Center for Software Science
   at the University of Utah.  */
   at the University of Utah.  */
 
 
#include "as.h"
#include "as.h"
#include "safe-ctype.h"
#include "safe-ctype.h"
#include "subsegs.h"
#include "subsegs.h"
#include "dw2gencfi.h"
#include "dw2gencfi.h"
 
 
#include "bfd/libhppa.h"
#include "bfd/libhppa.h"
 
 
/* Be careful, this file includes data *declarations*.  */
/* Be careful, this file includes data *declarations*.  */
#include "opcode/hppa.h"
#include "opcode/hppa.h"
 
 
#if defined (OBJ_ELF) && defined (OBJ_SOM)
#if defined (OBJ_ELF) && defined (OBJ_SOM)
error only one of OBJ_ELF and OBJ_SOM can be defined
error only one of OBJ_ELF and OBJ_SOM can be defined
#endif
#endif
 
 
/* If we are using ELF, then we probably can support dwarf2 debug
/* If we are using ELF, then we probably can support dwarf2 debug
   records.  Furthermore, if we are supporting dwarf2 debug records,
   records.  Furthermore, if we are supporting dwarf2 debug records,
   then we want to use the assembler support for compact line numbers.  */
   then we want to use the assembler support for compact line numbers.  */
#ifdef OBJ_ELF
#ifdef OBJ_ELF
#include "dwarf2dbg.h"
#include "dwarf2dbg.h"
 
 
/* A "convenient" place to put object file dependencies which do
/* A "convenient" place to put object file dependencies which do
   not need to be seen outside of tc-hppa.c.  */
   not need to be seen outside of tc-hppa.c.  */
 
 
/* Object file formats specify relocation types.  */
/* Object file formats specify relocation types.  */
typedef enum elf_hppa_reloc_type reloc_type;
typedef enum elf_hppa_reloc_type reloc_type;
 
 
/* Object file formats specify BFD symbol types.  */
/* Object file formats specify BFD symbol types.  */
typedef elf_symbol_type obj_symbol_type;
typedef elf_symbol_type obj_symbol_type;
#define symbol_arg_reloc_info(sym)\
#define symbol_arg_reloc_info(sym)\
  (((obj_symbol_type *) symbol_get_bfdsym (sym))->tc_data.hppa_arg_reloc)
  (((obj_symbol_type *) symbol_get_bfdsym (sym))->tc_data.hppa_arg_reloc)
 
 
#if TARGET_ARCH_SIZE == 64
#if TARGET_ARCH_SIZE == 64
/* How to generate a relocation.  */
/* How to generate a relocation.  */
#define hppa_gen_reloc_type _bfd_elf64_hppa_gen_reloc_type
#define hppa_gen_reloc_type _bfd_elf64_hppa_gen_reloc_type
#define elf_hppa_reloc_final_type elf64_hppa_reloc_final_type
#define elf_hppa_reloc_final_type elf64_hppa_reloc_final_type
#else
#else
#define hppa_gen_reloc_type _bfd_elf32_hppa_gen_reloc_type
#define hppa_gen_reloc_type _bfd_elf32_hppa_gen_reloc_type
#define elf_hppa_reloc_final_type elf32_hppa_reloc_final_type
#define elf_hppa_reloc_final_type elf32_hppa_reloc_final_type
#endif
#endif
 
 
/* ELF objects can have versions, but apparently do not have anywhere
/* ELF objects can have versions, but apparently do not have anywhere
   to store a copyright string.  */
   to store a copyright string.  */
#define obj_version obj_elf_version
#define obj_version obj_elf_version
#define obj_copyright obj_elf_version
#define obj_copyright obj_elf_version
 
 
#define UNWIND_SECTION_NAME ".PARISC.unwind"
#define UNWIND_SECTION_NAME ".PARISC.unwind"
#endif /* OBJ_ELF */
#endif /* OBJ_ELF */
 
 
#ifdef OBJ_SOM
#ifdef OBJ_SOM
/* Names of various debugging spaces/subspaces.  */
/* Names of various debugging spaces/subspaces.  */
#define GDB_DEBUG_SPACE_NAME "$GDB_DEBUG$"
#define GDB_DEBUG_SPACE_NAME "$GDB_DEBUG$"
#define GDB_STRINGS_SUBSPACE_NAME "$GDB_STRINGS$"
#define GDB_STRINGS_SUBSPACE_NAME "$GDB_STRINGS$"
#define GDB_SYMBOLS_SUBSPACE_NAME "$GDB_SYMBOLS$"
#define GDB_SYMBOLS_SUBSPACE_NAME "$GDB_SYMBOLS$"
#define UNWIND_SECTION_NAME "$UNWIND$"
#define UNWIND_SECTION_NAME "$UNWIND$"
 
 
/* Object file formats specify relocation types.  */
/* Object file formats specify relocation types.  */
typedef int reloc_type;
typedef int reloc_type;
 
 
/* SOM objects can have both a version string and a copyright string.  */
/* SOM objects can have both a version string and a copyright string.  */
#define obj_version obj_som_version
#define obj_version obj_som_version
#define obj_copyright obj_som_copyright
#define obj_copyright obj_som_copyright
 
 
/* How to generate a relocation.  */
/* How to generate a relocation.  */
#define hppa_gen_reloc_type hppa_som_gen_reloc_type
#define hppa_gen_reloc_type hppa_som_gen_reloc_type
 
 
/* Object file formats specify BFD symbol types.  */
/* Object file formats specify BFD symbol types.  */
typedef som_symbol_type obj_symbol_type;
typedef som_symbol_type obj_symbol_type;
#define symbol_arg_reloc_info(sym)\
#define symbol_arg_reloc_info(sym)\
  (((obj_symbol_type *) symbol_get_bfdsym (sym))->tc_data.ap.hppa_arg_reloc)
  (((obj_symbol_type *) symbol_get_bfdsym (sym))->tc_data.ap.hppa_arg_reloc)
 
 
/* This apparently isn't in older versions of hpux reloc.h.  */
/* This apparently isn't in older versions of hpux reloc.h.  */
#ifndef R_DLT_REL
#ifndef R_DLT_REL
#define R_DLT_REL 0x78
#define R_DLT_REL 0x78
#endif
#endif
 
 
#ifndef R_N0SEL
#ifndef R_N0SEL
#define R_N0SEL 0xd8
#define R_N0SEL 0xd8
#endif
#endif
 
 
#ifndef R_N1SEL
#ifndef R_N1SEL
#define R_N1SEL 0xd9
#define R_N1SEL 0xd9
#endif
#endif
#endif /* OBJ_SOM */
#endif /* OBJ_SOM */
 
 
#if TARGET_ARCH_SIZE == 64
#if TARGET_ARCH_SIZE == 64
#define DEFAULT_LEVEL 25
#define DEFAULT_LEVEL 25
#else
#else
#define DEFAULT_LEVEL 10
#define DEFAULT_LEVEL 10
#endif
#endif
 
 
/* Various structures and types used internally in tc-hppa.c.  */
/* Various structures and types used internally in tc-hppa.c.  */
 
 
/* Unwind table and descriptor.  FIXME: Sync this with GDB version.  */
/* Unwind table and descriptor.  FIXME: Sync this with GDB version.  */
 
 
struct unwind_desc
struct unwind_desc
  {
  {
    unsigned int cannot_unwind:1;
    unsigned int cannot_unwind:1;
    unsigned int millicode:1;
    unsigned int millicode:1;
    unsigned int millicode_save_rest:1;
    unsigned int millicode_save_rest:1;
    unsigned int region_desc:2;
    unsigned int region_desc:2;
    unsigned int save_sr:2;
    unsigned int save_sr:2;
    unsigned int entry_fr:4;
    unsigned int entry_fr:4;
    unsigned int entry_gr:5;
    unsigned int entry_gr:5;
    unsigned int args_stored:1;
    unsigned int args_stored:1;
    unsigned int call_fr:5;
    unsigned int call_fr:5;
    unsigned int call_gr:5;
    unsigned int call_gr:5;
    unsigned int save_sp:1;
    unsigned int save_sp:1;
    unsigned int save_rp:1;
    unsigned int save_rp:1;
    unsigned int save_rp_in_frame:1;
    unsigned int save_rp_in_frame:1;
    unsigned int extn_ptr_defined:1;
    unsigned int extn_ptr_defined:1;
    unsigned int cleanup_defined:1;
    unsigned int cleanup_defined:1;
 
 
    unsigned int hpe_interrupt_marker:1;
    unsigned int hpe_interrupt_marker:1;
    unsigned int hpux_interrupt_marker:1;
    unsigned int hpux_interrupt_marker:1;
    unsigned int reserved:3;
    unsigned int reserved:3;
    unsigned int frame_size:27;
    unsigned int frame_size:27;
  };
  };
 
 
/* We can't rely on compilers placing bitfields in any particular
/* We can't rely on compilers placing bitfields in any particular
   place, so use these macros when dumping unwind descriptors to
   place, so use these macros when dumping unwind descriptors to
   object files.  */
   object files.  */
#define UNWIND_LOW32(U) \
#define UNWIND_LOW32(U) \
  (((U)->cannot_unwind << 31)           \
  (((U)->cannot_unwind << 31)           \
   | ((U)->millicode << 30)             \
   | ((U)->millicode << 30)             \
   | ((U)->millicode_save_rest << 29)   \
   | ((U)->millicode_save_rest << 29)   \
   | ((U)->region_desc << 27)           \
   | ((U)->region_desc << 27)           \
   | ((U)->save_sr << 25)               \
   | ((U)->save_sr << 25)               \
   | ((U)->entry_fr << 21)              \
   | ((U)->entry_fr << 21)              \
   | ((U)->entry_gr << 16)              \
   | ((U)->entry_gr << 16)              \
   | ((U)->args_stored << 15)           \
   | ((U)->args_stored << 15)           \
   | ((U)->call_fr << 10)               \
   | ((U)->call_fr << 10)               \
   | ((U)->call_gr << 5)                \
   | ((U)->call_gr << 5)                \
   | ((U)->save_sp << 4)                \
   | ((U)->save_sp << 4)                \
   | ((U)->save_rp << 3)                \
   | ((U)->save_rp << 3)                \
   | ((U)->save_rp_in_frame << 2)       \
   | ((U)->save_rp_in_frame << 2)       \
   | ((U)->extn_ptr_defined << 1)       \
   | ((U)->extn_ptr_defined << 1)       \
   | ((U)->cleanup_defined << 0))
   | ((U)->cleanup_defined << 0))
 
 
#define UNWIND_HIGH32(U) \
#define UNWIND_HIGH32(U) \
  (((U)->hpe_interrupt_marker << 31)    \
  (((U)->hpe_interrupt_marker << 31)    \
   | ((U)->hpux_interrupt_marker << 30) \
   | ((U)->hpux_interrupt_marker << 30) \
   | ((U)->frame_size << 0))
   | ((U)->frame_size << 0))
 
 
struct unwind_table
struct unwind_table
  {
  {
    /* Starting and ending offsets of the region described by
    /* Starting and ending offsets of the region described by
       descriptor.  */
       descriptor.  */
    unsigned int start_offset;
    unsigned int start_offset;
    unsigned int end_offset;
    unsigned int end_offset;
    struct unwind_desc descriptor;
    struct unwind_desc descriptor;
  };
  };
 
 
/* This structure is used by the .callinfo, .enter, .leave pseudo-ops to
/* This structure is used by the .callinfo, .enter, .leave pseudo-ops to
   control the entry and exit code they generate. It is also used in
   control the entry and exit code they generate. It is also used in
   creation of the correct stack unwind descriptors.
   creation of the correct stack unwind descriptors.
 
 
   NOTE:  GAS does not support .enter and .leave for the generation of
   NOTE:  GAS does not support .enter and .leave for the generation of
   prologues and epilogues.  FIXME.
   prologues and epilogues.  FIXME.
 
 
   The fields in structure roughly correspond to the arguments available on the
   The fields in structure roughly correspond to the arguments available on the
   .callinfo pseudo-op.  */
   .callinfo pseudo-op.  */
 
 
struct call_info
struct call_info
  {
  {
    /* The unwind descriptor being built.  */
    /* The unwind descriptor being built.  */
    struct unwind_table ci_unwind;
    struct unwind_table ci_unwind;
 
 
    /* Name of this function.  */
    /* Name of this function.  */
    symbolS *start_symbol;
    symbolS *start_symbol;
 
 
    /* (temporary) symbol used to mark the end of this function.  */
    /* (temporary) symbol used to mark the end of this function.  */
    symbolS *end_symbol;
    symbolS *end_symbol;
 
 
    /* Next entry in the chain.  */
    /* Next entry in the chain.  */
    struct call_info *ci_next;
    struct call_info *ci_next;
  };
  };
 
 
/* Operand formats for FP instructions.   Note not all FP instructions
/* Operand formats for FP instructions.   Note not all FP instructions
   allow all four formats to be used (for example fmpysub only allows
   allow all four formats to be used (for example fmpysub only allows
   SGL and DBL).  */
   SGL and DBL).  */
typedef enum
typedef enum
  {
  {
    SGL, DBL, ILLEGAL_FMT, QUAD, W, UW, DW, UDW, QW, UQW
    SGL, DBL, ILLEGAL_FMT, QUAD, W, UW, DW, UDW, QW, UQW
  }
  }
fp_operand_format;
fp_operand_format;
 
 
/* This fully describes the symbol types which may be attached to
/* This fully describes the symbol types which may be attached to
   an EXPORT or IMPORT directive.  Only SOM uses this formation
   an EXPORT or IMPORT directive.  Only SOM uses this formation
   (ELF has no need for it).  */
   (ELF has no need for it).  */
typedef enum
typedef enum
  {
  {
    SYMBOL_TYPE_UNKNOWN,
    SYMBOL_TYPE_UNKNOWN,
    SYMBOL_TYPE_ABSOLUTE,
    SYMBOL_TYPE_ABSOLUTE,
    SYMBOL_TYPE_CODE,
    SYMBOL_TYPE_CODE,
    SYMBOL_TYPE_DATA,
    SYMBOL_TYPE_DATA,
    SYMBOL_TYPE_ENTRY,
    SYMBOL_TYPE_ENTRY,
    SYMBOL_TYPE_MILLICODE,
    SYMBOL_TYPE_MILLICODE,
    SYMBOL_TYPE_PLABEL,
    SYMBOL_TYPE_PLABEL,
    SYMBOL_TYPE_PRI_PROG,
    SYMBOL_TYPE_PRI_PROG,
    SYMBOL_TYPE_SEC_PROG,
    SYMBOL_TYPE_SEC_PROG,
  }
  }
pa_symbol_type;
pa_symbol_type;
 
 
/* This structure contains information needed to assemble
/* This structure contains information needed to assemble
   individual instructions.  */
   individual instructions.  */
struct pa_it
struct pa_it
  {
  {
    /* Holds the opcode after parsing by pa_ip.  */
    /* Holds the opcode after parsing by pa_ip.  */
    unsigned long opcode;
    unsigned long opcode;
 
 
    /* Holds an expression associated with the current instruction.  */
    /* Holds an expression associated with the current instruction.  */
    expressionS exp;
    expressionS exp;
 
 
    /* Does this instruction use PC-relative addressing.  */
    /* Does this instruction use PC-relative addressing.  */
    int pcrel;
    int pcrel;
 
 
    /* Floating point formats for operand1 and operand2.  */
    /* Floating point formats for operand1 and operand2.  */
    fp_operand_format fpof1;
    fp_operand_format fpof1;
    fp_operand_format fpof2;
    fp_operand_format fpof2;
 
 
    /* Whether or not we saw a truncation request on an fcnv insn.  */
    /* Whether or not we saw a truncation request on an fcnv insn.  */
    int trunc;
    int trunc;
 
 
    /* Holds the field selector for this instruction
    /* Holds the field selector for this instruction
       (for example L%, LR%, etc).  */
       (for example L%, LR%, etc).  */
    long field_selector;
    long field_selector;
 
 
    /* Holds any argument relocation bits associated with this
    /* Holds any argument relocation bits associated with this
       instruction.  (instruction should be some sort of call).  */
       instruction.  (instruction should be some sort of call).  */
    unsigned int arg_reloc;
    unsigned int arg_reloc;
 
 
    /* The format specification for this instruction.  */
    /* The format specification for this instruction.  */
    int format;
    int format;
 
 
    /* The relocation (if any) associated with this instruction.  */
    /* The relocation (if any) associated with this instruction.  */
    reloc_type reloc;
    reloc_type reloc;
  };
  };
 
 
/* PA-89 floating point registers are arranged like this:
/* PA-89 floating point registers are arranged like this:
 
 
   +--------------+--------------+
   +--------------+--------------+
   |   0 or 16L   |  16 or 16R   |
   |   0 or 16L   |  16 or 16R   |
   +--------------+--------------+
   +--------------+--------------+
   |   1 or 17L   |  17 or 17R   |
   |   1 or 17L   |  17 or 17R   |
   +--------------+--------------+
   +--------------+--------------+
   |              |              |
   |              |              |
 
 
   .              .              .
   .              .              .
   .              .              .
   .              .              .
   .              .              .
   .              .              .
 
 
   |              |              |
   |              |              |
   +--------------+--------------+
   +--------------+--------------+
   |  14 or 30L   |  30 or 30R   |
   |  14 or 30L   |  30 or 30R   |
   +--------------+--------------+
   +--------------+--------------+
   |  15 or 31L   |  31 or 31R   |
   |  15 or 31L   |  31 or 31R   |
   +--------------+--------------+  */
   +--------------+--------------+  */
 
 
/* Additional information needed to build argument relocation stubs.  */
/* Additional information needed to build argument relocation stubs.  */
struct call_desc
struct call_desc
  {
  {
    /* The argument relocation specification.  */
    /* The argument relocation specification.  */
    unsigned int arg_reloc;
    unsigned int arg_reloc;
 
 
    /* Number of arguments.  */
    /* Number of arguments.  */
    unsigned int arg_count;
    unsigned int arg_count;
  };
  };
 
 
#ifdef OBJ_SOM
#ifdef OBJ_SOM
/* This structure defines an entry in the subspace dictionary
/* This structure defines an entry in the subspace dictionary
   chain.  */
   chain.  */
 
 
struct subspace_dictionary_chain
struct subspace_dictionary_chain
  {
  {
    /* Nonzero if this space has been defined by the user code.  */
    /* Nonzero if this space has been defined by the user code.  */
    unsigned int ssd_defined;
    unsigned int ssd_defined;
 
 
    /* Name of this subspace.  */
    /* Name of this subspace.  */
    char *ssd_name;
    char *ssd_name;
 
 
    /* GAS segment and subsegment associated with this subspace.  */
    /* GAS segment and subsegment associated with this subspace.  */
    asection *ssd_seg;
    asection *ssd_seg;
    int ssd_subseg;
    int ssd_subseg;
 
 
    /* Next space in the subspace dictionary chain.  */
    /* Next space in the subspace dictionary chain.  */
    struct subspace_dictionary_chain *ssd_next;
    struct subspace_dictionary_chain *ssd_next;
  };
  };
 
 
typedef struct subspace_dictionary_chain ssd_chain_struct;
typedef struct subspace_dictionary_chain ssd_chain_struct;
 
 
/* This structure defines an entry in the subspace dictionary
/* This structure defines an entry in the subspace dictionary
   chain.  */
   chain.  */
 
 
struct space_dictionary_chain
struct space_dictionary_chain
  {
  {
    /* Nonzero if this space has been defined by the user code or
    /* Nonzero if this space has been defined by the user code or
       as a default space.  */
       as a default space.  */
    unsigned int sd_defined;
    unsigned int sd_defined;
 
 
    /* Nonzero if this spaces has been defined by the user code.  */
    /* Nonzero if this spaces has been defined by the user code.  */
    unsigned int sd_user_defined;
    unsigned int sd_user_defined;
 
 
    /* The space number (or index).  */
    /* The space number (or index).  */
    unsigned int sd_spnum;
    unsigned int sd_spnum;
 
 
    /* The name of this subspace.  */
    /* The name of this subspace.  */
    char *sd_name;
    char *sd_name;
 
 
    /* GAS segment to which this subspace corresponds.  */
    /* GAS segment to which this subspace corresponds.  */
    asection *sd_seg;
    asection *sd_seg;
 
 
    /* Current subsegment number being used.  */
    /* Current subsegment number being used.  */
    int sd_last_subseg;
    int sd_last_subseg;
 
 
    /* The chain of subspaces contained within this space.  */
    /* The chain of subspaces contained within this space.  */
    ssd_chain_struct *sd_subspaces;
    ssd_chain_struct *sd_subspaces;
 
 
    /* The next entry in the space dictionary chain.  */
    /* The next entry in the space dictionary chain.  */
    struct space_dictionary_chain *sd_next;
    struct space_dictionary_chain *sd_next;
  };
  };
 
 
typedef struct space_dictionary_chain sd_chain_struct;
typedef struct space_dictionary_chain sd_chain_struct;
 
 
/* This structure defines attributes of the default subspace
/* This structure defines attributes of the default subspace
   dictionary entries.  */
   dictionary entries.  */
 
 
struct default_subspace_dict
struct default_subspace_dict
  {
  {
    /* Name of the subspace.  */
    /* Name of the subspace.  */
    char *name;
    char *name;
 
 
    /* FIXME.  Is this still needed?  */
    /* FIXME.  Is this still needed?  */
    char defined;
    char defined;
 
 
    /* Nonzero if this subspace is loadable.  */
    /* Nonzero if this subspace is loadable.  */
    char loadable;
    char loadable;
 
 
    /* Nonzero if this subspace contains only code.  */
    /* Nonzero if this subspace contains only code.  */
    char code_only;
    char code_only;
 
 
    /* Nonzero if this is a comdat subspace.  */
    /* Nonzero if this is a comdat subspace.  */
    char comdat;
    char comdat;
 
 
    /* Nonzero if this is a common subspace.  */
    /* Nonzero if this is a common subspace.  */
    char common;
    char common;
 
 
    /* Nonzero if this is a common subspace which allows symbols
    /* Nonzero if this is a common subspace which allows symbols
       to be multiply defined.  */
       to be multiply defined.  */
    char dup_common;
    char dup_common;
 
 
    /* Nonzero if this subspace should be zero filled.  */
    /* Nonzero if this subspace should be zero filled.  */
    char zero;
    char zero;
 
 
    /* Sort key for this subspace.  */
    /* Sort key for this subspace.  */
    unsigned char sort;
    unsigned char sort;
 
 
    /* Access control bits for this subspace.  Can represent RWX access
    /* Access control bits for this subspace.  Can represent RWX access
       as well as privilege level changes for gateways.  */
       as well as privilege level changes for gateways.  */
    int access;
    int access;
 
 
    /* Index of containing space.  */
    /* Index of containing space.  */
    int space_index;
    int space_index;
 
 
    /* Alignment (in bytes) of this subspace.  */
    /* Alignment (in bytes) of this subspace.  */
    int alignment;
    int alignment;
 
 
    /* Quadrant within space where this subspace should be loaded.  */
    /* Quadrant within space where this subspace should be loaded.  */
    int quadrant;
    int quadrant;
 
 
    /* An index into the default spaces array.  */
    /* An index into the default spaces array.  */
    int def_space_index;
    int def_space_index;
 
 
    /* Subsegment associated with this subspace.  */
    /* Subsegment associated with this subspace.  */
    subsegT subsegment;
    subsegT subsegment;
  };
  };
 
 
/* This structure defines attributes of the default space
/* This structure defines attributes of the default space
   dictionary entries.  */
   dictionary entries.  */
 
 
struct default_space_dict
struct default_space_dict
  {
  {
    /* Name of the space.  */
    /* Name of the space.  */
    char *name;
    char *name;
 
 
    /* Space number.  It is possible to identify spaces within
    /* Space number.  It is possible to identify spaces within
       assembly code numerically!  */
       assembly code numerically!  */
    int spnum;
    int spnum;
 
 
    /* Nonzero if this space is loadable.  */
    /* Nonzero if this space is loadable.  */
    char loadable;
    char loadable;
 
 
    /* Nonzero if this space is "defined".  FIXME is still needed */
    /* Nonzero if this space is "defined".  FIXME is still needed */
    char defined;
    char defined;
 
 
    /* Nonzero if this space can not be shared.  */
    /* Nonzero if this space can not be shared.  */
    char private;
    char private;
 
 
    /* Sort key for this space.  */
    /* Sort key for this space.  */
    unsigned char sort;
    unsigned char sort;
 
 
    /* Segment associated with this space.  */
    /* Segment associated with this space.  */
    asection *segment;
    asection *segment;
  };
  };
#endif
#endif
 
 
/* Structure for previous label tracking.  Needed so that alignments,
/* Structure for previous label tracking.  Needed so that alignments,
   callinfo declarations, etc can be easily attached to a particular
   callinfo declarations, etc can be easily attached to a particular
   label.  */
   label.  */
typedef struct label_symbol_struct
typedef struct label_symbol_struct
  {
  {
    struct symbol *lss_label;
    struct symbol *lss_label;
#ifdef OBJ_SOM
#ifdef OBJ_SOM
    sd_chain_struct *lss_space;
    sd_chain_struct *lss_space;
#endif
#endif
#ifdef OBJ_ELF
#ifdef OBJ_ELF
    segT lss_segment;
    segT lss_segment;
#endif
#endif
    struct label_symbol_struct *lss_next;
    struct label_symbol_struct *lss_next;
  }
  }
label_symbol_struct;
label_symbol_struct;
 
 
/* Extra information needed to perform fixups (relocations) on the PA.  */
/* Extra information needed to perform fixups (relocations) on the PA.  */
struct hppa_fix_struct
struct hppa_fix_struct
  {
  {
    /* The field selector.  */
    /* The field selector.  */
    enum hppa_reloc_field_selector_type_alt fx_r_field;
    enum hppa_reloc_field_selector_type_alt fx_r_field;
 
 
    /* Type of fixup.  */
    /* Type of fixup.  */
    int fx_r_type;
    int fx_r_type;
 
 
    /* Format of fixup.  */
    /* Format of fixup.  */
    int fx_r_format;
    int fx_r_format;
 
 
    /* Argument relocation bits.  */
    /* Argument relocation bits.  */
    unsigned int fx_arg_reloc;
    unsigned int fx_arg_reloc;
 
 
    /* The segment this fixup appears in.  */
    /* The segment this fixup appears in.  */
    segT segment;
    segT segment;
  };
  };
 
 
/* Structure to hold information about predefined registers.  */
/* Structure to hold information about predefined registers.  */
 
 
struct pd_reg
struct pd_reg
  {
  {
    char *name;
    char *name;
    int value;
    int value;
  };
  };
 
 
/* This structure defines the mapping from a FP condition string
/* This structure defines the mapping from a FP condition string
   to a condition number which can be recorded in an instruction.  */
   to a condition number which can be recorded in an instruction.  */
struct fp_cond_map
struct fp_cond_map
  {
  {
    char *string;
    char *string;
    int cond;
    int cond;
  };
  };
 
 
/* This structure defines a mapping from a field selector
/* This structure defines a mapping from a field selector
   string to a field selector type.  */
   string to a field selector type.  */
struct selector_entry
struct selector_entry
  {
  {
    char *prefix;
    char *prefix;
    int field_selector;
    int field_selector;
  };
  };
 
 
/* Prototypes for functions local to tc-hppa.c.  */
/* Prototypes for functions local to tc-hppa.c.  */
 
 
#ifdef OBJ_SOM
#ifdef OBJ_SOM
static void pa_check_current_space_and_subspace (void);
static void pa_check_current_space_and_subspace (void);
#endif
#endif
 
 
#if !(defined (OBJ_ELF) && (defined (TE_LINUX) || defined (TE_NetBSD)))
#if !(defined (OBJ_ELF) && (defined (TE_LINUX) || defined (TE_NetBSD)))
static void pa_text (int);
static void pa_text (int);
static void pa_data (int);
static void pa_data (int);
static void pa_comm (int);
static void pa_comm (int);
#endif
#endif
#ifdef OBJ_SOM
#ifdef OBJ_SOM
static int exact_log2 (int);
static int exact_log2 (int);
static void pa_compiler (int);
static void pa_compiler (int);
static void pa_align (int);
static void pa_align (int);
static void pa_space (int);
static void pa_space (int);
static void pa_spnum (int);
static void pa_spnum (int);
static void pa_subspace (int);
static void pa_subspace (int);
static sd_chain_struct *create_new_space (char *, int, int,
static sd_chain_struct *create_new_space (char *, int, int,
                                                  int, int, int,
                                                  int, int, int,
                                                  asection *, int);
                                                  asection *, int);
static ssd_chain_struct *create_new_subspace (sd_chain_struct *,
static ssd_chain_struct *create_new_subspace (sd_chain_struct *,
                                                      char *, int, int,
                                                      char *, int, int,
                                                      int, int, int, int,
                                                      int, int, int, int,
                                                      int, int, int, int,
                                                      int, int, int, int,
                                                      int, asection *);
                                                      int, asection *);
static ssd_chain_struct *update_subspace (sd_chain_struct *,
static ssd_chain_struct *update_subspace (sd_chain_struct *,
                                                  char *, int, int, int,
                                                  char *, int, int, int,
                                                  int, int, int, int,
                                                  int, int, int, int,
                                                  int, int, int, int,
                                                  int, int, int, int,
                                                  asection *);
                                                  asection *);
static sd_chain_struct *is_defined_space (char *);
static sd_chain_struct *is_defined_space (char *);
static ssd_chain_struct *is_defined_subspace (char *);
static ssd_chain_struct *is_defined_subspace (char *);
static sd_chain_struct *pa_segment_to_space (asection *);
static sd_chain_struct *pa_segment_to_space (asection *);
static ssd_chain_struct *pa_subsegment_to_subspace (asection *,
static ssd_chain_struct *pa_subsegment_to_subspace (asection *,
                                                            subsegT);
                                                            subsegT);
static sd_chain_struct *pa_find_space_by_number (int);
static sd_chain_struct *pa_find_space_by_number (int);
static unsigned int pa_subspace_start (sd_chain_struct *, int);
static unsigned int pa_subspace_start (sd_chain_struct *, int);
static sd_chain_struct *pa_parse_space_stmt (char *, int);
static sd_chain_struct *pa_parse_space_stmt (char *, int);
#endif
#endif
 
 
/* File and globally scoped variable declarations.  */
/* File and globally scoped variable declarations.  */
 
 
#ifdef OBJ_SOM
#ifdef OBJ_SOM
/* Root and final entry in the space chain.  */
/* Root and final entry in the space chain.  */
static sd_chain_struct *space_dict_root;
static sd_chain_struct *space_dict_root;
static sd_chain_struct *space_dict_last;
static sd_chain_struct *space_dict_last;
 
 
/* The current space and subspace.  */
/* The current space and subspace.  */
static sd_chain_struct *current_space;
static sd_chain_struct *current_space;
static ssd_chain_struct *current_subspace;
static ssd_chain_struct *current_subspace;
#endif
#endif
 
 
/* Root of the call_info chain.  */
/* Root of the call_info chain.  */
static struct call_info *call_info_root;
static struct call_info *call_info_root;
 
 
/* The last call_info (for functions) structure
/* The last call_info (for functions) structure
   seen so it can be associated with fixups and
   seen so it can be associated with fixups and
   function labels.  */
   function labels.  */
static struct call_info *last_call_info;
static struct call_info *last_call_info;
 
 
/* The last call description (for actual calls).  */
/* The last call description (for actual calls).  */
static struct call_desc last_call_desc;
static struct call_desc last_call_desc;
 
 
/* handle of the OPCODE hash table */
/* handle of the OPCODE hash table */
static struct hash_control *op_hash = NULL;
static struct hash_control *op_hash = NULL;
 
 
/* These characters can be suffixes of opcode names and they may be
/* These characters can be suffixes of opcode names and they may be
   followed by meaningful whitespace.  We don't include `,' and `!'
   followed by meaningful whitespace.  We don't include `,' and `!'
   as they never appear followed by meaningful whitespace.  */
   as they never appear followed by meaningful whitespace.  */
const char hppa_symbol_chars[] = "*?=<>";
const char hppa_symbol_chars[] = "*?=<>";
 
 
/* This array holds the chars that only start a comment at the beginning of
/* This array holds the chars that only start a comment at the beginning of
   a line.  If the line seems to have the form '# 123 filename'
   a line.  If the line seems to have the form '# 123 filename'
   .line and .file directives will appear in the pre-processed output.
   .line and .file directives will appear in the pre-processed output.
 
 
   Note that input_file.c hand checks for '#' at the beginning of the
   Note that input_file.c hand checks for '#' at the beginning of the
   first line of the input file.  This is because the compiler outputs
   first line of the input file.  This is because the compiler outputs
   #NO_APP at the beginning of its output.
   #NO_APP at the beginning of its output.
 
 
   Also note that C style comments will always work.  */
   Also note that C style comments will always work.  */
const char line_comment_chars[] = "#";
const char line_comment_chars[] = "#";
 
 
/* This array holds the chars that always start a comment.  If the
/* This array holds the chars that always start a comment.  If the
   pre-processor is disabled, these aren't very useful.  */
   pre-processor is disabled, these aren't very useful.  */
const char comment_chars[] = ";";
const char comment_chars[] = ";";
 
 
/* This array holds the characters which act as line separators.  */
/* This array holds the characters which act as line separators.  */
const char line_separator_chars[] = "!";
const char line_separator_chars[] = "!";
 
 
/* Chars that can be used to separate mant from exp in floating point nums.  */
/* Chars that can be used to separate mant from exp in floating point nums.  */
const char EXP_CHARS[] = "eE";
const char EXP_CHARS[] = "eE";
 
 
/* Chars that mean this number is a floating point constant.
/* Chars that mean this number is a floating point constant.
   As in 0f12.456 or 0d1.2345e12.
   As in 0f12.456 or 0d1.2345e12.
 
 
   Be aware that MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT may have to be
   Be aware that MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT may have to be
   changed in read.c.  Ideally it shouldn't have to know about it
   changed in read.c.  Ideally it shouldn't have to know about it
   at all, but nothing is ideal around here.  */
   at all, but nothing is ideal around here.  */
const char FLT_CHARS[] = "rRsSfFdDxXpP";
const char FLT_CHARS[] = "rRsSfFdDxXpP";
 
 
static struct pa_it the_insn;
static struct pa_it the_insn;
 
 
/* Points to the end of an expression just parsed by get_expression
/* Points to the end of an expression just parsed by get_expression
   and friends.  FIXME.  This shouldn't be handled with a file-global
   and friends.  FIXME.  This shouldn't be handled with a file-global
   variable.  */
   variable.  */
static char *expr_end;
static char *expr_end;
 
 
/* Nonzero if a .callinfo appeared within the current procedure.  */
/* Nonzero if a .callinfo appeared within the current procedure.  */
static int callinfo_found;
static int callinfo_found;
 
 
/* Nonzero if the assembler is currently within a .entry/.exit pair.  */
/* Nonzero if the assembler is currently within a .entry/.exit pair.  */
static int within_entry_exit;
static int within_entry_exit;
 
 
/* Nonzero if the assembler is currently within a procedure definition.  */
/* Nonzero if the assembler is currently within a procedure definition.  */
static int within_procedure;
static int within_procedure;
 
 
/* Handle on structure which keep track of the last symbol
/* Handle on structure which keep track of the last symbol
   seen in each subspace.  */
   seen in each subspace.  */
static label_symbol_struct *label_symbols_rootp = NULL;
static label_symbol_struct *label_symbols_rootp = NULL;
 
 
/* Holds the last field selector.  */
/* Holds the last field selector.  */
static int hppa_field_selector;
static int hppa_field_selector;
 
 
/* Nonzero when strict matching is enabled.  Zero otherwise.
/* Nonzero when strict matching is enabled.  Zero otherwise.
 
 
   Each opcode in the table has a flag which indicates whether or
   Each opcode in the table has a flag which indicates whether or
   not strict matching should be enabled for that instruction.
   not strict matching should be enabled for that instruction.
 
 
   Mainly, strict causes errors to be ignored when a match failure
   Mainly, strict causes errors to be ignored when a match failure
   occurs.  However, it also affects the parsing of register fields
   occurs.  However, it also affects the parsing of register fields
   by pa_parse_number.  */
   by pa_parse_number.  */
static int strict;
static int strict;
 
 
/* pa_parse_number returns values in `pa_number'.  Mostly
/* pa_parse_number returns values in `pa_number'.  Mostly
   pa_parse_number is used to return a register number, with floating
   pa_parse_number is used to return a register number, with floating
   point registers being numbered from FP_REG_BASE upwards.
   point registers being numbered from FP_REG_BASE upwards.
   The bit specified with FP_REG_RSEL is set if the floating point
   The bit specified with FP_REG_RSEL is set if the floating point
   register has a `r' suffix.  */
   register has a `r' suffix.  */
#define FP_REG_BASE 64
#define FP_REG_BASE 64
#define FP_REG_RSEL 128
#define FP_REG_RSEL 128
static int pa_number;
static int pa_number;
 
 
#ifdef OBJ_SOM
#ifdef OBJ_SOM
/* A dummy bfd symbol so that all relocations have symbols of some kind.  */
/* A dummy bfd symbol so that all relocations have symbols of some kind.  */
static symbolS *dummy_symbol;
static symbolS *dummy_symbol;
#endif
#endif
 
 
/* Nonzero if errors are to be printed.  */
/* Nonzero if errors are to be printed.  */
static int print_errors = 1;
static int print_errors = 1;
 
 
/* List of registers that are pre-defined:
/* List of registers that are pre-defined:
 
 
   Each general register has one predefined name of the form
   Each general register has one predefined name of the form
   %r<REGNUM> which has the value <REGNUM>.
   %r<REGNUM> which has the value <REGNUM>.
 
 
   Space and control registers are handled in a similar manner,
   Space and control registers are handled in a similar manner,
   but use %sr<REGNUM> and %cr<REGNUM> as their predefined names.
   but use %sr<REGNUM> and %cr<REGNUM> as their predefined names.
 
 
   Likewise for the floating point registers, but of the form
   Likewise for the floating point registers, but of the form
   %fr<REGNUM>.  Floating point registers have additional predefined
   %fr<REGNUM>.  Floating point registers have additional predefined
   names with 'L' and 'R' suffixes (e.g. %fr19L, %fr19R) which
   names with 'L' and 'R' suffixes (e.g. %fr19L, %fr19R) which
   again have the value <REGNUM>.
   again have the value <REGNUM>.
 
 
   Many registers also have synonyms:
   Many registers also have synonyms:
 
 
   %r26 - %r23 have %arg0 - %arg3 as synonyms
   %r26 - %r23 have %arg0 - %arg3 as synonyms
   %r28 - %r29 have %ret0 - %ret1 as synonyms
   %r28 - %r29 have %ret0 - %ret1 as synonyms
   %fr4 - %fr7 have %farg0 - %farg3 as synonyms
   %fr4 - %fr7 have %farg0 - %farg3 as synonyms
   %r30 has %sp as a synonym
   %r30 has %sp as a synonym
   %r27 has %dp as a synonym
   %r27 has %dp as a synonym
   %r2  has %rp as a synonym
   %r2  has %rp as a synonym
 
 
   Almost every control register has a synonym; they are not listed
   Almost every control register has a synonym; they are not listed
   here for brevity.
   here for brevity.
 
 
   The table is sorted. Suitable for searching by a binary search.  */
   The table is sorted. Suitable for searching by a binary search.  */
 
 
static const struct pd_reg pre_defined_registers[] =
static const struct pd_reg pre_defined_registers[] =
{
{
  {"%arg0",  26},
  {"%arg0",  26},
  {"%arg1",  25},
  {"%arg1",  25},
  {"%arg2",  24},
  {"%arg2",  24},
  {"%arg3",  23},
  {"%arg3",  23},
  {"%cr0",    0},
  {"%cr0",    0},
  {"%cr10",  10},
  {"%cr10",  10},
  {"%cr11",  11},
  {"%cr11",  11},
  {"%cr12",  12},
  {"%cr12",  12},
  {"%cr13",  13},
  {"%cr13",  13},
  {"%cr14",  14},
  {"%cr14",  14},
  {"%cr15",  15},
  {"%cr15",  15},
  {"%cr16",  16},
  {"%cr16",  16},
  {"%cr17",  17},
  {"%cr17",  17},
  {"%cr18",  18},
  {"%cr18",  18},
  {"%cr19",  19},
  {"%cr19",  19},
  {"%cr20",  20},
  {"%cr20",  20},
  {"%cr21",  21},
  {"%cr21",  21},
  {"%cr22",  22},
  {"%cr22",  22},
  {"%cr23",  23},
  {"%cr23",  23},
  {"%cr24",  24},
  {"%cr24",  24},
  {"%cr25",  25},
  {"%cr25",  25},
  {"%cr26",  26},
  {"%cr26",  26},
  {"%cr27",  27},
  {"%cr27",  27},
  {"%cr28",  28},
  {"%cr28",  28},
  {"%cr29",  29},
  {"%cr29",  29},
  {"%cr30",  30},
  {"%cr30",  30},
  {"%cr31",  31},
  {"%cr31",  31},
  {"%cr8",    8},
  {"%cr8",    8},
  {"%cr9",    9},
  {"%cr9",    9},
  {"%dp",    27},
  {"%dp",    27},
  {"%eiem",  15},
  {"%eiem",  15},
  {"%eirr",  23},
  {"%eirr",  23},
  {"%farg0",  4 + FP_REG_BASE},
  {"%farg0",  4 + FP_REG_BASE},
  {"%farg1",  5 + FP_REG_BASE},
  {"%farg1",  5 + FP_REG_BASE},
  {"%farg2",  6 + FP_REG_BASE},
  {"%farg2",  6 + FP_REG_BASE},
  {"%farg3",  7 + FP_REG_BASE},
  {"%farg3",  7 + FP_REG_BASE},
  {"%fr0",    0 + FP_REG_BASE},
  {"%fr0",    0 + FP_REG_BASE},
  {"%fr0l",   0 + FP_REG_BASE},
  {"%fr0l",   0 + FP_REG_BASE},
  {"%fr0r",   0 + FP_REG_BASE + FP_REG_RSEL},
  {"%fr0r",   0 + FP_REG_BASE + FP_REG_RSEL},
  {"%fr1",    1 + FP_REG_BASE},
  {"%fr1",    1 + FP_REG_BASE},
  {"%fr10",  10 + FP_REG_BASE},
  {"%fr10",  10 + FP_REG_BASE},
  {"%fr10l", 10 + FP_REG_BASE},
  {"%fr10l", 10 + FP_REG_BASE},
  {"%fr10r", 10 + FP_REG_BASE + FP_REG_RSEL},
  {"%fr10r", 10 + FP_REG_BASE + FP_REG_RSEL},
  {"%fr11",  11 + FP_REG_BASE},
  {"%fr11",  11 + FP_REG_BASE},
  {"%fr11l", 11 + FP_REG_BASE},
  {"%fr11l", 11 + FP_REG_BASE},
  {"%fr11r", 11 + FP_REG_BASE + FP_REG_RSEL},
  {"%fr11r", 11 + FP_REG_BASE + FP_REG_RSEL},
  {"%fr12",  12 + FP_REG_BASE},
  {"%fr12",  12 + FP_REG_BASE},
  {"%fr12l", 12 + FP_REG_BASE},
  {"%fr12l", 12 + FP_REG_BASE},
  {"%fr12r", 12 + FP_REG_BASE + FP_REG_RSEL},
  {"%fr12r", 12 + FP_REG_BASE + FP_REG_RSEL},
  {"%fr13",  13 + FP_REG_BASE},
  {"%fr13",  13 + FP_REG_BASE},
  {"%fr13l", 13 + FP_REG_BASE},
  {"%fr13l", 13 + FP_REG_BASE},
  {"%fr13r", 13 + FP_REG_BASE + FP_REG_RSEL},
  {"%fr13r", 13 + FP_REG_BASE + FP_REG_RSEL},
  {"%fr14",  14 + FP_REG_BASE},
  {"%fr14",  14 + FP_REG_BASE},
  {"%fr14l", 14 + FP_REG_BASE},
  {"%fr14l", 14 + FP_REG_BASE},
  {"%fr14r", 14 + FP_REG_BASE + FP_REG_RSEL},
  {"%fr14r", 14 + FP_REG_BASE + FP_REG_RSEL},
  {"%fr15",  15 + FP_REG_BASE},
  {"%fr15",  15 + FP_REG_BASE},
  {"%fr15l", 15 + FP_REG_BASE},
  {"%fr15l", 15 + FP_REG_BASE},
  {"%fr15r", 15 + FP_REG_BASE + FP_REG_RSEL},
  {"%fr15r", 15 + FP_REG_BASE + FP_REG_RSEL},
  {"%fr16",  16 + FP_REG_BASE},
  {"%fr16",  16 + FP_REG_BASE},
  {"%fr16l", 16 + FP_REG_BASE},
  {"%fr16l", 16 + FP_REG_BASE},
  {"%fr16r", 16 + FP_REG_BASE + FP_REG_RSEL},
  {"%fr16r", 16 + FP_REG_BASE + FP_REG_RSEL},
  {"%fr17",  17 + FP_REG_BASE},
  {"%fr17",  17 + FP_REG_BASE},
  {"%fr17l", 17 + FP_REG_BASE},
  {"%fr17l", 17 + FP_REG_BASE},
  {"%fr17r", 17 + FP_REG_BASE + FP_REG_RSEL},
  {"%fr17r", 17 + FP_REG_BASE + FP_REG_RSEL},
  {"%fr18",  18 + FP_REG_BASE},
  {"%fr18",  18 + FP_REG_BASE},
  {"%fr18l", 18 + FP_REG_BASE},
  {"%fr18l", 18 + FP_REG_BASE},
  {"%fr18r", 18 + FP_REG_BASE + FP_REG_RSEL},
  {"%fr18r", 18 + FP_REG_BASE + FP_REG_RSEL},
  {"%fr19",  19 + FP_REG_BASE},
  {"%fr19",  19 + FP_REG_BASE},
  {"%fr19l", 19 + FP_REG_BASE},
  {"%fr19l", 19 + FP_REG_BASE},
  {"%fr19r", 19 + FP_REG_BASE + FP_REG_RSEL},
  {"%fr19r", 19 + FP_REG_BASE + FP_REG_RSEL},
  {"%fr1l",   1 + FP_REG_BASE},
  {"%fr1l",   1 + FP_REG_BASE},
  {"%fr1r",   1 + FP_REG_BASE + FP_REG_RSEL},
  {"%fr1r",   1 + FP_REG_BASE + FP_REG_RSEL},
  {"%fr2",    2 + FP_REG_BASE},
  {"%fr2",    2 + FP_REG_BASE},
  {"%fr20",  20 + FP_REG_BASE},
  {"%fr20",  20 + FP_REG_BASE},
  {"%fr20l", 20 + FP_REG_BASE},
  {"%fr20l", 20 + FP_REG_BASE},
  {"%fr20r", 20 + FP_REG_BASE + FP_REG_RSEL},
  {"%fr20r", 20 + FP_REG_BASE + FP_REG_RSEL},
  {"%fr21",  21 + FP_REG_BASE},
  {"%fr21",  21 + FP_REG_BASE},
  {"%fr21l", 21 + FP_REG_BASE},
  {"%fr21l", 21 + FP_REG_BASE},
  {"%fr21r", 21 + FP_REG_BASE + FP_REG_RSEL},
  {"%fr21r", 21 + FP_REG_BASE + FP_REG_RSEL},
  {"%fr22",  22 + FP_REG_BASE},
  {"%fr22",  22 + FP_REG_BASE},
  {"%fr22l", 22 + FP_REG_BASE},
  {"%fr22l", 22 + FP_REG_BASE},
  {"%fr22r", 22 + FP_REG_BASE + FP_REG_RSEL},
  {"%fr22r", 22 + FP_REG_BASE + FP_REG_RSEL},
  {"%fr23",  23 + FP_REG_BASE},
  {"%fr23",  23 + FP_REG_BASE},
  {"%fr23l", 23 + FP_REG_BASE},
  {"%fr23l", 23 + FP_REG_BASE},
  {"%fr23r", 23 + FP_REG_BASE + FP_REG_RSEL},
  {"%fr23r", 23 + FP_REG_BASE + FP_REG_RSEL},
  {"%fr24",  24 + FP_REG_BASE},
  {"%fr24",  24 + FP_REG_BASE},
  {"%fr24l", 24 + FP_REG_BASE},
  {"%fr24l", 24 + FP_REG_BASE},
  {"%fr24r", 24 + FP_REG_BASE + FP_REG_RSEL},
  {"%fr24r", 24 + FP_REG_BASE + FP_REG_RSEL},
  {"%fr25",  25 + FP_REG_BASE},
  {"%fr25",  25 + FP_REG_BASE},
  {"%fr25l", 25 + FP_REG_BASE},
  {"%fr25l", 25 + FP_REG_BASE},
  {"%fr25r", 25 + FP_REG_BASE + FP_REG_RSEL},
  {"%fr25r", 25 + FP_REG_BASE + FP_REG_RSEL},
  {"%fr26",  26 + FP_REG_BASE},
  {"%fr26",  26 + FP_REG_BASE},
  {"%fr26l", 26 + FP_REG_BASE},
  {"%fr26l", 26 + FP_REG_BASE},
  {"%fr26r", 26 + FP_REG_BASE + FP_REG_RSEL},
  {"%fr26r", 26 + FP_REG_BASE + FP_REG_RSEL},
  {"%fr27",  27 + FP_REG_BASE},
  {"%fr27",  27 + FP_REG_BASE},
  {"%fr27l", 27 + FP_REG_BASE},
  {"%fr27l", 27 + FP_REG_BASE},
  {"%fr27r", 27 + FP_REG_BASE + FP_REG_RSEL},
  {"%fr27r", 27 + FP_REG_BASE + FP_REG_RSEL},
  {"%fr28",  28 + FP_REG_BASE},
  {"%fr28",  28 + FP_REG_BASE},
  {"%fr28l", 28 + FP_REG_BASE},
  {"%fr28l", 28 + FP_REG_BASE},
  {"%fr28r", 28 + FP_REG_BASE + FP_REG_RSEL},
  {"%fr28r", 28 + FP_REG_BASE + FP_REG_RSEL},
  {"%fr29",  29 + FP_REG_BASE},
  {"%fr29",  29 + FP_REG_BASE},
  {"%fr29l", 29 + FP_REG_BASE},
  {"%fr29l", 29 + FP_REG_BASE},
  {"%fr29r", 29 + FP_REG_BASE + FP_REG_RSEL},
  {"%fr29r", 29 + FP_REG_BASE + FP_REG_RSEL},
  {"%fr2l",   2 + FP_REG_BASE},
  {"%fr2l",   2 + FP_REG_BASE},
  {"%fr2r",   2 + FP_REG_BASE + FP_REG_RSEL},
  {"%fr2r",   2 + FP_REG_BASE + FP_REG_RSEL},
  {"%fr3",    3 + FP_REG_BASE},
  {"%fr3",    3 + FP_REG_BASE},
  {"%fr30",  30 + FP_REG_BASE},
  {"%fr30",  30 + FP_REG_BASE},
  {"%fr30l", 30 + FP_REG_BASE},
  {"%fr30l", 30 + FP_REG_BASE},
  {"%fr30r", 30 + FP_REG_BASE + FP_REG_RSEL},
  {"%fr30r", 30 + FP_REG_BASE + FP_REG_RSEL},
  {"%fr31",  31 + FP_REG_BASE},
  {"%fr31",  31 + FP_REG_BASE},
  {"%fr31l", 31 + FP_REG_BASE},
  {"%fr31l", 31 + FP_REG_BASE},
  {"%fr31r", 31 + FP_REG_BASE + FP_REG_RSEL},
  {"%fr31r", 31 + FP_REG_BASE + FP_REG_RSEL},
  {"%fr3l",   3 + FP_REG_BASE},
  {"%fr3l",   3 + FP_REG_BASE},
  {"%fr3r",   3 + FP_REG_BASE + FP_REG_RSEL},
  {"%fr3r",   3 + FP_REG_BASE + FP_REG_RSEL},
  {"%fr4",    4 + FP_REG_BASE},
  {"%fr4",    4 + FP_REG_BASE},
  {"%fr4l",   4 + FP_REG_BASE},
  {"%fr4l",   4 + FP_REG_BASE},
  {"%fr4r",   4 + FP_REG_BASE + FP_REG_RSEL},
  {"%fr4r",   4 + FP_REG_BASE + FP_REG_RSEL},
  {"%fr5",    5 + FP_REG_BASE},
  {"%fr5",    5 + FP_REG_BASE},
  {"%fr5l",   5 + FP_REG_BASE},
  {"%fr5l",   5 + FP_REG_BASE},
  {"%fr5r",   5 + FP_REG_BASE + FP_REG_RSEL},
  {"%fr5r",   5 + FP_REG_BASE + FP_REG_RSEL},
  {"%fr6",    6 + FP_REG_BASE},
  {"%fr6",    6 + FP_REG_BASE},
  {"%fr6l",   6 + FP_REG_BASE},
  {"%fr6l",   6 + FP_REG_BASE},
  {"%fr6r",   6 + FP_REG_BASE + FP_REG_RSEL},
  {"%fr6r",   6 + FP_REG_BASE + FP_REG_RSEL},
  {"%fr7",    7 + FP_REG_BASE},
  {"%fr7",    7 + FP_REG_BASE},
  {"%fr7l",   7 + FP_REG_BASE},
  {"%fr7l",   7 + FP_REG_BASE},
  {"%fr7r",   7 + FP_REG_BASE + FP_REG_RSEL},
  {"%fr7r",   7 + FP_REG_BASE + FP_REG_RSEL},
  {"%fr8",    8 + FP_REG_BASE},
  {"%fr8",    8 + FP_REG_BASE},
  {"%fr8l",   8 + FP_REG_BASE},
  {"%fr8l",   8 + FP_REG_BASE},
  {"%fr8r",   8 + FP_REG_BASE + FP_REG_RSEL},
  {"%fr8r",   8 + FP_REG_BASE + FP_REG_RSEL},
  {"%fr9",    9 + FP_REG_BASE},
  {"%fr9",    9 + FP_REG_BASE},
  {"%fr9l",   9 + FP_REG_BASE},
  {"%fr9l",   9 + FP_REG_BASE},
  {"%fr9r",   9 + FP_REG_BASE + FP_REG_RSEL},
  {"%fr9r",   9 + FP_REG_BASE + FP_REG_RSEL},
  {"%fret",   4},
  {"%fret",   4},
  {"%hta",   25},
  {"%hta",   25},
  {"%iir",   19},
  {"%iir",   19},
  {"%ior",   21},
  {"%ior",   21},
  {"%ipsw",  22},
  {"%ipsw",  22},
  {"%isr",   20},
  {"%isr",   20},
  {"%itmr",  16},
  {"%itmr",  16},
  {"%iva",   14},
  {"%iva",   14},
#if TARGET_ARCH_SIZE == 64
#if TARGET_ARCH_SIZE == 64
  {"%mrp",    2},
  {"%mrp",    2},
#else
#else
  {"%mrp",   31},
  {"%mrp",   31},
#endif
#endif
  {"%pcoq",  18},
  {"%pcoq",  18},
  {"%pcsq",  17},
  {"%pcsq",  17},
  {"%pidr1",  8},
  {"%pidr1",  8},
  {"%pidr2",  9},
  {"%pidr2",  9},
  {"%pidr3", 12},
  {"%pidr3", 12},
  {"%pidr4", 13},
  {"%pidr4", 13},
  {"%ppda",  24},
  {"%ppda",  24},
  {"%r0",     0},
  {"%r0",     0},
  {"%r1",     1},
  {"%r1",     1},
  {"%r10",   10},
  {"%r10",   10},
  {"%r11",   11},
  {"%r11",   11},
  {"%r12",   12},
  {"%r12",   12},
  {"%r13",   13},
  {"%r13",   13},
  {"%r14",   14},
  {"%r14",   14},
  {"%r15",   15},
  {"%r15",   15},
  {"%r16",   16},
  {"%r16",   16},
  {"%r17",   17},
  {"%r17",   17},
  {"%r18",   18},
  {"%r18",   18},
  {"%r19",   19},
  {"%r19",   19},
  {"%r2",     2},
  {"%r2",     2},
  {"%r20",   20},
  {"%r20",   20},
  {"%r21",   21},
  {"%r21",   21},
  {"%r22",   22},
  {"%r22",   22},
  {"%r23",   23},
  {"%r23",   23},
  {"%r24",   24},
  {"%r24",   24},
  {"%r25",   25},
  {"%r25",   25},
  {"%r26",   26},
  {"%r26",   26},
  {"%r27",   27},
  {"%r27",   27},
  {"%r28",   28},
  {"%r28",   28},
  {"%r29",   29},
  {"%r29",   29},
  {"%r3",     3},
  {"%r3",     3},
  {"%r30",   30},
  {"%r30",   30},
  {"%r31",   31},
  {"%r31",   31},
  {"%r4",     4},
  {"%r4",     4},
  {"%r5",     5},
  {"%r5",     5},
  {"%r6",     6},
  {"%r6",     6},
  {"%r7",     7},
  {"%r7",     7},
  {"%r8",     8},
  {"%r8",     8},
  {"%r9",     9},
  {"%r9",     9},
  {"%rctr",   0},
  {"%rctr",   0},
  {"%ret0",  28},
  {"%ret0",  28},
  {"%ret1",  29},
  {"%ret1",  29},
  {"%rp",     2},
  {"%rp",     2},
  {"%sar",   11},
  {"%sar",   11},
  {"%sp",    30},
  {"%sp",    30},
  {"%sr0",    0},
  {"%sr0",    0},
  {"%sr1",    1},
  {"%sr1",    1},
  {"%sr2",    2},
  {"%sr2",    2},
  {"%sr3",    3},
  {"%sr3",    3},
  {"%sr4",    4},
  {"%sr4",    4},
  {"%sr5",    5},
  {"%sr5",    5},
  {"%sr6",    6},
  {"%sr6",    6},
  {"%sr7",    7},
  {"%sr7",    7},
  {"%t1",    22},
  {"%t1",    22},
  {"%t2",    21},
  {"%t2",    21},
  {"%t3",    20},
  {"%t3",    20},
  {"%t4",    19},
  {"%t4",    19},
  {"%tf1",   11},
  {"%tf1",   11},
  {"%tf2",   10},
  {"%tf2",   10},
  {"%tf3",    9},
  {"%tf3",    9},
  {"%tf4",    8},
  {"%tf4",    8},
  {"%tr0",   24},
  {"%tr0",   24},
  {"%tr1",   25},
  {"%tr1",   25},
  {"%tr2",   26},
  {"%tr2",   26},
  {"%tr3",   27},
  {"%tr3",   27},
  {"%tr4",   28},
  {"%tr4",   28},
  {"%tr5",   29},
  {"%tr5",   29},
  {"%tr6",   30},
  {"%tr6",   30},
  {"%tr7",   31}
  {"%tr7",   31}
};
};
 
 
/* This table is sorted by order of the length of the string. This is
/* This table is sorted by order of the length of the string. This is
   so we check for <> before we check for <. If we had a <> and checked
   so we check for <> before we check for <. If we had a <> and checked
   for < first, we would get a false match.  */
   for < first, we would get a false match.  */
static const struct fp_cond_map fp_cond_map[] =
static const struct fp_cond_map fp_cond_map[] =
{
{
  {"false?", 0},
  {"false?", 0},
  {"false", 1},
  {"false", 1},
  {"true?", 30},
  {"true?", 30},
  {"true", 31},
  {"true", 31},
  {"!<=>", 3},
  {"!<=>", 3},
  {"!?>=", 8},
  {"!?>=", 8},
  {"!?<=", 16},
  {"!?<=", 16},
  {"!<>", 7},
  {"!<>", 7},
  {"!>=", 11},
  {"!>=", 11},
  {"!?>", 12},
  {"!?>", 12},
  {"?<=", 14},
  {"?<=", 14},
  {"!<=", 19},
  {"!<=", 19},
  {"!?<", 20},
  {"!?<", 20},
  {"?>=", 22},
  {"?>=", 22},
  {"!?=", 24},
  {"!?=", 24},
  {"!=t", 27},
  {"!=t", 27},
  {"<=>", 29},
  {"<=>", 29},
  {"=t", 5},
  {"=t", 5},
  {"?=", 6},
  {"?=", 6},
  {"?<", 10},
  {"?<", 10},
  {"<=", 13},
  {"<=", 13},
  {"!>", 15},
  {"!>", 15},
  {"?>", 18},
  {"?>", 18},
  {">=", 21},
  {">=", 21},
  {"!<", 23},
  {"!<", 23},
  {"<>", 25},
  {"<>", 25},
  {"!=", 26},
  {"!=", 26},
  {"!?", 28},
  {"!?", 28},
  {"?", 2},
  {"?", 2},
  {"=", 4},
  {"=", 4},
  {"<", 9},
  {"<", 9},
  {">", 17}
  {">", 17}
};
};
 
 
static const struct selector_entry selector_table[] =
static const struct selector_entry selector_table[] =
{
{
  {"f", e_fsel},
  {"f", e_fsel},
  {"l", e_lsel},
  {"l", e_lsel},
  {"ld", e_ldsel},
  {"ld", e_ldsel},
  {"lp", e_lpsel},
  {"lp", e_lpsel},
  {"lr", e_lrsel},
  {"lr", e_lrsel},
  {"ls", e_lssel},
  {"ls", e_lssel},
  {"lt", e_ltsel},
  {"lt", e_ltsel},
  {"ltp", e_ltpsel},
  {"ltp", e_ltpsel},
  {"n", e_nsel},
  {"n", e_nsel},
  {"nl", e_nlsel},
  {"nl", e_nlsel},
  {"nlr", e_nlrsel},
  {"nlr", e_nlrsel},
  {"p", e_psel},
  {"p", e_psel},
  {"r", e_rsel},
  {"r", e_rsel},
  {"rd", e_rdsel},
  {"rd", e_rdsel},
  {"rp", e_rpsel},
  {"rp", e_rpsel},
  {"rr", e_rrsel},
  {"rr", e_rrsel},
  {"rs", e_rssel},
  {"rs", e_rssel},
  {"rt", e_rtsel},
  {"rt", e_rtsel},
  {"rtp", e_rtpsel},
  {"rtp", e_rtpsel},
  {"t", e_tsel},
  {"t", e_tsel},
};
};
 
 
#ifdef OBJ_SOM
#ifdef OBJ_SOM
/* default space and subspace dictionaries */
/* default space and subspace dictionaries */
 
 
#define GDB_SYMBOLS          GDB_SYMBOLS_SUBSPACE_NAME
#define GDB_SYMBOLS          GDB_SYMBOLS_SUBSPACE_NAME
#define GDB_STRINGS          GDB_STRINGS_SUBSPACE_NAME
#define GDB_STRINGS          GDB_STRINGS_SUBSPACE_NAME
 
 
/* pre-defined subsegments (subspaces) for the HPPA.  */
/* pre-defined subsegments (subspaces) for the HPPA.  */
#define SUBSEG_CODE   0
#define SUBSEG_CODE   0
#define SUBSEG_LIT    1
#define SUBSEG_LIT    1
#define SUBSEG_MILLI  2
#define SUBSEG_MILLI  2
#define SUBSEG_DATA   0
#define SUBSEG_DATA   0
#define SUBSEG_BSS    2
#define SUBSEG_BSS    2
#define SUBSEG_UNWIND 3
#define SUBSEG_UNWIND 3
#define SUBSEG_GDB_STRINGS 0
#define SUBSEG_GDB_STRINGS 0
#define SUBSEG_GDB_SYMBOLS 1
#define SUBSEG_GDB_SYMBOLS 1
 
 
static struct default_subspace_dict pa_def_subspaces[] =
static struct default_subspace_dict pa_def_subspaces[] =
{
{
  {"$CODE$", 1, 1, 1, 0, 0, 0, 0, 24, 0x2c, 0, 8, 0, 0, SUBSEG_CODE},
  {"$CODE$", 1, 1, 1, 0, 0, 0, 0, 24, 0x2c, 0, 8, 0, 0, SUBSEG_CODE},
  {"$DATA$", 1, 1, 0, 0, 0, 0, 0, 24, 0x1f, 1, 8, 1, 1, SUBSEG_DATA},
  {"$DATA$", 1, 1, 0, 0, 0, 0, 0, 24, 0x1f, 1, 8, 1, 1, SUBSEG_DATA},
  {"$LIT$", 1, 1, 0, 0, 0, 0, 0, 16, 0x2c, 0, 8, 0, 0, SUBSEG_LIT},
  {"$LIT$", 1, 1, 0, 0, 0, 0, 0, 16, 0x2c, 0, 8, 0, 0, SUBSEG_LIT},
  {"$MILLICODE$", 1, 1, 0, 0, 0, 0, 0, 8, 0x2c, 0, 8, 0, 0, SUBSEG_MILLI},
  {"$MILLICODE$", 1, 1, 0, 0, 0, 0, 0, 8, 0x2c, 0, 8, 0, 0, SUBSEG_MILLI},
  {"$BSS$", 1, 1, 0, 0, 0, 0, 1, 80, 0x1f, 1, 8, 1, 1, SUBSEG_BSS},
  {"$BSS$", 1, 1, 0, 0, 0, 0, 1, 80, 0x1f, 1, 8, 1, 1, SUBSEG_BSS},
  {NULL, 0, 1, 0, 0, 0, 0, 0, 255, 0x1f, 0, 4, 0, 0, 0}
  {NULL, 0, 1, 0, 0, 0, 0, 0, 255, 0x1f, 0, 4, 0, 0, 0}
};
};
 
 
static struct default_space_dict pa_def_spaces[] =
static struct default_space_dict pa_def_spaces[] =
{
{
  {"$TEXT$", 0, 1, 1, 0, 8, ASEC_NULL},
  {"$TEXT$", 0, 1, 1, 0, 8, ASEC_NULL},
  {"$PRIVATE$", 1, 1, 1, 1, 16, ASEC_NULL},
  {"$PRIVATE$", 1, 1, 1, 1, 16, ASEC_NULL},
  {NULL, 0, 0, 0, 0, 0, ASEC_NULL}
  {NULL, 0, 0, 0, 0, 0, ASEC_NULL}
};
};
 
 
/* Misc local definitions used by the assembler.  */
/* Misc local definitions used by the assembler.  */
 
 
/* These macros are used to maintain spaces/subspaces.  */
/* These macros are used to maintain spaces/subspaces.  */
#define SPACE_DEFINED(space_chain)      (space_chain)->sd_defined
#define SPACE_DEFINED(space_chain)      (space_chain)->sd_defined
#define SPACE_USER_DEFINED(space_chain) (space_chain)->sd_user_defined
#define SPACE_USER_DEFINED(space_chain) (space_chain)->sd_user_defined
#define SPACE_SPNUM(space_chain)        (space_chain)->sd_spnum
#define SPACE_SPNUM(space_chain)        (space_chain)->sd_spnum
#define SPACE_NAME(space_chain)         (space_chain)->sd_name
#define SPACE_NAME(space_chain)         (space_chain)->sd_name
 
 
#define SUBSPACE_DEFINED(ss_chain)      (ss_chain)->ssd_defined
#define SUBSPACE_DEFINED(ss_chain)      (ss_chain)->ssd_defined
#define SUBSPACE_NAME(ss_chain)         (ss_chain)->ssd_name
#define SUBSPACE_NAME(ss_chain)         (ss_chain)->ssd_name
#endif
#endif
 
 
/* Return nonzero if the string pointed to by S potentially represents
/* Return nonzero if the string pointed to by S potentially represents
   a right or left half of a FP register  */
   a right or left half of a FP register  */
#define IS_R_SELECT(S)   (*(S) == 'R' || *(S) == 'r')
#define IS_R_SELECT(S)   (*(S) == 'R' || *(S) == 'r')
#define IS_L_SELECT(S)   (*(S) == 'L' || *(S) == 'l')
#define IS_L_SELECT(S)   (*(S) == 'L' || *(S) == 'l')
 
 
/* Insert FIELD into OPCODE starting at bit START.  Continue pa_ip
/* Insert FIELD into OPCODE starting at bit START.  Continue pa_ip
   main loop after insertion.  */
   main loop after insertion.  */
 
 
#define INSERT_FIELD_AND_CONTINUE(OPCODE, FIELD, START) \
#define INSERT_FIELD_AND_CONTINUE(OPCODE, FIELD, START) \
  { \
  { \
    ((OPCODE) |= (FIELD) << (START)); \
    ((OPCODE) |= (FIELD) << (START)); \
    continue; \
    continue; \
  }
  }
 
 
/* Simple range checking for FIELD against HIGH and LOW bounds.
/* Simple range checking for FIELD against HIGH and LOW bounds.
   IGNORE is used to suppress the error message.  */
   IGNORE is used to suppress the error message.  */
 
 
#define CHECK_FIELD(FIELD, HIGH, LOW, IGNORE) \
#define CHECK_FIELD(FIELD, HIGH, LOW, IGNORE) \
  { \
  { \
    if ((FIELD) > (HIGH) || (FIELD) < (LOW)) \
    if ((FIELD) > (HIGH) || (FIELD) < (LOW)) \
      { \
      { \
        if (! IGNORE) \
        if (! IGNORE) \
          as_bad (_("Field out of range [%d..%d] (%d)."), (LOW), (HIGH), \
          as_bad (_("Field out of range [%d..%d] (%d)."), (LOW), (HIGH), \
                  (int) (FIELD));\
                  (int) (FIELD));\
        break; \
        break; \
      } \
      } \
  }
  }
 
 
/* Variant of CHECK_FIELD for use in md_apply_fix and other places where
/* Variant of CHECK_FIELD for use in md_apply_fix and other places where
   the current file and line number are not valid.  */
   the current file and line number are not valid.  */
 
 
#define CHECK_FIELD_WHERE(FIELD, HIGH, LOW, FILENAME, LINE) \
#define CHECK_FIELD_WHERE(FIELD, HIGH, LOW, FILENAME, LINE) \
  { \
  { \
    if ((FIELD) > (HIGH) || (FIELD) < (LOW)) \
    if ((FIELD) > (HIGH) || (FIELD) < (LOW)) \
      { \
      { \
        as_bad_where ((FILENAME), (LINE), \
        as_bad_where ((FILENAME), (LINE), \
                      _("Field out of range [%d..%d] (%d)."), (LOW), (HIGH), \
                      _("Field out of range [%d..%d] (%d)."), (LOW), (HIGH), \
                      (int) (FIELD));\
                      (int) (FIELD));\
        break; \
        break; \
      } \
      } \
  }
  }
 
 
/* Simple alignment checking for FIELD against ALIGN (a power of two).
/* Simple alignment checking for FIELD against ALIGN (a power of two).
   IGNORE is used to suppress the error message.  */
   IGNORE is used to suppress the error message.  */
 
 
#define CHECK_ALIGN(FIELD, ALIGN, IGNORE) \
#define CHECK_ALIGN(FIELD, ALIGN, IGNORE) \
  { \
  { \
    if ((FIELD) & ((ALIGN) - 1)) \
    if ((FIELD) & ((ALIGN) - 1)) \
      { \
      { \
        if (! IGNORE) \
        if (! IGNORE) \
          as_bad (_("Field not properly aligned [%d] (%d)."), (ALIGN), \
          as_bad (_("Field not properly aligned [%d] (%d)."), (ALIGN), \
                  (int) (FIELD));\
                  (int) (FIELD));\
        break; \
        break; \
      } \
      } \
  }
  }
 
 
#define is_DP_relative(exp)                     \
#define is_DP_relative(exp)                     \
  ((exp).X_op == O_subtract                     \
  ((exp).X_op == O_subtract                     \
   && strcmp (S_GET_NAME ((exp).X_op_symbol), "$global$") == 0)
   && strcmp (S_GET_NAME ((exp).X_op_symbol), "$global$") == 0)
 
 
#define is_PC_relative(exp)                     \
#define is_PC_relative(exp)                     \
  ((exp).X_op == O_subtract                     \
  ((exp).X_op == O_subtract                     \
   && strcmp (S_GET_NAME ((exp).X_op_symbol), "$PIC_pcrel$0") == 0)
   && strcmp (S_GET_NAME ((exp).X_op_symbol), "$PIC_pcrel$0") == 0)
 
 
#define is_tls_gdidx(exp)                       \
#define is_tls_gdidx(exp)                       \
  ((exp).X_op == O_subtract                     \
  ((exp).X_op == O_subtract                     \
   && strcmp (S_GET_NAME ((exp).X_op_symbol), "$tls_gdidx$") == 0)
   && strcmp (S_GET_NAME ((exp).X_op_symbol), "$tls_gdidx$") == 0)
 
 
#define is_tls_ldidx(exp)                       \
#define is_tls_ldidx(exp)                       \
  ((exp).X_op == O_subtract                     \
  ((exp).X_op == O_subtract                     \
   && strcmp (S_GET_NAME ((exp).X_op_symbol), "$tls_ldidx$") == 0)
   && strcmp (S_GET_NAME ((exp).X_op_symbol), "$tls_ldidx$") == 0)
 
 
#define is_tls_dtpoff(exp)                      \
#define is_tls_dtpoff(exp)                      \
  ((exp).X_op == O_subtract                     \
  ((exp).X_op == O_subtract                     \
   && strcmp (S_GET_NAME ((exp).X_op_symbol), "$tls_dtpoff$") == 0)
   && strcmp (S_GET_NAME ((exp).X_op_symbol), "$tls_dtpoff$") == 0)
 
 
#define is_tls_ieoff(exp)                       \
#define is_tls_ieoff(exp)                       \
  ((exp).X_op == O_subtract                     \
  ((exp).X_op == O_subtract                     \
   && strcmp (S_GET_NAME ((exp).X_op_symbol), "$tls_ieoff$") == 0)
   && strcmp (S_GET_NAME ((exp).X_op_symbol), "$tls_ieoff$") == 0)
 
 
#define is_tls_leoff(exp)                       \
#define is_tls_leoff(exp)                       \
  ((exp).X_op == O_subtract                     \
  ((exp).X_op == O_subtract                     \
   && strcmp (S_GET_NAME ((exp).X_op_symbol), "$tls_leoff$") == 0)
   && strcmp (S_GET_NAME ((exp).X_op_symbol), "$tls_leoff$") == 0)
 
 
/* We need some complex handling for stabs (sym1 - sym2).  Luckily, we'll
/* We need some complex handling for stabs (sym1 - sym2).  Luckily, we'll
   always be able to reduce the expression to a constant, so we don't
   always be able to reduce the expression to a constant, so we don't
   need real complex handling yet.  */
   need real complex handling yet.  */
#define is_complex(exp)                         \
#define is_complex(exp)                         \
  ((exp).X_op != O_constant && (exp).X_op != O_symbol)
  ((exp).X_op != O_constant && (exp).X_op != O_symbol)
 
 
/* Actual functions to implement the PA specific code for the assembler.  */
/* Actual functions to implement the PA specific code for the assembler.  */
 
 
/* Called before writing the object file.  Make sure entry/exit and
/* Called before writing the object file.  Make sure entry/exit and
   proc/procend pairs match.  */
   proc/procend pairs match.  */
 
 
void
void
pa_check_eof (void)
pa_check_eof (void)
{
{
  if (within_entry_exit)
  if (within_entry_exit)
    as_fatal (_("Missing .exit\n"));
    as_fatal (_("Missing .exit\n"));
 
 
  if (within_procedure)
  if (within_procedure)
    as_fatal (_("Missing .procend\n"));
    as_fatal (_("Missing .procend\n"));
}
}
 
 
/* Returns a pointer to the label_symbol_struct for the current space.
/* Returns a pointer to the label_symbol_struct for the current space.
   or NULL if no label_symbol_struct exists for the current space.  */
   or NULL if no label_symbol_struct exists for the current space.  */
 
 
static label_symbol_struct *
static label_symbol_struct *
pa_get_label (void)
pa_get_label (void)
{
{
  label_symbol_struct *label_chain;
  label_symbol_struct *label_chain;
 
 
  for (label_chain = label_symbols_rootp;
  for (label_chain = label_symbols_rootp;
       label_chain;
       label_chain;
       label_chain = label_chain->lss_next)
       label_chain = label_chain->lss_next)
    {
    {
#ifdef OBJ_SOM
#ifdef OBJ_SOM
    if (current_space == label_chain->lss_space && label_chain->lss_label)
    if (current_space == label_chain->lss_space && label_chain->lss_label)
      return label_chain;
      return label_chain;
#endif
#endif
#ifdef OBJ_ELF
#ifdef OBJ_ELF
    if (now_seg == label_chain->lss_segment && label_chain->lss_label)
    if (now_seg == label_chain->lss_segment && label_chain->lss_label)
      return label_chain;
      return label_chain;
#endif
#endif
    }
    }
 
 
  return NULL;
  return NULL;
}
}
 
 
/* Defines a label for the current space.  If one is already defined,
/* Defines a label for the current space.  If one is already defined,
   this function will replace it with the new label.  */
   this function will replace it with the new label.  */
 
 
void
void
pa_define_label (symbolS *symbol)
pa_define_label (symbolS *symbol)
{
{
  label_symbol_struct *label_chain = pa_get_label ();
  label_symbol_struct *label_chain = pa_get_label ();
 
 
  if (label_chain)
  if (label_chain)
    label_chain->lss_label = symbol;
    label_chain->lss_label = symbol;
  else
  else
    {
    {
      /* Create a new label entry and add it to the head of the chain.  */
      /* Create a new label entry and add it to the head of the chain.  */
      label_chain = xmalloc (sizeof (label_symbol_struct));
      label_chain = xmalloc (sizeof (label_symbol_struct));
      label_chain->lss_label = symbol;
      label_chain->lss_label = symbol;
#ifdef OBJ_SOM
#ifdef OBJ_SOM
      label_chain->lss_space = current_space;
      label_chain->lss_space = current_space;
#endif
#endif
#ifdef OBJ_ELF
#ifdef OBJ_ELF
      label_chain->lss_segment = now_seg;
      label_chain->lss_segment = now_seg;
#endif
#endif
      label_chain->lss_next = NULL;
      label_chain->lss_next = NULL;
 
 
      if (label_symbols_rootp)
      if (label_symbols_rootp)
        label_chain->lss_next = label_symbols_rootp;
        label_chain->lss_next = label_symbols_rootp;
 
 
      label_symbols_rootp = label_chain;
      label_symbols_rootp = label_chain;
    }
    }
 
 
#ifdef OBJ_ELF
#ifdef OBJ_ELF
  dwarf2_emit_label (symbol);
  dwarf2_emit_label (symbol);
#endif
#endif
}
}
 
 
/* Removes a label definition for the current space.
/* Removes a label definition for the current space.
   If there is no label_symbol_struct entry, then no action is taken.  */
   If there is no label_symbol_struct entry, then no action is taken.  */
 
 
static void
static void
pa_undefine_label (void)
pa_undefine_label (void)
{
{
  label_symbol_struct *label_chain;
  label_symbol_struct *label_chain;
  label_symbol_struct *prev_label_chain = NULL;
  label_symbol_struct *prev_label_chain = NULL;
 
 
  for (label_chain = label_symbols_rootp;
  for (label_chain = label_symbols_rootp;
       label_chain;
       label_chain;
       label_chain = label_chain->lss_next)
       label_chain = label_chain->lss_next)
    {
    {
      if (1
      if (1
#ifdef OBJ_SOM
#ifdef OBJ_SOM
          && current_space == label_chain->lss_space && label_chain->lss_label
          && current_space == label_chain->lss_space && label_chain->lss_label
#endif
#endif
#ifdef OBJ_ELF
#ifdef OBJ_ELF
          && now_seg == label_chain->lss_segment && label_chain->lss_label
          && now_seg == label_chain->lss_segment && label_chain->lss_label
#endif
#endif
          )
          )
        {
        {
          /* Remove the label from the chain and free its memory.  */
          /* Remove the label from the chain and free its memory.  */
          if (prev_label_chain)
          if (prev_label_chain)
            prev_label_chain->lss_next = label_chain->lss_next;
            prev_label_chain->lss_next = label_chain->lss_next;
          else
          else
            label_symbols_rootp = label_chain->lss_next;
            label_symbols_rootp = label_chain->lss_next;
 
 
          free (label_chain);
          free (label_chain);
          break;
          break;
        }
        }
      prev_label_chain = label_chain;
      prev_label_chain = label_chain;
    }
    }
}
}
 
 
/* An HPPA-specific version of fix_new.  This is required because the HPPA
/* An HPPA-specific version of fix_new.  This is required because the HPPA
   code needs to keep track of some extra stuff.  Each call to fix_new_hppa
   code needs to keep track of some extra stuff.  Each call to fix_new_hppa
   results in the creation of an instance of an hppa_fix_struct.  An
   results in the creation of an instance of an hppa_fix_struct.  An
   hppa_fix_struct stores the extra information along with a pointer to the
   hppa_fix_struct stores the extra information along with a pointer to the
   original fixS.  This is attached to the original fixup via the
   original fixS.  This is attached to the original fixup via the
   tc_fix_data field.  */
   tc_fix_data field.  */
 
 
static void
static void
fix_new_hppa (fragS *frag,
fix_new_hppa (fragS *frag,
              int where,
              int where,
              int size,
              int size,
              symbolS *add_symbol,
              symbolS *add_symbol,
              offsetT offset,
              offsetT offset,
              expressionS *exp,
              expressionS *exp,
              int pcrel,
              int pcrel,
              bfd_reloc_code_real_type r_type,
              bfd_reloc_code_real_type r_type,
              enum hppa_reloc_field_selector_type_alt r_field,
              enum hppa_reloc_field_selector_type_alt r_field,
              int r_format,
              int r_format,
              unsigned int arg_reloc,
              unsigned int arg_reloc,
              int unwind_bits ATTRIBUTE_UNUSED)
              int unwind_bits ATTRIBUTE_UNUSED)
{
{
  fixS *new_fix;
  fixS *new_fix;
  struct hppa_fix_struct *hppa_fix = obstack_alloc (&notes, sizeof (struct hppa_fix_struct));
  struct hppa_fix_struct *hppa_fix = obstack_alloc (&notes, sizeof (struct hppa_fix_struct));
 
 
  if (exp != NULL)
  if (exp != NULL)
    new_fix = fix_new_exp (frag, where, size, exp, pcrel, r_type);
    new_fix = fix_new_exp (frag, where, size, exp, pcrel, r_type);
  else
  else
    new_fix = fix_new (frag, where, size, add_symbol, offset, pcrel, r_type);
    new_fix = fix_new (frag, where, size, add_symbol, offset, pcrel, r_type);
  new_fix->tc_fix_data = (void *) hppa_fix;
  new_fix->tc_fix_data = (void *) hppa_fix;
  hppa_fix->fx_r_type = r_type;
  hppa_fix->fx_r_type = r_type;
  hppa_fix->fx_r_field = r_field;
  hppa_fix->fx_r_field = r_field;
  hppa_fix->fx_r_format = r_format;
  hppa_fix->fx_r_format = r_format;
  hppa_fix->fx_arg_reloc = arg_reloc;
  hppa_fix->fx_arg_reloc = arg_reloc;
  hppa_fix->segment = now_seg;
  hppa_fix->segment = now_seg;
#ifdef OBJ_SOM
#ifdef OBJ_SOM
  if (r_type == R_ENTRY || r_type == R_EXIT)
  if (r_type == R_ENTRY || r_type == R_EXIT)
    new_fix->fx_offset = unwind_bits;
    new_fix->fx_offset = unwind_bits;
#endif
#endif
 
 
  /* foo-$global$ is used to access non-automatic storage.  $global$
  /* foo-$global$ is used to access non-automatic storage.  $global$
     is really just a marker and has served its purpose, so eliminate
     is really just a marker and has served its purpose, so eliminate
     it now so as not to confuse write.c.  Ditto for $PIC_pcrel$0.  */
     it now so as not to confuse write.c.  Ditto for $PIC_pcrel$0.  */
  if (new_fix->fx_subsy
  if (new_fix->fx_subsy
      && (strcmp (S_GET_NAME (new_fix->fx_subsy), "$global$") == 0
      && (strcmp (S_GET_NAME (new_fix->fx_subsy), "$global$") == 0
          || strcmp (S_GET_NAME (new_fix->fx_subsy), "$PIC_pcrel$0") == 0
          || strcmp (S_GET_NAME (new_fix->fx_subsy), "$PIC_pcrel$0") == 0
          || strcmp (S_GET_NAME (new_fix->fx_subsy), "$tls_gdidx$") == 0
          || strcmp (S_GET_NAME (new_fix->fx_subsy), "$tls_gdidx$") == 0
          || strcmp (S_GET_NAME (new_fix->fx_subsy), "$tls_ldidx$") == 0
          || strcmp (S_GET_NAME (new_fix->fx_subsy), "$tls_ldidx$") == 0
          || strcmp (S_GET_NAME (new_fix->fx_subsy), "$tls_dtpoff$") == 0
          || strcmp (S_GET_NAME (new_fix->fx_subsy), "$tls_dtpoff$") == 0
          || strcmp (S_GET_NAME (new_fix->fx_subsy), "$tls_ieoff$") == 0
          || strcmp (S_GET_NAME (new_fix->fx_subsy), "$tls_ieoff$") == 0
          || strcmp (S_GET_NAME (new_fix->fx_subsy), "$tls_leoff$") == 0))
          || strcmp (S_GET_NAME (new_fix->fx_subsy), "$tls_leoff$") == 0))
    new_fix->fx_subsy = NULL;
    new_fix->fx_subsy = NULL;
}
}
 
 
/* This fix_new is called by cons via TC_CONS_FIX_NEW.
/* This fix_new is called by cons via TC_CONS_FIX_NEW.
   hppa_field_selector is set by the parse_cons_expression_hppa.  */
   hppa_field_selector is set by the parse_cons_expression_hppa.  */
 
 
void
void
cons_fix_new_hppa (fragS *frag, int where, int size, expressionS *exp)
cons_fix_new_hppa (fragS *frag, int where, int size, expressionS *exp)
{
{
  unsigned int rel_type;
  unsigned int rel_type;
 
 
  /* Get a base relocation type.  */
  /* Get a base relocation type.  */
  if (is_DP_relative (*exp))
  if (is_DP_relative (*exp))
    rel_type = R_HPPA_GOTOFF;
    rel_type = R_HPPA_GOTOFF;
  else if (is_PC_relative (*exp))
  else if (is_PC_relative (*exp))
    rel_type = R_HPPA_PCREL_CALL;
    rel_type = R_HPPA_PCREL_CALL;
#ifdef OBJ_ELF
#ifdef OBJ_ELF
  else if (is_tls_gdidx (*exp))
  else if (is_tls_gdidx (*exp))
    rel_type = R_PARISC_TLS_GD21L;
    rel_type = R_PARISC_TLS_GD21L;
  else if (is_tls_ldidx (*exp))
  else if (is_tls_ldidx (*exp))
    rel_type = R_PARISC_TLS_LDM21L;
    rel_type = R_PARISC_TLS_LDM21L;
  else if (is_tls_dtpoff (*exp))
  else if (is_tls_dtpoff (*exp))
    rel_type = R_PARISC_TLS_LDO21L;
    rel_type = R_PARISC_TLS_LDO21L;
  else if (is_tls_ieoff (*exp))
  else if (is_tls_ieoff (*exp))
    rel_type = R_PARISC_TLS_IE21L;
    rel_type = R_PARISC_TLS_IE21L;
  else if (is_tls_leoff (*exp))
  else if (is_tls_leoff (*exp))
    rel_type = R_PARISC_TLS_LE21L;
    rel_type = R_PARISC_TLS_LE21L;
#endif
#endif
  else if (is_complex (*exp))
  else if (is_complex (*exp))
    rel_type = R_HPPA_COMPLEX;
    rel_type = R_HPPA_COMPLEX;
  else
  else
    rel_type = R_HPPA;
    rel_type = R_HPPA;
 
 
  if (hppa_field_selector != e_psel && hppa_field_selector != e_fsel)
  if (hppa_field_selector != e_psel && hppa_field_selector != e_fsel)
    {
    {
      as_warn (_("Invalid field selector.  Assuming F%%."));
      as_warn (_("Invalid field selector.  Assuming F%%."));
      hppa_field_selector = e_fsel;
      hppa_field_selector = e_fsel;
    }
    }
 
 
  fix_new_hppa (frag, where, size,
  fix_new_hppa (frag, where, size,
                (symbolS *) NULL, (offsetT) 0, exp, 0, rel_type,
                (symbolS *) NULL, (offsetT) 0, exp, 0, rel_type,
                hppa_field_selector, size * 8, 0, 0);
                hppa_field_selector, size * 8, 0, 0);
 
 
  /* Reset field selector to its default state.  */
  /* Reset field selector to its default state.  */
  hppa_field_selector = 0;
  hppa_field_selector = 0;
}
}
 
 
/* Mark (via expr_end) the end of an expression (I think).  FIXME.  */
/* Mark (via expr_end) the end of an expression (I think).  FIXME.  */
 
 
static void
static void
get_expression (char *str)
get_expression (char *str)
{
{
  char *save_in;
  char *save_in;
  asection *seg;
  asection *seg;
 
 
  save_in = input_line_pointer;
  save_in = input_line_pointer;
  input_line_pointer = str;
  input_line_pointer = str;
  seg = expression (&the_insn.exp);
  seg = expression (&the_insn.exp);
  if (!(seg == absolute_section
  if (!(seg == absolute_section
        || seg == undefined_section
        || seg == undefined_section
        || SEG_NORMAL (seg)))
        || SEG_NORMAL (seg)))
    {
    {
      as_warn (_("Bad segment in expression."));
      as_warn (_("Bad segment in expression."));
      expr_end = input_line_pointer;
      expr_end = input_line_pointer;
      input_line_pointer = save_in;
      input_line_pointer = save_in;
      return;
      return;
    }
    }
  expr_end = input_line_pointer;
  expr_end = input_line_pointer;
  input_line_pointer = save_in;
  input_line_pointer = save_in;
}
}
 
 
/* Parse a PA nullification completer (,n).  Return nonzero if the
/* Parse a PA nullification completer (,n).  Return nonzero if the
   completer was found; return zero if no completer was found.  */
   completer was found; return zero if no completer was found.  */
 
 
static int
static int
pa_parse_nullif (char **s)
pa_parse_nullif (char **s)
{
{
  int nullif;
  int nullif;
 
 
  nullif = 0;
  nullif = 0;
  if (**s == ',')
  if (**s == ',')
    {
    {
      *s = *s + 1;
      *s = *s + 1;
      if (strncasecmp (*s, "n", 1) == 0)
      if (strncasecmp (*s, "n", 1) == 0)
        nullif = 1;
        nullif = 1;
      else
      else
        {
        {
          as_bad (_("Invalid Nullification: (%c)"), **s);
          as_bad (_("Invalid Nullification: (%c)"), **s);
          nullif = 0;
          nullif = 0;
        }
        }
      *s = *s + 1;
      *s = *s + 1;
    }
    }
 
 
  return nullif;
  return nullif;
}
}
 
 
char *
char *
md_atof (int type, char *litP, int *sizeP)
md_atof (int type, char *litP, int *sizeP)
{
{
  return ieee_md_atof (type, litP, sizeP, TRUE);
  return ieee_md_atof (type, litP, sizeP, TRUE);
}
}
 
 
/* Write out big-endian.  */
/* Write out big-endian.  */
 
 
void
void
md_number_to_chars (char *buf, valueT val, int n)
md_number_to_chars (char *buf, valueT val, int n)
{
{
  number_to_chars_bigendian (buf, val, n);
  number_to_chars_bigendian (buf, val, n);
}
}
 
 
/* Translate internal representation of relocation info to BFD target
/* Translate internal representation of relocation info to BFD target
   format.  */
   format.  */
 
 
arelent **
arelent **
tc_gen_reloc (asection *section, fixS *fixp)
tc_gen_reloc (asection *section, fixS *fixp)
{
{
  arelent *reloc;
  arelent *reloc;
  struct hppa_fix_struct *hppa_fixp;
  struct hppa_fix_struct *hppa_fixp;
  static arelent *no_relocs = NULL;
  static arelent *no_relocs = NULL;
  arelent **relocs;
  arelent **relocs;
  reloc_type **codes;
  reloc_type **codes;
  reloc_type code;
  reloc_type code;
  int n_relocs;
  int n_relocs;
  int i;
  int i;
 
 
  hppa_fixp = (struct hppa_fix_struct *) fixp->tc_fix_data;
  hppa_fixp = (struct hppa_fix_struct *) fixp->tc_fix_data;
  if (fixp->fx_addsy == 0)
  if (fixp->fx_addsy == 0)
    return &no_relocs;
    return &no_relocs;
 
 
  assert (hppa_fixp != 0);
  assert (hppa_fixp != 0);
  assert (section != 0);
  assert (section != 0);
 
 
  reloc = xmalloc (sizeof (arelent));
  reloc = xmalloc (sizeof (arelent));
 
 
  reloc->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
  reloc->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
  *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
  *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
  codes = hppa_gen_reloc_type (stdoutput,
  codes = hppa_gen_reloc_type (stdoutput,
                               fixp->fx_r_type,
                               fixp->fx_r_type,
                               hppa_fixp->fx_r_format,
                               hppa_fixp->fx_r_format,
                               hppa_fixp->fx_r_field,
                               hppa_fixp->fx_r_field,
                               fixp->fx_subsy != NULL,
                               fixp->fx_subsy != NULL,
                               symbol_get_bfdsym (fixp->fx_addsy));
                               symbol_get_bfdsym (fixp->fx_addsy));
 
 
  if (codes == NULL)
  if (codes == NULL)
    {
    {
      as_bad_where (fixp->fx_file, fixp->fx_line, _("Cannot handle fixup"));
      as_bad_where (fixp->fx_file, fixp->fx_line, _("Cannot handle fixup"));
      abort ();
      abort ();
    }
    }
 
 
  for (n_relocs = 0; codes[n_relocs]; n_relocs++)
  for (n_relocs = 0; codes[n_relocs]; n_relocs++)
    ;
    ;
 
 
  relocs = xmalloc (sizeof (arelent *) * n_relocs + 1);
  relocs = xmalloc (sizeof (arelent *) * n_relocs + 1);
  reloc = xmalloc (sizeof (arelent) * n_relocs);
  reloc = xmalloc (sizeof (arelent) * n_relocs);
  for (i = 0; i < n_relocs; i++)
  for (i = 0; i < n_relocs; i++)
    relocs[i] = &reloc[i];
    relocs[i] = &reloc[i];
 
 
  relocs[n_relocs] = NULL;
  relocs[n_relocs] = NULL;
 
 
#ifdef OBJ_ELF
#ifdef OBJ_ELF
  switch (fixp->fx_r_type)
  switch (fixp->fx_r_type)
    {
    {
    default:
    default:
      assert (n_relocs == 1);
      assert (n_relocs == 1);
 
 
      code = *codes[0];
      code = *codes[0];
 
 
      /* Now, do any processing that is dependent on the relocation type.  */
      /* Now, do any processing that is dependent on the relocation type.  */
      switch (code)
      switch (code)
        {
        {
        case R_PARISC_DLTREL21L:
        case R_PARISC_DLTREL21L:
        case R_PARISC_DLTREL14R:
        case R_PARISC_DLTREL14R:
        case R_PARISC_DLTREL14F:
        case R_PARISC_DLTREL14F:
        case R_PARISC_PLABEL32:
        case R_PARISC_PLABEL32:
        case R_PARISC_PLABEL21L:
        case R_PARISC_PLABEL21L:
        case R_PARISC_PLABEL14R:
        case R_PARISC_PLABEL14R:
          /* For plabel relocations, the addend of the
          /* For plabel relocations, the addend of the
             relocation should be either 0 (no static link) or 2
             relocation should be either 0 (no static link) or 2
             (static link required).  This adjustment is done in
             (static link required).  This adjustment is done in
             bfd/elf32-hppa.c:elf32_hppa_relocate_section.
             bfd/elf32-hppa.c:elf32_hppa_relocate_section.
 
 
             We also slam a zero addend into the DLT relative relocs;
             We also slam a zero addend into the DLT relative relocs;
             it doesn't make a lot of sense to use any addend since
             it doesn't make a lot of sense to use any addend since
             it gets you a different (eg unknown) DLT entry.  */
             it gets you a different (eg unknown) DLT entry.  */
          reloc->addend = 0;
          reloc->addend = 0;
          break;
          break;
 
 
#ifdef ELF_ARG_RELOC
#ifdef ELF_ARG_RELOC
        case R_PARISC_PCREL17R:
        case R_PARISC_PCREL17R:
        case R_PARISC_PCREL17F:
        case R_PARISC_PCREL17F:
        case R_PARISC_PCREL17C:
        case R_PARISC_PCREL17C:
        case R_PARISC_DIR17R:
        case R_PARISC_DIR17R:
        case R_PARISC_DIR17F:
        case R_PARISC_DIR17F:
        case R_PARISC_PCREL21L:
        case R_PARISC_PCREL21L:
        case R_PARISC_DIR21L:
        case R_PARISC_DIR21L:
          reloc->addend = HPPA_R_ADDEND (hppa_fixp->fx_arg_reloc,
          reloc->addend = HPPA_R_ADDEND (hppa_fixp->fx_arg_reloc,
                                         fixp->fx_offset);
                                         fixp->fx_offset);
          break;
          break;
#endif
#endif
 
 
        case R_PARISC_DIR32:
        case R_PARISC_DIR32:
          /* Facilitate hand-crafted unwind info.  */
          /* Facilitate hand-crafted unwind info.  */
          if (strcmp (section->name, UNWIND_SECTION_NAME) == 0)
          if (strcmp (section->name, UNWIND_SECTION_NAME) == 0)
            code = R_PARISC_SEGREL32;
            code = R_PARISC_SEGREL32;
          /* Fall thru */
          /* Fall thru */
 
 
        default:
        default:
          reloc->addend = fixp->fx_offset;
          reloc->addend = fixp->fx_offset;
          break;
          break;
        }
        }
 
 
      reloc->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
      reloc->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
      *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
      *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
      reloc->howto = bfd_reloc_type_lookup (stdoutput,
      reloc->howto = bfd_reloc_type_lookup (stdoutput,
                                            (bfd_reloc_code_real_type) code);
                                            (bfd_reloc_code_real_type) code);
      reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
      reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
 
 
      assert (reloc->howto && (unsigned int) code == reloc->howto->type);
      assert (reloc->howto && (unsigned int) code == reloc->howto->type);
      break;
      break;
    }
    }
#else /* OBJ_SOM */
#else /* OBJ_SOM */
 
 
  /* Walk over reach relocation returned by the BFD backend.  */
  /* Walk over reach relocation returned by the BFD backend.  */
  for (i = 0; i < n_relocs; i++)
  for (i = 0; i < n_relocs; i++)
    {
    {
      code = *codes[i];
      code = *codes[i];
 
 
      relocs[i]->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
      relocs[i]->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
      *relocs[i]->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
      *relocs[i]->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
      relocs[i]->howto =
      relocs[i]->howto =
        bfd_reloc_type_lookup (stdoutput,
        bfd_reloc_type_lookup (stdoutput,
                               (bfd_reloc_code_real_type) code);
                               (bfd_reloc_code_real_type) code);
      relocs[i]->address = fixp->fx_frag->fr_address + fixp->fx_where;
      relocs[i]->address = fixp->fx_frag->fr_address + fixp->fx_where;
 
 
      switch (code)
      switch (code)
        {
        {
        case R_COMP2:
        case R_COMP2:
          /* The only time we ever use a R_COMP2 fixup is for the difference
          /* The only time we ever use a R_COMP2 fixup is for the difference
             of two symbols.  With that in mind we fill in all four
             of two symbols.  With that in mind we fill in all four
             relocs now and break out of the loop.  */
             relocs now and break out of the loop.  */
          assert (i == 1);
          assert (i == 1);
          relocs[0]->sym_ptr_ptr
          relocs[0]->sym_ptr_ptr
            = (asymbol **) bfd_abs_section_ptr->symbol_ptr_ptr;
            = (asymbol **) bfd_abs_section_ptr->symbol_ptr_ptr;
          relocs[0]->howto
          relocs[0]->howto
            = bfd_reloc_type_lookup (stdoutput,
            = bfd_reloc_type_lookup (stdoutput,
                                     (bfd_reloc_code_real_type) *codes[0]);
                                     (bfd_reloc_code_real_type) *codes[0]);
          relocs[0]->address = fixp->fx_frag->fr_address + fixp->fx_where;
          relocs[0]->address = fixp->fx_frag->fr_address + fixp->fx_where;
          relocs[0]->addend = 0;
          relocs[0]->addend = 0;
          relocs[1]->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
          relocs[1]->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
          *relocs[1]->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
          *relocs[1]->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
          relocs[1]->howto
          relocs[1]->howto
            = bfd_reloc_type_lookup (stdoutput,
            = bfd_reloc_type_lookup (stdoutput,
                                     (bfd_reloc_code_real_type) *codes[1]);
                                     (bfd_reloc_code_real_type) *codes[1]);
          relocs[1]->address = fixp->fx_frag->fr_address + fixp->fx_where;
          relocs[1]->address = fixp->fx_frag->fr_address + fixp->fx_where;
          relocs[1]->addend = 0;
          relocs[1]->addend = 0;
          relocs[2]->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
          relocs[2]->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
          *relocs[2]->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_subsy);
          *relocs[2]->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_subsy);
          relocs[2]->howto
          relocs[2]->howto
            = bfd_reloc_type_lookup (stdoutput,
            = bfd_reloc_type_lookup (stdoutput,
                                     (bfd_reloc_code_real_type) *codes[2]);
                                     (bfd_reloc_code_real_type) *codes[2]);
          relocs[2]->address = fixp->fx_frag->fr_address + fixp->fx_where;
          relocs[2]->address = fixp->fx_frag->fr_address + fixp->fx_where;
          relocs[2]->addend = 0;
          relocs[2]->addend = 0;
          relocs[3]->sym_ptr_ptr
          relocs[3]->sym_ptr_ptr
            = (asymbol **) bfd_abs_section_ptr->symbol_ptr_ptr;
            = (asymbol **) bfd_abs_section_ptr->symbol_ptr_ptr;
          relocs[3]->howto
          relocs[3]->howto
            = bfd_reloc_type_lookup (stdoutput,
            = bfd_reloc_type_lookup (stdoutput,
                                     (bfd_reloc_code_real_type) *codes[3]);
                                     (bfd_reloc_code_real_type) *codes[3]);
          relocs[3]->address = fixp->fx_frag->fr_address + fixp->fx_where;
          relocs[3]->address = fixp->fx_frag->fr_address + fixp->fx_where;
          relocs[3]->addend = 0;
          relocs[3]->addend = 0;
          relocs[4]->sym_ptr_ptr
          relocs[4]->sym_ptr_ptr
            = (asymbol **) bfd_abs_section_ptr->symbol_ptr_ptr;
            = (asymbol **) bfd_abs_section_ptr->symbol_ptr_ptr;
          relocs[4]->howto
          relocs[4]->howto
            = bfd_reloc_type_lookup (stdoutput,
            = bfd_reloc_type_lookup (stdoutput,
                                     (bfd_reloc_code_real_type) *codes[4]);
                                     (bfd_reloc_code_real_type) *codes[4]);
          relocs[4]->address = fixp->fx_frag->fr_address + fixp->fx_where;
          relocs[4]->address = fixp->fx_frag->fr_address + fixp->fx_where;
          relocs[4]->addend = 0;
          relocs[4]->addend = 0;
          goto done;
          goto done;
        case R_PCREL_CALL:
        case R_PCREL_CALL:
        case R_ABS_CALL:
        case R_ABS_CALL:
          relocs[i]->addend = HPPA_R_ADDEND (hppa_fixp->fx_arg_reloc, 0);
          relocs[i]->addend = HPPA_R_ADDEND (hppa_fixp->fx_arg_reloc, 0);
          break;
          break;
 
 
        case R_DLT_REL:
        case R_DLT_REL:
        case R_DATA_PLABEL:
        case R_DATA_PLABEL:
        case R_CODE_PLABEL:
        case R_CODE_PLABEL:
          /* For plabel relocations, the addend of the
          /* For plabel relocations, the addend of the
             relocation should be either 0 (no static link) or 2
             relocation should be either 0 (no static link) or 2
             (static link required).
             (static link required).
 
 
             FIXME: We always assume no static link!
             FIXME: We always assume no static link!
 
 
             We also slam a zero addend into the DLT relative relocs;
             We also slam a zero addend into the DLT relative relocs;
             it doesn't make a lot of sense to use any addend since
             it doesn't make a lot of sense to use any addend since
             it gets you a different (eg unknown) DLT entry.  */
             it gets you a different (eg unknown) DLT entry.  */
          relocs[i]->addend = 0;
          relocs[i]->addend = 0;
          break;
          break;
 
 
        case R_N_MODE:
        case R_N_MODE:
        case R_S_MODE:
        case R_S_MODE:
        case R_D_MODE:
        case R_D_MODE:
        case R_R_MODE:
        case R_R_MODE:
        case R_FSEL:
        case R_FSEL:
        case R_LSEL:
        case R_LSEL:
        case R_RSEL:
        case R_RSEL:
        case R_BEGIN_BRTAB:
        case R_BEGIN_BRTAB:
        case R_END_BRTAB:
        case R_END_BRTAB:
        case R_BEGIN_TRY:
        case R_BEGIN_TRY:
        case R_N0SEL:
        case R_N0SEL:
        case R_N1SEL:
        case R_N1SEL:
          /* There is no symbol or addend associated with these fixups.  */
          /* There is no symbol or addend associated with these fixups.  */
          relocs[i]->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
          relocs[i]->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
          *relocs[i]->sym_ptr_ptr = symbol_get_bfdsym (dummy_symbol);
          *relocs[i]->sym_ptr_ptr = symbol_get_bfdsym (dummy_symbol);
          relocs[i]->addend = 0;
          relocs[i]->addend = 0;
          break;
          break;
 
 
        case R_END_TRY:
        case R_END_TRY:
        case R_ENTRY:
        case R_ENTRY:
        case R_EXIT:
        case R_EXIT:
          /* There is no symbol associated with these fixups.  */
          /* There is no symbol associated with these fixups.  */
          relocs[i]->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
          relocs[i]->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
          *relocs[i]->sym_ptr_ptr = symbol_get_bfdsym (dummy_symbol);
          *relocs[i]->sym_ptr_ptr = symbol_get_bfdsym (dummy_symbol);
          relocs[i]->addend = fixp->fx_offset;
          relocs[i]->addend = fixp->fx_offset;
          break;
          break;
 
 
        default:
        default:
          relocs[i]->addend = fixp->fx_offset;
          relocs[i]->addend = fixp->fx_offset;
        }
        }
    }
    }
 
 
 done:
 done:
#endif
#endif
 
 
  return relocs;
  return relocs;
}
}
 
 
/* Process any machine dependent frag types.  */
/* Process any machine dependent frag types.  */
 
 
void
void
md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED,
md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED,
                 asection *sec ATTRIBUTE_UNUSED,
                 asection *sec ATTRIBUTE_UNUSED,
                 fragS *fragP)
                 fragS *fragP)
{
{
  unsigned int address;
  unsigned int address;
 
 
  if (fragP->fr_type == rs_machine_dependent)
  if (fragP->fr_type == rs_machine_dependent)
    {
    {
      switch ((int) fragP->fr_subtype)
      switch ((int) fragP->fr_subtype)
        {
        {
        case 0:
        case 0:
          fragP->fr_type = rs_fill;
          fragP->fr_type = rs_fill;
          know (fragP->fr_var == 1);
          know (fragP->fr_var == 1);
          know (fragP->fr_next);
          know (fragP->fr_next);
          address = fragP->fr_address + fragP->fr_fix;
          address = fragP->fr_address + fragP->fr_fix;
          if (address % fragP->fr_offset)
          if (address % fragP->fr_offset)
            {
            {
              fragP->fr_offset =
              fragP->fr_offset =
                fragP->fr_next->fr_address
                fragP->fr_next->fr_address
                - fragP->fr_address
                - fragP->fr_address
                - fragP->fr_fix;
                - fragP->fr_fix;
            }
            }
          else
          else
            fragP->fr_offset = 0;
            fragP->fr_offset = 0;
          break;
          break;
        }
        }
    }
    }
}
}
 
 
/* Round up a section size to the appropriate boundary.  */
/* Round up a section size to the appropriate boundary.  */
 
 
valueT
valueT
md_section_align (asection *segment, valueT size)
md_section_align (asection *segment, valueT size)
{
{
  int align = bfd_get_section_alignment (stdoutput, segment);
  int align = bfd_get_section_alignment (stdoutput, segment);
  int align2 = (1 << align) - 1;
  int align2 = (1 << align) - 1;
 
 
  return (size + align2) & ~align2;
  return (size + align2) & ~align2;
}
}
 
 
/* Return the approximate size of a frag before relaxation has occurred.  */
/* Return the approximate size of a frag before relaxation has occurred.  */
 
 
int
int
md_estimate_size_before_relax (fragS *fragP, asection *segment ATTRIBUTE_UNUSED)
md_estimate_size_before_relax (fragS *fragP, asection *segment ATTRIBUTE_UNUSED)
{
{
  int size;
  int size;
 
 
  size = 0;
  size = 0;
 
 
  while ((fragP->fr_fix + size) % fragP->fr_offset)
  while ((fragP->fr_fix + size) % fragP->fr_offset)
    size++;
    size++;
 
 
  return size;
  return size;
}
}


#ifdef OBJ_ELF
#ifdef OBJ_ELF
# ifdef WARN_COMMENTS
# ifdef WARN_COMMENTS
const char *md_shortopts = "Vc";
const char *md_shortopts = "Vc";
# else
# else
const char *md_shortopts = "V";
const char *md_shortopts = "V";
# endif
# endif
#else
#else
# ifdef WARN_COMMENTS
# ifdef WARN_COMMENTS
const char *md_shortopts = "c";
const char *md_shortopts = "c";
# else
# else
const char *md_shortopts = "";
const char *md_shortopts = "";
# endif
# endif
#endif
#endif
 
 
struct option md_longopts[] =
struct option md_longopts[] =
{
{
#ifdef WARN_COMMENTS
#ifdef WARN_COMMENTS
  {"warn-comment", no_argument, NULL, 'c'},
  {"warn-comment", no_argument, NULL, 'c'},
#endif
#endif
  {NULL, no_argument, NULL, 0}
  {NULL, no_argument, NULL, 0}
};
};
size_t md_longopts_size = sizeof (md_longopts);
size_t md_longopts_size = sizeof (md_longopts);
 
 
int
int
md_parse_option (int c, char *arg ATTRIBUTE_UNUSED)
md_parse_option (int c, char *arg ATTRIBUTE_UNUSED)
{
{
  switch (c)
  switch (c)
    {
    {
    default:
    default:
      return 0;
      return 0;
 
 
#ifdef OBJ_ELF
#ifdef OBJ_ELF
    case 'V':
    case 'V':
      print_version_id ();
      print_version_id ();
      break;
      break;
#endif
#endif
#ifdef WARN_COMMENTS
#ifdef WARN_COMMENTS
    case 'c':
    case 'c':
      warn_comment = 1;
      warn_comment = 1;
      break;
      break;
#endif
#endif
    }
    }
 
 
  return 1;
  return 1;
}
}
 
 
void
void
md_show_usage (FILE *stream ATTRIBUTE_UNUSED)
md_show_usage (FILE *stream ATTRIBUTE_UNUSED)
{
{
#ifdef OBJ_ELF
#ifdef OBJ_ELF
  fprintf (stream, _("\
  fprintf (stream, _("\
  -Q                      ignored\n"));
  -Q                      ignored\n"));
#endif
#endif
#ifdef WARN_COMMENTS
#ifdef WARN_COMMENTS
  fprintf (stream, _("\
  fprintf (stream, _("\
  -c                      print a warning if a comment is found\n"));
  -c                      print a warning if a comment is found\n"));
#endif
#endif
}
}


/* We have no need to default values of symbols.  */
/* We have no need to default values of symbols.  */
 
 
symbolS *
symbolS *
md_undefined_symbol (char *name ATTRIBUTE_UNUSED)
md_undefined_symbol (char *name ATTRIBUTE_UNUSED)
{
{
  return NULL;
  return NULL;
}
}
 
 
#if defined (OBJ_SOM) || defined (ELF_ARG_RELOC)
#if defined (OBJ_SOM) || defined (ELF_ARG_RELOC)
#define nonzero_dibits(x) \
#define nonzero_dibits(x) \
  ((x) | (((x) & 0x55555555) << 1) | (((x) & 0xAAAAAAAA) >> 1))
  ((x) | (((x) & 0x55555555) << 1) | (((x) & 0xAAAAAAAA) >> 1))
#define arg_reloc_stub_needed(CALLER, CALLEE) \
#define arg_reloc_stub_needed(CALLER, CALLEE) \
  (((CALLER) ^ (CALLEE)) & nonzero_dibits (CALLER) & nonzero_dibits (CALLEE))
  (((CALLER) ^ (CALLEE)) & nonzero_dibits (CALLER) & nonzero_dibits (CALLEE))
#else
#else
#define arg_reloc_stub_needed(CALLER, CALLEE) 0
#define arg_reloc_stub_needed(CALLER, CALLEE) 0
#endif
#endif
 
 
/* Apply a fixup to an instruction.  */
/* Apply a fixup to an instruction.  */
 
 
void
void
md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
{
{
  char *fixpos;
  char *fixpos;
  struct hppa_fix_struct *hppa_fixP;
  struct hppa_fix_struct *hppa_fixP;
  offsetT new_val;
  offsetT new_val;
  int insn, val, fmt;
  int insn, val, fmt;
 
 
  /* SOM uses R_HPPA_ENTRY and R_HPPA_EXIT relocations which can
  /* SOM uses R_HPPA_ENTRY and R_HPPA_EXIT relocations which can
     never be "applied" (they are just markers).  Likewise for
     never be "applied" (they are just markers).  Likewise for
     R_HPPA_BEGIN_BRTAB and R_HPPA_END_BRTAB.  */
     R_HPPA_BEGIN_BRTAB and R_HPPA_END_BRTAB.  */
#ifdef OBJ_SOM
#ifdef OBJ_SOM
  if (fixP->fx_r_type == R_HPPA_ENTRY
  if (fixP->fx_r_type == R_HPPA_ENTRY
      || fixP->fx_r_type == R_HPPA_EXIT
      || fixP->fx_r_type == R_HPPA_EXIT
      || fixP->fx_r_type == R_HPPA_BEGIN_BRTAB
      || fixP->fx_r_type == R_HPPA_BEGIN_BRTAB
      || fixP->fx_r_type == R_HPPA_END_BRTAB
      || fixP->fx_r_type == R_HPPA_END_BRTAB
      || fixP->fx_r_type == R_HPPA_BEGIN_TRY)
      || fixP->fx_r_type == R_HPPA_BEGIN_TRY)
    return;
    return;
 
 
  /* Disgusting.  We must set fx_offset ourselves -- R_HPPA_END_TRY
  /* Disgusting.  We must set fx_offset ourselves -- R_HPPA_END_TRY
     fixups are considered not adjustable, which in turn causes
     fixups are considered not adjustable, which in turn causes
     adjust_reloc_syms to not set fx_offset.  Ugh.  */
     adjust_reloc_syms to not set fx_offset.  Ugh.  */
  if (fixP->fx_r_type == R_HPPA_END_TRY)
  if (fixP->fx_r_type == R_HPPA_END_TRY)
    {
    {
      fixP->fx_offset = * valP;
      fixP->fx_offset = * valP;
      return;
      return;
    }
    }
#endif
#endif
#ifdef OBJ_ELF
#ifdef OBJ_ELF
  if (fixP->fx_r_type == (int) R_PARISC_GNU_VTENTRY
  if (fixP->fx_r_type == (int) R_PARISC_GNU_VTENTRY
      || fixP->fx_r_type == (int) R_PARISC_GNU_VTINHERIT)
      || fixP->fx_r_type == (int) R_PARISC_GNU_VTINHERIT)
    return;
    return;
#endif
#endif
 
 
  if (fixP->fx_addsy == NULL && fixP->fx_pcrel == 0)
  if (fixP->fx_addsy == NULL && fixP->fx_pcrel == 0)
    fixP->fx_done = 1;
    fixP->fx_done = 1;
 
 
  /* There should be a HPPA specific fixup associated with the GAS fixup.  */
  /* There should be a HPPA specific fixup associated with the GAS fixup.  */
  hppa_fixP = (struct hppa_fix_struct *) fixP->tc_fix_data;
  hppa_fixP = (struct hppa_fix_struct *) fixP->tc_fix_data;
  if (hppa_fixP == NULL)
  if (hppa_fixP == NULL)
    {
    {
      as_bad_where (fixP->fx_file, fixP->fx_line,
      as_bad_where (fixP->fx_file, fixP->fx_line,
                    _("no hppa_fixup entry for fixup type 0x%x"),
                    _("no hppa_fixup entry for fixup type 0x%x"),
                    fixP->fx_r_type);
                    fixP->fx_r_type);
      return;
      return;
    }
    }
 
 
  fixpos = fixP->fx_frag->fr_literal + fixP->fx_where;
  fixpos = fixP->fx_frag->fr_literal + fixP->fx_where;
 
 
  if (fixP->fx_size != 4 || hppa_fixP->fx_r_format == 32)
  if (fixP->fx_size != 4 || hppa_fixP->fx_r_format == 32)
    {
    {
      /* Handle constant output. */
      /* Handle constant output. */
      number_to_chars_bigendian (fixpos, *valP, fixP->fx_size);
      number_to_chars_bigendian (fixpos, *valP, fixP->fx_size);
      return;
      return;
    }
    }
 
 
  insn = bfd_get_32 (stdoutput, fixpos);
  insn = bfd_get_32 (stdoutput, fixpos);
  fmt = bfd_hppa_insn2fmt (stdoutput, insn);
  fmt = bfd_hppa_insn2fmt (stdoutput, insn);
 
 
  /* If there is a symbol associated with this fixup, then it's something
  /* If there is a symbol associated with this fixup, then it's something
     which will need a SOM relocation (except for some PC-relative relocs).
     which will need a SOM relocation (except for some PC-relative relocs).
     In such cases we should treat the "val" or "addend" as zero since it
     In such cases we should treat the "val" or "addend" as zero since it
     will be added in as needed from fx_offset in tc_gen_reloc.  */
     will be added in as needed from fx_offset in tc_gen_reloc.  */
  if ((fixP->fx_addsy != NULL
  if ((fixP->fx_addsy != NULL
       || fixP->fx_r_type == (int) R_HPPA_NONE)
       || fixP->fx_r_type == (int) R_HPPA_NONE)
#ifdef OBJ_SOM
#ifdef OBJ_SOM
      && fmt != 32
      && fmt != 32
#endif
#endif
      )
      )
    new_val = ((fmt == 12 || fmt == 17 || fmt == 22) ? 8 : 0);
    new_val = ((fmt == 12 || fmt == 17 || fmt == 22) ? 8 : 0);
#ifdef OBJ_SOM
#ifdef OBJ_SOM
  /* These field selectors imply that we do not want an addend.  */
  /* These field selectors imply that we do not want an addend.  */
  else if (hppa_fixP->fx_r_field == e_psel
  else if (hppa_fixP->fx_r_field == e_psel
           || hppa_fixP->fx_r_field == e_rpsel
           || hppa_fixP->fx_r_field == e_rpsel
           || hppa_fixP->fx_r_field == e_lpsel
           || hppa_fixP->fx_r_field == e_lpsel
           || hppa_fixP->fx_r_field == e_tsel
           || hppa_fixP->fx_r_field == e_tsel
           || hppa_fixP->fx_r_field == e_rtsel
           || hppa_fixP->fx_r_field == e_rtsel
           || hppa_fixP->fx_r_field == e_ltsel)
           || hppa_fixP->fx_r_field == e_ltsel)
    new_val = ((fmt == 12 || fmt == 17 || fmt == 22) ? 8 : 0);
    new_val = ((fmt == 12 || fmt == 17 || fmt == 22) ? 8 : 0);
#endif
#endif
  else
  else
    new_val = hppa_field_adjust (* valP, 0, hppa_fixP->fx_r_field);
    new_val = hppa_field_adjust (* valP, 0, hppa_fixP->fx_r_field);
 
 
  /* Handle pc-relative exceptions from above.  */
  /* Handle pc-relative exceptions from above.  */
  if ((fmt == 12 || fmt == 17 || fmt == 22)
  if ((fmt == 12 || fmt == 17 || fmt == 22)
      && fixP->fx_addsy
      && fixP->fx_addsy
      && fixP->fx_pcrel
      && fixP->fx_pcrel
      && !arg_reloc_stub_needed (symbol_arg_reloc_info (fixP->fx_addsy),
      && !arg_reloc_stub_needed (symbol_arg_reloc_info (fixP->fx_addsy),
                                 hppa_fixP->fx_arg_reloc)
                                 hppa_fixP->fx_arg_reloc)
#ifdef OBJ_ELF
#ifdef OBJ_ELF
      && (* valP - 8 + 8192 < 16384
      && (* valP - 8 + 8192 < 16384
          || (fmt == 17 && * valP - 8 + 262144 < 524288)
          || (fmt == 17 && * valP - 8 + 262144 < 524288)
          || (fmt == 22 && * valP - 8 + 8388608 < 16777216))
          || (fmt == 22 && * valP - 8 + 8388608 < 16777216))
#endif
#endif
#ifdef OBJ_SOM
#ifdef OBJ_SOM
      && (* valP - 8 + 262144 < 524288
      && (* valP - 8 + 262144 < 524288
          || (fmt == 22 && * valP - 8 + 8388608 < 16777216))
          || (fmt == 22 && * valP - 8 + 8388608 < 16777216))
#endif
#endif
      && !S_IS_EXTERNAL (fixP->fx_addsy)
      && !S_IS_EXTERNAL (fixP->fx_addsy)
      && !S_IS_WEAK (fixP->fx_addsy)
      && !S_IS_WEAK (fixP->fx_addsy)
      && S_GET_SEGMENT (fixP->fx_addsy) == hppa_fixP->segment
      && S_GET_SEGMENT (fixP->fx_addsy) == hppa_fixP->segment
      && !(fixP->fx_subsy
      && !(fixP->fx_subsy
           && S_GET_SEGMENT (fixP->fx_subsy) != hppa_fixP->segment))
           && S_GET_SEGMENT (fixP->fx_subsy) != hppa_fixP->segment))
    {
    {
      new_val = hppa_field_adjust (* valP, 0, hppa_fixP->fx_r_field);
      new_val = hppa_field_adjust (* valP, 0, hppa_fixP->fx_r_field);
    }
    }
 
 
  switch (fmt)
  switch (fmt)
    {
    {
    case 10:
    case 10:
      CHECK_FIELD_WHERE (new_val, 8191, -8192,
      CHECK_FIELD_WHERE (new_val, 8191, -8192,
                         fixP->fx_file, fixP->fx_line);
                         fixP->fx_file, fixP->fx_line);
      val = new_val;
      val = new_val;
 
 
      insn = (insn & ~ 0x3ff1) | (((val & 0x1ff8) << 1)
      insn = (insn & ~ 0x3ff1) | (((val & 0x1ff8) << 1)
                                  | ((val & 0x2000) >> 13));
                                  | ((val & 0x2000) >> 13));
      break;
      break;
    case -11:
    case -11:
      CHECK_FIELD_WHERE (new_val, 8191, -8192,
      CHECK_FIELD_WHERE (new_val, 8191, -8192,
                         fixP->fx_file, fixP->fx_line);
                         fixP->fx_file, fixP->fx_line);
      val = new_val;
      val = new_val;
 
 
      insn = (insn & ~ 0x3ff9) | (((val & 0x1ffc) << 1)
      insn = (insn & ~ 0x3ff9) | (((val & 0x1ffc) << 1)
                                  | ((val & 0x2000) >> 13));
                                  | ((val & 0x2000) >> 13));
      break;
      break;
      /* Handle all opcodes with the 'j' operand type.  */
      /* Handle all opcodes with the 'j' operand type.  */
    case 14:
    case 14:
      CHECK_FIELD_WHERE (new_val, 8191, -8192,
      CHECK_FIELD_WHERE (new_val, 8191, -8192,
                         fixP->fx_file, fixP->fx_line);
                         fixP->fx_file, fixP->fx_line);
      val = new_val;
      val = new_val;
 
 
      insn = ((insn & ~ 0x3fff) | low_sign_unext (val, 14));
      insn = ((insn & ~ 0x3fff) | low_sign_unext (val, 14));
      break;
      break;
 
 
      /* Handle all opcodes with the 'k' operand type.  */
      /* Handle all opcodes with the 'k' operand type.  */
    case 21:
    case 21:
      CHECK_FIELD_WHERE (new_val, 1048575, -1048576,
      CHECK_FIELD_WHERE (new_val, 1048575, -1048576,
                         fixP->fx_file, fixP->fx_line);
                         fixP->fx_file, fixP->fx_line);
      val = new_val;
      val = new_val;
 
 
      insn = (insn & ~ 0x1fffff) | re_assemble_21 (val);
      insn = (insn & ~ 0x1fffff) | re_assemble_21 (val);
      break;
      break;
 
 
      /* Handle all the opcodes with the 'i' operand type.  */
      /* Handle all the opcodes with the 'i' operand type.  */
    case 11:
    case 11:
      CHECK_FIELD_WHERE (new_val, 1023, -1024,
      CHECK_FIELD_WHERE (new_val, 1023, -1024,
                         fixP->fx_file, fixP->fx_line);
                         fixP->fx_file, fixP->fx_line);
      val = new_val;
      val = new_val;
 
 
      insn = (insn & ~ 0x7ff) | low_sign_unext (val, 11);
      insn = (insn & ~ 0x7ff) | low_sign_unext (val, 11);
      break;
      break;
 
 
      /* Handle all the opcodes with the 'w' operand type.  */
      /* Handle all the opcodes with the 'w' operand type.  */
    case 12:
    case 12:
      CHECK_FIELD_WHERE (new_val - 8, 8191, -8192,
      CHECK_FIELD_WHERE (new_val - 8, 8191, -8192,
                         fixP->fx_file, fixP->fx_line);
                         fixP->fx_file, fixP->fx_line);
      val = new_val - 8;
      val = new_val - 8;
 
 
      insn = (insn & ~ 0x1ffd) | re_assemble_12 (val >> 2);
      insn = (insn & ~ 0x1ffd) | re_assemble_12 (val >> 2);
      break;
      break;
 
 
      /* Handle some of the opcodes with the 'W' operand type.  */
      /* Handle some of the opcodes with the 'W' operand type.  */
    case 17:
    case 17:
      {
      {
        offsetT distance = * valP;
        offsetT distance = * valP;
 
 
        /* If this is an absolute branch (ie no link) with an out of
        /* If this is an absolute branch (ie no link) with an out of
           range target, then we want to complain.  */
           range target, then we want to complain.  */
        if (fixP->fx_r_type == (int) R_HPPA_PCREL_CALL
        if (fixP->fx_r_type == (int) R_HPPA_PCREL_CALL
            && (insn & 0xffe00000) == 0xe8000000)
            && (insn & 0xffe00000) == 0xe8000000)
          CHECK_FIELD_WHERE (distance - 8, 262143, -262144,
          CHECK_FIELD_WHERE (distance - 8, 262143, -262144,
                             fixP->fx_file, fixP->fx_line);
                             fixP->fx_file, fixP->fx_line);
 
 
        CHECK_FIELD_WHERE (new_val - 8, 262143, -262144,
        CHECK_FIELD_WHERE (new_val - 8, 262143, -262144,
                           fixP->fx_file, fixP->fx_line);
                           fixP->fx_file, fixP->fx_line);
        val = new_val - 8;
        val = new_val - 8;
 
 
        insn = (insn & ~ 0x1f1ffd) | re_assemble_17 (val >> 2);
        insn = (insn & ~ 0x1f1ffd) | re_assemble_17 (val >> 2);
        break;
        break;
      }
      }
 
 
    case 22:
    case 22:
      {
      {
        offsetT distance = * valP;
        offsetT distance = * valP;
 
 
        /* If this is an absolute branch (ie no link) with an out of
        /* If this is an absolute branch (ie no link) with an out of
           range target, then we want to complain.  */
           range target, then we want to complain.  */
        if (fixP->fx_r_type == (int) R_HPPA_PCREL_CALL
        if (fixP->fx_r_type == (int) R_HPPA_PCREL_CALL
            && (insn & 0xffe00000) == 0xe8000000)
            && (insn & 0xffe00000) == 0xe8000000)
          CHECK_FIELD_WHERE (distance - 8, 8388607, -8388608,
          CHECK_FIELD_WHERE (distance - 8, 8388607, -8388608,
                             fixP->fx_file, fixP->fx_line);
                             fixP->fx_file, fixP->fx_line);
 
 
        CHECK_FIELD_WHERE (new_val - 8, 8388607, -8388608,
        CHECK_FIELD_WHERE (new_val - 8, 8388607, -8388608,
                           fixP->fx_file, fixP->fx_line);
                           fixP->fx_file, fixP->fx_line);
        val = new_val - 8;
        val = new_val - 8;
 
 
        insn = (insn & ~ 0x3ff1ffd) | re_assemble_22 (val >> 2);
        insn = (insn & ~ 0x3ff1ffd) | re_assemble_22 (val >> 2);
        break;
        break;
      }
      }
 
 
    case -10:
    case -10:
      val = new_val;
      val = new_val;
      insn = (insn & ~ 0xfff1) | re_assemble_16 (val & -8);
      insn = (insn & ~ 0xfff1) | re_assemble_16 (val & -8);
      break;
      break;
 
 
    case -16:
    case -16:
      val = new_val;
      val = new_val;
      insn = (insn & ~ 0xfff9) | re_assemble_16 (val & -4);
      insn = (insn & ~ 0xfff9) | re_assemble_16 (val & -4);
      break;
      break;
 
 
    case 16:
    case 16:
      val = new_val;
      val = new_val;
      insn = (insn & ~ 0xffff) | re_assemble_16 (val);
      insn = (insn & ~ 0xffff) | re_assemble_16 (val);
      break;
      break;
 
 
    case 32:
    case 32:
      insn = new_val;
      insn = new_val;
      break;
      break;
 
 
    default:
    default:
      as_bad_where (fixP->fx_file, fixP->fx_line,
      as_bad_where (fixP->fx_file, fixP->fx_line,
                    _("Unknown relocation encountered in md_apply_fix."));
                    _("Unknown relocation encountered in md_apply_fix."));
      return;
      return;
    }
    }
 
 
#ifdef OBJ_ELF
#ifdef OBJ_ELF
  switch (fixP->fx_r_type)
  switch (fixP->fx_r_type)
    {
    {
      case R_PARISC_TLS_GD21L:
      case R_PARISC_TLS_GD21L:
      case R_PARISC_TLS_GD14R:
      case R_PARISC_TLS_GD14R:
      case R_PARISC_TLS_LDM21L:
      case R_PARISC_TLS_LDM21L:
      case R_PARISC_TLS_LDM14R:
      case R_PARISC_TLS_LDM14R:
      case R_PARISC_TLS_LE21L:
      case R_PARISC_TLS_LE21L:
      case R_PARISC_TLS_LE14R:
      case R_PARISC_TLS_LE14R:
      case R_PARISC_TLS_IE21L:
      case R_PARISC_TLS_IE21L:
      case R_PARISC_TLS_IE14R:
      case R_PARISC_TLS_IE14R:
        if (fixP->fx_addsy)
        if (fixP->fx_addsy)
          S_SET_THREAD_LOCAL (fixP->fx_addsy);
          S_SET_THREAD_LOCAL (fixP->fx_addsy);
        break;
        break;
      default:
      default:
        break;
        break;
    }
    }
#endif
#endif
 
 
  /* Insert the relocation.  */
  /* Insert the relocation.  */
  bfd_put_32 (stdoutput, insn, fixpos);
  bfd_put_32 (stdoutput, insn, fixpos);
}
}
 
 
/* Exactly what point is a PC-relative offset relative TO?
/* Exactly what point is a PC-relative offset relative TO?
   On the PA, they're relative to the address of the offset.  */
   On the PA, they're relative to the address of the offset.  */
 
 
long
long
md_pcrel_from (fixS *fixP)
md_pcrel_from (fixS *fixP)
{
{
  return fixP->fx_where + fixP->fx_frag->fr_address;
  return fixP->fx_where + fixP->fx_frag->fr_address;
}
}
 
 
/* Return nonzero if the input line pointer is at the end of
/* Return nonzero if the input line pointer is at the end of
   a statement.  */
   a statement.  */
 
 
static int
static int
is_end_of_statement (void)
is_end_of_statement (void)
{
{
  return ((*input_line_pointer == '\n')
  return ((*input_line_pointer == '\n')
          || (*input_line_pointer == ';')
          || (*input_line_pointer == ';')
          || (*input_line_pointer == '!'));
          || (*input_line_pointer == '!'));
}
}
 
 
#define REG_NAME_CNT    (sizeof (pre_defined_registers) / sizeof (struct pd_reg))
#define REG_NAME_CNT    (sizeof (pre_defined_registers) / sizeof (struct pd_reg))
 
 
/* Given NAME, find the register number associated with that name, return
/* Given NAME, find the register number associated with that name, return
   the integer value associated with the given name or -1 on failure.  */
   the integer value associated with the given name or -1 on failure.  */
 
 
static int
static int
reg_name_search (char *name)
reg_name_search (char *name)
{
{
  int middle, low, high;
  int middle, low, high;
  int cmp;
  int cmp;
 
 
  low = 0;
  low = 0;
  high = REG_NAME_CNT - 1;
  high = REG_NAME_CNT - 1;
 
 
  do
  do
    {
    {
      middle = (low + high) / 2;
      middle = (low + high) / 2;
      cmp = strcasecmp (name, pre_defined_registers[middle].name);
      cmp = strcasecmp (name, pre_defined_registers[middle].name);
      if (cmp < 0)
      if (cmp < 0)
        high = middle - 1;
        high = middle - 1;
      else if (cmp > 0)
      else if (cmp > 0)
        low = middle + 1;
        low = middle + 1;
      else
      else
        return pre_defined_registers[middle].value;
        return pre_defined_registers[middle].value;
    }
    }
  while (low <= high);
  while (low <= high);
 
 
  return -1;
  return -1;
}
}
 
 
/* Read a number from S.  The number might come in one of many forms,
/* Read a number from S.  The number might come in one of many forms,
   the most common will be a hex or decimal constant, but it could be
   the most common will be a hex or decimal constant, but it could be
   a pre-defined register (Yuk!), or an absolute symbol.
   a pre-defined register (Yuk!), or an absolute symbol.
 
 
   Return 1 on success or 0 on failure.  If STRICT, then a missing
   Return 1 on success or 0 on failure.  If STRICT, then a missing
   register prefix will cause a failure.  The number itself is
   register prefix will cause a failure.  The number itself is
   returned in `pa_number'.
   returned in `pa_number'.
 
 
   IS_FLOAT indicates that a PA-89 FP register number should be
   IS_FLOAT indicates that a PA-89 FP register number should be
   parsed;  A `l' or `r' suffix is checked for if but 2 of IS_FLOAT is
   parsed;  A `l' or `r' suffix is checked for if but 2 of IS_FLOAT is
   not set.
   not set.
 
 
   pa_parse_number can not handle negative constants and will fail
   pa_parse_number can not handle negative constants and will fail
   horribly if it is passed such a constant.  */
   horribly if it is passed such a constant.  */
 
 
static int
static int
pa_parse_number (char **s, int is_float)
pa_parse_number (char **s, int is_float)
{
{
  int num;
  int num;
  char *name;
  char *name;
  char c;
  char c;
  symbolS *sym;
  symbolS *sym;
  int status;
  int status;
  char *p = *s;
  char *p = *s;
  bfd_boolean have_prefix;
  bfd_boolean have_prefix;
 
 
  /* Skip whitespace before the number.  */
  /* Skip whitespace before the number.  */
  while (*p == ' ' || *p == '\t')
  while (*p == ' ' || *p == '\t')
    p = p + 1;
    p = p + 1;
 
 
  pa_number = -1;
  pa_number = -1;
  have_prefix = 0;
  have_prefix = 0;
  num = 0;
  num = 0;
  if (!strict && ISDIGIT (*p))
  if (!strict && ISDIGIT (*p))
    {
    {
      /* Looks like a number.  */
      /* Looks like a number.  */
 
 
      if (*p == '0' && (*(p + 1) == 'x' || *(p + 1) == 'X'))
      if (*p == '0' && (*(p + 1) == 'x' || *(p + 1) == 'X'))
        {
        {
          /* The number is specified in hex.  */
          /* The number is specified in hex.  */
          p += 2;
          p += 2;
          while (ISDIGIT (*p) || ((*p >= 'a') && (*p <= 'f'))
          while (ISDIGIT (*p) || ((*p >= 'a') && (*p <= 'f'))
                 || ((*p >= 'A') && (*p <= 'F')))
                 || ((*p >= 'A') && (*p <= 'F')))
            {
            {
              if (ISDIGIT (*p))
              if (ISDIGIT (*p))
                num = num * 16 + *p - '0';
                num = num * 16 + *p - '0';
              else if (*p >= 'a' && *p <= 'f')
              else if (*p >= 'a' && *p <= 'f')
                num = num * 16 + *p - 'a' + 10;
                num = num * 16 + *p - 'a' + 10;
              else
              else
                num = num * 16 + *p - 'A' + 10;
                num = num * 16 + *p - 'A' + 10;
              ++p;
              ++p;
            }
            }
        }
        }
      else
      else
        {
        {
          /* The number is specified in decimal.  */
          /* The number is specified in decimal.  */
          while (ISDIGIT (*p))
          while (ISDIGIT (*p))
            {
            {
              num = num * 10 + *p - '0';
              num = num * 10 + *p - '0';
              ++p;
              ++p;
            }
            }
        }
        }
 
 
      pa_number = num;
      pa_number = num;
 
 
      /* Check for a `l' or `r' suffix.  */
      /* Check for a `l' or `r' suffix.  */
      if (is_float)
      if (is_float)
        {
        {
          pa_number += FP_REG_BASE;
          pa_number += FP_REG_BASE;
          if (! (is_float & 2))
          if (! (is_float & 2))
            {
            {
              if (IS_R_SELECT (p))
              if (IS_R_SELECT (p))
                {
                {
                  pa_number += FP_REG_RSEL;
                  pa_number += FP_REG_RSEL;
                  ++p;
                  ++p;
                }
                }
              else if (IS_L_SELECT (p))
              else if (IS_L_SELECT (p))
                {
                {
                  ++p;
                  ++p;
                }
                }
            }
            }
        }
        }
    }
    }
  else if (*p == '%')
  else if (*p == '%')
    {
    {
      /* The number might be a predefined register.  */
      /* The number might be a predefined register.  */
      have_prefix = 1;
      have_prefix = 1;
      name = p;
      name = p;
      p++;
      p++;
      c = *p;
      c = *p;
      /* Tege hack: Special case for general registers as the general
      /* Tege hack: Special case for general registers as the general
         code makes a binary search with case translation, and is VERY
         code makes a binary search with case translation, and is VERY
         slow.  */
         slow.  */
      if (c == 'r')
      if (c == 'r')
        {
        {
          p++;
          p++;
          if (*p == 'e' && *(p + 1) == 't'
          if (*p == 'e' && *(p + 1) == 't'
              && (*(p + 2) == '0' || *(p + 2) == '1'))
              && (*(p + 2) == '0' || *(p + 2) == '1'))
            {
            {
              p += 2;
              p += 2;
              num = *p - '0' + 28;
              num = *p - '0' + 28;
              p++;
              p++;
            }
            }
          else if (*p == 'p')
          else if (*p == 'p')
            {
            {
              num = 2;
              num = 2;
              p++;
              p++;
            }
            }
          else if (!ISDIGIT (*p))
          else if (!ISDIGIT (*p))
            {
            {
              if (print_errors)
              if (print_errors)
                as_bad (_("Undefined register: '%s'."), name);
                as_bad (_("Undefined register: '%s'."), name);
              num = -1;
              num = -1;
            }
            }
          else
          else
            {
            {
              do
              do
                num = num * 10 + *p++ - '0';
                num = num * 10 + *p++ - '0';
              while (ISDIGIT (*p));
              while (ISDIGIT (*p));
            }
            }
        }
        }
      else
      else
        {
        {
          /* Do a normal register search.  */
          /* Do a normal register search.  */
          while (is_part_of_name (c))
          while (is_part_of_name (c))
            {
            {
              p = p + 1;
              p = p + 1;
              c = *p;
              c = *p;
            }
            }
          *p = 0;
          *p = 0;
          status = reg_name_search (name);
          status = reg_name_search (name);
          if (status >= 0)
          if (status >= 0)
            num = status;
            num = status;
          else
          else
            {
            {
              if (print_errors)
              if (print_errors)
                as_bad (_("Undefined register: '%s'."), name);
                as_bad (_("Undefined register: '%s'."), name);
              num = -1;
              num = -1;
            }
            }
          *p = c;
          *p = c;
        }
        }
 
 
      pa_number = num;
      pa_number = num;
    }
    }
  else
  else
    {
    {
      /* And finally, it could be a symbol in the absolute section which
      /* And finally, it could be a symbol in the absolute section which
         is effectively a constant, or a register alias symbol.  */
         is effectively a constant, or a register alias symbol.  */
      name = p;
      name = p;
      c = *p;
      c = *p;
      while (is_part_of_name (c))
      while (is_part_of_name (c))
        {
        {
          p = p + 1;
          p = p + 1;
          c = *p;
          c = *p;
        }
        }
      *p = 0;
      *p = 0;
      if ((sym = symbol_find (name)) != NULL)
      if ((sym = symbol_find (name)) != NULL)
        {
        {
          if (S_GET_SEGMENT (sym) == reg_section)
          if (S_GET_SEGMENT (sym) == reg_section)
            {
            {
              num = S_GET_VALUE (sym);
              num = S_GET_VALUE (sym);
              /* Well, we don't really have one, but we do have a
              /* Well, we don't really have one, but we do have a
                 register, so...  */
                 register, so...  */
              have_prefix = TRUE;
              have_prefix = TRUE;
            }
            }
          else if (S_GET_SEGMENT (sym) == &bfd_abs_section)
          else if (S_GET_SEGMENT (sym) == &bfd_abs_section)
            num = S_GET_VALUE (sym);
            num = S_GET_VALUE (sym);
          else if (!strict)
          else if (!strict)
            {
            {
              if (print_errors)
              if (print_errors)
                as_bad (_("Non-absolute symbol: '%s'."), name);
                as_bad (_("Non-absolute symbol: '%s'."), name);
              num = -1;
              num = -1;
            }
            }
        }
        }
      else if (!strict)
      else if (!strict)
        {
        {
          /* There is where we'd come for an undefined symbol
          /* There is where we'd come for an undefined symbol
             or for an empty string.  For an empty string we
             or for an empty string.  For an empty string we
             will return zero.  That's a concession made for
             will return zero.  That's a concession made for
             compatibility with the braindamaged HP assemblers.  */
             compatibility with the braindamaged HP assemblers.  */
          if (*name == 0)
          if (*name == 0)
            num = 0;
            num = 0;
          else
          else
            {
            {
              if (print_errors)
              if (print_errors)
                as_bad (_("Undefined absolute constant: '%s'."), name);
                as_bad (_("Undefined absolute constant: '%s'."), name);
              num = -1;
              num = -1;
            }
            }
        }
        }
      *p = c;
      *p = c;
 
 
      pa_number = num;
      pa_number = num;
    }
    }
 
 
  if (!strict || have_prefix)
  if (!strict || have_prefix)
    {
    {
      *s = p;
      *s = p;
      return 1;
      return 1;
    }
    }
  return 0;
  return 0;
}
}
 
 
/* Return nonzero if the given INSN and L/R information will require
/* Return nonzero if the given INSN and L/R information will require
   a new PA-1.1 opcode.  */
   a new PA-1.1 opcode.  */
 
 
static int
static int
need_pa11_opcode (void)
need_pa11_opcode (void)
{
{
  if ((pa_number & FP_REG_RSEL) != 0
  if ((pa_number & FP_REG_RSEL) != 0
      && !(the_insn.fpof1 == DBL && the_insn.fpof2 == DBL))
      && !(the_insn.fpof1 == DBL && the_insn.fpof2 == DBL))
    {
    {
      /* If this instruction is specific to a particular architecture,
      /* If this instruction is specific to a particular architecture,
         then set a new architecture.  */
         then set a new architecture.  */
      if (bfd_get_mach (stdoutput) < pa11)
      if (bfd_get_mach (stdoutput) < pa11)
        {
        {
          if (!bfd_set_arch_mach (stdoutput, bfd_arch_hppa, pa11))
          if (!bfd_set_arch_mach (stdoutput, bfd_arch_hppa, pa11))
            as_warn (_("could not update architecture and machine"));
            as_warn (_("could not update architecture and machine"));
        }
        }
      return TRUE;
      return TRUE;
    }
    }
  else
  else
    return FALSE;
    return FALSE;
}
}
 
 
/* Parse a condition for a fcmp instruction.  Return the numerical
/* Parse a condition for a fcmp instruction.  Return the numerical
   code associated with the condition.  */
   code associated with the condition.  */
 
 
static int
static int
pa_parse_fp_cmp_cond (char **s)
pa_parse_fp_cmp_cond (char **s)
{
{
  int cond, i;
  int cond, i;
 
 
  cond = 0;
  cond = 0;
 
 
  for (i = 0; i < 32; i++)
  for (i = 0; i < 32; i++)
    {
    {
      if (strncasecmp (*s, fp_cond_map[i].string,
      if (strncasecmp (*s, fp_cond_map[i].string,
                       strlen (fp_cond_map[i].string)) == 0)
                       strlen (fp_cond_map[i].string)) == 0)
        {
        {
          cond = fp_cond_map[i].cond;
          cond = fp_cond_map[i].cond;
          *s += strlen (fp_cond_map[i].string);
          *s += strlen (fp_cond_map[i].string);
          /* If not a complete match, back up the input string and
          /* If not a complete match, back up the input string and
             report an error.  */
             report an error.  */
          if (**s != ' ' && **s != '\t')
          if (**s != ' ' && **s != '\t')
            {
            {
              *s -= strlen (fp_cond_map[i].string);
              *s -= strlen (fp_cond_map[i].string);
              break;
              break;
            }
            }
          while (**s == ' ' || **s == '\t')
          while (**s == ' ' || **s == '\t')
            *s = *s + 1;
            *s = *s + 1;
          return cond;
          return cond;
        }
        }
    }
    }
 
 
  as_bad (_("Invalid FP Compare Condition: %s"), *s);
  as_bad (_("Invalid FP Compare Condition: %s"), *s);
 
 
  /* Advance over the bogus completer.  */
  /* Advance over the bogus completer.  */
  while (**s != ',' && **s != ' ' && **s != '\t')
  while (**s != ',' && **s != ' ' && **s != '\t')
    *s += 1;
    *s += 1;
 
 
  return 0;
  return 0;
}
}
 
 
/* Parse a graphics test complete for ftest.  */
/* Parse a graphics test complete for ftest.  */
 
 
static int
static int
pa_parse_ftest_gfx_completer (char **s)
pa_parse_ftest_gfx_completer (char **s)
{
{
  int value;
  int value;
 
 
  value = 0;
  value = 0;
  if (strncasecmp (*s, "acc8", 4) == 0)
  if (strncasecmp (*s, "acc8", 4) == 0)
    {
    {
      value = 5;
      value = 5;
      *s += 4;
      *s += 4;
    }
    }
  else if (strncasecmp (*s, "acc6", 4) == 0)
  else if (strncasecmp (*s, "acc6", 4) == 0)
    {
    {
      value = 9;
      value = 9;
      *s += 4;
      *s += 4;
    }
    }
  else if (strncasecmp (*s, "acc4", 4) == 0)
  else if (strncasecmp (*s, "acc4", 4) == 0)
    {
    {
      value = 13;
      value = 13;
      *s += 4;
      *s += 4;
    }
    }
  else if (strncasecmp (*s, "acc2", 4) == 0)
  else if (strncasecmp (*s, "acc2", 4) == 0)
    {
    {
      value = 17;
      value = 17;
      *s += 4;
      *s += 4;
    }
    }
  else if (strncasecmp (*s, "acc", 3) == 0)
  else if (strncasecmp (*s, "acc", 3) == 0)
    {
    {
      value = 1;
      value = 1;
      *s += 3;
      *s += 3;
    }
    }
  else if (strncasecmp (*s, "rej8", 4) == 0)
  else if (strncasecmp (*s, "rej8", 4) == 0)
    {
    {
      value = 6;
      value = 6;
      *s += 4;
      *s += 4;
    }
    }
  else if (strncasecmp (*s, "rej", 3) == 0)
  else if (strncasecmp (*s, "rej", 3) == 0)
    {
    {
      value = 2;
      value = 2;
      *s += 3;
      *s += 3;
    }
    }
  else
  else
    {
    {
      value = 0;
      value = 0;
      as_bad (_("Invalid FTEST completer: %s"), *s);
      as_bad (_("Invalid FTEST completer: %s"), *s);
    }
    }
 
 
  return value;
  return value;
}
}
 
 
/* Parse an FP operand format completer returning the completer
/* Parse an FP operand format completer returning the completer
   type.  */
   type.  */
 
 
static fp_operand_format
static fp_operand_format
pa_parse_fp_cnv_format (char **s)
pa_parse_fp_cnv_format (char **s)
{
{
  int format;
  int format;
 
 
  format = SGL;
  format = SGL;
  if (**s == ',')
  if (**s == ',')
    {
    {
      *s += 1;
      *s += 1;
      if (strncasecmp (*s, "sgl", 3) == 0)
      if (strncasecmp (*s, "sgl", 3) == 0)
        {
        {
          format = SGL;
          format = SGL;
          *s += 4;
          *s += 4;
        }
        }
      else if (strncasecmp (*s, "dbl", 3) == 0)
      else if (strncasecmp (*s, "dbl", 3) == 0)
        {
        {
          format = DBL;
          format = DBL;
          *s += 4;
          *s += 4;
        }
        }
      else if (strncasecmp (*s, "quad", 4) == 0)
      else if (strncasecmp (*s, "quad", 4) == 0)
        {
        {
          format = QUAD;
          format = QUAD;
          *s += 5;
          *s += 5;
        }
        }
      else if (strncasecmp (*s, "w", 1) == 0)
      else if (strncasecmp (*s, "w", 1) == 0)
        {
        {
          format = W;
          format = W;
          *s += 2;
          *s += 2;
        }
        }
      else if (strncasecmp (*s, "uw", 2) == 0)
      else if (strncasecmp (*s, "uw", 2) == 0)
        {
        {
          format = UW;
          format = UW;
          *s += 3;
          *s += 3;
        }
        }
      else if (strncasecmp (*s, "dw", 2) == 0)
      else if (strncasecmp (*s, "dw", 2) == 0)
        {
        {
          format = DW;
          format = DW;
          *s += 3;
          *s += 3;
        }
        }
      else if (strncasecmp (*s, "udw", 3) == 0)
      else if (strncasecmp (*s, "udw", 3) == 0)
        {
        {
          format = UDW;
          format = UDW;
          *s += 4;
          *s += 4;
        }
        }
      else if (strncasecmp (*s, "qw", 2) == 0)
      else if (strncasecmp (*s, "qw", 2) == 0)
        {
        {
          format = QW;
          format = QW;
          *s += 3;
          *s += 3;
        }
        }
      else if (strncasecmp (*s, "uqw", 3) == 0)
      else if (strncasecmp (*s, "uqw", 3) == 0)
        {
        {
          format = UQW;
          format = UQW;
          *s += 4;
          *s += 4;
        }
        }
      else
      else
        {
        {
          format = ILLEGAL_FMT;
          format = ILLEGAL_FMT;
          as_bad (_("Invalid FP Operand Format: %3s"), *s);
          as_bad (_("Invalid FP Operand Format: %3s"), *s);
        }
        }
    }
    }
 
 
  return format;
  return format;
}
}
 
 
/* Parse an FP operand format completer returning the completer
/* Parse an FP operand format completer returning the completer
   type.  */
   type.  */
 
 
static fp_operand_format
static fp_operand_format
pa_parse_fp_format (char **s)
pa_parse_fp_format (char **s)
{
{
  int format;
  int format;
 
 
  format = SGL;
  format = SGL;
  if (**s == ',')
  if (**s == ',')
    {
    {
      *s += 1;
      *s += 1;
      if (strncasecmp (*s, "sgl", 3) == 0)
      if (strncasecmp (*s, "sgl", 3) == 0)
        {
        {
          format = SGL;
          format = SGL;
          *s += 4;
          *s += 4;
        }
        }
      else if (strncasecmp (*s, "dbl", 3) == 0)
      else if (strncasecmp (*s, "dbl", 3) == 0)
        {
        {
          format = DBL;
          format = DBL;
          *s += 4;
          *s += 4;
        }
        }
      else if (strncasecmp (*s, "quad", 4) == 0)
      else if (strncasecmp (*s, "quad", 4) == 0)
        {
        {
          format = QUAD;
          format = QUAD;
          *s += 5;
          *s += 5;
        }
        }
      else
      else
        {
        {
          format = ILLEGAL_FMT;
          format = ILLEGAL_FMT;
          as_bad (_("Invalid FP Operand Format: %3s"), *s);
          as_bad (_("Invalid FP Operand Format: %3s"), *s);
        }
        }
    }
    }
 
 
  return format;
  return format;
}
}
 
 
/* Convert from a selector string into a selector type.  */
/* Convert from a selector string into a selector type.  */
 
 
static int
static int
pa_chk_field_selector (char **str)
pa_chk_field_selector (char **str)
{
{
  int middle, low, high;
  int middle, low, high;
  int cmp;
  int cmp;
  char name[4];
  char name[4];
 
 
  /* Read past any whitespace.  */
  /* Read past any whitespace.  */
  /* FIXME: should we read past newlines and formfeeds??? */
  /* FIXME: should we read past newlines and formfeeds??? */
  while (**str == ' ' || **str == '\t' || **str == '\n' || **str == '\f')
  while (**str == ' ' || **str == '\t' || **str == '\n' || **str == '\f')
    *str = *str + 1;
    *str = *str + 1;
 
 
  if ((*str)[1] == '\'' || (*str)[1] == '%')
  if ((*str)[1] == '\'' || (*str)[1] == '%')
    name[0] = TOLOWER ((*str)[0]),
    name[0] = TOLOWER ((*str)[0]),
    name[1] = 0;
    name[1] = 0;
  else if ((*str)[2] == '\'' || (*str)[2] == '%')
  else if ((*str)[2] == '\'' || (*str)[2] == '%')
    name[0] = TOLOWER ((*str)[0]),
    name[0] = TOLOWER ((*str)[0]),
    name[1] = TOLOWER ((*str)[1]),
    name[1] = TOLOWER ((*str)[1]),
    name[2] = 0;
    name[2] = 0;
  else if ((*str)[3] == '\'' || (*str)[3] == '%')
  else if ((*str)[3] == '\'' || (*str)[3] == '%')
    name[0] = TOLOWER ((*str)[0]),
    name[0] = TOLOWER ((*str)[0]),
    name[1] = TOLOWER ((*str)[1]),
    name[1] = TOLOWER ((*str)[1]),
    name[2] = TOLOWER ((*str)[2]),
    name[2] = TOLOWER ((*str)[2]),
    name[3] = 0;
    name[3] = 0;
  else
  else
    return e_fsel;
    return e_fsel;
 
 
  low = 0;
  low = 0;
  high = sizeof (selector_table) / sizeof (struct selector_entry) - 1;
  high = sizeof (selector_table) / sizeof (struct selector_entry) - 1;
 
 
  do
  do
    {
    {
      middle = (low + high) / 2;
      middle = (low + high) / 2;
      cmp = strcmp (name, selector_table[middle].prefix);
      cmp = strcmp (name, selector_table[middle].prefix);
      if (cmp < 0)
      if (cmp < 0)
        high = middle - 1;
        high = middle - 1;
      else if (cmp > 0)
      else if (cmp > 0)
        low = middle + 1;
        low = middle + 1;
      else
      else
        {
        {
          *str += strlen (name) + 1;
          *str += strlen (name) + 1;
#ifndef OBJ_SOM
#ifndef OBJ_SOM
          if (selector_table[middle].field_selector == e_nsel)
          if (selector_table[middle].field_selector == e_nsel)
            return e_fsel;
            return e_fsel;
#endif
#endif
          return selector_table[middle].field_selector;
          return selector_table[middle].field_selector;
        }
        }
    }
    }
  while (low <= high);
  while (low <= high);
 
 
  return e_fsel;
  return e_fsel;
}
}
 
 
/* Parse a .byte, .word, .long expression for the HPPA.  Called by
/* Parse a .byte, .word, .long expression for the HPPA.  Called by
   cons via the TC_PARSE_CONS_EXPRESSION macro.  */
   cons via the TC_PARSE_CONS_EXPRESSION macro.  */
 
 
void
void
parse_cons_expression_hppa (expressionS *exp)
parse_cons_expression_hppa (expressionS *exp)
{
{
  hppa_field_selector = pa_chk_field_selector (&input_line_pointer);
  hppa_field_selector = pa_chk_field_selector (&input_line_pointer);
  expression (exp);
  expression (exp);
}
}
 
 
/* Evaluate an absolute expression EXP which may be modified by
/* Evaluate an absolute expression EXP which may be modified by
   the selector FIELD_SELECTOR.  Return the value of the expression.  */
   the selector FIELD_SELECTOR.  Return the value of the expression.  */
static int
static int
evaluate_absolute (struct pa_it *insn)
evaluate_absolute (struct pa_it *insn)
{
{
  offsetT value;
  offsetT value;
  expressionS exp;
  expressionS exp;
  int field_selector = insn->field_selector;
  int field_selector = insn->field_selector;
 
 
  exp = insn->exp;
  exp = insn->exp;
  value = exp.X_add_number;
  value = exp.X_add_number;
 
 
  return hppa_field_adjust (0, value, field_selector);
  return hppa_field_adjust (0, value, field_selector);
}
}
 
 
/* Mark (via expr_end) the end of an absolute expression.  FIXME.  */
/* Mark (via expr_end) the end of an absolute expression.  FIXME.  */
 
 
static int
static int
pa_get_absolute_expression (struct pa_it *insn, char **strp)
pa_get_absolute_expression (struct pa_it *insn, char **strp)
{
{
  char *save_in;
  char *save_in;
 
 
  insn->field_selector = pa_chk_field_selector (strp);
  insn->field_selector = pa_chk_field_selector (strp);
  save_in = input_line_pointer;
  save_in = input_line_pointer;
  input_line_pointer = *strp;
  input_line_pointer = *strp;
  expression (&insn->exp);
  expression (&insn->exp);
  /* This is not perfect, but is a huge improvement over doing nothing.
  /* This is not perfect, but is a huge improvement over doing nothing.
 
 
     The PA assembly syntax is ambiguous in a variety of ways.  Consider
     The PA assembly syntax is ambiguous in a variety of ways.  Consider
     this string "4 %r5"  Is that the number 4 followed by the register
     this string "4 %r5"  Is that the number 4 followed by the register
     r5, or is that 4 MOD r5?
     r5, or is that 4 MOD r5?
 
 
     If we get a modulo expression when looking for an absolute, we try
     If we get a modulo expression when looking for an absolute, we try
     again cutting off the input string at the first whitespace character.  */
     again cutting off the input string at the first whitespace character.  */
  if (insn->exp.X_op == O_modulus)
  if (insn->exp.X_op == O_modulus)
    {
    {
      char *s, c;
      char *s, c;
      int retval;
      int retval;
 
 
      input_line_pointer = *strp;
      input_line_pointer = *strp;
      s = *strp;
      s = *strp;
      while (*s != ',' && *s != ' ' && *s != '\t')
      while (*s != ',' && *s != ' ' && *s != '\t')
        s++;
        s++;
 
 
      c = *s;
      c = *s;
      *s = 0;
      *s = 0;
 
 
      retval = pa_get_absolute_expression (insn, strp);
      retval = pa_get_absolute_expression (insn, strp);
 
 
      input_line_pointer = save_in;
      input_line_pointer = save_in;
      *s = c;
      *s = c;
      return evaluate_absolute (insn);
      return evaluate_absolute (insn);
    }
    }
  /* When in strict mode we have a non-match, fix up the pointers
  /* When in strict mode we have a non-match, fix up the pointers
     and return to our caller.  */
     and return to our caller.  */
  if (insn->exp.X_op != O_constant && strict)
  if (insn->exp.X_op != O_constant && strict)
    {
    {
      expr_end = input_line_pointer;
      expr_end = input_line_pointer;
      input_line_pointer = save_in;
      input_line_pointer = save_in;
      return 0;
      return 0;
    }
    }
  if (insn->exp.X_op != O_constant)
  if (insn->exp.X_op != O_constant)
    {
    {
      as_bad (_("Bad segment (should be absolute)."));
      as_bad (_("Bad segment (should be absolute)."));
      expr_end = input_line_pointer;
      expr_end = input_line_pointer;
      input_line_pointer = save_in;
      input_line_pointer = save_in;
      return 0;
      return 0;
    }
    }
  expr_end = input_line_pointer;
  expr_end = input_line_pointer;
  input_line_pointer = save_in;
  input_line_pointer = save_in;
  return evaluate_absolute (insn);
  return evaluate_absolute (insn);
}
}
 
 
/* Given an argument location specification return the associated
/* Given an argument location specification return the associated
   argument location number.  */
   argument location number.  */
 
 
static unsigned int
static unsigned int
pa_build_arg_reloc (char *type_name)
pa_build_arg_reloc (char *type_name)
{
{
 
 
  if (strncasecmp (type_name, "no", 2) == 0)
  if (strncasecmp (type_name, "no", 2) == 0)
    return 0;
    return 0;
  if (strncasecmp (type_name, "gr", 2) == 0)
  if (strncasecmp (type_name, "gr", 2) == 0)
    return 1;
    return 1;
  else if (strncasecmp (type_name, "fr", 2) == 0)
  else if (strncasecmp (type_name, "fr", 2) == 0)
    return 2;
    return 2;
  else if (strncasecmp (type_name, "fu", 2) == 0)
  else if (strncasecmp (type_name, "fu", 2) == 0)
    return 3;
    return 3;
  else
  else
    as_bad (_("Invalid argument location: %s\n"), type_name);
    as_bad (_("Invalid argument location: %s\n"), type_name);
 
 
  return 0;
  return 0;
}
}
 
 
/* Encode and return an argument relocation specification for
/* Encode and return an argument relocation specification for
   the given register in the location specified by arg_reloc.  */
   the given register in the location specified by arg_reloc.  */
 
 
static unsigned int
static unsigned int
pa_align_arg_reloc (unsigned int reg, unsigned int arg_reloc)
pa_align_arg_reloc (unsigned int reg, unsigned int arg_reloc)
{
{
  unsigned int new_reloc;
  unsigned int new_reloc;
 
 
  new_reloc = arg_reloc;
  new_reloc = arg_reloc;
  switch (reg)
  switch (reg)
    {
    {
    case 0:
    case 0:
      new_reloc <<= 8;
      new_reloc <<= 8;
      break;
      break;
    case 1:
    case 1:
      new_reloc <<= 6;
      new_reloc <<= 6;
      break;
      break;
    case 2:
    case 2:
      new_reloc <<= 4;
      new_reloc <<= 4;
      break;
      break;
    case 3:
    case 3:
      new_reloc <<= 2;
      new_reloc <<= 2;
      break;
      break;
    default:
    default:
      as_bad (_("Invalid argument description: %d"), reg);
      as_bad (_("Invalid argument description: %d"), reg);
    }
    }
 
 
  return new_reloc;
  return new_reloc;
}
}
 
 
/* Parse a non-negated compare/subtract completer returning the
/* Parse a non-negated compare/subtract completer returning the
   number (for encoding in instructions) of the given completer.  */
   number (for encoding in instructions) of the given completer.  */
 
 
static int
static int
pa_parse_nonneg_cmpsub_cmpltr (char **s)
pa_parse_nonneg_cmpsub_cmpltr (char **s)
{
{
  int cmpltr;
  int cmpltr;
  char *name = *s + 1;
  char *name = *s + 1;
  char c;
  char c;
  char *save_s = *s;
  char *save_s = *s;
  int nullify = 0;
  int nullify = 0;
 
 
  cmpltr = 0;
  cmpltr = 0;
  if (**s == ',')
  if (**s == ',')
    {
    {
      *s += 1;
      *s += 1;
      while (**s != ',' && **s != ' ' && **s != '\t')
      while (**s != ',' && **s != ' ' && **s != '\t')
        *s += 1;
        *s += 1;
      c = **s;
      c = **s;
      **s = 0x00;
      **s = 0x00;
 
 
      if (strcmp (name, "=") == 0)
      if (strcmp (name, "=") == 0)
        {
        {
          cmpltr = 1;
          cmpltr = 1;
        }
        }
      else if (strcmp (name, "<") == 0)
      else if (strcmp (name, "<") == 0)
        {
        {
          cmpltr = 2;
          cmpltr = 2;
        }
        }
      else if (strcmp (name, "<=") == 0)
      else if (strcmp (name, "<=") == 0)
        {
        {
          cmpltr = 3;
          cmpltr = 3;
        }
        }
      else if (strcmp (name, "<<") == 0)
      else if (strcmp (name, "<<") == 0)
        {
        {
          cmpltr = 4;
          cmpltr = 4;
        }
        }
      else if (strcmp (name, "<<=") == 0)
      else if (strcmp (name, "<<=") == 0)
        {
        {
          cmpltr = 5;
          cmpltr = 5;
        }
        }
      else if (strcasecmp (name, "sv") == 0)
      else if (strcasecmp (name, "sv") == 0)
        {
        {
          cmpltr = 6;
          cmpltr = 6;
        }
        }
      else if (strcasecmp (name, "od") == 0)
      else if (strcasecmp (name, "od") == 0)
        {
        {
          cmpltr = 7;
          cmpltr = 7;
        }
        }
      /* If we have something like addb,n then there is no condition
      /* If we have something like addb,n then there is no condition
         completer.  */
         completer.  */
      else if (strcasecmp (name, "n") == 0)
      else if (strcasecmp (name, "n") == 0)
        {
        {
          cmpltr = 0;
          cmpltr = 0;
          nullify = 1;
          nullify = 1;
        }
        }
      else
      else
        {
        {
          cmpltr = -1;
          cmpltr = -1;
        }
        }
      **s = c;
      **s = c;
    }
    }
 
 
  /* Reset pointers if this was really a ,n for a branch instruction.  */
  /* Reset pointers if this was really a ,n for a branch instruction.  */
  if (nullify)
  if (nullify)
    *s = save_s;
    *s = save_s;
 
 
  return cmpltr;
  return cmpltr;
}
}
 
 
/* Parse a negated compare/subtract completer returning the
/* Parse a negated compare/subtract completer returning the
   number (for encoding in instructions) of the given completer.  */
   number (for encoding in instructions) of the given completer.  */
 
 
static int
static int
pa_parse_neg_cmpsub_cmpltr (char **s)
pa_parse_neg_cmpsub_cmpltr (char **s)
{
{
  int cmpltr;
  int cmpltr;
  char *name = *s + 1;
  char *name = *s + 1;
  char c;
  char c;
  char *save_s = *s;
  char *save_s = *s;
  int nullify = 0;
  int nullify = 0;
 
 
  cmpltr = 0;
  cmpltr = 0;
  if (**s == ',')
  if (**s == ',')
    {
    {
      *s += 1;
      *s += 1;
      while (**s != ',' && **s != ' ' && **s != '\t')
      while (**s != ',' && **s != ' ' && **s != '\t')
        *s += 1;
        *s += 1;
      c = **s;
      c = **s;
      **s = 0x00;
      **s = 0x00;
 
 
      if (strcasecmp (name, "tr") == 0)
      if (strcasecmp (name, "tr") == 0)
        {
        {
          cmpltr = 0;
          cmpltr = 0;
        }
        }
      else if (strcmp (name, "<>") == 0)
      else if (strcmp (name, "<>") == 0)
        {
        {
          cmpltr = 1;
          cmpltr = 1;
        }
        }
      else if (strcmp (name, ">=") == 0)
      else if (strcmp (name, ">=") == 0)
        {
        {
          cmpltr = 2;
          cmpltr = 2;
        }
        }
      else if (strcmp (name, ">") == 0)
      else if (strcmp (name, ">") == 0)
        {
        {
          cmpltr = 3;
          cmpltr = 3;
        }
        }
      else if (strcmp (name, ">>=") == 0)
      else if (strcmp (name, ">>=") == 0)
        {
        {
          cmpltr = 4;
          cmpltr = 4;
        }
        }
      else if (strcmp (name, ">>") == 0)
      else if (strcmp (name, ">>") == 0)
        {
        {
          cmpltr = 5;
          cmpltr = 5;
        }
        }
      else if (strcasecmp (name, "nsv") == 0)
      else if (strcasecmp (name, "nsv") == 0)
        {
        {
          cmpltr = 6;
          cmpltr = 6;
        }
        }
      else if (strcasecmp (name, "ev") == 0)
      else if (strcasecmp (name, "ev") == 0)
        {
        {
          cmpltr = 7;
          cmpltr = 7;
        }
        }
      /* If we have something like addb,n then there is no condition
      /* If we have something like addb,n then there is no condition
         completer.  */
         completer.  */
      else if (strcasecmp (name, "n") == 0)
      else if (strcasecmp (name, "n") == 0)
        {
        {
          cmpltr = 0;
          cmpltr = 0;
          nullify = 1;
          nullify = 1;
        }
        }
      else
      else
        {
        {
          cmpltr = -1;
          cmpltr = -1;
        }
        }
      **s = c;
      **s = c;
    }
    }
 
 
  /* Reset pointers if this was really a ,n for a branch instruction.  */
  /* Reset pointers if this was really a ,n for a branch instruction.  */
  if (nullify)
  if (nullify)
    *s = save_s;
    *s = save_s;
 
 
  return cmpltr;
  return cmpltr;
}
}
 
 
/* Parse a 64 bit compare and branch completer returning the number (for
/* Parse a 64 bit compare and branch completer returning the number (for
   encoding in instructions) of the given completer.
   encoding in instructions) of the given completer.
 
 
   Nonnegated comparisons are returned as 0-7, negated comparisons are
   Nonnegated comparisons are returned as 0-7, negated comparisons are
   returned as 8-15.  */
   returned as 8-15.  */
 
 
static int
static int
pa_parse_cmpb_64_cmpltr (char **s)
pa_parse_cmpb_64_cmpltr (char **s)
{
{
  int cmpltr;
  int cmpltr;
  char *name = *s + 1;
  char *name = *s + 1;
  char c;
  char c;
 
 
  cmpltr = -1;
  cmpltr = -1;
  if (**s == ',')
  if (**s == ',')
    {
    {
      *s += 1;
      *s += 1;
      while (**s != ',' && **s != ' ' && **s != '\t')
      while (**s != ',' && **s != ' ' && **s != '\t')
        *s += 1;
        *s += 1;
      c = **s;
      c = **s;
      **s = 0x00;
      **s = 0x00;
 
 
      if (strcmp (name, "*") == 0)
      if (strcmp (name, "*") == 0)
        {
        {
          cmpltr = 0;
          cmpltr = 0;
        }
        }
      else if (strcmp (name, "*=") == 0)
      else if (strcmp (name, "*=") == 0)
        {
        {
          cmpltr = 1;
          cmpltr = 1;
        }
        }
      else if (strcmp (name, "*<") == 0)
      else if (strcmp (name, "*<") == 0)
        {
        {
          cmpltr = 2;
          cmpltr = 2;
        }
        }
      else if (strcmp (name, "*<=") == 0)
      else if (strcmp (name, "*<=") == 0)
        {
        {
          cmpltr = 3;
          cmpltr = 3;
        }
        }
      else if (strcmp (name, "*<<") == 0)
      else if (strcmp (name, "*<<") == 0)
        {
        {
          cmpltr = 4;
          cmpltr = 4;
        }
        }
      else if (strcmp (name, "*<<=") == 0)
      else if (strcmp (name, "*<<=") == 0)
        {
        {
          cmpltr = 5;
          cmpltr = 5;
        }
        }
      else if (strcasecmp (name, "*sv") == 0)
      else if (strcasecmp (name, "*sv") == 0)
        {
        {
          cmpltr = 6;
          cmpltr = 6;
        }
        }
      else if (strcasecmp (name, "*od") == 0)
      else if (strcasecmp (name, "*od") == 0)
        {
        {
          cmpltr = 7;
          cmpltr = 7;
        }
        }
      else if (strcasecmp (name, "*tr") == 0)
      else if (strcasecmp (name, "*tr") == 0)
        {
        {
          cmpltr = 8;
          cmpltr = 8;
        }
        }
      else if (strcmp (name, "*<>") == 0)
      else if (strcmp (name, "*<>") == 0)
        {
        {
          cmpltr = 9;
          cmpltr = 9;
        }
        }
      else if (strcmp (name, "*>=") == 0)
      else if (strcmp (name, "*>=") == 0)
        {
        {
          cmpltr = 10;
          cmpltr = 10;
        }
        }
      else if (strcmp (name, "*>") == 0)
      else if (strcmp (name, "*>") == 0)
        {
        {
          cmpltr = 11;
          cmpltr = 11;
        }
        }
      else if (strcmp (name, "*>>=") == 0)
      else if (strcmp (name, "*>>=") == 0)
        {
        {
          cmpltr = 12;
          cmpltr = 12;
        }
        }
      else if (strcmp (name, "*>>") == 0)
      else if (strcmp (name, "*>>") == 0)
        {
        {
          cmpltr = 13;
          cmpltr = 13;
        }
        }
      else if (strcasecmp (name, "*nsv") == 0)
      else if (strcasecmp (name, "*nsv") == 0)
        {
        {
          cmpltr = 14;
          cmpltr = 14;
        }
        }
      else if (strcasecmp (name, "*ev") == 0)
      else if (strcasecmp (name, "*ev") == 0)
        {
        {
          cmpltr = 15;
          cmpltr = 15;
        }
        }
      else
      else
        {
        {
          cmpltr = -1;
          cmpltr = -1;
        }
        }
      **s = c;
      **s = c;
    }
    }
 
 
  return cmpltr;
  return cmpltr;
}
}
 
 
/* Parse a 64 bit compare immediate and branch completer returning the number
/* Parse a 64 bit compare immediate and branch completer returning the number
   (for encoding in instructions) of the given completer.  */
   (for encoding in instructions) of the given completer.  */
 
 
static int
static int
pa_parse_cmpib_64_cmpltr (char **s)
pa_parse_cmpib_64_cmpltr (char **s)
{
{
  int cmpltr;
  int cmpltr;
  char *name = *s + 1;
  char *name = *s + 1;
  char c;
  char c;
 
 
  cmpltr = -1;
  cmpltr = -1;
  if (**s == ',')
  if (**s == ',')
    {
    {
      *s += 1;
      *s += 1;
      while (**s != ',' && **s != ' ' && **s != '\t')
      while (**s != ',' && **s != ' ' && **s != '\t')
        *s += 1;
        *s += 1;
      c = **s;
      c = **s;
      **s = 0x00;
      **s = 0x00;
 
 
      if (strcmp (name, "*<<") == 0)
      if (strcmp (name, "*<<") == 0)
        {
        {
          cmpltr = 0;
          cmpltr = 0;
        }
        }
      else if (strcmp (name, "*=") == 0)
      else if (strcmp (name, "*=") == 0)
        {
        {
          cmpltr = 1;
          cmpltr = 1;
        }
        }
      else if (strcmp (name, "*<") == 0)
      else if (strcmp (name, "*<") == 0)
        {
        {
          cmpltr = 2;
          cmpltr = 2;
        }
        }
      else if (strcmp (name, "*<=") == 0)
      else if (strcmp (name, "*<=") == 0)
        {
        {
          cmpltr = 3;
          cmpltr = 3;
        }
        }
      else if (strcmp (name, "*>>=") == 0)
      else if (strcmp (name, "*>>=") == 0)
        {
        {
          cmpltr = 4;
          cmpltr = 4;
        }
        }
      else if (strcmp (name, "*<>") == 0)
      else if (strcmp (name, "*<>") == 0)
        {
        {
          cmpltr = 5;
          cmpltr = 5;
        }
        }
      else if (strcasecmp (name, "*>=") == 0)
      else if (strcasecmp (name, "*>=") == 0)
        {
        {
          cmpltr = 6;
          cmpltr = 6;
        }
        }
      else if (strcasecmp (name, "*>") == 0)
      else if (strcasecmp (name, "*>") == 0)
        {
        {
          cmpltr = 7;
          cmpltr = 7;
        }
        }
      else
      else
        {
        {
          cmpltr = -1;
          cmpltr = -1;
        }
        }
      **s = c;
      **s = c;
    }
    }
 
 
  return cmpltr;
  return cmpltr;
}
}
 
 
/* Parse a non-negated addition completer returning the number
/* Parse a non-negated addition completer returning the number
   (for encoding in instructions) of the given completer.  */
   (for encoding in instructions) of the given completer.  */
 
 
static int
static int
pa_parse_nonneg_add_cmpltr (char **s)
pa_parse_nonneg_add_cmpltr (char **s)
{
{
  int cmpltr;
  int cmpltr;
  char *name = *s + 1;
  char *name = *s + 1;
  char c;
  char c;
  char *save_s = *s;
  char *save_s = *s;
  int nullify = 0;
  int nullify = 0;
 
 
  cmpltr = 0;
  cmpltr = 0;
  if (**s == ',')
  if (**s == ',')
    {
    {
      *s += 1;
      *s += 1;
      while (**s != ',' && **s != ' ' && **s != '\t')
      while (**s != ',' && **s != ' ' && **s != '\t')
        *s += 1;
        *s += 1;
      c = **s;
      c = **s;
      **s = 0x00;
      **s = 0x00;
      if (strcmp (name, "=") == 0)
      if (strcmp (name, "=") == 0)
        {
        {
          cmpltr = 1;
          cmpltr = 1;
        }
        }
      else if (strcmp (name, "<") == 0)
      else if (strcmp (name, "<") == 0)
        {
        {
          cmpltr = 2;
          cmpltr = 2;
        }
        }
      else if (strcmp (name, "<=") == 0)
      else if (strcmp (name, "<=") == 0)
        {
        {
          cmpltr = 3;
          cmpltr = 3;
        }
        }
      else if (strcasecmp (name, "nuv") == 0)
      else if (strcasecmp (name, "nuv") == 0)
        {
        {
          cmpltr = 4;
          cmpltr = 4;
        }
        }
      else if (strcasecmp (name, "znv") == 0)
      else if (strcasecmp (name, "znv") == 0)
        {
        {
          cmpltr = 5;
          cmpltr = 5;
        }
        }
      else if (strcasecmp (name, "sv") == 0)
      else if (strcasecmp (name, "sv") == 0)
        {
        {
          cmpltr = 6;
          cmpltr = 6;
        }
        }
      else if (strcasecmp (name, "od") == 0)
      else if (strcasecmp (name, "od") == 0)
        {
        {
          cmpltr = 7;
          cmpltr = 7;
        }
        }
      /* If we have something like addb,n then there is no condition
      /* If we have something like addb,n then there is no condition
         completer.  */
         completer.  */
      else if (strcasecmp (name, "n") == 0)
      else if (strcasecmp (name, "n") == 0)
        {
        {
          cmpltr = 0;
          cmpltr = 0;
          nullify = 1;
          nullify = 1;
        }
        }
      else
      else
        {
        {
          cmpltr = -1;
          cmpltr = -1;
        }
        }
      **s = c;
      **s = c;
    }
    }
 
 
  /* Reset pointers if this was really a ,n for a branch instruction.  */
  /* Reset pointers if this was really a ,n for a branch instruction.  */
  if (nullify)
  if (nullify)
    *s = save_s;
    *s = save_s;
 
 
  return cmpltr;
  return cmpltr;
}
}
 
 
/* Parse a negated addition completer returning the number
/* Parse a negated addition completer returning the number
   (for encoding in instructions) of the given completer.  */
   (for encoding in instructions) of the given completer.  */
 
 
static int
static int
pa_parse_neg_add_cmpltr (char **s)
pa_parse_neg_add_cmpltr (char **s)
{
{
  int cmpltr;
  int cmpltr;
  char *name = *s + 1;
  char *name = *s + 1;
  char c;
  char c;
  char *save_s = *s;
  char *save_s = *s;
  int nullify = 0;
  int nullify = 0;
 
 
  cmpltr = 0;
  cmpltr = 0;
  if (**s == ',')
  if (**s == ',')
    {
    {
      *s += 1;
      *s += 1;
      while (**s != ',' && **s != ' ' && **s != '\t')
      while (**s != ',' && **s != ' ' && **s != '\t')
        *s += 1;
        *s += 1;
      c = **s;
      c = **s;
      **s = 0x00;
      **s = 0x00;
      if (strcasecmp (name, "tr") == 0)
      if (strcasecmp (name, "tr") == 0)
        {
        {
          cmpltr = 0;
          cmpltr = 0;
        }
        }
      else if (strcmp (name, "<>") == 0)
      else if (strcmp (name, "<>") == 0)
        {
        {
          cmpltr = 1;
          cmpltr = 1;
        }
        }
      else if (strcmp (name, ">=") == 0)
      else if (strcmp (name, ">=") == 0)
        {
        {
          cmpltr = 2;
          cmpltr = 2;
        }
        }
      else if (strcmp (name, ">") == 0)
      else if (strcmp (name, ">") == 0)
        {
        {
          cmpltr = 3;
          cmpltr = 3;
        }
        }
      else if (strcasecmp (name, "uv") == 0)
      else if (strcasecmp (name, "uv") == 0)
        {
        {
          cmpltr = 4;
          cmpltr = 4;
        }
        }
      else if (strcasecmp (name, "vnz") == 0)
      else if (strcasecmp (name, "vnz") == 0)
        {
        {
          cmpltr = 5;
          cmpltr = 5;
        }
        }
      else if (strcasecmp (name, "nsv") == 0)
      else if (strcasecmp (name, "nsv") == 0)
        {
        {
          cmpltr = 6;
          cmpltr = 6;
        }
        }
      else if (strcasecmp (name, "ev") == 0)
      else if (strcasecmp (name, "ev") == 0)
        {
        {
          cmpltr = 7;
          cmpltr = 7;
        }
        }
      /* If we have something like addb,n then there is no condition
      /* If we have something like addb,n then there is no condition
         completer.  */
         completer.  */
      else if (strcasecmp (name, "n") == 0)
      else if (strcasecmp (name, "n") == 0)
        {
        {
          cmpltr = 0;
          cmpltr = 0;
          nullify = 1;
          nullify = 1;
        }
        }
      else
      else
        {
        {
          cmpltr = -1;
          cmpltr = -1;
        }
        }
      **s = c;
      **s = c;
    }
    }
 
 
  /* Reset pointers if this was really a ,n for a branch instruction.  */
  /* Reset pointers if this was really a ,n for a branch instruction.  */
  if (nullify)
  if (nullify)
    *s = save_s;
    *s = save_s;
 
 
  return cmpltr;
  return cmpltr;
}
}
 
 
/* Parse a 64 bit wide mode add and branch completer returning the number (for
/* Parse a 64 bit wide mode add and branch completer returning the number (for
   encoding in instructions) of the given completer.  */
   encoding in instructions) of the given completer.  */
 
 
static int
static int
pa_parse_addb_64_cmpltr (char **s)
pa_parse_addb_64_cmpltr (char **s)
{
{
  int cmpltr;
  int cmpltr;
  char *name = *s + 1;
  char *name = *s + 1;
  char c;
  char c;
  char *save_s = *s;
  char *save_s = *s;
  int nullify = 0;
  int nullify = 0;
 
 
  cmpltr = 0;
  cmpltr = 0;
  if (**s == ',')
  if (**s == ',')
    {
    {
      *s += 1;
      *s += 1;
      while (**s != ',' && **s != ' ' && **s != '\t')
      while (**s != ',' && **s != ' ' && **s != '\t')
        *s += 1;
        *s += 1;
      c = **s;
      c = **s;
      **s = 0x00;
      **s = 0x00;
      if (strcmp (name, "=") == 0)
      if (strcmp (name, "=") == 0)
        {
        {
          cmpltr = 1;
          cmpltr = 1;
        }
        }
      else if (strcmp (name, "<") == 0)
      else if (strcmp (name, "<") == 0)
        {
        {
          cmpltr = 2;
          cmpltr = 2;
        }
        }
      else if (strcmp (name, "<=") == 0)
      else if (strcmp (name, "<=") == 0)
        {
        {
          cmpltr = 3;
          cmpltr = 3;
        }
        }
      else if (strcasecmp (name, "nuv") == 0)
      else if (strcasecmp (name, "nuv") == 0)
        {
        {
          cmpltr = 4;
          cmpltr = 4;
        }
        }
      else if (strcasecmp (name, "*=") == 0)
      else if (strcasecmp (name, "*=") == 0)
        {
        {
          cmpltr = 5;
          cmpltr = 5;
        }
        }
      else if (strcasecmp (name, "*<") == 0)
      else if (strcasecmp (name, "*<") == 0)
        {
        {
          cmpltr = 6;
          cmpltr = 6;
        }
        }
      else if (strcasecmp (name, "*<=") == 0)
      else if (strcasecmp (name, "*<=") == 0)
        {
        {
          cmpltr = 7;
          cmpltr = 7;
        }
        }
      else if (strcmp (name, "tr") == 0)
      else if (strcmp (name, "tr") == 0)
        {
        {
          cmpltr = 8;
          cmpltr = 8;
        }
        }
      else if (strcmp (name, "<>") == 0)
      else if (strcmp (name, "<>") == 0)
        {
        {
          cmpltr = 9;
          cmpltr = 9;
        }
        }
      else if (strcmp (name, ">=") == 0)
      else if (strcmp (name, ">=") == 0)
        {
        {
          cmpltr = 10;
          cmpltr = 10;
        }
        }
      else if (strcmp (name, ">") == 0)
      else if (strcmp (name, ">") == 0)
        {
        {
          cmpltr = 11;
          cmpltr = 11;
        }
        }
      else if (strcasecmp (name, "uv") == 0)
      else if (strcasecmp (name, "uv") == 0)
        {
        {
          cmpltr = 12;
          cmpltr = 12;
        }
        }
      else if (strcasecmp (name, "*<>") == 0)
      else if (strcasecmp (name, "*<>") == 0)
        {
        {
          cmpltr = 13;
          cmpltr = 13;
        }
        }
      else if (strcasecmp (name, "*>=") == 0)
      else if (strcasecmp (name, "*>=") == 0)
        {
        {
          cmpltr = 14;
          cmpltr = 14;
        }
        }
      else if (strcasecmp (name, "*>") == 0)
      else if (strcasecmp (name, "*>") == 0)
        {
        {
          cmpltr = 15;
          cmpltr = 15;
        }
        }
      /* If we have something like addb,n then there is no condition
      /* If we have something like addb,n then there is no condition
         completer.  */
         completer.  */
      else if (strcasecmp (name, "n") == 0)
      else if (strcasecmp (name, "n") == 0)
        {
        {
          cmpltr = 0;
          cmpltr = 0;
          nullify = 1;
          nullify = 1;
        }
        }
      else
      else
        {
        {
          cmpltr = -1;
          cmpltr = -1;
        }
        }
      **s = c;
      **s = c;
    }
    }
 
 
  /* Reset pointers if this was really a ,n for a branch instruction.  */
  /* Reset pointers if this was really a ,n for a branch instruction.  */
  if (nullify)
  if (nullify)
    *s = save_s;
    *s = save_s;
 
 
  return cmpltr;
  return cmpltr;
}
}
 
 
/* Do the real work for assembling a single instruction.  Store results
/* Do the real work for assembling a single instruction.  Store results
   into the global "the_insn" variable.  */
   into the global "the_insn" variable.  */
 
 
static void
static void
pa_ip (char *str)
pa_ip (char *str)
{
{
  char *error_message = "";
  char *error_message = "";
  char *s, c, *argstart, *name, *save_s;
  char *s, c, *argstart, *name, *save_s;
  const char *args;
  const char *args;
  int match = FALSE;
  int match = FALSE;
  int comma = 0;
  int comma = 0;
  int cmpltr, nullif, flag, cond, num;
  int cmpltr, nullif, flag, cond, num;
  unsigned long opcode;
  unsigned long opcode;
  struct pa_opcode *insn;
  struct pa_opcode *insn;
 
 
#ifdef OBJ_SOM
#ifdef OBJ_SOM
  /* We must have a valid space and subspace.  */
  /* We must have a valid space and subspace.  */
  pa_check_current_space_and_subspace ();
  pa_check_current_space_and_subspace ();
#endif
#endif
 
 
  /* Convert everything up to the first whitespace character into lower
  /* Convert everything up to the first whitespace character into lower
     case.  */
     case.  */
  for (s = str; *s != ' ' && *s != '\t' && *s != '\n' && *s != '\0'; s++)
  for (s = str; *s != ' ' && *s != '\t' && *s != '\n' && *s != '\0'; s++)
    *s = TOLOWER (*s);
    *s = TOLOWER (*s);
 
 
  /* Skip to something interesting.  */
  /* Skip to something interesting.  */
  for (s = str;
  for (s = str;
       ISUPPER (*s) || ISLOWER (*s) || (*s >= '0' && *s <= '3');
       ISUPPER (*s) || ISLOWER (*s) || (*s >= '0' && *s <= '3');
       ++s)
       ++s)
    ;
    ;
 
 
  switch (*s)
  switch (*s)
    {
    {
 
 
    case '\0':
    case '\0':
      break;
      break;
 
 
    case ',':
    case ',':
      comma = 1;
      comma = 1;
 
 
      /*FALLTHROUGH */
      /*FALLTHROUGH */
 
 
    case ' ':
    case ' ':
      *s++ = '\0';
      *s++ = '\0';
      break;
      break;
 
 
    default:
    default:
      as_bad (_("Unknown opcode: `%s'"), str);
      as_bad (_("Unknown opcode: `%s'"), str);
      return;
      return;
    }
    }
 
 
  /* Look up the opcode in the hash table.  */
  /* Look up the opcode in the hash table.  */
  if ((insn = (struct pa_opcode *) hash_find (op_hash, str)) == NULL)
  if ((insn = (struct pa_opcode *) hash_find (op_hash, str)) == NULL)
    {
    {
      as_bad ("Unknown opcode: `%s'", str);
      as_bad ("Unknown opcode: `%s'", str);
      return;
      return;
    }
    }
 
 
  if (comma)
  if (comma)
    *--s = ',';
    *--s = ',';
 
 
  /* Mark the location where arguments for the instruction start, then
  /* Mark the location where arguments for the instruction start, then
     start processing them.  */
     start processing them.  */
  argstart = s;
  argstart = s;
  for (;;)
  for (;;)
    {
    {
      /* Do some initialization.  */
      /* Do some initialization.  */
      opcode = insn->match;
      opcode = insn->match;
      strict = (insn->flags & FLAG_STRICT);
      strict = (insn->flags & FLAG_STRICT);
      memset (&the_insn, 0, sizeof (the_insn));
      memset (&the_insn, 0, sizeof (the_insn));
 
 
      the_insn.reloc = R_HPPA_NONE;
      the_insn.reloc = R_HPPA_NONE;
 
 
      if (insn->arch >= pa20
      if (insn->arch >= pa20
          && bfd_get_mach (stdoutput) < insn->arch)
          && bfd_get_mach (stdoutput) < insn->arch)
        goto failed;
        goto failed;
 
 
      /* Build the opcode, checking as we go to make
      /* Build the opcode, checking as we go to make
         sure that the operands match.  */
         sure that the operands match.  */
      for (args = insn->args;; ++args)
      for (args = insn->args;; ++args)
        {
        {
          /* Absorb white space in instruction.  */
          /* Absorb white space in instruction.  */
          while (*s == ' ' || *s == '\t')
          while (*s == ' ' || *s == '\t')
            s++;
            s++;
 
 
          switch (*args)
          switch (*args)
            {
            {
            /* End of arguments.  */
            /* End of arguments.  */
            case '\0':
            case '\0':
              if (*s == '\0')
              if (*s == '\0')
                match = TRUE;
                match = TRUE;
              break;
              break;
 
 
            case '+':
            case '+':
              if (*s == '+')
              if (*s == '+')
                {
                {
                  ++s;
                  ++s;
                  continue;
                  continue;
                }
                }
              if (*s == '-')
              if (*s == '-')
                continue;
                continue;
              break;
              break;
 
 
            /* These must match exactly.  */
            /* These must match exactly.  */
            case '(':
            case '(':
            case ')':
            case ')':
            case ',':
            case ',':
            case ' ':
            case ' ':
              if (*s++ == *args)
              if (*s++ == *args)
                continue;
                continue;
              break;
              break;
 
 
            /* Handle a 5 bit register or control register field at 10.  */
            /* Handle a 5 bit register or control register field at 10.  */
            case 'b':
            case 'b':
            case '^':
            case '^':
              if (!pa_parse_number (&s, 0))
              if (!pa_parse_number (&s, 0))
                break;
                break;
              num = pa_number;
              num = pa_number;
              CHECK_FIELD (num, 31, 0, 0);
              CHECK_FIELD (num, 31, 0, 0);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 21);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 21);
 
 
            /* Handle %sar or %cr11.  No bits get set, we just verify that it
            /* Handle %sar or %cr11.  No bits get set, we just verify that it
               is there.  */
               is there.  */
            case '!':
            case '!':
              /* Skip whitespace before register.  */
              /* Skip whitespace before register.  */
              while (*s == ' ' || *s == '\t')
              while (*s == ' ' || *s == '\t')
                s = s + 1;
                s = s + 1;
 
 
              if (!strncasecmp (s, "%sar", 4))
              if (!strncasecmp (s, "%sar", 4))
                {
                {
                  s += 4;
                  s += 4;
                  continue;
                  continue;
                }
                }
              else if (!strncasecmp (s, "%cr11", 5))
              else if (!strncasecmp (s, "%cr11", 5))
                {
                {
                  s += 5;
                  s += 5;
                  continue;
                  continue;
                }
                }
              break;
              break;
 
 
            /* Handle a 5 bit register field at 15.  */
            /* Handle a 5 bit register field at 15.  */
            case 'x':
            case 'x':
              if (!pa_parse_number (&s, 0))
              if (!pa_parse_number (&s, 0))
                break;
                break;
              num = pa_number;
              num = pa_number;
              CHECK_FIELD (num, 31, 0, 0);
              CHECK_FIELD (num, 31, 0, 0);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 16);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 16);
 
 
            /* Handle a 5 bit register field at 31.  */
            /* Handle a 5 bit register field at 31.  */
            case 't':
            case 't':
              if (!pa_parse_number (&s, 0))
              if (!pa_parse_number (&s, 0))
                break;
                break;
              num = pa_number;
              num = pa_number;
              CHECK_FIELD (num, 31, 0, 0);
              CHECK_FIELD (num, 31, 0, 0);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
 
 
            /* Handle a 5 bit register field at 10 and 15.  */
            /* Handle a 5 bit register field at 10 and 15.  */
            case 'a':
            case 'a':
              if (!pa_parse_number (&s, 0))
              if (!pa_parse_number (&s, 0))
                break;
                break;
              num = pa_number;
              num = pa_number;
              CHECK_FIELD (num, 31, 0, 0);
              CHECK_FIELD (num, 31, 0, 0);
              opcode |= num << 16;
              opcode |= num << 16;
              INSERT_FIELD_AND_CONTINUE (opcode, num, 21);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 21);
 
 
            /* Handle a 5 bit field length at 31.  */
            /* Handle a 5 bit field length at 31.  */
            case 'T':
            case 'T':
              num = pa_get_absolute_expression (&the_insn, &s);
              num = pa_get_absolute_expression (&the_insn, &s);
              if (strict && the_insn.exp.X_op != O_constant)
              if (strict && the_insn.exp.X_op != O_constant)
                break;
                break;
              s = expr_end;
              s = expr_end;
              CHECK_FIELD (num, 32, 1, 0);
              CHECK_FIELD (num, 32, 1, 0);
              INSERT_FIELD_AND_CONTINUE (opcode, 32 - num, 0);
              INSERT_FIELD_AND_CONTINUE (opcode, 32 - num, 0);
 
 
            /* Handle a 5 bit immediate at 15.  */
            /* Handle a 5 bit immediate at 15.  */
            case '5':
            case '5':
              num = pa_get_absolute_expression (&the_insn, &s);
              num = pa_get_absolute_expression (&the_insn, &s);
              if (strict && the_insn.exp.X_op != O_constant)
              if (strict && the_insn.exp.X_op != O_constant)
                break;
                break;
              s = expr_end;
              s = expr_end;
              /* When in strict mode, we want to just reject this
              /* When in strict mode, we want to just reject this
                 match instead of giving an out of range error.  */
                 match instead of giving an out of range error.  */
              CHECK_FIELD (num, 15, -16, strict);
              CHECK_FIELD (num, 15, -16, strict);
              num = low_sign_unext (num, 5);
              num = low_sign_unext (num, 5);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 16);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 16);
 
 
            /* Handle a 5 bit immediate at 31.  */
            /* Handle a 5 bit immediate at 31.  */
            case 'V':
            case 'V':
              num = pa_get_absolute_expression (&the_insn, &s);
              num = pa_get_absolute_expression (&the_insn, &s);
              if (strict && the_insn.exp.X_op != O_constant)
              if (strict && the_insn.exp.X_op != O_constant)
                break;
                break;
              s = expr_end;
              s = expr_end;
              /* When in strict mode, we want to just reject this
              /* When in strict mode, we want to just reject this
                 match instead of giving an out of range error.  */
                 match instead of giving an out of range error.  */
              CHECK_FIELD (num, 15, -16, strict);
              CHECK_FIELD (num, 15, -16, strict);
              num = low_sign_unext (num, 5);
              num = low_sign_unext (num, 5);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
 
 
            /* Handle an unsigned 5 bit immediate at 31.  */
            /* Handle an unsigned 5 bit immediate at 31.  */
            case 'r':
            case 'r':
              num = pa_get_absolute_expression (&the_insn, &s);
              num = pa_get_absolute_expression (&the_insn, &s);
              if (strict && the_insn.exp.X_op != O_constant)
              if (strict && the_insn.exp.X_op != O_constant)
                break;
                break;
              s = expr_end;
              s = expr_end;
              CHECK_FIELD (num, 31, 0, strict);
              CHECK_FIELD (num, 31, 0, strict);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
 
 
            /* Handle an unsigned 5 bit immediate at 15.  */
            /* Handle an unsigned 5 bit immediate at 15.  */
            case 'R':
            case 'R':
              num = pa_get_absolute_expression (&the_insn, &s);
              num = pa_get_absolute_expression (&the_insn, &s);
              if (strict && the_insn.exp.X_op != O_constant)
              if (strict && the_insn.exp.X_op != O_constant)
                break;
                break;
              s = expr_end;
              s = expr_end;
              CHECK_FIELD (num, 31, 0, strict);
              CHECK_FIELD (num, 31, 0, strict);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 16);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 16);
 
 
            /* Handle an unsigned 10 bit immediate at 15.  */
            /* Handle an unsigned 10 bit immediate at 15.  */
            case 'U':
            case 'U':
              num = pa_get_absolute_expression (&the_insn, &s);
              num = pa_get_absolute_expression (&the_insn, &s);
              if (strict && the_insn.exp.X_op != O_constant)
              if (strict && the_insn.exp.X_op != O_constant)
                break;
                break;
              s = expr_end;
              s = expr_end;
              CHECK_FIELD (num, 1023, 0, strict);
              CHECK_FIELD (num, 1023, 0, strict);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 16);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 16);
 
 
            /* Handle a 2 bit space identifier at 17.  */
            /* Handle a 2 bit space identifier at 17.  */
            case 's':
            case 's':
              if (!pa_parse_number (&s, 0))
              if (!pa_parse_number (&s, 0))
                break;
                break;
              num = pa_number;
              num = pa_number;
              CHECK_FIELD (num, 3, 0, 1);
              CHECK_FIELD (num, 3, 0, 1);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 14);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 14);
 
 
            /* Handle a 3 bit space identifier at 18.  */
            /* Handle a 3 bit space identifier at 18.  */
            case 'S':
            case 'S':
              if (!pa_parse_number (&s, 0))
              if (!pa_parse_number (&s, 0))
                break;
                break;
              num = pa_number;
              num = pa_number;
              CHECK_FIELD (num, 7, 0, 1);
              CHECK_FIELD (num, 7, 0, 1);
              opcode |= re_assemble_3 (num);
              opcode |= re_assemble_3 (num);
              continue;
              continue;
 
 
            /* Handle all completers.  */
            /* Handle all completers.  */
            case 'c':
            case 'c':
              switch (*++args)
              switch (*++args)
                {
                {
 
 
                /* Handle a completer for an indexing load or store.  */
                /* Handle a completer for an indexing load or store.  */
                case 'X':
                case 'X':
                case 'x':
                case 'x':
                  {
                  {
                    int uu = 0;
                    int uu = 0;
                    int m = 0;
                    int m = 0;
                    int i = 0;
                    int i = 0;
                    while (*s == ',' && i < 2)
                    while (*s == ',' && i < 2)
                      {
                      {
                        s++;
                        s++;
                        if (strncasecmp (s, "sm", 2) == 0)
                        if (strncasecmp (s, "sm", 2) == 0)
                          {
                          {
                            uu = 1;
                            uu = 1;
                            m = 1;
                            m = 1;
                            s++;
                            s++;
                            i++;
                            i++;
                          }
                          }
                        else if (strncasecmp (s, "m", 1) == 0)
                        else if (strncasecmp (s, "m", 1) == 0)
                          m = 1;
                          m = 1;
                        else if ((strncasecmp (s, "s ", 2) == 0)
                        else if ((strncasecmp (s, "s ", 2) == 0)
                                 || (strncasecmp (s, "s,", 2) == 0))
                                 || (strncasecmp (s, "s,", 2) == 0))
                          uu = 1;
                          uu = 1;
                        else if (strict)
                        else if (strict)
                          {
                          {
                            /* This is a match failure.  */
                            /* This is a match failure.  */
                            s--;
                            s--;
                            break;
                            break;
                          }
                          }
                        else
                        else
                          as_bad (_("Invalid Indexed Load Completer."));
                          as_bad (_("Invalid Indexed Load Completer."));
                        s++;
                        s++;
                        i++;
                        i++;
                      }
                      }
                    if (i > 2)
                    if (i > 2)
                      as_bad (_("Invalid Indexed Load Completer Syntax."));
                      as_bad (_("Invalid Indexed Load Completer Syntax."));
                    opcode |= m << 5;
                    opcode |= m << 5;
                    INSERT_FIELD_AND_CONTINUE (opcode, uu, 13);
                    INSERT_FIELD_AND_CONTINUE (opcode, uu, 13);
                  }
                  }
 
 
                /* Handle a short load/store completer.  */
                /* Handle a short load/store completer.  */
                case 'M':
                case 'M':
                case 'm':
                case 'm':
                case 'q':
                case 'q':
                case 'J':
                case 'J':
                case 'e':
                case 'e':
                  {
                  {
                    int a = 0;
                    int a = 0;
                    int m = 0;
                    int m = 0;
                    if (*s == ',')
                    if (*s == ',')
                      {
                      {
                        s++;
                        s++;
                        if (strncasecmp (s, "ma", 2) == 0)
                        if (strncasecmp (s, "ma", 2) == 0)
                          {
                          {
                            a = 0;
                            a = 0;
                            m = 1;
                            m = 1;
                            s += 2;
                            s += 2;
                          }
                          }
                        else if (strncasecmp (s, "mb", 2) == 0)
                        else if (strncasecmp (s, "mb", 2) == 0)
                          {
                          {
                            a = 1;
                            a = 1;
                            m = 1;
                            m = 1;
                            s += 2;
                            s += 2;
                          }
                          }
                        else if (strict)
                        else if (strict)
                          /* This is a match failure.  */
                          /* This is a match failure.  */
                          s--;
                          s--;
                        else
                        else
                          {
                          {
                            as_bad (_("Invalid Short Load/Store Completer."));
                            as_bad (_("Invalid Short Load/Store Completer."));
                            s += 2;
                            s += 2;
                          }
                          }
                      }
                      }
                    /* If we did not get a ma/mb completer, then we do not
                    /* If we did not get a ma/mb completer, then we do not
                       consider this a positive match for 'ce'.  */
                       consider this a positive match for 'ce'.  */
                    else if (*args == 'e')
                    else if (*args == 'e')
                      break;
                      break;
 
 
                   /* 'J', 'm', 'M' and 'q' are the same, except for where they
                   /* 'J', 'm', 'M' and 'q' are the same, except for where they
                       encode the before/after field.  */
                       encode the before/after field.  */
                   if (*args == 'm' || *args == 'M')
                   if (*args == 'm' || *args == 'M')
                      {
                      {
                        opcode |= m << 5;
                        opcode |= m << 5;
                        INSERT_FIELD_AND_CONTINUE (opcode, a, 13);
                        INSERT_FIELD_AND_CONTINUE (opcode, a, 13);
                      }
                      }
                    else if (*args == 'q')
                    else if (*args == 'q')
                      {
                      {
                        opcode |= m << 3;
                        opcode |= m << 3;
                        INSERT_FIELD_AND_CONTINUE (opcode, a, 2);
                        INSERT_FIELD_AND_CONTINUE (opcode, a, 2);
                      }
                      }
                    else if (*args == 'J')
                    else if (*args == 'J')
                      {
                      {
                        /* M bit is explicit in the major opcode.  */
                        /* M bit is explicit in the major opcode.  */
                        INSERT_FIELD_AND_CONTINUE (opcode, a, 2);
                        INSERT_FIELD_AND_CONTINUE (opcode, a, 2);
                      }
                      }
                    else if (*args == 'e')
                    else if (*args == 'e')
                      {
                      {
                        /* Stash the ma/mb flag temporarily in the
                        /* Stash the ma/mb flag temporarily in the
                           instruction.  We will use (and remove it)
                           instruction.  We will use (and remove it)
                           later when handling 'J', 'K', '<' & '>'.  */
                           later when handling 'J', 'K', '<' & '>'.  */
                        opcode |= a;
                        opcode |= a;
                        continue;
                        continue;
                      }
                      }
                  }
                  }
 
 
                /* Handle a stbys completer.  */
                /* Handle a stbys completer.  */
                case 'A':
                case 'A':
                case 's':
                case 's':
                  {
                  {
                    int a = 0;
                    int a = 0;
                    int m = 0;
                    int m = 0;
                    int i = 0;
                    int i = 0;
                    while (*s == ',' && i < 2)
                    while (*s == ',' && i < 2)
                      {
                      {
                        s++;
                        s++;
                        if (strncasecmp (s, "m", 1) == 0)
                        if (strncasecmp (s, "m", 1) == 0)
                          m = 1;
                          m = 1;
                        else if ((strncasecmp (s, "b ", 2) == 0)
                        else if ((strncasecmp (s, "b ", 2) == 0)
                                 || (strncasecmp (s, "b,", 2) == 0))
                                 || (strncasecmp (s, "b,", 2) == 0))
                          a = 0;
                          a = 0;
                        else if (strncasecmp (s, "e", 1) == 0)
                        else if (strncasecmp (s, "e", 1) == 0)
                          a = 1;
                          a = 1;
                        /* In strict mode, this is a match failure.  */
                        /* In strict mode, this is a match failure.  */
                        else if (strict)
                        else if (strict)
                          {
                          {
                            s--;
                            s--;
                            break;
                            break;
                          }
                          }
                        else
                        else
                          as_bad (_("Invalid Store Bytes Short Completer"));
                          as_bad (_("Invalid Store Bytes Short Completer"));
                        s++;
                        s++;
                        i++;
                        i++;
                      }
                      }
                    if (i > 2)
                    if (i > 2)
                      as_bad (_("Invalid Store Bytes Short Completer"));
                      as_bad (_("Invalid Store Bytes Short Completer"));
                    opcode |= m << 5;
                    opcode |= m << 5;
                    INSERT_FIELD_AND_CONTINUE (opcode, a, 13);
                    INSERT_FIELD_AND_CONTINUE (opcode, a, 13);
                  }
                  }
 
 
                /* Handle load cache hint completer.  */
                /* Handle load cache hint completer.  */
                case 'c':
                case 'c':
                  cmpltr = 0;
                  cmpltr = 0;
                  if (!strncmp (s, ",sl", 3))
                  if (!strncmp (s, ",sl", 3))
                    {
                    {
                      s += 3;
                      s += 3;
                      cmpltr = 2;
                      cmpltr = 2;
                    }
                    }
                  INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 10);
                  INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 10);
 
 
                /* Handle store cache hint completer.  */
                /* Handle store cache hint completer.  */
                case 'C':
                case 'C':
                  cmpltr = 0;
                  cmpltr = 0;
                  if (!strncmp (s, ",sl", 3))
                  if (!strncmp (s, ",sl", 3))
                    {
                    {
                      s += 3;
                      s += 3;
                      cmpltr = 2;
                      cmpltr = 2;
                    }
                    }
                  else if (!strncmp (s, ",bc", 3))
                  else if (!strncmp (s, ",bc", 3))
                    {
                    {
                      s += 3;
                      s += 3;
                      cmpltr = 1;
                      cmpltr = 1;
                    }
                    }
                  INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 10);
                  INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 10);
 
 
                /* Handle load and clear cache hint completer.  */
                /* Handle load and clear cache hint completer.  */
                case 'd':
                case 'd':
                  cmpltr = 0;
                  cmpltr = 0;
                  if (!strncmp (s, ",co", 3))
                  if (!strncmp (s, ",co", 3))
                    {
                    {
                      s += 3;
                      s += 3;
                      cmpltr = 1;
                      cmpltr = 1;
                    }
                    }
                  INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 10);
                  INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 10);
 
 
                /* Handle load ordering completer.  */
                /* Handle load ordering completer.  */
                case 'o':
                case 'o':
                  if (strncmp (s, ",o", 2) != 0)
                  if (strncmp (s, ",o", 2) != 0)
                    break;
                    break;
                  s += 2;
                  s += 2;
                  continue;
                  continue;
 
 
                /* Handle a branch gate completer.  */
                /* Handle a branch gate completer.  */
                case 'g':
                case 'g':
                  if (strncasecmp (s, ",gate", 5) != 0)
                  if (strncasecmp (s, ",gate", 5) != 0)
                    break;
                    break;
                  s += 5;
                  s += 5;
                  continue;
                  continue;
 
 
                /* Handle a branch link and push completer.  */
                /* Handle a branch link and push completer.  */
                case 'p':
                case 'p':
                  if (strncasecmp (s, ",l,push", 7) != 0)
                  if (strncasecmp (s, ",l,push", 7) != 0)
                    break;
                    break;
                  s += 7;
                  s += 7;
                  continue;
                  continue;
 
 
                /* Handle a branch link completer.  */
                /* Handle a branch link completer.  */
                case 'l':
                case 'l':
                  if (strncasecmp (s, ",l", 2) != 0)
                  if (strncasecmp (s, ",l", 2) != 0)
                    break;
                    break;
                  s += 2;
                  s += 2;
                  continue;
                  continue;
 
 
                /* Handle a branch pop completer.  */
                /* Handle a branch pop completer.  */
                case 'P':
                case 'P':
                  if (strncasecmp (s, ",pop", 4) != 0)
                  if (strncasecmp (s, ",pop", 4) != 0)
                    break;
                    break;
                  s += 4;
                  s += 4;
                  continue;
                  continue;
 
 
                /* Handle a local processor completer.  */
                /* Handle a local processor completer.  */
                case 'L':
                case 'L':
                  if (strncasecmp (s, ",l", 2) != 0)
                  if (strncasecmp (s, ",l", 2) != 0)
                    break;
                    break;
                  s += 2;
                  s += 2;
                  continue;
                  continue;
 
 
                /* Handle a PROBE read/write completer.  */
                /* Handle a PROBE read/write completer.  */
                case 'w':
                case 'w':
                  flag = 0;
                  flag = 0;
                  if (!strncasecmp (s, ",w", 2))
                  if (!strncasecmp (s, ",w", 2))
                    {
                    {
                      flag = 1;
                      flag = 1;
                      s += 2;
                      s += 2;
                    }
                    }
                  else if (!strncasecmp (s, ",r", 2))
                  else if (!strncasecmp (s, ",r", 2))
                    {
                    {
                      flag = 0;
                      flag = 0;
                      s += 2;
                      s += 2;
                    }
                    }
 
 
                  INSERT_FIELD_AND_CONTINUE (opcode, flag, 6);
                  INSERT_FIELD_AND_CONTINUE (opcode, flag, 6);
 
 
                /* Handle MFCTL wide completer.  */
                /* Handle MFCTL wide completer.  */
                case 'W':
                case 'W':
                  if (strncasecmp (s, ",w", 2) != 0)
                  if (strncasecmp (s, ",w", 2) != 0)
                    break;
                    break;
                  s += 2;
                  s += 2;
                  continue;
                  continue;
 
 
                /* Handle an RFI restore completer.  */
                /* Handle an RFI restore completer.  */
                case 'r':
                case 'r':
                  flag = 0;
                  flag = 0;
                  if (!strncasecmp (s, ",r", 2))
                  if (!strncasecmp (s, ",r", 2))
                    {
                    {
                      flag = 5;
                      flag = 5;
                      s += 2;
                      s += 2;
                    }
                    }
 
 
                  INSERT_FIELD_AND_CONTINUE (opcode, flag, 5);
                  INSERT_FIELD_AND_CONTINUE (opcode, flag, 5);
 
 
                /* Handle a system control completer.  */
                /* Handle a system control completer.  */
                case 'Z':
                case 'Z':
                  if (*s == ',' && (*(s + 1) == 'm' || *(s + 1) == 'M'))
                  if (*s == ',' && (*(s + 1) == 'm' || *(s + 1) == 'M'))
                    {
                    {
                      flag = 1;
                      flag = 1;
                      s += 2;
                      s += 2;
                    }
                    }
                  else
                  else
                    flag = 0;
                    flag = 0;
 
 
                  INSERT_FIELD_AND_CONTINUE (opcode, flag, 5);
                  INSERT_FIELD_AND_CONTINUE (opcode, flag, 5);
 
 
                /* Handle intermediate/final completer for DCOR.  */
                /* Handle intermediate/final completer for DCOR.  */
                case 'i':
                case 'i':
                  flag = 0;
                  flag = 0;
                  if (!strncasecmp (s, ",i", 2))
                  if (!strncasecmp (s, ",i", 2))
                    {
                    {
                      flag = 1;
                      flag = 1;
                      s += 2;
                      s += 2;
                    }
                    }
 
 
                  INSERT_FIELD_AND_CONTINUE (opcode, flag, 6);
                  INSERT_FIELD_AND_CONTINUE (opcode, flag, 6);
 
 
                /* Handle zero/sign extension completer.  */
                /* Handle zero/sign extension completer.  */
                case 'z':
                case 'z':
                  flag = 1;
                  flag = 1;
                  if (!strncasecmp (s, ",z", 2))
                  if (!strncasecmp (s, ",z", 2))
                    {
                    {
                      flag = 0;
                      flag = 0;
                      s += 2;
                      s += 2;
                    }
                    }
 
 
                  INSERT_FIELD_AND_CONTINUE (opcode, flag, 10);
                  INSERT_FIELD_AND_CONTINUE (opcode, flag, 10);
 
 
                /* Handle add completer.  */
                /* Handle add completer.  */
                case 'a':
                case 'a':
                  flag = 1;
                  flag = 1;
                  if (!strncasecmp (s, ",l", 2))
                  if (!strncasecmp (s, ",l", 2))
                    {
                    {
                      flag = 2;
                      flag = 2;
                      s += 2;
                      s += 2;
                    }
                    }
                  else if (!strncasecmp (s, ",tsv", 4))
                  else if (!strncasecmp (s, ",tsv", 4))
                    {
                    {
                      flag = 3;
                      flag = 3;
                      s += 4;
                      s += 4;
                    }
                    }
 
 
                  INSERT_FIELD_AND_CONTINUE (opcode, flag, 10);
                  INSERT_FIELD_AND_CONTINUE (opcode, flag, 10);
 
 
                /* Handle 64 bit carry for ADD.  */
                /* Handle 64 bit carry for ADD.  */
                case 'Y':
                case 'Y':
                  flag = 0;
                  flag = 0;
                  if (!strncasecmp (s, ",dc,tsv", 7) ||
                  if (!strncasecmp (s, ",dc,tsv", 7) ||
                      !strncasecmp (s, ",tsv,dc", 7))
                      !strncasecmp (s, ",tsv,dc", 7))
                    {
                    {
                      flag = 1;
                      flag = 1;
                      s += 7;
                      s += 7;
                    }
                    }
                  else if (!strncasecmp (s, ",dc", 3))
                  else if (!strncasecmp (s, ",dc", 3))
                    {
                    {
                      flag = 0;
                      flag = 0;
                      s += 3;
                      s += 3;
                    }
                    }
                  else
                  else
                    break;
                    break;
 
 
                  INSERT_FIELD_AND_CONTINUE (opcode, flag, 11);
                  INSERT_FIELD_AND_CONTINUE (opcode, flag, 11);
 
 
                /* Handle 32 bit carry for ADD.  */
                /* Handle 32 bit carry for ADD.  */
                case 'y':
                case 'y':
                  flag = 0;
                  flag = 0;
                  if (!strncasecmp (s, ",c,tsv", 6) ||
                  if (!strncasecmp (s, ",c,tsv", 6) ||
                      !strncasecmp (s, ",tsv,c", 6))
                      !strncasecmp (s, ",tsv,c", 6))
                    {
                    {
                      flag = 1;
                      flag = 1;
                      s += 6;
                      s += 6;
                    }
                    }
                  else if (!strncasecmp (s, ",c", 2))
                  else if (!strncasecmp (s, ",c", 2))
                    {
                    {
                      flag = 0;
                      flag = 0;
                      s += 2;
                      s += 2;
                    }
                    }
                  else
                  else
                    break;
                    break;
 
 
                  INSERT_FIELD_AND_CONTINUE (opcode, flag, 11);
                  INSERT_FIELD_AND_CONTINUE (opcode, flag, 11);
 
 
                /* Handle trap on signed overflow.  */
                /* Handle trap on signed overflow.  */
                case 'v':
                case 'v':
                  flag = 0;
                  flag = 0;
                  if (!strncasecmp (s, ",tsv", 4))
                  if (!strncasecmp (s, ",tsv", 4))
                    {
                    {
                      flag = 1;
                      flag = 1;
                      s += 4;
                      s += 4;
                    }
                    }
 
 
                  INSERT_FIELD_AND_CONTINUE (opcode, flag, 11);
                  INSERT_FIELD_AND_CONTINUE (opcode, flag, 11);
 
 
                /* Handle trap on condition and overflow.  */
                /* Handle trap on condition and overflow.  */
                case 't':
                case 't':
                  flag = 0;
                  flag = 0;
                  if (!strncasecmp (s, ",tc,tsv", 7) ||
                  if (!strncasecmp (s, ",tc,tsv", 7) ||
                      !strncasecmp (s, ",tsv,tc", 7))
                      !strncasecmp (s, ",tsv,tc", 7))
                    {
                    {
                      flag = 1;
                      flag = 1;
                      s += 7;
                      s += 7;
                    }
                    }
                  else if (!strncasecmp (s, ",tc", 3))
                  else if (!strncasecmp (s, ",tc", 3))
                    {
                    {
                      flag = 0;
                      flag = 0;
                      s += 3;
                      s += 3;
                    }
                    }
                  else
                  else
                    break;
                    break;
 
 
                  INSERT_FIELD_AND_CONTINUE (opcode, flag, 11);
                  INSERT_FIELD_AND_CONTINUE (opcode, flag, 11);
 
 
                /* Handle 64 bit borrow for SUB.  */
                /* Handle 64 bit borrow for SUB.  */
                case 'B':
                case 'B':
                  flag = 0;
                  flag = 0;
                  if (!strncasecmp (s, ",db,tsv", 7) ||
                  if (!strncasecmp (s, ",db,tsv", 7) ||
                      !strncasecmp (s, ",tsv,db", 7))
                      !strncasecmp (s, ",tsv,db", 7))
                    {
                    {
                      flag = 1;
                      flag = 1;
                      s += 7;
                      s += 7;
                    }
                    }
                  else if (!strncasecmp (s, ",db", 3))
                  else if (!strncasecmp (s, ",db", 3))
                    {
                    {
                      flag = 0;
                      flag = 0;
                      s += 3;
                      s += 3;
                    }
                    }
                  else
                  else
                    break;
                    break;
 
 
                  INSERT_FIELD_AND_CONTINUE (opcode, flag, 11);
                  INSERT_FIELD_AND_CONTINUE (opcode, flag, 11);
 
 
                /* Handle 32 bit borrow for SUB.  */
                /* Handle 32 bit borrow for SUB.  */
                case 'b':
                case 'b':
                  flag = 0;
                  flag = 0;
                  if (!strncasecmp (s, ",b,tsv", 6) ||
                  if (!strncasecmp (s, ",b,tsv", 6) ||
                      !strncasecmp (s, ",tsv,b", 6))
                      !strncasecmp (s, ",tsv,b", 6))
                    {
                    {
                      flag = 1;
                      flag = 1;
                      s += 6;
                      s += 6;
                    }
                    }
                  else if (!strncasecmp (s, ",b", 2))
                  else if (!strncasecmp (s, ",b", 2))
                    {
                    {
                      flag = 0;
                      flag = 0;
                      s += 2;
                      s += 2;
                    }
                    }
                  else
                  else
                    break;
                    break;
 
 
                  INSERT_FIELD_AND_CONTINUE (opcode, flag, 11);
                  INSERT_FIELD_AND_CONTINUE (opcode, flag, 11);
 
 
                /* Handle trap condition completer for UADDCM.  */
                /* Handle trap condition completer for UADDCM.  */
                case 'T':
                case 'T':
                  flag = 0;
                  flag = 0;
                  if (!strncasecmp (s, ",tc", 3))
                  if (!strncasecmp (s, ",tc", 3))
                    {
                    {
                      flag = 1;
                      flag = 1;
                      s += 3;
                      s += 3;
                    }
                    }
 
 
                  INSERT_FIELD_AND_CONTINUE (opcode, flag, 6);
                  INSERT_FIELD_AND_CONTINUE (opcode, flag, 6);
 
 
                /* Handle signed/unsigned at 21.  */
                /* Handle signed/unsigned at 21.  */
                case 'S':
                case 'S':
                  {
                  {
                    int sign = 1;
                    int sign = 1;
                    if (strncasecmp (s, ",s", 2) == 0)
                    if (strncasecmp (s, ",s", 2) == 0)
                      {
                      {
                        sign = 1;
                        sign = 1;
                        s += 2;
                        s += 2;
                      }
                      }
                    else if (strncasecmp (s, ",u", 2) == 0)
                    else if (strncasecmp (s, ",u", 2) == 0)
                      {
                      {
                        sign = 0;
                        sign = 0;
                        s += 2;
                        s += 2;
                      }
                      }
 
 
                    INSERT_FIELD_AND_CONTINUE (opcode, sign, 10);
                    INSERT_FIELD_AND_CONTINUE (opcode, sign, 10);
                  }
                  }
 
 
                /* Handle left/right combination at 17:18.  */
                /* Handle left/right combination at 17:18.  */
                case 'h':
                case 'h':
                  if (*s++ == ',')
                  if (*s++ == ',')
                    {
                    {
                      int lr = 0;
                      int lr = 0;
                      if (*s == 'r')
                      if (*s == 'r')
                        lr = 2;
                        lr = 2;
                      else if (*s == 'l')
                      else if (*s == 'l')
                        lr = 0;
                        lr = 0;
                      else
                      else
                        as_bad (_("Invalid left/right combination completer"));
                        as_bad (_("Invalid left/right combination completer"));
 
 
                      s++;
                      s++;
                      INSERT_FIELD_AND_CONTINUE (opcode, lr, 13);
                      INSERT_FIELD_AND_CONTINUE (opcode, lr, 13);
                    }
                    }
                  else
                  else
                    as_bad (_("Invalid left/right combination completer"));
                    as_bad (_("Invalid left/right combination completer"));
                  break;
                  break;
 
 
                /* Handle saturation at 24:25.  */
                /* Handle saturation at 24:25.  */
                case 'H':
                case 'H':
                  {
                  {
                    int sat = 3;
                    int sat = 3;
                    if (strncasecmp (s, ",ss", 3) == 0)
                    if (strncasecmp (s, ",ss", 3) == 0)
                      {
                      {
                        sat = 1;
                        sat = 1;
                        s += 3;
                        s += 3;
                      }
                      }
                    else if (strncasecmp (s, ",us", 3) == 0)
                    else if (strncasecmp (s, ",us", 3) == 0)
                      {
                      {
                        sat = 0;
                        sat = 0;
                        s += 3;
                        s += 3;
                      }
                      }
 
 
                    INSERT_FIELD_AND_CONTINUE (opcode, sat, 6);
                    INSERT_FIELD_AND_CONTINUE (opcode, sat, 6);
                  }
                  }
 
 
                /* Handle permutation completer.  */
                /* Handle permutation completer.  */
                case '*':
                case '*':
                  if (*s++ == ',')
                  if (*s++ == ',')
                    {
                    {
                      int permloc[4];
                      int permloc[4];
                      int perm = 0;
                      int perm = 0;
                      int i = 0;
                      int i = 0;
                      permloc[0] = 13;
                      permloc[0] = 13;
                      permloc[1] = 10;
                      permloc[1] = 10;
                      permloc[2] = 8;
                      permloc[2] = 8;
                      permloc[3] = 6;
                      permloc[3] = 6;
                      for (; i < 4; i++)
                      for (; i < 4; i++)
                        {
                        {
                          switch (*s++)
                          switch (*s++)
                            {
                            {
                            case '0':
                            case '0':
                              perm = 0;
                              perm = 0;
                              break;
                              break;
                            case '1':
                            case '1':
                              perm = 1;
                              perm = 1;
                              break;
                              break;
                            case '2':
                            case '2':
                              perm = 2;
                              perm = 2;
                              break;
                              break;
                            case '3':
                            case '3':
                              perm = 3;
                              perm = 3;
                              break;
                              break;
                            default:
                            default:
                              as_bad (_("Invalid permutation completer"));
                              as_bad (_("Invalid permutation completer"));
                            }
                            }
                          opcode |= perm << permloc[i];
                          opcode |= perm << permloc[i];
                        }
                        }
                      continue;
                      continue;
                    }
                    }
                  else
                  else
                    as_bad (_("Invalid permutation completer"));
                    as_bad (_("Invalid permutation completer"));
                  break;
                  break;
 
 
                default:
                default:
                  abort ();
                  abort ();
                }
                }
              break;
              break;
 
 
            /* Handle all conditions.  */
            /* Handle all conditions.  */
            case '?':
            case '?':
              {
              {
                args++;
                args++;
                switch (*args)
                switch (*args)
                  {
                  {
                  /* Handle FP compare conditions.  */
                  /* Handle FP compare conditions.  */
                  case 'f':
                  case 'f':
                    cond = pa_parse_fp_cmp_cond (&s);
                    cond = pa_parse_fp_cmp_cond (&s);
                    INSERT_FIELD_AND_CONTINUE (opcode, cond, 0);
                    INSERT_FIELD_AND_CONTINUE (opcode, cond, 0);
 
 
                  /* Handle an add condition.  */
                  /* Handle an add condition.  */
                  case 'A':
                  case 'A':
                  case 'a':
                  case 'a':
                    cmpltr = 0;
                    cmpltr = 0;
                    flag = 0;
                    flag = 0;
                    if (*s == ',')
                    if (*s == ',')
                      {
                      {
                        s++;
                        s++;
 
 
                        /* 64 bit conditions.  */
                        /* 64 bit conditions.  */
                        if (*args == 'A')
                        if (*args == 'A')
                          {
                          {
                            if (*s == '*')
                            if (*s == '*')
                              s++;
                              s++;
                            else
                            else
                              break;
                              break;
                          }
                          }
                        else if (*s == '*')
                        else if (*s == '*')
                          break;
                          break;
 
 
                        name = s;
                        name = s;
                        while (*s != ',' && *s != ' ' && *s != '\t')
                        while (*s != ',' && *s != ' ' && *s != '\t')
                          s += 1;
                          s += 1;
                        c = *s;
                        c = *s;
                        *s = 0x00;
                        *s = 0x00;
                        if (strcmp (name, "=") == 0)
                        if (strcmp (name, "=") == 0)
                          cmpltr = 1;
                          cmpltr = 1;
                        else if (strcmp (name, "<") == 0)
                        else if (strcmp (name, "<") == 0)
                          cmpltr = 2;
                          cmpltr = 2;
                        else if (strcmp (name, "<=") == 0)
                        else if (strcmp (name, "<=") == 0)
                          cmpltr = 3;
                          cmpltr = 3;
                        else if (strcasecmp (name, "nuv") == 0)
                        else if (strcasecmp (name, "nuv") == 0)
                          cmpltr = 4;
                          cmpltr = 4;
                        else if (strcasecmp (name, "znv") == 0)
                        else if (strcasecmp (name, "znv") == 0)
                          cmpltr = 5;
                          cmpltr = 5;
                        else if (strcasecmp (name, "sv") == 0)
                        else if (strcasecmp (name, "sv") == 0)
                          cmpltr = 6;
                          cmpltr = 6;
                        else if (strcasecmp (name, "od") == 0)
                        else if (strcasecmp (name, "od") == 0)
                          cmpltr = 7;
                          cmpltr = 7;
                        else if (strcasecmp (name, "tr") == 0)
                        else if (strcasecmp (name, "tr") == 0)
                          {
                          {
                            cmpltr = 0;
                            cmpltr = 0;
                            flag = 1;
                            flag = 1;
                          }
                          }
                        else if (strcmp (name, "<>") == 0)
                        else if (strcmp (name, "<>") == 0)
                          {
                          {
                            cmpltr = 1;
                            cmpltr = 1;
                            flag = 1;
                            flag = 1;
                          }
                          }
                        else if (strcmp (name, ">=") == 0)
                        else if (strcmp (name, ">=") == 0)
                          {
                          {
                            cmpltr = 2;
                            cmpltr = 2;
                            flag = 1;
                            flag = 1;
                          }
                          }
                        else if (strcmp (name, ">") == 0)
                        else if (strcmp (name, ">") == 0)
                          {
                          {
                            cmpltr = 3;
                            cmpltr = 3;
                            flag = 1;
                            flag = 1;
                          }
                          }
                        else if (strcasecmp (name, "uv") == 0)
                        else if (strcasecmp (name, "uv") == 0)
                          {
                          {
                            cmpltr = 4;
                            cmpltr = 4;
                            flag = 1;
                            flag = 1;
                          }
                          }
                        else if (strcasecmp (name, "vnz") == 0)
                        else if (strcasecmp (name, "vnz") == 0)
                          {
                          {
                            cmpltr = 5;
                            cmpltr = 5;
                            flag = 1;
                            flag = 1;
                          }
                          }
                        else if (strcasecmp (name, "nsv") == 0)
                        else if (strcasecmp (name, "nsv") == 0)
                          {
                          {
                            cmpltr = 6;
                            cmpltr = 6;
                            flag = 1;
                            flag = 1;
                          }
                          }
                        else if (strcasecmp (name, "ev") == 0)
                        else if (strcasecmp (name, "ev") == 0)
                          {
                          {
                            cmpltr = 7;
                            cmpltr = 7;
                            flag = 1;
                            flag = 1;
                          }
                          }
                        /* ",*" is a valid condition.  */
                        /* ",*" is a valid condition.  */
                        else if (*args == 'a' || *name)
                        else if (*args == 'a' || *name)
                          as_bad (_("Invalid Add Condition: %s"), name);
                          as_bad (_("Invalid Add Condition: %s"), name);
                        *s = c;
                        *s = c;
                      }
                      }
                    opcode |= cmpltr << 13;
                    opcode |= cmpltr << 13;
                    INSERT_FIELD_AND_CONTINUE (opcode, flag, 12);
                    INSERT_FIELD_AND_CONTINUE (opcode, flag, 12);
 
 
                  /* Handle non-negated add and branch condition.  */
                  /* Handle non-negated add and branch condition.  */
                  case 'd':
                  case 'd':
                    cmpltr = pa_parse_nonneg_add_cmpltr (&s);
                    cmpltr = pa_parse_nonneg_add_cmpltr (&s);
                    if (cmpltr < 0)
                    if (cmpltr < 0)
                      {
                      {
                        as_bad (_("Invalid Add and Branch Condition"));
                        as_bad (_("Invalid Add and Branch Condition"));
                        cmpltr = 0;
                        cmpltr = 0;
                      }
                      }
                    INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 13);
                    INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 13);
 
 
                  /* Handle 64 bit wide-mode add and branch condition.  */
                  /* Handle 64 bit wide-mode add and branch condition.  */
                  case 'W':
                  case 'W':
                    cmpltr = pa_parse_addb_64_cmpltr (&s);
                    cmpltr = pa_parse_addb_64_cmpltr (&s);
                    if (cmpltr < 0)
                    if (cmpltr < 0)
                      {
                      {
                        as_bad (_("Invalid Add and Branch Condition"));
                        as_bad (_("Invalid Add and Branch Condition"));
                        cmpltr = 0;
                        cmpltr = 0;
                      }
                      }
                    else
                    else
                      {
                      {
                        /* Negated condition requires an opcode change.  */
                        /* Negated condition requires an opcode change.  */
                        opcode |= (cmpltr & 8) << 24;
                        opcode |= (cmpltr & 8) << 24;
                      }
                      }
                    INSERT_FIELD_AND_CONTINUE (opcode, cmpltr & 7, 13);
                    INSERT_FIELD_AND_CONTINUE (opcode, cmpltr & 7, 13);
 
 
                  /* Handle a negated or non-negated add and branch
                  /* Handle a negated or non-negated add and branch
                     condition.  */
                     condition.  */
                  case '@':
                  case '@':
                    save_s = s;
                    save_s = s;
                    cmpltr = pa_parse_nonneg_add_cmpltr (&s);
                    cmpltr = pa_parse_nonneg_add_cmpltr (&s);
                    if (cmpltr < 0)
                    if (cmpltr < 0)
                      {
                      {
                        s = save_s;
                        s = save_s;
                        cmpltr = pa_parse_neg_add_cmpltr (&s);
                        cmpltr = pa_parse_neg_add_cmpltr (&s);
                        if (cmpltr < 0)
                        if (cmpltr < 0)
                          {
                          {
                            as_bad (_("Invalid Compare/Subtract Condition"));
                            as_bad (_("Invalid Compare/Subtract Condition"));
                            cmpltr = 0;
                            cmpltr = 0;
                          }
                          }
                        else
                        else
                          {
                          {
                            /* Negated condition requires an opcode change.  */
                            /* Negated condition requires an opcode change.  */
                            opcode |= 1 << 27;
                            opcode |= 1 << 27;
                          }
                          }
                      }
                      }
                    INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 13);
                    INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 13);
 
 
                  /* Handle branch on bit conditions.  */
                  /* Handle branch on bit conditions.  */
                  case 'B':
                  case 'B':
                  case 'b':
                  case 'b':
                    cmpltr = 0;
                    cmpltr = 0;
                    if (*s == ',')
                    if (*s == ',')
                      {
                      {
                        s++;
                        s++;
 
 
                        if (*args == 'B')
                        if (*args == 'B')
                          {
                          {
                            if (*s == '*')
                            if (*s == '*')
                              s++;
                              s++;
                            else
                            else
                              break;
                              break;
                          }
                          }
                        else if (*s == '*')
                        else if (*s == '*')
                          break;
                          break;
 
 
                        if (strncmp (s, "<", 1) == 0)
                        if (strncmp (s, "<", 1) == 0)
                          {
                          {
                            cmpltr = 0;
                            cmpltr = 0;
                            s++;
                            s++;
                          }
                          }
                        else if (strncmp (s, ">=", 2) == 0)
                        else if (strncmp (s, ">=", 2) == 0)
                          {
                          {
                            cmpltr = 1;
                            cmpltr = 1;
                            s += 2;
                            s += 2;
                          }
                          }
                        else
                        else
                          as_bad (_("Invalid Bit Branch Condition: %c"), *s);
                          as_bad (_("Invalid Bit Branch Condition: %c"), *s);
                      }
                      }
                    INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 15);
                    INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 15);
 
 
                  /* Handle a compare/subtract condition.  */
                  /* Handle a compare/subtract condition.  */
                  case 'S':
                  case 'S':
                  case 's':
                  case 's':
                    cmpltr = 0;
                    cmpltr = 0;
                    flag = 0;
                    flag = 0;
                    if (*s == ',')
                    if (*s == ',')
                      {
                      {
                        s++;
                        s++;
 
 
                        /* 64 bit conditions.  */
                        /* 64 bit conditions.  */
                        if (*args == 'S')
                        if (*args == 'S')
                          {
                          {
                            if (*s == '*')
                            if (*s == '*')
                              s++;
                              s++;
                            else
                            else
                              break;
                              break;
                          }
                          }
                        else if (*s == '*')
                        else if (*s == '*')
                          break;
                          break;
 
 
                        name = s;
                        name = s;
                        while (*s != ',' && *s != ' ' && *s != '\t')
                        while (*s != ',' && *s != ' ' && *s != '\t')
                          s += 1;
                          s += 1;
                        c = *s;
                        c = *s;
                        *s = 0x00;
                        *s = 0x00;
                        if (strcmp (name, "=") == 0)
                        if (strcmp (name, "=") == 0)
                          cmpltr = 1;
                          cmpltr = 1;
                        else if (strcmp (name, "<") == 0)
                        else if (strcmp (name, "<") == 0)
                          cmpltr = 2;
                          cmpltr = 2;
                        else if (strcmp (name, "<=") == 0)
                        else if (strcmp (name, "<=") == 0)
                          cmpltr = 3;
                          cmpltr = 3;
                        else if (strcasecmp (name, "<<") == 0)
                        else if (strcasecmp (name, "<<") == 0)
                          cmpltr = 4;
                          cmpltr = 4;
                        else if (strcasecmp (name, "<<=") == 0)
                        else if (strcasecmp (name, "<<=") == 0)
                          cmpltr = 5;
                          cmpltr = 5;
                        else if (strcasecmp (name, "sv") == 0)
                        else if (strcasecmp (name, "sv") == 0)
                          cmpltr = 6;
                          cmpltr = 6;
                        else if (strcasecmp (name, "od") == 0)
                        else if (strcasecmp (name, "od") == 0)
                          cmpltr = 7;
                          cmpltr = 7;
                        else if (strcasecmp (name, "tr") == 0)
                        else if (strcasecmp (name, "tr") == 0)
                          {
                          {
                            cmpltr = 0;
                            cmpltr = 0;
                            flag = 1;
                            flag = 1;
                          }
                          }
                        else if (strcmp (name, "<>") == 0)
                        else if (strcmp (name, "<>") == 0)
                          {
                          {
                            cmpltr = 1;
                            cmpltr = 1;
                            flag = 1;
                            flag = 1;
                          }
                          }
                        else if (strcmp (name, ">=") == 0)
                        else if (strcmp (name, ">=") == 0)
                          {
                          {
                            cmpltr = 2;
                            cmpltr = 2;
                            flag = 1;
                            flag = 1;
                          }
                          }
                        else if (strcmp (name, ">") == 0)
                        else if (strcmp (name, ">") == 0)
                          {
                          {
                            cmpltr = 3;
                            cmpltr = 3;
                            flag = 1;
                            flag = 1;
                          }
                          }
                        else if (strcasecmp (name, ">>=") == 0)
                        else if (strcasecmp (name, ">>=") == 0)
                          {
                          {
                            cmpltr = 4;
                            cmpltr = 4;
                            flag = 1;
                            flag = 1;
                          }
                          }
                        else if (strcasecmp (name, ">>") == 0)
                        else if (strcasecmp (name, ">>") == 0)
                          {
                          {
                            cmpltr = 5;
                            cmpltr = 5;
                            flag = 1;
                            flag = 1;
                          }
                          }
                        else if (strcasecmp (name, "nsv") == 0)
                        else if (strcasecmp (name, "nsv") == 0)
                          {
                          {
                            cmpltr = 6;
                            cmpltr = 6;
                            flag = 1;
                            flag = 1;
                          }
                          }
                        else if (strcasecmp (name, "ev") == 0)
                        else if (strcasecmp (name, "ev") == 0)
                          {
                          {
                            cmpltr = 7;
                            cmpltr = 7;
                            flag = 1;
                            flag = 1;
                          }
                          }
                        /* ",*" is a valid condition.  */
                        /* ",*" is a valid condition.  */
                        else if (*args != 'S' || *name)
                        else if (*args != 'S' || *name)
                          as_bad (_("Invalid Compare/Subtract Condition: %s"),
                          as_bad (_("Invalid Compare/Subtract Condition: %s"),
                                  name);
                                  name);
                        *s = c;
                        *s = c;
                      }
                      }
                    opcode |= cmpltr << 13;
                    opcode |= cmpltr << 13;
                    INSERT_FIELD_AND_CONTINUE (opcode, flag, 12);
                    INSERT_FIELD_AND_CONTINUE (opcode, flag, 12);
 
 
                  /* Handle a non-negated compare condition.  */
                  /* Handle a non-negated compare condition.  */
                  case 't':
                  case 't':
                    cmpltr = pa_parse_nonneg_cmpsub_cmpltr (&s);
                    cmpltr = pa_parse_nonneg_cmpsub_cmpltr (&s);
                    if (cmpltr < 0)
                    if (cmpltr < 0)
                      {
                      {
                        as_bad (_("Invalid Compare/Subtract Condition"));
                        as_bad (_("Invalid Compare/Subtract Condition"));
                        cmpltr = 0;
                        cmpltr = 0;
                      }
                      }
                    INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 13);
                    INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 13);
 
 
                  /* Handle a 32 bit compare and branch condition.  */
                  /* Handle a 32 bit compare and branch condition.  */
                  case 'n':
                  case 'n':
                    save_s = s;
                    save_s = s;
                    cmpltr = pa_parse_nonneg_cmpsub_cmpltr (&s);
                    cmpltr = pa_parse_nonneg_cmpsub_cmpltr (&s);
                    if (cmpltr < 0)
                    if (cmpltr < 0)
                      {
                      {
                        s = save_s;
                        s = save_s;
                        cmpltr = pa_parse_neg_cmpsub_cmpltr (&s);
                        cmpltr = pa_parse_neg_cmpsub_cmpltr (&s);
                        if (cmpltr < 0)
                        if (cmpltr < 0)
                          {
                          {
                            as_bad (_("Invalid Compare and Branch Condition"));
                            as_bad (_("Invalid Compare and Branch Condition"));
                            cmpltr = 0;
                            cmpltr = 0;
                          }
                          }
                        else
                        else
                          {
                          {
                            /* Negated condition requires an opcode change.  */
                            /* Negated condition requires an opcode change.  */
                            opcode |= 1 << 27;
                            opcode |= 1 << 27;
                          }
                          }
                      }
                      }
 
 
                    INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 13);
                    INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 13);
 
 
                  /* Handle a 64 bit compare and branch condition.  */
                  /* Handle a 64 bit compare and branch condition.  */
                  case 'N':
                  case 'N':
                    cmpltr = pa_parse_cmpb_64_cmpltr (&s);
                    cmpltr = pa_parse_cmpb_64_cmpltr (&s);
                    if (cmpltr >= 0)
                    if (cmpltr >= 0)
                      {
                      {
                        /* Negated condition requires an opcode change.  */
                        /* Negated condition requires an opcode change.  */
                        opcode |= (cmpltr & 8) << 26;
                        opcode |= (cmpltr & 8) << 26;
                      }
                      }
                    else
                    else
                      /* Not a 64 bit cond.  Give 32 bit a chance.  */
                      /* Not a 64 bit cond.  Give 32 bit a chance.  */
                      break;
                      break;
 
 
                    INSERT_FIELD_AND_CONTINUE (opcode, cmpltr & 7, 13);
                    INSERT_FIELD_AND_CONTINUE (opcode, cmpltr & 7, 13);
 
 
                  /* Handle a 64 bit cmpib condition.  */
                  /* Handle a 64 bit cmpib condition.  */
                  case 'Q':
                  case 'Q':
                    cmpltr = pa_parse_cmpib_64_cmpltr (&s);
                    cmpltr = pa_parse_cmpib_64_cmpltr (&s);
                    if (cmpltr < 0)
                    if (cmpltr < 0)
                      /* Not a 64 bit cond.  Give 32 bit a chance.  */
                      /* Not a 64 bit cond.  Give 32 bit a chance.  */
                      break;
                      break;
 
 
                    INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 13);
                    INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 13);
 
 
                    /* Handle a logical instruction condition.  */
                    /* Handle a logical instruction condition.  */
                  case 'L':
                  case 'L':
                  case 'l':
                  case 'l':
                    cmpltr = 0;
                    cmpltr = 0;
                    flag = 0;
                    flag = 0;
                    if (*s == ',')
                    if (*s == ',')
                      {
                      {
                        s++;
                        s++;
 
 
                        /* 64 bit conditions.  */
                        /* 64 bit conditions.  */
                        if (*args == 'L')
                        if (*args == 'L')
                          {
                          {
                            if (*s == '*')
                            if (*s == '*')
                              s++;
                              s++;
                            else
                            else
                              break;
                              break;
                          }
                          }
                        else if (*s == '*')
                        else if (*s == '*')
                          break;
                          break;
 
 
                        name = s;
                        name = s;
                        while (*s != ',' && *s != ' ' && *s != '\t')
                        while (*s != ',' && *s != ' ' && *s != '\t')
                          s += 1;
                          s += 1;
                        c = *s;
                        c = *s;
                        *s = 0x00;
                        *s = 0x00;
 
 
                        if (strcmp (name, "=") == 0)
                        if (strcmp (name, "=") == 0)
                          cmpltr = 1;
                          cmpltr = 1;
                        else if (strcmp (name, "<") == 0)
                        else if (strcmp (name, "<") == 0)
                          cmpltr = 2;
                          cmpltr = 2;
                        else if (strcmp (name, "<=") == 0)
                        else if (strcmp (name, "<=") == 0)
                          cmpltr = 3;
                          cmpltr = 3;
                        else if (strcasecmp (name, "od") == 0)
                        else if (strcasecmp (name, "od") == 0)
                          cmpltr = 7;
                          cmpltr = 7;
                        else if (strcasecmp (name, "tr") == 0)
                        else if (strcasecmp (name, "tr") == 0)
                          {
                          {
                            cmpltr = 0;
                            cmpltr = 0;
                            flag = 1;
                            flag = 1;
                          }
                          }
                        else if (strcmp (name, "<>") == 0)
                        else if (strcmp (name, "<>") == 0)
                          {
                          {
                            cmpltr = 1;
                            cmpltr = 1;
                            flag = 1;
                            flag = 1;
                          }
                          }
                        else if (strcmp (name, ">=") == 0)
                        else if (strcmp (name, ">=") == 0)
                          {
                          {
                            cmpltr = 2;
                            cmpltr = 2;
                            flag = 1;
                            flag = 1;
                          }
                          }
                        else if (strcmp (name, ">") == 0)
                        else if (strcmp (name, ">") == 0)
                          {
                          {
                            cmpltr = 3;
                            cmpltr = 3;
                            flag = 1;
                            flag = 1;
                          }
                          }
                        else if (strcasecmp (name, "ev") == 0)
                        else if (strcasecmp (name, "ev") == 0)
                          {
                          {
                            cmpltr = 7;
                            cmpltr = 7;
                            flag = 1;
                            flag = 1;
                          }
                          }
                        /* ",*" is a valid condition.  */
                        /* ",*" is a valid condition.  */
                        else if (*args != 'L' || *name)
                        else if (*args != 'L' || *name)
                          as_bad (_("Invalid Logical Instruction Condition."));
                          as_bad (_("Invalid Logical Instruction Condition."));
                        *s = c;
                        *s = c;
                      }
                      }
                    opcode |= cmpltr << 13;
                    opcode |= cmpltr << 13;
                    INSERT_FIELD_AND_CONTINUE (opcode, flag, 12);
                    INSERT_FIELD_AND_CONTINUE (opcode, flag, 12);
 
 
                  /* Handle a shift/extract/deposit condition.  */
                  /* Handle a shift/extract/deposit condition.  */
                  case 'X':
                  case 'X':
                  case 'x':
                  case 'x':
                  case 'y':
                  case 'y':
                    cmpltr = 0;
                    cmpltr = 0;
                    if (*s == ',')
                    if (*s == ',')
                      {
                      {
                        save_s = s++;
                        save_s = s++;
 
 
                        /* 64 bit conditions.  */
                        /* 64 bit conditions.  */
                        if (*args == 'X')
                        if (*args == 'X')
                          {
                          {
                            if (*s == '*')
                            if (*s == '*')
                              s++;
                              s++;
                            else
                            else
                              break;
                              break;
                          }
                          }
                        else if (*s == '*')
                        else if (*s == '*')
                          break;
                          break;
 
 
                        name = s;
                        name = s;
                        while (*s != ',' && *s != ' ' && *s != '\t')
                        while (*s != ',' && *s != ' ' && *s != '\t')
                          s += 1;
                          s += 1;
                        c = *s;
                        c = *s;
                        *s = 0x00;
                        *s = 0x00;
                        if (strcmp (name, "=") == 0)
                        if (strcmp (name, "=") == 0)
                          cmpltr = 1;
                          cmpltr = 1;
                        else if (strcmp (name, "<") == 0)
                        else if (strcmp (name, "<") == 0)
                          cmpltr = 2;
                          cmpltr = 2;
                        else if (strcasecmp (name, "od") == 0)
                        else if (strcasecmp (name, "od") == 0)
                          cmpltr = 3;
                          cmpltr = 3;
                        else if (strcasecmp (name, "tr") == 0)
                        else if (strcasecmp (name, "tr") == 0)
                          cmpltr = 4;
                          cmpltr = 4;
                        else if (strcmp (name, "<>") == 0)
                        else if (strcmp (name, "<>") == 0)
                          cmpltr = 5;
                          cmpltr = 5;
                        else if (strcmp (name, ">=") == 0)
                        else if (strcmp (name, ">=") == 0)
                          cmpltr = 6;
                          cmpltr = 6;
                        else if (strcasecmp (name, "ev") == 0)
                        else if (strcasecmp (name, "ev") == 0)
                          cmpltr = 7;
                          cmpltr = 7;
                        /* Handle movb,n.  Put things back the way they were.
                        /* Handle movb,n.  Put things back the way they were.
                           This includes moving s back to where it started.  */
                           This includes moving s back to where it started.  */
                        else if (strcasecmp (name, "n") == 0 && *args == 'y')
                        else if (strcasecmp (name, "n") == 0 && *args == 'y')
                          {
                          {
                            *s = c;
                            *s = c;
                            s = save_s;
                            s = save_s;
                            continue;
                            continue;
                          }
                          }
                        /* ",*" is a valid condition.  */
                        /* ",*" is a valid condition.  */
                        else if (*args != 'X' || *name)
                        else if (*args != 'X' || *name)
                          as_bad (_("Invalid Shift/Extract/Deposit Condition."));
                          as_bad (_("Invalid Shift/Extract/Deposit Condition."));
                        *s = c;
                        *s = c;
                      }
                      }
                    INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 13);
                    INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 13);
 
 
                  /* Handle a unit instruction condition.  */
                  /* Handle a unit instruction condition.  */
                  case 'U':
                  case 'U':
                  case 'u':
                  case 'u':
                    cmpltr = 0;
                    cmpltr = 0;
                    flag = 0;
                    flag = 0;
                    if (*s == ',')
                    if (*s == ',')
                      {
                      {
                        s++;
                        s++;
 
 
                        /* 64 bit conditions.  */
                        /* 64 bit conditions.  */
                        if (*args == 'U')
                        if (*args == 'U')
                          {
                          {
                            if (*s == '*')
                            if (*s == '*')
                              s++;
                              s++;
                            else
                            else
                              break;
                              break;
                          }
                          }
                        else if (*s == '*')
                        else if (*s == '*')
                          break;
                          break;
 
 
                        if (strncasecmp (s, "sbz", 3) == 0)
                        if (strncasecmp (s, "sbz", 3) == 0)
                          {
                          {
                            cmpltr = 2;
                            cmpltr = 2;
                            s += 3;
                            s += 3;
                          }
                          }
                        else if (strncasecmp (s, "shz", 3) == 0)
                        else if (strncasecmp (s, "shz", 3) == 0)
                          {
                          {
                            cmpltr = 3;
                            cmpltr = 3;
                            s += 3;
                            s += 3;
                          }
                          }
                        else if (strncasecmp (s, "sdc", 3) == 0)
                        else if (strncasecmp (s, "sdc", 3) == 0)
                          {
                          {
                            cmpltr = 4;
                            cmpltr = 4;
                            s += 3;
                            s += 3;
                          }
                          }
                        else if (strncasecmp (s, "sbc", 3) == 0)
                        else if (strncasecmp (s, "sbc", 3) == 0)
                          {
                          {
                            cmpltr = 6;
                            cmpltr = 6;
                            s += 3;
                            s += 3;
                          }
                          }
                        else if (strncasecmp (s, "shc", 3) == 0)
                        else if (strncasecmp (s, "shc", 3) == 0)
                          {
                          {
                            cmpltr = 7;
                            cmpltr = 7;
                            s += 3;
                            s += 3;
                          }
                          }
                        else if (strncasecmp (s, "tr", 2) == 0)
                        else if (strncasecmp (s, "tr", 2) == 0)
                          {
                          {
                            cmpltr = 0;
                            cmpltr = 0;
                            flag = 1;
                            flag = 1;
                            s += 2;
                            s += 2;
                          }
                          }
                        else if (strncasecmp (s, "nbz", 3) == 0)
                        else if (strncasecmp (s, "nbz", 3) == 0)
                          {
                          {
                            cmpltr = 2;
                            cmpltr = 2;
                            flag = 1;
                            flag = 1;
                            s += 3;
                            s += 3;
                          }
                          }
                        else if (strncasecmp (s, "nhz", 3) == 0)
                        else if (strncasecmp (s, "nhz", 3) == 0)
                          {
                          {
                            cmpltr = 3;
                            cmpltr = 3;
                            flag = 1;
                            flag = 1;
                            s += 3;
                            s += 3;
                          }
                          }
                        else if (strncasecmp (s, "ndc", 3) == 0)
                        else if (strncasecmp (s, "ndc", 3) == 0)
                          {
                          {
                            cmpltr = 4;
                            cmpltr = 4;
                            flag = 1;
                            flag = 1;
                            s += 3;
                            s += 3;
                          }
                          }
                        else if (strncasecmp (s, "nbc", 3) == 0)
                        else if (strncasecmp (s, "nbc", 3) == 0)
                          {
                          {
                            cmpltr = 6;
                            cmpltr = 6;
                            flag = 1;
                            flag = 1;
                            s += 3;
                            s += 3;
                          }
                          }
                        else if (strncasecmp (s, "nhc", 3) == 0)
                        else if (strncasecmp (s, "nhc", 3) == 0)
                          {
                          {
                            cmpltr = 7;
                            cmpltr = 7;
                            flag = 1;
                            flag = 1;
                            s += 3;
                            s += 3;
                          }
                          }
                        else if (strncasecmp (s, "swz", 3) == 0)
                        else if (strncasecmp (s, "swz", 3) == 0)
                          {
                          {
                            cmpltr = 1;
                            cmpltr = 1;
                            flag = 0;
                            flag = 0;
                            s += 3;
                            s += 3;
                          }
                          }
                        else if (strncasecmp (s, "swc", 3) == 0)
                        else if (strncasecmp (s, "swc", 3) == 0)
                          {
                          {
                            cmpltr = 5;
                            cmpltr = 5;
                            flag = 0;
                            flag = 0;
                            s += 3;
                            s += 3;
                          }
                          }
                        else if (strncasecmp (s, "nwz", 3) == 0)
                        else if (strncasecmp (s, "nwz", 3) == 0)
                          {
                          {
                            cmpltr = 1;
                            cmpltr = 1;
                            flag = 1;
                            flag = 1;
                            s += 3;
                            s += 3;
                          }
                          }
                        else if (strncasecmp (s, "nwc", 3) == 0)
                        else if (strncasecmp (s, "nwc", 3) == 0)
                          {
                          {
                            cmpltr = 5;
                            cmpltr = 5;
                            flag = 1;
                            flag = 1;
                            s += 3;
                            s += 3;
                          }
                          }
                        /* ",*" is a valid condition.  */
                        /* ",*" is a valid condition.  */
                        else if (*args != 'U' || (*s != ' ' && *s != '\t'))
                        else if (*args != 'U' || (*s != ' ' && *s != '\t'))
                          as_bad (_("Invalid Unit Instruction Condition."));
                          as_bad (_("Invalid Unit Instruction Condition."));
                      }
                      }
                    opcode |= cmpltr << 13;
                    opcode |= cmpltr << 13;
                    INSERT_FIELD_AND_CONTINUE (opcode, flag, 12);
                    INSERT_FIELD_AND_CONTINUE (opcode, flag, 12);
 
 
                  default:
                  default:
                    abort ();
                    abort ();
                  }
                  }
                break;
                break;
              }
              }
 
 
            /* Handle a nullification completer for branch instructions.  */
            /* Handle a nullification completer for branch instructions.  */
            case 'n':
            case 'n':
              nullif = pa_parse_nullif (&s);
              nullif = pa_parse_nullif (&s);
              INSERT_FIELD_AND_CONTINUE (opcode, nullif, 1);
              INSERT_FIELD_AND_CONTINUE (opcode, nullif, 1);
 
 
            /* Handle a nullification completer for copr and spop insns.  */
            /* Handle a nullification completer for copr and spop insns.  */
            case 'N':
            case 'N':
              nullif = pa_parse_nullif (&s);
              nullif = pa_parse_nullif (&s);
              INSERT_FIELD_AND_CONTINUE (opcode, nullif, 5);
              INSERT_FIELD_AND_CONTINUE (opcode, nullif, 5);
 
 
            /* Handle ,%r2 completer for new syntax branches.  */
            /* Handle ,%r2 completer for new syntax branches.  */
            case 'L':
            case 'L':
              if (*s == ',' && strncasecmp (s + 1, "%r2", 3) == 0)
              if (*s == ',' && strncasecmp (s + 1, "%r2", 3) == 0)
                s += 4;
                s += 4;
              else if (*s == ',' && strncasecmp (s + 1, "%rp", 3) == 0)
              else if (*s == ',' && strncasecmp (s + 1, "%rp", 3) == 0)
                s += 4;
                s += 4;
              else
              else
                break;
                break;
              continue;
              continue;
 
 
            /* Handle 3 bit entry into the fp compare array.   Valid values
            /* Handle 3 bit entry into the fp compare array.   Valid values
               are 0..6 inclusive.  */
               are 0..6 inclusive.  */
            case 'h':
            case 'h':
              get_expression (s);
              get_expression (s);
              s = expr_end;
              s = expr_end;
              if (the_insn.exp.X_op == O_constant)
              if (the_insn.exp.X_op == O_constant)
                {
                {
                  num = evaluate_absolute (&the_insn);
                  num = evaluate_absolute (&the_insn);
                  CHECK_FIELD (num, 6, 0, 0);
                  CHECK_FIELD (num, 6, 0, 0);
                  num++;
                  num++;
                  INSERT_FIELD_AND_CONTINUE (opcode, num, 13);
                  INSERT_FIELD_AND_CONTINUE (opcode, num, 13);
                }
                }
              else
              else
                break;
                break;
 
 
            /* Handle 3 bit entry into the fp compare array.   Valid values
            /* Handle 3 bit entry into the fp compare array.   Valid values
               are 0..6 inclusive.  */
               are 0..6 inclusive.  */
            case 'm':
            case 'm':
              get_expression (s);
              get_expression (s);
              if (the_insn.exp.X_op == O_constant)
              if (the_insn.exp.X_op == O_constant)
                {
                {
                  s = expr_end;
                  s = expr_end;
                  num = evaluate_absolute (&the_insn);
                  num = evaluate_absolute (&the_insn);
                  CHECK_FIELD (num, 6, 0, 0);
                  CHECK_FIELD (num, 6, 0, 0);
                  num = (num + 1) ^ 1;
                  num = (num + 1) ^ 1;
                  INSERT_FIELD_AND_CONTINUE (opcode, num, 13);
                  INSERT_FIELD_AND_CONTINUE (opcode, num, 13);
                }
                }
              else
              else
                break;
                break;
 
 
            /* Handle graphics test completers for ftest */
            /* Handle graphics test completers for ftest */
            case '=':
            case '=':
              {
              {
                num = pa_parse_ftest_gfx_completer (&s);
                num = pa_parse_ftest_gfx_completer (&s);
                INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
                INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
              }
              }
 
 
            /* Handle a 11 bit immediate at 31.  */
            /* Handle a 11 bit immediate at 31.  */
            case 'i':
            case 'i':
              the_insn.field_selector = pa_chk_field_selector (&s);
              the_insn.field_selector = pa_chk_field_selector (&s);
              get_expression (s);
              get_expression (s);
              s = expr_end;
              s = expr_end;
              if (the_insn.exp.X_op == O_constant)
              if (the_insn.exp.X_op == O_constant)
                {
                {
                  num = evaluate_absolute (&the_insn);
                  num = evaluate_absolute (&the_insn);
                  CHECK_FIELD (num, 1023, -1024, 0);
                  CHECK_FIELD (num, 1023, -1024, 0);
                  num = low_sign_unext (num, 11);
                  num = low_sign_unext (num, 11);
                  INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
                  INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
                }
                }
              else
              else
                {
                {
                  if (is_DP_relative (the_insn.exp))
                  if (is_DP_relative (the_insn.exp))
                    the_insn.reloc = R_HPPA_GOTOFF;
                    the_insn.reloc = R_HPPA_GOTOFF;
                  else if (is_PC_relative (the_insn.exp))
                  else if (is_PC_relative (the_insn.exp))
                    the_insn.reloc = R_HPPA_PCREL_CALL;
                    the_insn.reloc = R_HPPA_PCREL_CALL;
#ifdef OBJ_ELF
#ifdef OBJ_ELF
                  else if (is_tls_gdidx (the_insn.exp))
                  else if (is_tls_gdidx (the_insn.exp))
                    the_insn.reloc = R_PARISC_TLS_GD21L;
                    the_insn.reloc = R_PARISC_TLS_GD21L;
                  else if (is_tls_ldidx (the_insn.exp))
                  else if (is_tls_ldidx (the_insn.exp))
                    the_insn.reloc = R_PARISC_TLS_LDM21L;
                    the_insn.reloc = R_PARISC_TLS_LDM21L;
                  else if (is_tls_dtpoff (the_insn.exp))
                  else if (is_tls_dtpoff (the_insn.exp))
                    the_insn.reloc = R_PARISC_TLS_LDO21L;
                    the_insn.reloc = R_PARISC_TLS_LDO21L;
                  else if (is_tls_ieoff (the_insn.exp))
                  else if (is_tls_ieoff (the_insn.exp))
                    the_insn.reloc = R_PARISC_TLS_IE21L;
                    the_insn.reloc = R_PARISC_TLS_IE21L;
                  else if (is_tls_leoff (the_insn.exp))
                  else if (is_tls_leoff (the_insn.exp))
                    the_insn.reloc = R_PARISC_TLS_LE21L;
                    the_insn.reloc = R_PARISC_TLS_LE21L;
#endif
#endif
                  else
                  else
                    the_insn.reloc = R_HPPA;
                    the_insn.reloc = R_HPPA;
                  the_insn.format = 11;
                  the_insn.format = 11;
                  continue;
                  continue;
                }
                }
 
 
            /* Handle a 14 bit immediate at 31.  */
            /* Handle a 14 bit immediate at 31.  */
            case 'J':
            case 'J':
              the_insn.field_selector = pa_chk_field_selector (&s);
              the_insn.field_selector = pa_chk_field_selector (&s);
              get_expression (s);
              get_expression (s);
              s = expr_end;
              s = expr_end;
              if (the_insn.exp.X_op == O_constant)
              if (the_insn.exp.X_op == O_constant)
                {
                {
                  int mb;
                  int mb;
 
 
                  /* XXX the completer stored away tidbits of information
                  /* XXX the completer stored away tidbits of information
                     for us to extract.  We need a cleaner way to do this.
                     for us to extract.  We need a cleaner way to do this.
                     Now that we have lots of letters again, it would be
                     Now that we have lots of letters again, it would be
                     good to rethink this.  */
                     good to rethink this.  */
                  mb = opcode & 1;
                  mb = opcode & 1;
                  opcode -= mb;
                  opcode -= mb;
                  num = evaluate_absolute (&the_insn);
                  num = evaluate_absolute (&the_insn);
                  if (mb != (num < 0))
                  if (mb != (num < 0))
                    break;
                    break;
                  CHECK_FIELD (num, 8191, -8192, 0);
                  CHECK_FIELD (num, 8191, -8192, 0);
                  num = low_sign_unext (num, 14);
                  num = low_sign_unext (num, 14);
                  INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
                  INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
                }
                }
              break;
              break;
 
 
            /* Handle a 14 bit immediate at 31.  */
            /* Handle a 14 bit immediate at 31.  */
            case 'K':
            case 'K':
              the_insn.field_selector = pa_chk_field_selector (&s);
              the_insn.field_selector = pa_chk_field_selector (&s);
              get_expression (s);
              get_expression (s);
              s = expr_end;
              s = expr_end;
              if (the_insn.exp.X_op == O_constant)
              if (the_insn.exp.X_op == O_constant)
                {
                {
                  int mb;
                  int mb;
 
 
                  mb = opcode & 1;
                  mb = opcode & 1;
                  opcode -= mb;
                  opcode -= mb;
                  num = evaluate_absolute (&the_insn);
                  num = evaluate_absolute (&the_insn);
                  if (mb == (num < 0))
                  if (mb == (num < 0))
                    break;
                    break;
                  if (num % 4)
                  if (num % 4)
                    break;
                    break;
                  CHECK_FIELD (num, 8191, -8192, 0);
                  CHECK_FIELD (num, 8191, -8192, 0);
                  num = low_sign_unext (num, 14);
                  num = low_sign_unext (num, 14);
                  INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
                  INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
                }
                }
              break;
              break;
 
 
            /* Handle a 16 bit immediate at 31.  */
            /* Handle a 16 bit immediate at 31.  */
            case '<':
            case '<':
              the_insn.field_selector = pa_chk_field_selector (&s);
              the_insn.field_selector = pa_chk_field_selector (&s);
              get_expression (s);
              get_expression (s);
              s = expr_end;
              s = expr_end;
              if (the_insn.exp.X_op == O_constant)
              if (the_insn.exp.X_op == O_constant)
                {
                {
                  int mb;
                  int mb;
 
 
                  mb = opcode & 1;
                  mb = opcode & 1;
                  opcode -= mb;
                  opcode -= mb;
                  num = evaluate_absolute (&the_insn);
                  num = evaluate_absolute (&the_insn);
                  if (mb != (num < 0))
                  if (mb != (num < 0))
                    break;
                    break;
                  CHECK_FIELD (num, 32767, -32768, 0);
                  CHECK_FIELD (num, 32767, -32768, 0);
                  num = re_assemble_16 (num);
                  num = re_assemble_16 (num);
                  INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
                  INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
                }
                }
              break;
              break;
 
 
            /* Handle a 16 bit immediate at 31.  */
            /* Handle a 16 bit immediate at 31.  */
            case '>':
            case '>':
              the_insn.field_selector = pa_chk_field_selector (&s);
              the_insn.field_selector = pa_chk_field_selector (&s);
              get_expression (s);
              get_expression (s);
              s = expr_end;
              s = expr_end;
              if (the_insn.exp.X_op == O_constant)
              if (the_insn.exp.X_op == O_constant)
                {
                {
                  int mb;
                  int mb;
 
 
                  mb = opcode & 1;
                  mb = opcode & 1;
                  opcode -= mb;
                  opcode -= mb;
                  num = evaluate_absolute (&the_insn);
                  num = evaluate_absolute (&the_insn);
                  if (mb == (num < 0))
                  if (mb == (num < 0))
                    break;
                    break;
                  if (num % 4)
                  if (num % 4)
                    break;
                    break;
                  CHECK_FIELD (num, 32767, -32768, 0);
                  CHECK_FIELD (num, 32767, -32768, 0);
                  num = re_assemble_16 (num);
                  num = re_assemble_16 (num);
                  INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
                  INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
                }
                }
              break;
              break;
 
 
            /* Handle 14 bit immediate, shifted left three times.  */
            /* Handle 14 bit immediate, shifted left three times.  */
            case '#':
            case '#':
              if (bfd_get_mach (stdoutput) != pa20)
              if (bfd_get_mach (stdoutput) != pa20)
                break;
                break;
              the_insn.field_selector = pa_chk_field_selector (&s);
              the_insn.field_selector = pa_chk_field_selector (&s);
              get_expression (s);
              get_expression (s);
              s = expr_end;
              s = expr_end;
              if (the_insn.exp.X_op == O_constant)
              if (the_insn.exp.X_op == O_constant)
                {
                {
                  num = evaluate_absolute (&the_insn);
                  num = evaluate_absolute (&the_insn);
                  if (num & 0x7)
                  if (num & 0x7)
                    break;
                    break;
                  CHECK_FIELD (num, 8191, -8192, 0);
                  CHECK_FIELD (num, 8191, -8192, 0);
                  if (num < 0)
                  if (num < 0)
                    opcode |= 1;
                    opcode |= 1;
                  num &= 0x1fff;
                  num &= 0x1fff;
                  num >>= 3;
                  num >>= 3;
                  INSERT_FIELD_AND_CONTINUE (opcode, num, 4);
                  INSERT_FIELD_AND_CONTINUE (opcode, num, 4);
                }
                }
              else
              else
                {
                {
                  if (is_DP_relative (the_insn.exp))
                  if (is_DP_relative (the_insn.exp))
                    the_insn.reloc = R_HPPA_GOTOFF;
                    the_insn.reloc = R_HPPA_GOTOFF;
                  else if (is_PC_relative (the_insn.exp))
                  else if (is_PC_relative (the_insn.exp))
                    the_insn.reloc = R_HPPA_PCREL_CALL;
                    the_insn.reloc = R_HPPA_PCREL_CALL;
#ifdef OBJ_ELF
#ifdef OBJ_ELF
                  else if (is_tls_gdidx (the_insn.exp))
                  else if (is_tls_gdidx (the_insn.exp))
                    the_insn.reloc = R_PARISC_TLS_GD21L;
                    the_insn.reloc = R_PARISC_TLS_GD21L;
                  else if (is_tls_ldidx (the_insn.exp))
                  else if (is_tls_ldidx (the_insn.exp))
                    the_insn.reloc = R_PARISC_TLS_LDM21L;
                    the_insn.reloc = R_PARISC_TLS_LDM21L;
                  else if (is_tls_dtpoff (the_insn.exp))
                  else if (is_tls_dtpoff (the_insn.exp))
                    the_insn.reloc = R_PARISC_TLS_LDO21L;
                    the_insn.reloc = R_PARISC_TLS_LDO21L;
                  else if (is_tls_ieoff (the_insn.exp))
                  else if (is_tls_ieoff (the_insn.exp))
                    the_insn.reloc = R_PARISC_TLS_IE21L;
                    the_insn.reloc = R_PARISC_TLS_IE21L;
                  else if (is_tls_leoff (the_insn.exp))
                  else if (is_tls_leoff (the_insn.exp))
                    the_insn.reloc = R_PARISC_TLS_LE21L;
                    the_insn.reloc = R_PARISC_TLS_LE21L;
#endif
#endif
                  else
                  else
                    the_insn.reloc = R_HPPA;
                    the_insn.reloc = R_HPPA;
                  the_insn.format = 14;
                  the_insn.format = 14;
                  continue;
                  continue;
                }
                }
              break;
              break;
 
 
            /* Handle 14 bit immediate, shifted left twice.  */
            /* Handle 14 bit immediate, shifted left twice.  */
            case 'd':
            case 'd':
              the_insn.field_selector = pa_chk_field_selector (&s);
              the_insn.field_selector = pa_chk_field_selector (&s);
              get_expression (s);
              get_expression (s);
              s = expr_end;
              s = expr_end;
              if (the_insn.exp.X_op == O_constant)
              if (the_insn.exp.X_op == O_constant)
                {
                {
                  num = evaluate_absolute (&the_insn);
                  num = evaluate_absolute (&the_insn);
                  if (num & 0x3)
                  if (num & 0x3)
                    break;
                    break;
                  CHECK_FIELD (num, 8191, -8192, 0);
                  CHECK_FIELD (num, 8191, -8192, 0);
                  if (num < 0)
                  if (num < 0)
                    opcode |= 1;
                    opcode |= 1;
                  num &= 0x1fff;
                  num &= 0x1fff;
                  num >>= 2;
                  num >>= 2;
                  INSERT_FIELD_AND_CONTINUE (opcode, num, 3);
                  INSERT_FIELD_AND_CONTINUE (opcode, num, 3);
                }
                }
              else
              else
                {
                {
                  if (is_DP_relative (the_insn.exp))
                  if (is_DP_relative (the_insn.exp))
                    the_insn.reloc = R_HPPA_GOTOFF;
                    the_insn.reloc = R_HPPA_GOTOFF;
                  else if (is_PC_relative (the_insn.exp))
                  else if (is_PC_relative (the_insn.exp))
                    the_insn.reloc = R_HPPA_PCREL_CALL;
                    the_insn.reloc = R_HPPA_PCREL_CALL;
#ifdef OBJ_ELF
#ifdef OBJ_ELF
                  else if (is_tls_gdidx (the_insn.exp))
                  else if (is_tls_gdidx (the_insn.exp))
                    the_insn.reloc = R_PARISC_TLS_GD21L;
                    the_insn.reloc = R_PARISC_TLS_GD21L;
                  else if (is_tls_ldidx (the_insn.exp))
                  else if (is_tls_ldidx (the_insn.exp))
                    the_insn.reloc = R_PARISC_TLS_LDM21L;
                    the_insn.reloc = R_PARISC_TLS_LDM21L;
                  else if (is_tls_dtpoff (the_insn.exp))
                  else if (is_tls_dtpoff (the_insn.exp))
                    the_insn.reloc = R_PARISC_TLS_LDO21L;
                    the_insn.reloc = R_PARISC_TLS_LDO21L;
                  else if (is_tls_ieoff (the_insn.exp))
                  else if (is_tls_ieoff (the_insn.exp))
                    the_insn.reloc = R_PARISC_TLS_IE21L;
                    the_insn.reloc = R_PARISC_TLS_IE21L;
                  else if (is_tls_leoff (the_insn.exp))
                  else if (is_tls_leoff (the_insn.exp))
                    the_insn.reloc = R_PARISC_TLS_LE21L;
                    the_insn.reloc = R_PARISC_TLS_LE21L;
#endif
#endif
                  else
                  else
                    the_insn.reloc = R_HPPA;
                    the_insn.reloc = R_HPPA;
                  the_insn.format = 14;
                  the_insn.format = 14;
                  continue;
                  continue;
                }
                }
 
 
            /* Handle a 14 bit immediate at 31.  */
            /* Handle a 14 bit immediate at 31.  */
            case 'j':
            case 'j':
              the_insn.field_selector = pa_chk_field_selector (&s);
              the_insn.field_selector = pa_chk_field_selector (&s);
              get_expression (s);
              get_expression (s);
              s = expr_end;
              s = expr_end;
              if (the_insn.exp.X_op == O_constant)
              if (the_insn.exp.X_op == O_constant)
                {
                {
                  num = evaluate_absolute (&the_insn);
                  num = evaluate_absolute (&the_insn);
                  CHECK_FIELD (num, 8191, -8192, 0);
                  CHECK_FIELD (num, 8191, -8192, 0);
                  num = low_sign_unext (num, 14);
                  num = low_sign_unext (num, 14);
                  INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
                  INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
                }
                }
              else
              else
                {
                {
                  if (is_DP_relative (the_insn.exp))
                  if (is_DP_relative (the_insn.exp))
                    the_insn.reloc = R_HPPA_GOTOFF;
                    the_insn.reloc = R_HPPA_GOTOFF;
                  else if (is_PC_relative (the_insn.exp))
                  else if (is_PC_relative (the_insn.exp))
                    the_insn.reloc = R_HPPA_PCREL_CALL;
                    the_insn.reloc = R_HPPA_PCREL_CALL;
#ifdef OBJ_ELF
#ifdef OBJ_ELF
                  else if (is_tls_gdidx (the_insn.exp))
                  else if (is_tls_gdidx (the_insn.exp))
                    the_insn.reloc = R_PARISC_TLS_GD21L;
                    the_insn.reloc = R_PARISC_TLS_GD21L;
                  else if (is_tls_ldidx (the_insn.exp))
                  else if (is_tls_ldidx (the_insn.exp))
                    the_insn.reloc = R_PARISC_TLS_LDM21L;
                    the_insn.reloc = R_PARISC_TLS_LDM21L;
                  else if (is_tls_dtpoff (the_insn.exp))
                  else if (is_tls_dtpoff (the_insn.exp))
                    the_insn.reloc = R_PARISC_TLS_LDO21L;
                    the_insn.reloc = R_PARISC_TLS_LDO21L;
                  else if (is_tls_ieoff (the_insn.exp))
                  else if (is_tls_ieoff (the_insn.exp))
                    the_insn.reloc = R_PARISC_TLS_IE21L;
                    the_insn.reloc = R_PARISC_TLS_IE21L;
                  else if (is_tls_leoff (the_insn.exp))
                  else if (is_tls_leoff (the_insn.exp))
                    the_insn.reloc = R_PARISC_TLS_LE21L;
                    the_insn.reloc = R_PARISC_TLS_LE21L;
#endif
#endif
                  else
                  else
                    the_insn.reloc = R_HPPA;
                    the_insn.reloc = R_HPPA;
                  the_insn.format = 14;
                  the_insn.format = 14;
                  continue;
                  continue;
                }
                }
 
 
            /* Handle a 21 bit immediate at 31.  */
            /* Handle a 21 bit immediate at 31.  */
            case 'k':
            case 'k':
              the_insn.field_selector = pa_chk_field_selector (&s);
              the_insn.field_selector = pa_chk_field_selector (&s);
              get_expression (s);
              get_expression (s);
              s = expr_end;
              s = expr_end;
              if (the_insn.exp.X_op == O_constant)
              if (the_insn.exp.X_op == O_constant)
                {
                {
                  num = evaluate_absolute (&the_insn);
                  num = evaluate_absolute (&the_insn);
                  CHECK_FIELD (num >> 11, 1048575, -1048576, 0);
                  CHECK_FIELD (num >> 11, 1048575, -1048576, 0);
                  opcode |= re_assemble_21 (num);
                  opcode |= re_assemble_21 (num);
                  continue;
                  continue;
                }
                }
              else
              else
                {
                {
                  if (is_DP_relative (the_insn.exp))
                  if (is_DP_relative (the_insn.exp))
                    the_insn.reloc = R_HPPA_GOTOFF;
                    the_insn.reloc = R_HPPA_GOTOFF;
                  else if (is_PC_relative (the_insn.exp))
                  else if (is_PC_relative (the_insn.exp))
                    the_insn.reloc = R_HPPA_PCREL_CALL;
                    the_insn.reloc = R_HPPA_PCREL_CALL;
#ifdef OBJ_ELF
#ifdef OBJ_ELF
                  else if (is_tls_gdidx (the_insn.exp))
                  else if (is_tls_gdidx (the_insn.exp))
                    the_insn.reloc = R_PARISC_TLS_GD21L;
                    the_insn.reloc = R_PARISC_TLS_GD21L;
                  else if (is_tls_ldidx (the_insn.exp))
                  else if (is_tls_ldidx (the_insn.exp))
                    the_insn.reloc = R_PARISC_TLS_LDM21L;
                    the_insn.reloc = R_PARISC_TLS_LDM21L;
                  else if (is_tls_dtpoff (the_insn.exp))
                  else if (is_tls_dtpoff (the_insn.exp))
                    the_insn.reloc = R_PARISC_TLS_LDO21L;
                    the_insn.reloc = R_PARISC_TLS_LDO21L;
                  else if (is_tls_ieoff (the_insn.exp))
                  else if (is_tls_ieoff (the_insn.exp))
                    the_insn.reloc = R_PARISC_TLS_IE21L;
                    the_insn.reloc = R_PARISC_TLS_IE21L;
                  else if (is_tls_leoff (the_insn.exp))
                  else if (is_tls_leoff (the_insn.exp))
                    the_insn.reloc = R_PARISC_TLS_LE21L;
                    the_insn.reloc = R_PARISC_TLS_LE21L;
#endif
#endif
                  else
                  else
                    the_insn.reloc = R_HPPA;
                    the_insn.reloc = R_HPPA;
                  the_insn.format = 21;
                  the_insn.format = 21;
                  continue;
                  continue;
                }
                }
 
 
            /* Handle a 16 bit immediate at 31 (PA 2.0 wide mode only).  */
            /* Handle a 16 bit immediate at 31 (PA 2.0 wide mode only).  */
            case 'l':
            case 'l':
              the_insn.field_selector = pa_chk_field_selector (&s);
              the_insn.field_selector = pa_chk_field_selector (&s);
              get_expression (s);
              get_expression (s);
              s = expr_end;
              s = expr_end;
              if (the_insn.exp.X_op == O_constant)
              if (the_insn.exp.X_op == O_constant)
                {
                {
                  num = evaluate_absolute (&the_insn);
                  num = evaluate_absolute (&the_insn);
                  CHECK_FIELD (num, 32767, -32768, 0);
                  CHECK_FIELD (num, 32767, -32768, 0);
                  opcode |= re_assemble_16 (num);
                  opcode |= re_assemble_16 (num);
                  continue;
                  continue;
                }
                }
              else
              else
                {
                {
                  /* ??? Is this valid for wide mode?  */
                  /* ??? Is this valid for wide mode?  */
                  if (is_DP_relative (the_insn.exp))
                  if (is_DP_relative (the_insn.exp))
                    the_insn.reloc = R_HPPA_GOTOFF;
                    the_insn.reloc = R_HPPA_GOTOFF;
                  else if (is_PC_relative (the_insn.exp))
                  else if (is_PC_relative (the_insn.exp))
                    the_insn.reloc = R_HPPA_PCREL_CALL;
                    the_insn.reloc = R_HPPA_PCREL_CALL;
#ifdef OBJ_ELF
#ifdef OBJ_ELF
                  else if (is_tls_gdidx (the_insn.exp))
                  else if (is_tls_gdidx (the_insn.exp))
                    the_insn.reloc = R_PARISC_TLS_GD21L;
                    the_insn.reloc = R_PARISC_TLS_GD21L;
                  else if (is_tls_ldidx (the_insn.exp))
                  else if (is_tls_ldidx (the_insn.exp))
                    the_insn.reloc = R_PARISC_TLS_LDM21L;
                    the_insn.reloc = R_PARISC_TLS_LDM21L;
                  else if (is_tls_dtpoff (the_insn.exp))
                  else if (is_tls_dtpoff (the_insn.exp))
                    the_insn.reloc = R_PARISC_TLS_LDO21L;
                    the_insn.reloc = R_PARISC_TLS_LDO21L;
                  else if (is_tls_ieoff (the_insn.exp))
                  else if (is_tls_ieoff (the_insn.exp))
                    the_insn.reloc = R_PARISC_TLS_IE21L;
                    the_insn.reloc = R_PARISC_TLS_IE21L;
                  else if (is_tls_leoff (the_insn.exp))
                  else if (is_tls_leoff (the_insn.exp))
                    the_insn.reloc = R_PARISC_TLS_LE21L;
                    the_insn.reloc = R_PARISC_TLS_LE21L;
#endif
#endif
                  else
                  else
                    the_insn.reloc = R_HPPA;
                    the_insn.reloc = R_HPPA;
                  the_insn.format = 14;
                  the_insn.format = 14;
                  continue;
                  continue;
                }
                }
 
 
            /* Handle a word-aligned 16-bit imm. at 31 (PA2.0 wide).  */
            /* Handle a word-aligned 16-bit imm. at 31 (PA2.0 wide).  */
            case 'y':
            case 'y':
              the_insn.field_selector = pa_chk_field_selector (&s);
              the_insn.field_selector = pa_chk_field_selector (&s);
              get_expression (s);
              get_expression (s);
              s = expr_end;
              s = expr_end;
              if (the_insn.exp.X_op == O_constant)
              if (the_insn.exp.X_op == O_constant)
                {
                {
                  num = evaluate_absolute (&the_insn);
                  num = evaluate_absolute (&the_insn);
                  CHECK_FIELD (num, 32767, -32768, 0);
                  CHECK_FIELD (num, 32767, -32768, 0);
                  CHECK_ALIGN (num, 4, 0);
                  CHECK_ALIGN (num, 4, 0);
                  opcode |= re_assemble_16 (num);
                  opcode |= re_assemble_16 (num);
                  continue;
                  continue;
                }
                }
              else
              else
                {
                {
                  /* ??? Is this valid for wide mode?  */
                  /* ??? Is this valid for wide mode?  */
                  if (is_DP_relative (the_insn.exp))
                  if (is_DP_relative (the_insn.exp))
                    the_insn.reloc = R_HPPA_GOTOFF;
                    the_insn.reloc = R_HPPA_GOTOFF;
                  else if (is_PC_relative (the_insn.exp))
                  else if (is_PC_relative (the_insn.exp))
                    the_insn.reloc = R_HPPA_PCREL_CALL;
                    the_insn.reloc = R_HPPA_PCREL_CALL;
#ifdef OBJ_ELF
#ifdef OBJ_ELF
                  else if (is_tls_gdidx (the_insn.exp))
                  else if (is_tls_gdidx (the_insn.exp))
                    the_insn.reloc = R_PARISC_TLS_GD21L;
                    the_insn.reloc = R_PARISC_TLS_GD21L;
                  else if (is_tls_ldidx (the_insn.exp))
                  else if (is_tls_ldidx (the_insn.exp))
                    the_insn.reloc = R_PARISC_TLS_LDM21L;
                    the_insn.reloc = R_PARISC_TLS_LDM21L;
                  else if (is_tls_dtpoff (the_insn.exp))
                  else if (is_tls_dtpoff (the_insn.exp))
                    the_insn.reloc = R_PARISC_TLS_LDO21L;
                    the_insn.reloc = R_PARISC_TLS_LDO21L;
                  else if (is_tls_ieoff (the_insn.exp))
                  else if (is_tls_ieoff (the_insn.exp))
                    the_insn.reloc = R_PARISC_TLS_IE21L;
                    the_insn.reloc = R_PARISC_TLS_IE21L;
                  else if (is_tls_leoff (the_insn.exp))
                  else if (is_tls_leoff (the_insn.exp))
                    the_insn.reloc = R_PARISC_TLS_LE21L;
                    the_insn.reloc = R_PARISC_TLS_LE21L;
#endif
#endif
                  else
                  else
                    the_insn.reloc = R_HPPA;
                    the_insn.reloc = R_HPPA;
                  the_insn.format = 14;
                  the_insn.format = 14;
                  continue;
                  continue;
                }
                }
 
 
            /* Handle a dword-aligned 16-bit imm. at 31 (PA2.0 wide).  */
            /* Handle a dword-aligned 16-bit imm. at 31 (PA2.0 wide).  */
            case '&':
            case '&':
              the_insn.field_selector = pa_chk_field_selector (&s);
              the_insn.field_selector = pa_chk_field_selector (&s);
              get_expression (s);
              get_expression (s);
              s = expr_end;
              s = expr_end;
              if (the_insn.exp.X_op == O_constant)
              if (the_insn.exp.X_op == O_constant)
                {
                {
                  num = evaluate_absolute (&the_insn);
                  num = evaluate_absolute (&the_insn);
                  CHECK_FIELD (num, 32767, -32768, 0);
                  CHECK_FIELD (num, 32767, -32768, 0);
                  CHECK_ALIGN (num, 8, 0);
                  CHECK_ALIGN (num, 8, 0);
                  opcode |= re_assemble_16 (num);
                  opcode |= re_assemble_16 (num);
                  continue;
                  continue;
                }
                }
              else
              else
                {
                {
                  /* ??? Is this valid for wide mode?  */
                  /* ??? Is this valid for wide mode?  */
                  if (is_DP_relative (the_insn.exp))
                  if (is_DP_relative (the_insn.exp))
                    the_insn.reloc = R_HPPA_GOTOFF;
                    the_insn.reloc = R_HPPA_GOTOFF;
                  else if (is_PC_relative (the_insn.exp))
                  else if (is_PC_relative (the_insn.exp))
                    the_insn.reloc = R_HPPA_PCREL_CALL;
                    the_insn.reloc = R_HPPA_PCREL_CALL;
#ifdef OBJ_ELF
#ifdef OBJ_ELF
                  else if (is_tls_gdidx (the_insn.exp))
                  else if (is_tls_gdidx (the_insn.exp))
                    the_insn.reloc = R_PARISC_TLS_GD21L;
                    the_insn.reloc = R_PARISC_TLS_GD21L;
                  else if (is_tls_ldidx (the_insn.exp))
                  else if (is_tls_ldidx (the_insn.exp))
                    the_insn.reloc = R_PARISC_TLS_LDM21L;
                    the_insn.reloc = R_PARISC_TLS_LDM21L;
                  else if (is_tls_dtpoff (the_insn.exp))
                  else if (is_tls_dtpoff (the_insn.exp))
                    the_insn.reloc = R_PARISC_TLS_LDO21L;
                    the_insn.reloc = R_PARISC_TLS_LDO21L;
                  else if (is_tls_ieoff (the_insn.exp))
                  else if (is_tls_ieoff (the_insn.exp))
                    the_insn.reloc = R_PARISC_TLS_IE21L;
                    the_insn.reloc = R_PARISC_TLS_IE21L;
                  else if (is_tls_leoff (the_insn.exp))
                  else if (is_tls_leoff (the_insn.exp))
                    the_insn.reloc = R_PARISC_TLS_LE21L;
                    the_insn.reloc = R_PARISC_TLS_LE21L;
#endif
#endif
                  else
                  else
                    the_insn.reloc = R_HPPA;
                    the_insn.reloc = R_HPPA;
                  the_insn.format = 14;
                  the_insn.format = 14;
                  continue;
                  continue;
                }
                }
 
 
            /* Handle a 12 bit branch displacement.  */
            /* Handle a 12 bit branch displacement.  */
            case 'w':
            case 'w':
              the_insn.field_selector = pa_chk_field_selector (&s);
              the_insn.field_selector = pa_chk_field_selector (&s);
              get_expression (s);
              get_expression (s);
              s = expr_end;
              s = expr_end;
              the_insn.pcrel = 1;
              the_insn.pcrel = 1;
              if (!the_insn.exp.X_add_symbol
              if (!the_insn.exp.X_add_symbol
                  || !strcmp (S_GET_NAME (the_insn.exp.X_add_symbol),
                  || !strcmp (S_GET_NAME (the_insn.exp.X_add_symbol),
                              FAKE_LABEL_NAME))
                              FAKE_LABEL_NAME))
                {
                {
                  num = evaluate_absolute (&the_insn);
                  num = evaluate_absolute (&the_insn);
                  if (num % 4)
                  if (num % 4)
                    {
                    {
                      as_bad (_("Branch to unaligned address"));
                      as_bad (_("Branch to unaligned address"));
                      break;
                      break;
                    }
                    }
                  if (the_insn.exp.X_add_symbol)
                  if (the_insn.exp.X_add_symbol)
                    num -= 8;
                    num -= 8;
                  CHECK_FIELD (num, 8191, -8192, 0);
                  CHECK_FIELD (num, 8191, -8192, 0);
                  opcode |= re_assemble_12 (num >> 2);
                  opcode |= re_assemble_12 (num >> 2);
                  continue;
                  continue;
                }
                }
              else
              else
                {
                {
                  the_insn.reloc = R_HPPA_PCREL_CALL;
                  the_insn.reloc = R_HPPA_PCREL_CALL;
                  the_insn.format = 12;
                  the_insn.format = 12;
                  the_insn.arg_reloc = last_call_desc.arg_reloc;
                  the_insn.arg_reloc = last_call_desc.arg_reloc;
                  memset (&last_call_desc, 0, sizeof (struct call_desc));
                  memset (&last_call_desc, 0, sizeof (struct call_desc));
                  s = expr_end;
                  s = expr_end;
                  continue;
                  continue;
                }
                }
 
 
            /* Handle a 17 bit branch displacement.  */
            /* Handle a 17 bit branch displacement.  */
            case 'W':
            case 'W':
              the_insn.field_selector = pa_chk_field_selector (&s);
              the_insn.field_selector = pa_chk_field_selector (&s);
              get_expression (s);
              get_expression (s);
              s = expr_end;
              s = expr_end;
              the_insn.pcrel = 1;
              the_insn.pcrel = 1;
              if (!the_insn.exp.X_add_symbol
              if (!the_insn.exp.X_add_symbol
                  || !strcmp (S_GET_NAME (the_insn.exp.X_add_symbol),
                  || !strcmp (S_GET_NAME (the_insn.exp.X_add_symbol),
                              FAKE_LABEL_NAME))
                              FAKE_LABEL_NAME))
                {
                {
                  num = evaluate_absolute (&the_insn);
                  num = evaluate_absolute (&the_insn);
                  if (num % 4)
                  if (num % 4)
                    {
                    {
                      as_bad (_("Branch to unaligned address"));
                      as_bad (_("Branch to unaligned address"));
                      break;
                      break;
                    }
                    }
                  if (the_insn.exp.X_add_symbol)
                  if (the_insn.exp.X_add_symbol)
                    num -= 8;
                    num -= 8;
                  CHECK_FIELD (num, 262143, -262144, 0);
                  CHECK_FIELD (num, 262143, -262144, 0);
                  opcode |= re_assemble_17 (num >> 2);
                  opcode |= re_assemble_17 (num >> 2);
                  continue;
                  continue;
                }
                }
              else
              else
                {
                {
                  the_insn.reloc = R_HPPA_PCREL_CALL;
                  the_insn.reloc = R_HPPA_PCREL_CALL;
                  the_insn.format = 17;
                  the_insn.format = 17;
                  the_insn.arg_reloc = last_call_desc.arg_reloc;
                  the_insn.arg_reloc = last_call_desc.arg_reloc;
                  memset (&last_call_desc, 0, sizeof (struct call_desc));
                  memset (&last_call_desc, 0, sizeof (struct call_desc));
                  continue;
                  continue;
                }
                }
 
 
            /* Handle a 22 bit branch displacement.  */
            /* Handle a 22 bit branch displacement.  */
            case 'X':
            case 'X':
              the_insn.field_selector = pa_chk_field_selector (&s);
              the_insn.field_selector = pa_chk_field_selector (&s);
              get_expression (s);
              get_expression (s);
              s = expr_end;
              s = expr_end;
              the_insn.pcrel = 1;
              the_insn.pcrel = 1;
              if (!the_insn.exp.X_add_symbol
              if (!the_insn.exp.X_add_symbol
                  || !strcmp (S_GET_NAME (the_insn.exp.X_add_symbol),
                  || !strcmp (S_GET_NAME (the_insn.exp.X_add_symbol),
                              FAKE_LABEL_NAME))
                              FAKE_LABEL_NAME))
                {
                {
                  num = evaluate_absolute (&the_insn);
                  num = evaluate_absolute (&the_insn);
                  if (num % 4)
                  if (num % 4)
                    {
                    {
                      as_bad (_("Branch to unaligned address"));
                      as_bad (_("Branch to unaligned address"));
                      break;
                      break;
                    }
                    }
                  if (the_insn.exp.X_add_symbol)
                  if (the_insn.exp.X_add_symbol)
                    num -= 8;
                    num -= 8;
                  CHECK_FIELD (num, 8388607, -8388608, 0);
                  CHECK_FIELD (num, 8388607, -8388608, 0);
                  opcode |= re_assemble_22 (num >> 2);
                  opcode |= re_assemble_22 (num >> 2);
                }
                }
              else
              else
                {
                {
                  the_insn.reloc = R_HPPA_PCREL_CALL;
                  the_insn.reloc = R_HPPA_PCREL_CALL;
                  the_insn.format = 22;
                  the_insn.format = 22;
                  the_insn.arg_reloc = last_call_desc.arg_reloc;
                  the_insn.arg_reloc = last_call_desc.arg_reloc;
                  memset (&last_call_desc, 0, sizeof (struct call_desc));
                  memset (&last_call_desc, 0, sizeof (struct call_desc));
                  continue;
                  continue;
                }
                }
 
 
            /* Handle an absolute 17 bit branch target.  */
            /* Handle an absolute 17 bit branch target.  */
            case 'z':
            case 'z':
              the_insn.field_selector = pa_chk_field_selector (&s);
              the_insn.field_selector = pa_chk_field_selector (&s);
              get_expression (s);
              get_expression (s);
              s = expr_end;
              s = expr_end;
              the_insn.pcrel = 0;
              the_insn.pcrel = 0;
              if (!the_insn.exp.X_add_symbol
              if (!the_insn.exp.X_add_symbol
                  || !strcmp (S_GET_NAME (the_insn.exp.X_add_symbol),
                  || !strcmp (S_GET_NAME (the_insn.exp.X_add_symbol),
                              FAKE_LABEL_NAME))
                              FAKE_LABEL_NAME))
                {
                {
                  num = evaluate_absolute (&the_insn);
                  num = evaluate_absolute (&the_insn);
                  if (num % 4)
                  if (num % 4)
                    {
                    {
                      as_bad (_("Branch to unaligned address"));
                      as_bad (_("Branch to unaligned address"));
                      break;
                      break;
                    }
                    }
                  if (the_insn.exp.X_add_symbol)
                  if (the_insn.exp.X_add_symbol)
                    num -= 8;
                    num -= 8;
                  CHECK_FIELD (num, 262143, -262144, 0);
                  CHECK_FIELD (num, 262143, -262144, 0);
                  opcode |= re_assemble_17 (num >> 2);
                  opcode |= re_assemble_17 (num >> 2);
                  continue;
                  continue;
                }
                }
              else
              else
                {
                {
                  the_insn.reloc = R_HPPA_ABS_CALL;
                  the_insn.reloc = R_HPPA_ABS_CALL;
                  the_insn.format = 17;
                  the_insn.format = 17;
                  the_insn.arg_reloc = last_call_desc.arg_reloc;
                  the_insn.arg_reloc = last_call_desc.arg_reloc;
                  memset (&last_call_desc, 0, sizeof (struct call_desc));
                  memset (&last_call_desc, 0, sizeof (struct call_desc));
                  continue;
                  continue;
                }
                }
 
 
            /* Handle '%r1' implicit operand of addil instruction.  */
            /* Handle '%r1' implicit operand of addil instruction.  */
            case 'Z':
            case 'Z':
              if (*s == ',' && *(s + 1) == '%' && *(s + 3) == '1'
              if (*s == ',' && *(s + 1) == '%' && *(s + 3) == '1'
                  && (*(s + 2) == 'r' || *(s + 2) == 'R'))
                  && (*(s + 2) == 'r' || *(s + 2) == 'R'))
                {
                {
                  s += 4;
                  s += 4;
                  continue;
                  continue;
                }
                }
              else
              else
                break;
                break;
 
 
            /* Handle '%sr0,%r31' implicit operand of be,l instruction.  */
            /* Handle '%sr0,%r31' implicit operand of be,l instruction.  */
            case 'Y':
            case 'Y':
              if (strncasecmp (s, "%sr0,%r31", 9) != 0)
              if (strncasecmp (s, "%sr0,%r31", 9) != 0)
                break;
                break;
              s += 9;
              s += 9;
              continue;
              continue;
 
 
            /* Handle immediate value of 0 for ordered load/store instructions.  */
            /* Handle immediate value of 0 for ordered load/store instructions.  */
            case '@':
            case '@':
              if (*s != '0')
              if (*s != '0')
                break;
                break;
              s++;
              s++;
              continue;
              continue;
 
 
            /* Handle a 2 bit shift count at 25.  */
            /* Handle a 2 bit shift count at 25.  */
            case '.':
            case '.':
              num = pa_get_absolute_expression (&the_insn, &s);
              num = pa_get_absolute_expression (&the_insn, &s);
              if (strict && the_insn.exp.X_op != O_constant)
              if (strict && the_insn.exp.X_op != O_constant)
                break;
                break;
              s = expr_end;
              s = expr_end;
              CHECK_FIELD (num, 3, 1, strict);
              CHECK_FIELD (num, 3, 1, strict);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 6);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 6);
 
 
            /* Handle a 4 bit shift count at 25.  */
            /* Handle a 4 bit shift count at 25.  */
            case '*':
            case '*':
              num = pa_get_absolute_expression (&the_insn, &s);
              num = pa_get_absolute_expression (&the_insn, &s);
              if (strict && the_insn.exp.X_op != O_constant)
              if (strict && the_insn.exp.X_op != O_constant)
                break;
                break;
              s = expr_end;
              s = expr_end;
              CHECK_FIELD (num, 15, 0, strict);
              CHECK_FIELD (num, 15, 0, strict);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 6);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 6);
 
 
            /* Handle a 5 bit shift count at 26.  */
            /* Handle a 5 bit shift count at 26.  */
            case 'p':
            case 'p':
              num = pa_get_absolute_expression (&the_insn, &s);
              num = pa_get_absolute_expression (&the_insn, &s);
              if (strict && the_insn.exp.X_op != O_constant)
              if (strict && the_insn.exp.X_op != O_constant)
                break;
                break;
              s = expr_end;
              s = expr_end;
              CHECK_FIELD (num, 31, 0, strict);
              CHECK_FIELD (num, 31, 0, strict);
              INSERT_FIELD_AND_CONTINUE (opcode, 31 - num, 5);
              INSERT_FIELD_AND_CONTINUE (opcode, 31 - num, 5);
 
 
            /* Handle a 6 bit shift count at 20,22:26.  */
            /* Handle a 6 bit shift count at 20,22:26.  */
            case '~':
            case '~':
              num = pa_get_absolute_expression (&the_insn, &s);
              num = pa_get_absolute_expression (&the_insn, &s);
              if (strict && the_insn.exp.X_op != O_constant)
              if (strict && the_insn.exp.X_op != O_constant)
                break;
                break;
              s = expr_end;
              s = expr_end;
              CHECK_FIELD (num, 63, 0, strict);
              CHECK_FIELD (num, 63, 0, strict);
              num = 63 - num;
              num = 63 - num;
              opcode |= (num & 0x20) << 6;
              opcode |= (num & 0x20) << 6;
              INSERT_FIELD_AND_CONTINUE (opcode, num & 0x1f, 5);
              INSERT_FIELD_AND_CONTINUE (opcode, num & 0x1f, 5);
 
 
            /* Handle a 6 bit field length at 23,27:31.  */
            /* Handle a 6 bit field length at 23,27:31.  */
            case '%':
            case '%':
              flag = 0;
              flag = 0;
              num = pa_get_absolute_expression (&the_insn, &s);
              num = pa_get_absolute_expression (&the_insn, &s);
              if (strict && the_insn.exp.X_op != O_constant)
              if (strict && the_insn.exp.X_op != O_constant)
                break;
                break;
              s = expr_end;
              s = expr_end;
              CHECK_FIELD (num, 64, 1, strict);
              CHECK_FIELD (num, 64, 1, strict);
              num--;
              num--;
              opcode |= (num & 0x20) << 3;
              opcode |= (num & 0x20) << 3;
              num = 31 - (num & 0x1f);
              num = 31 - (num & 0x1f);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
 
 
            /* Handle a 6 bit field length at 19,27:31.  */
            /* Handle a 6 bit field length at 19,27:31.  */
            case '|':
            case '|':
              num = pa_get_absolute_expression (&the_insn, &s);
              num = pa_get_absolute_expression (&the_insn, &s);
              if (strict && the_insn.exp.X_op != O_constant)
              if (strict && the_insn.exp.X_op != O_constant)
                break;
                break;
              s = expr_end;
              s = expr_end;
              CHECK_FIELD (num, 64, 1, strict);
              CHECK_FIELD (num, 64, 1, strict);
              num--;
              num--;
              opcode |= (num & 0x20) << 7;
              opcode |= (num & 0x20) << 7;
              num = 31 - (num & 0x1f);
              num = 31 - (num & 0x1f);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
 
 
            /* Handle a 5 bit bit position at 26.  */
            /* Handle a 5 bit bit position at 26.  */
            case 'P':
            case 'P':
              num = pa_get_absolute_expression (&the_insn, &s);
              num = pa_get_absolute_expression (&the_insn, &s);
              if (strict && the_insn.exp.X_op != O_constant)
              if (strict && the_insn.exp.X_op != O_constant)
                break;
                break;
              s = expr_end;
              s = expr_end;
              CHECK_FIELD (num, 31, 0, strict);
              CHECK_FIELD (num, 31, 0, strict);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 5);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 5);
 
 
            /* Handle a 6 bit bit position at 20,22:26.  */
            /* Handle a 6 bit bit position at 20,22:26.  */
            case 'q':
            case 'q':
              num = pa_get_absolute_expression (&the_insn, &s);
              num = pa_get_absolute_expression (&the_insn, &s);
              if (strict && the_insn.exp.X_op != O_constant)
              if (strict && the_insn.exp.X_op != O_constant)
                break;
                break;
              s = expr_end;
              s = expr_end;
              CHECK_FIELD (num, 63, 0, strict);
              CHECK_FIELD (num, 63, 0, strict);
              opcode |= (num & 0x20) << 6;
              opcode |= (num & 0x20) << 6;
              INSERT_FIELD_AND_CONTINUE (opcode, num & 0x1f, 5);
              INSERT_FIELD_AND_CONTINUE (opcode, num & 0x1f, 5);
 
 
            /* Handle a 5 bit immediate at 10 with 'd' as the complement
            /* Handle a 5 bit immediate at 10 with 'd' as the complement
               of the high bit of the immediate.  */
               of the high bit of the immediate.  */
            case 'B':
            case 'B':
              num = pa_get_absolute_expression (&the_insn, &s);
              num = pa_get_absolute_expression (&the_insn, &s);
              if (strict && the_insn.exp.X_op != O_constant)
              if (strict && the_insn.exp.X_op != O_constant)
                break;
                break;
              s = expr_end;
              s = expr_end;
              CHECK_FIELD (num, 63, 0, strict);
              CHECK_FIELD (num, 63, 0, strict);
              if (num & 0x20)
              if (num & 0x20)
                ;
                ;
              else
              else
                opcode |= (1 << 13);
                opcode |= (1 << 13);
              INSERT_FIELD_AND_CONTINUE (opcode, num & 0x1f, 21);
              INSERT_FIELD_AND_CONTINUE (opcode, num & 0x1f, 21);
 
 
            /* Handle a 5 bit immediate at 10.  */
            /* Handle a 5 bit immediate at 10.  */
            case 'Q':
            case 'Q':
              num = pa_get_absolute_expression (&the_insn, &s);
              num = pa_get_absolute_expression (&the_insn, &s);
              if (strict && the_insn.exp.X_op != O_constant)
              if (strict && the_insn.exp.X_op != O_constant)
                break;
                break;
              s = expr_end;
              s = expr_end;
              CHECK_FIELD (num, 31, 0, strict);
              CHECK_FIELD (num, 31, 0, strict);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 21);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 21);
 
 
            /* Handle a 9 bit immediate at 28.  */
            /* Handle a 9 bit immediate at 28.  */
            case '$':
            case '$':
              num = pa_get_absolute_expression (&the_insn, &s);
              num = pa_get_absolute_expression (&the_insn, &s);
              if (strict && the_insn.exp.X_op != O_constant)
              if (strict && the_insn.exp.X_op != O_constant)
                break;
                break;
              s = expr_end;
              s = expr_end;
              CHECK_FIELD (num, 511, 1, strict);
              CHECK_FIELD (num, 511, 1, strict);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 3);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 3);
 
 
            /* Handle a 13 bit immediate at 18.  */
            /* Handle a 13 bit immediate at 18.  */
            case 'A':
            case 'A':
              num = pa_get_absolute_expression (&the_insn, &s);
              num = pa_get_absolute_expression (&the_insn, &s);
              if (strict && the_insn.exp.X_op != O_constant)
              if (strict && the_insn.exp.X_op != O_constant)
                break;
                break;
              s = expr_end;
              s = expr_end;
              CHECK_FIELD (num, 8191, 0, strict);
              CHECK_FIELD (num, 8191, 0, strict);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 13);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 13);
 
 
            /* Handle a 26 bit immediate at 31.  */
            /* Handle a 26 bit immediate at 31.  */
            case 'D':
            case 'D':
              num = pa_get_absolute_expression (&the_insn, &s);
              num = pa_get_absolute_expression (&the_insn, &s);
              if (strict && the_insn.exp.X_op != O_constant)
              if (strict && the_insn.exp.X_op != O_constant)
                break;
                break;
              s = expr_end;
              s = expr_end;
              CHECK_FIELD (num, 67108863, 0, strict);
              CHECK_FIELD (num, 67108863, 0, strict);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
 
 
            /* Handle a 3 bit SFU identifier at 25.  */
            /* Handle a 3 bit SFU identifier at 25.  */
            case 'v':
            case 'v':
              if (*s++ != ',')
              if (*s++ != ',')
                as_bad (_("Invalid SFU identifier"));
                as_bad (_("Invalid SFU identifier"));
              num = pa_get_absolute_expression (&the_insn, &s);
              num = pa_get_absolute_expression (&the_insn, &s);
              if (strict && the_insn.exp.X_op != O_constant)
              if (strict && the_insn.exp.X_op != O_constant)
                break;
                break;
              s = expr_end;
              s = expr_end;
              CHECK_FIELD (num, 7, 0, strict);
              CHECK_FIELD (num, 7, 0, strict);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 6);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 6);
 
 
            /* Handle a 20 bit SOP field for spop0.  */
            /* Handle a 20 bit SOP field for spop0.  */
            case 'O':
            case 'O':
              num = pa_get_absolute_expression (&the_insn, &s);
              num = pa_get_absolute_expression (&the_insn, &s);
              if (strict && the_insn.exp.X_op != O_constant)
              if (strict && the_insn.exp.X_op != O_constant)
                break;
                break;
              s = expr_end;
              s = expr_end;
              CHECK_FIELD (num, 1048575, 0, strict);
              CHECK_FIELD (num, 1048575, 0, strict);
              num = (num & 0x1f) | ((num & 0x000fffe0) << 6);
              num = (num & 0x1f) | ((num & 0x000fffe0) << 6);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
 
 
            /* Handle a 15bit SOP field for spop1.  */
            /* Handle a 15bit SOP field for spop1.  */
            case 'o':
            case 'o':
              num = pa_get_absolute_expression (&the_insn, &s);
              num = pa_get_absolute_expression (&the_insn, &s);
              if (strict && the_insn.exp.X_op != O_constant)
              if (strict && the_insn.exp.X_op != O_constant)
                break;
                break;
              s = expr_end;
              s = expr_end;
              CHECK_FIELD (num, 32767, 0, strict);
              CHECK_FIELD (num, 32767, 0, strict);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 11);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 11);
 
 
            /* Handle a 10bit SOP field for spop3.  */
            /* Handle a 10bit SOP field for spop3.  */
            case '0':
            case '0':
              num = pa_get_absolute_expression (&the_insn, &s);
              num = pa_get_absolute_expression (&the_insn, &s);
              if (strict && the_insn.exp.X_op != O_constant)
              if (strict && the_insn.exp.X_op != O_constant)
                break;
                break;
              s = expr_end;
              s = expr_end;
              CHECK_FIELD (num, 1023, 0, strict);
              CHECK_FIELD (num, 1023, 0, strict);
              num = (num & 0x1f) | ((num & 0x000003e0) << 6);
              num = (num & 0x1f) | ((num & 0x000003e0) << 6);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
 
 
            /* Handle a 15 bit SOP field for spop2.  */
            /* Handle a 15 bit SOP field for spop2.  */
            case '1':
            case '1':
              num = pa_get_absolute_expression (&the_insn, &s);
              num = pa_get_absolute_expression (&the_insn, &s);
              if (strict && the_insn.exp.X_op != O_constant)
              if (strict && the_insn.exp.X_op != O_constant)
                break;
                break;
              s = expr_end;
              s = expr_end;
              CHECK_FIELD (num, 32767, 0, strict);
              CHECK_FIELD (num, 32767, 0, strict);
              num = (num & 0x1f) | ((num & 0x00007fe0) << 6);
              num = (num & 0x1f) | ((num & 0x00007fe0) << 6);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
 
 
            /* Handle a 3-bit co-processor ID field.  */
            /* Handle a 3-bit co-processor ID field.  */
            case 'u':
            case 'u':
              if (*s++ != ',')
              if (*s++ != ',')
                as_bad (_("Invalid COPR identifier"));
                as_bad (_("Invalid COPR identifier"));
              num = pa_get_absolute_expression (&the_insn, &s);
              num = pa_get_absolute_expression (&the_insn, &s);
              if (strict && the_insn.exp.X_op != O_constant)
              if (strict && the_insn.exp.X_op != O_constant)
                break;
                break;
              s = expr_end;
              s = expr_end;
              CHECK_FIELD (num, 7, 0, strict);
              CHECK_FIELD (num, 7, 0, strict);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 6);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 6);
 
 
            /* Handle a 22bit SOP field for copr.  */
            /* Handle a 22bit SOP field for copr.  */
            case '2':
            case '2':
              num = pa_get_absolute_expression (&the_insn, &s);
              num = pa_get_absolute_expression (&the_insn, &s);
              if (strict && the_insn.exp.X_op != O_constant)
              if (strict && the_insn.exp.X_op != O_constant)
                break;
                break;
              s = expr_end;
              s = expr_end;
              CHECK_FIELD (num, 4194303, 0, strict);
              CHECK_FIELD (num, 4194303, 0, strict);
              num = (num & 0x1f) | ((num & 0x003fffe0) << 4);
              num = (num & 0x1f) | ((num & 0x003fffe0) << 4);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
 
 
            /* Handle a source FP operand format completer.  */
            /* Handle a source FP operand format completer.  */
            case '{':
            case '{':
              if (*s == ',' && *(s+1) == 't')
              if (*s == ',' && *(s+1) == 't')
                {
                {
                  the_insn.trunc = 1;
                  the_insn.trunc = 1;
                  s += 2;
                  s += 2;
                }
                }
              else
              else
                the_insn.trunc = 0;
                the_insn.trunc = 0;
              flag = pa_parse_fp_cnv_format (&s);
              flag = pa_parse_fp_cnv_format (&s);
              the_insn.fpof1 = flag;
              the_insn.fpof1 = flag;
              if (flag == W || flag == UW)
              if (flag == W || flag == UW)
                flag = SGL;
                flag = SGL;
              if (flag == DW || flag == UDW)
              if (flag == DW || flag == UDW)
                flag = DBL;
                flag = DBL;
              if (flag == QW || flag == UQW)
              if (flag == QW || flag == UQW)
                flag = QUAD;
                flag = QUAD;
              INSERT_FIELD_AND_CONTINUE (opcode, flag, 11);
              INSERT_FIELD_AND_CONTINUE (opcode, flag, 11);
 
 
            /* Handle a destination FP operand format completer.  */
            /* Handle a destination FP operand format completer.  */
            case '_':
            case '_':
              /* pa_parse_format needs the ',' prefix.  */
              /* pa_parse_format needs the ',' prefix.  */
              s--;
              s--;
              flag = pa_parse_fp_cnv_format (&s);
              flag = pa_parse_fp_cnv_format (&s);
              the_insn.fpof2 = flag;
              the_insn.fpof2 = flag;
              if (flag == W || flag == UW)
              if (flag == W || flag == UW)
                flag = SGL;
                flag = SGL;
              if (flag == DW || flag == UDW)
              if (flag == DW || flag == UDW)
                flag = DBL;
                flag = DBL;
              if (flag == QW || flag == UQW)
              if (flag == QW || flag == UQW)
                flag = QUAD;
                flag = QUAD;
              opcode |= flag << 13;
              opcode |= flag << 13;
              if (the_insn.fpof1 == SGL
              if (the_insn.fpof1 == SGL
                  || the_insn.fpof1 == DBL
                  || the_insn.fpof1 == DBL
                  || the_insn.fpof1 == QUAD)
                  || the_insn.fpof1 == QUAD)
                {
                {
                  if (the_insn.fpof2 == SGL
                  if (the_insn.fpof2 == SGL
                      || the_insn.fpof2 == DBL
                      || the_insn.fpof2 == DBL
                      || the_insn.fpof2 == QUAD)
                      || the_insn.fpof2 == QUAD)
                    flag = 0;
                    flag = 0;
                  else if (the_insn.fpof2 == W
                  else if (the_insn.fpof2 == W
                      || the_insn.fpof2 == DW
                      || the_insn.fpof2 == DW
                      || the_insn.fpof2 == QW)
                      || the_insn.fpof2 == QW)
                    flag = 2;
                    flag = 2;
                  else if (the_insn.fpof2 == UW
                  else if (the_insn.fpof2 == UW
                      || the_insn.fpof2 == UDW
                      || the_insn.fpof2 == UDW
                      || the_insn.fpof2 == UQW)
                      || the_insn.fpof2 == UQW)
                    flag = 6;
                    flag = 6;
                  else
                  else
                    abort ();
                    abort ();
                }
                }
              else if (the_insn.fpof1 == W
              else if (the_insn.fpof1 == W
                       || the_insn.fpof1 == DW
                       || the_insn.fpof1 == DW
                       || the_insn.fpof1 == QW)
                       || the_insn.fpof1 == QW)
                {
                {
                  if (the_insn.fpof2 == SGL
                  if (the_insn.fpof2 == SGL
                      || the_insn.fpof2 == DBL
                      || the_insn.fpof2 == DBL
                      || the_insn.fpof2 == QUAD)
                      || the_insn.fpof2 == QUAD)
                    flag = 1;
                    flag = 1;
                  else
                  else
                    abort ();
                    abort ();
                }
                }
              else if (the_insn.fpof1 == UW
              else if (the_insn.fpof1 == UW
                       || the_insn.fpof1 == UDW
                       || the_insn.fpof1 == UDW
                       || the_insn.fpof1 == UQW)
                       || the_insn.fpof1 == UQW)
                {
                {
                  if (the_insn.fpof2 == SGL
                  if (the_insn.fpof2 == SGL
                      || the_insn.fpof2 == DBL
                      || the_insn.fpof2 == DBL
                      || the_insn.fpof2 == QUAD)
                      || the_insn.fpof2 == QUAD)
                    flag = 5;
                    flag = 5;
                  else
                  else
                    abort ();
                    abort ();
                }
                }
              flag |= the_insn.trunc;
              flag |= the_insn.trunc;
              INSERT_FIELD_AND_CONTINUE (opcode, flag, 15);
              INSERT_FIELD_AND_CONTINUE (opcode, flag, 15);
 
 
            /* Handle a source FP operand format completer.  */
            /* Handle a source FP operand format completer.  */
            case 'F':
            case 'F':
              flag = pa_parse_fp_format (&s);
              flag = pa_parse_fp_format (&s);
              the_insn.fpof1 = flag;
              the_insn.fpof1 = flag;
              INSERT_FIELD_AND_CONTINUE (opcode, flag, 11);
              INSERT_FIELD_AND_CONTINUE (opcode, flag, 11);
 
 
            /* Handle a destination FP operand format completer.  */
            /* Handle a destination FP operand format completer.  */
            case 'G':
            case 'G':
              /* pa_parse_format needs the ',' prefix.  */
              /* pa_parse_format needs the ',' prefix.  */
              s--;
              s--;
              flag = pa_parse_fp_format (&s);
              flag = pa_parse_fp_format (&s);
              the_insn.fpof2 = flag;
              the_insn.fpof2 = flag;
              INSERT_FIELD_AND_CONTINUE (opcode, flag, 13);
              INSERT_FIELD_AND_CONTINUE (opcode, flag, 13);
 
 
            /* Handle a source FP operand format completer at 20.  */
            /* Handle a source FP operand format completer at 20.  */
            case 'I':
            case 'I':
              flag = pa_parse_fp_format (&s);
              flag = pa_parse_fp_format (&s);
              the_insn.fpof1 = flag;
              the_insn.fpof1 = flag;
              INSERT_FIELD_AND_CONTINUE (opcode, flag, 11);
              INSERT_FIELD_AND_CONTINUE (opcode, flag, 11);
 
 
            /* Handle a floating point operand format at 26.
            /* Handle a floating point operand format at 26.
               Only allows single and double precision.  */
               Only allows single and double precision.  */
            case 'H':
            case 'H':
              flag = pa_parse_fp_format (&s);
              flag = pa_parse_fp_format (&s);
              switch (flag)
              switch (flag)
                {
                {
                case SGL:
                case SGL:
                  opcode |= 0x20;
                  opcode |= 0x20;
                case DBL:
                case DBL:
                  the_insn.fpof1 = flag;
                  the_insn.fpof1 = flag;
                  continue;
                  continue;
 
 
                case QUAD:
                case QUAD:
                case ILLEGAL_FMT:
                case ILLEGAL_FMT:
                default:
                default:
                  as_bad (_("Invalid Floating Point Operand Format."));
                  as_bad (_("Invalid Floating Point Operand Format."));
                }
                }
              break;
              break;
 
 
            /* Handle all floating point registers.  */
            /* Handle all floating point registers.  */
            case 'f':
            case 'f':
              switch (*++args)
              switch (*++args)
                {
                {
                /* Float target register.  */
                /* Float target register.  */
                case 't':
                case 't':
                  if (!pa_parse_number (&s, 3))
                  if (!pa_parse_number (&s, 3))
                    break;
                    break;
                  num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
                  num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
                  CHECK_FIELD (num, 31, 0, 0);
                  CHECK_FIELD (num, 31, 0, 0);
                  INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
                  INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
 
 
                /* Float target register with L/R selection.  */
                /* Float target register with L/R selection.  */
                case 'T':
                case 'T':
                  {
                  {
                    if (!pa_parse_number (&s, 1))
                    if (!pa_parse_number (&s, 1))
                      break;
                      break;
                    num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
                    num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
                    CHECK_FIELD (num, 31, 0, 0);
                    CHECK_FIELD (num, 31, 0, 0);
                    opcode |= num;
                    opcode |= num;
 
 
                    /* 0x30 opcodes are FP arithmetic operation opcodes
                    /* 0x30 opcodes are FP arithmetic operation opcodes
                       and need to be turned into 0x38 opcodes.  This
                       and need to be turned into 0x38 opcodes.  This
                       is not necessary for loads/stores.  */
                       is not necessary for loads/stores.  */
                    if (need_pa11_opcode ()
                    if (need_pa11_opcode ()
                        && ((opcode & 0xfc000000) == 0x30000000))
                        && ((opcode & 0xfc000000) == 0x30000000))
                      opcode |= 1 << 27;
                      opcode |= 1 << 27;
 
 
                    opcode |= (pa_number & FP_REG_RSEL ? 1 << 6 : 0);
                    opcode |= (pa_number & FP_REG_RSEL ? 1 << 6 : 0);
                    continue;
                    continue;
                  }
                  }
 
 
                /* Float operand 1.  */
                /* Float operand 1.  */
                case 'a':
                case 'a':
                  {
                  {
                    if (!pa_parse_number (&s, 1))
                    if (!pa_parse_number (&s, 1))
                      break;
                      break;
                    num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
                    num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
                    CHECK_FIELD (num, 31, 0, 0);
                    CHECK_FIELD (num, 31, 0, 0);
                    opcode |= num << 21;
                    opcode |= num << 21;
                    if (need_pa11_opcode ())
                    if (need_pa11_opcode ())
                      {
                      {
                        opcode |= (pa_number & FP_REG_RSEL ? 1 << 7 : 0);
                        opcode |= (pa_number & FP_REG_RSEL ? 1 << 7 : 0);
                        opcode |= 1 << 27;
                        opcode |= 1 << 27;
                      }
                      }
                    continue;
                    continue;
                  }
                  }
 
 
                /* Float operand 1 with L/R selection.  */
                /* Float operand 1 with L/R selection.  */
                case 'X':
                case 'X':
                case 'A':
                case 'A':
                  {
                  {
                    if (!pa_parse_number (&s, 1))
                    if (!pa_parse_number (&s, 1))
                      break;
                      break;
                    num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
                    num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
                    CHECK_FIELD (num, 31, 0, 0);
                    CHECK_FIELD (num, 31, 0, 0);
                    opcode |= num << 21;
                    opcode |= num << 21;
                    opcode |= (pa_number & FP_REG_RSEL ? 1 << 7 : 0);
                    opcode |= (pa_number & FP_REG_RSEL ? 1 << 7 : 0);
                    continue;
                    continue;
                  }
                  }
 
 
                /* Float operand 2.  */
                /* Float operand 2.  */
                case 'b':
                case 'b':
                  {
                  {
                    if (!pa_parse_number (&s, 1))
                    if (!pa_parse_number (&s, 1))
                      break;
                      break;
                    num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
                    num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
                    CHECK_FIELD (num, 31, 0, 0);
                    CHECK_FIELD (num, 31, 0, 0);
                    opcode |= num << 16;
                    opcode |= num << 16;
                    if (need_pa11_opcode ())
                    if (need_pa11_opcode ())
                      {
                      {
                        opcode |= (pa_number & FP_REG_RSEL ? 1 << 12 : 0);
                        opcode |= (pa_number & FP_REG_RSEL ? 1 << 12 : 0);
                        opcode |= 1 << 27;
                        opcode |= 1 << 27;
                      }
                      }
                    continue;
                    continue;
                  }
                  }
 
 
                /* Float operand 2 with L/R selection.  */
                /* Float operand 2 with L/R selection.  */
                case 'B':
                case 'B':
                  {
                  {
                    if (!pa_parse_number (&s, 1))
                    if (!pa_parse_number (&s, 1))
                      break;
                      break;
                    num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
                    num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
                    CHECK_FIELD (num, 31, 0, 0);
                    CHECK_FIELD (num, 31, 0, 0);
                    opcode |= num << 16;
                    opcode |= num << 16;
                    opcode |= (pa_number & FP_REG_RSEL ? 1 << 12 : 0);
                    opcode |= (pa_number & FP_REG_RSEL ? 1 << 12 : 0);
                    continue;
                    continue;
                  }
                  }
 
 
                /* Float operand 3 for fmpyfadd, fmpynfadd.  */
                /* Float operand 3 for fmpyfadd, fmpynfadd.  */
                case 'C':
                case 'C':
                  {
                  {
                    if (!pa_parse_number (&s, 1))
                    if (!pa_parse_number (&s, 1))
                      break;
                      break;
                    num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
                    num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
                    CHECK_FIELD (num, 31, 0, 0);
                    CHECK_FIELD (num, 31, 0, 0);
                    opcode |= (num & 0x1c) << 11;
                    opcode |= (num & 0x1c) << 11;
                    opcode |= (num & 0x03) << 9;
                    opcode |= (num & 0x03) << 9;
                    opcode |= (pa_number & FP_REG_RSEL ? 1 << 8 : 0);
                    opcode |= (pa_number & FP_REG_RSEL ? 1 << 8 : 0);
                    continue;
                    continue;
                  }
                  }
 
 
                /* Float mult operand 1 for fmpyadd, fmpysub */
                /* Float mult operand 1 for fmpyadd, fmpysub */
                case 'i':
                case 'i':
                  {
                  {
                    if (!pa_parse_number (&s, 1))
                    if (!pa_parse_number (&s, 1))
                      break;
                      break;
                    num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
                    num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
                    CHECK_FIELD (num, 31, 0, 0);
                    CHECK_FIELD (num, 31, 0, 0);
                    if (the_insn.fpof1 == SGL)
                    if (the_insn.fpof1 == SGL)
                      {
                      {
                        if (num < 16)
                        if (num < 16)
                          {
                          {
                            as_bad  (_("Invalid register for single precision fmpyadd or fmpysub"));
                            as_bad  (_("Invalid register for single precision fmpyadd or fmpysub"));
                            break;
                            break;
                          }
                          }
                        num &= 0xF;
                        num &= 0xF;
                        num |= (pa_number & FP_REG_RSEL ? 1 << 4 : 0);
                        num |= (pa_number & FP_REG_RSEL ? 1 << 4 : 0);
                      }
                      }
                    INSERT_FIELD_AND_CONTINUE (opcode, num, 21);
                    INSERT_FIELD_AND_CONTINUE (opcode, num, 21);
                  }
                  }
 
 
                /* Float mult operand 2 for fmpyadd, fmpysub */
                /* Float mult operand 2 for fmpyadd, fmpysub */
                case 'j':
                case 'j':
                  {
                  {
                    if (!pa_parse_number (&s, 1))
                    if (!pa_parse_number (&s, 1))
                      break;
                      break;
                    num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
                    num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
                    CHECK_FIELD (num, 31, 0, 0);
                    CHECK_FIELD (num, 31, 0, 0);
                    if (the_insn.fpof1 == SGL)
                    if (the_insn.fpof1 == SGL)
                      {
                      {
                        if (num < 16)
                        if (num < 16)
                          {
                          {
                            as_bad  (_("Invalid register for single precision fmpyadd or fmpysub"));
                            as_bad  (_("Invalid register for single precision fmpyadd or fmpysub"));
                            break;
                            break;
                          }
                          }
                        num &= 0xF;
                        num &= 0xF;
                        num |= (pa_number & FP_REG_RSEL ? 1 << 4 : 0);
                        num |= (pa_number & FP_REG_RSEL ? 1 << 4 : 0);
                      }
                      }
                    INSERT_FIELD_AND_CONTINUE (opcode, num, 16);
                    INSERT_FIELD_AND_CONTINUE (opcode, num, 16);
                  }
                  }
 
 
                /* Float mult target for fmpyadd, fmpysub */
                /* Float mult target for fmpyadd, fmpysub */
                case 'k':
                case 'k':
                  {
                  {
                    if (!pa_parse_number (&s, 1))
                    if (!pa_parse_number (&s, 1))
                      break;
                      break;
                    num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
                    num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
                    CHECK_FIELD (num, 31, 0, 0);
                    CHECK_FIELD (num, 31, 0, 0);
                    if (the_insn.fpof1 == SGL)
                    if (the_insn.fpof1 == SGL)
                      {
                      {
                        if (num < 16)
                        if (num < 16)
                          {
                          {
                            as_bad  (_("Invalid register for single precision fmpyadd or fmpysub"));
                            as_bad  (_("Invalid register for single precision fmpyadd or fmpysub"));
                            break;
                            break;
                          }
                          }
                        num &= 0xF;
                        num &= 0xF;
                        num |= (pa_number & FP_REG_RSEL ? 1 << 4 : 0);
                        num |= (pa_number & FP_REG_RSEL ? 1 << 4 : 0);
                      }
                      }
                    INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
                    INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
                  }
                  }
 
 
                /* Float add operand 1 for fmpyadd, fmpysub */
                /* Float add operand 1 for fmpyadd, fmpysub */
                case 'l':
                case 'l':
                  {
                  {
                    if (!pa_parse_number (&s, 1))
                    if (!pa_parse_number (&s, 1))
                      break;
                      break;
                    num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
                    num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
                    CHECK_FIELD (num, 31, 0, 0);
                    CHECK_FIELD (num, 31, 0, 0);
                    if (the_insn.fpof1 == SGL)
                    if (the_insn.fpof1 == SGL)
                      {
                      {
                        if (num < 16)
                        if (num < 16)
                          {
                          {
                            as_bad  (_("Invalid register for single precision fmpyadd or fmpysub"));
                            as_bad  (_("Invalid register for single precision fmpyadd or fmpysub"));
                            break;
                            break;
                          }
                          }
                        num &= 0xF;
                        num &= 0xF;
                        num |= (pa_number & FP_REG_RSEL ? 1 << 4 : 0);
                        num |= (pa_number & FP_REG_RSEL ? 1 << 4 : 0);
                      }
                      }
                    INSERT_FIELD_AND_CONTINUE (opcode, num, 6);
                    INSERT_FIELD_AND_CONTINUE (opcode, num, 6);
                  }
                  }
 
 
                /* Float add target for fmpyadd, fmpysub */
                /* Float add target for fmpyadd, fmpysub */
                case 'm':
                case 'm':
                  {
                  {
                    if (!pa_parse_number (&s, 1))
                    if (!pa_parse_number (&s, 1))
                      break;
                      break;
                    num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
                    num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
                    CHECK_FIELD (num, 31, 0, 0);
                    CHECK_FIELD (num, 31, 0, 0);
                    if (the_insn.fpof1 == SGL)
                    if (the_insn.fpof1 == SGL)
                      {
                      {
                        if (num < 16)
                        if (num < 16)
                          {
                          {
                            as_bad  (_("Invalid register for single precision fmpyadd or fmpysub"));
                            as_bad  (_("Invalid register for single precision fmpyadd or fmpysub"));
                            break;
                            break;
                          }
                          }
                        num &= 0xF;
                        num &= 0xF;
                        num |= (pa_number & FP_REG_RSEL ? 1 << 4 : 0);
                        num |= (pa_number & FP_REG_RSEL ? 1 << 4 : 0);
                      }
                      }
                    INSERT_FIELD_AND_CONTINUE (opcode, num, 11);
                    INSERT_FIELD_AND_CONTINUE (opcode, num, 11);
                  }
                  }
 
 
                /* Handle L/R register halves like 'x'.  */
                /* Handle L/R register halves like 'x'.  */
                case 'E':
                case 'E':
                case 'e':
                case 'e':
                  {
                  {
                    if (!pa_parse_number (&s, 1))
                    if (!pa_parse_number (&s, 1))
                      break;
                      break;
                    num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
                    num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
                    CHECK_FIELD (num, 31, 0, 0);
                    CHECK_FIELD (num, 31, 0, 0);
                    opcode |= num << 16;
                    opcode |= num << 16;
                    if (need_pa11_opcode ())
                    if (need_pa11_opcode ())
                      {
                      {
                        opcode |= (pa_number & FP_REG_RSEL ? 1 << 1 : 0);
                        opcode |= (pa_number & FP_REG_RSEL ? 1 << 1 : 0);
                      }
                      }
                    continue;
                    continue;
                  }
                  }
 
 
                /* Float target register (PA 2.0 wide).  */
                /* Float target register (PA 2.0 wide).  */
                case 'x':
                case 'x':
                  if (!pa_parse_number (&s, 3))
                  if (!pa_parse_number (&s, 3))
                    break;
                    break;
                  num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
                  num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
                  CHECK_FIELD (num, 31, 0, 0);
                  CHECK_FIELD (num, 31, 0, 0);
                  INSERT_FIELD_AND_CONTINUE (opcode, num, 16);
                  INSERT_FIELD_AND_CONTINUE (opcode, num, 16);
 
 
                default:
                default:
                  abort ();
                  abort ();
                }
                }
              break;
              break;
 
 
            default:
            default:
              abort ();
              abort ();
            }
            }
          break;
          break;
        }
        }
 
 
      /* If this instruction is specific to a particular architecture,
      /* If this instruction is specific to a particular architecture,
         then set a new architecture.  This automatic promotion crud is
         then set a new architecture.  This automatic promotion crud is
         for compatibility with HP's old assemblers only.  */
         for compatibility with HP's old assemblers only.  */
      if (match == TRUE
      if (match == TRUE
          && bfd_get_mach (stdoutput) < insn->arch
          && bfd_get_mach (stdoutput) < insn->arch
          && !bfd_set_arch_mach (stdoutput, bfd_arch_hppa, insn->arch))
          && !bfd_set_arch_mach (stdoutput, bfd_arch_hppa, insn->arch))
        {
        {
          as_warn (_("could not update architecture and machine"));
          as_warn (_("could not update architecture and machine"));
          match = FALSE;
          match = FALSE;
        }
        }
 
 
 failed:
 failed:
      /* Check if the args matched.  */
      /* Check if the args matched.  */
      if (!match)
      if (!match)
        {
        {
          if (&insn[1] - pa_opcodes < (int) NUMOPCODES
          if (&insn[1] - pa_opcodes < (int) NUMOPCODES
              && !strcmp (insn->name, insn[1].name))
              && !strcmp (insn->name, insn[1].name))
            {
            {
              ++insn;
              ++insn;
              s = argstart;
              s = argstart;
              continue;
              continue;
            }
            }
          else
          else
            {
            {
              as_bad (_("Invalid operands %s"), error_message);
              as_bad (_("Invalid operands %s"), error_message);
              return;
              return;
            }
            }
        }
        }
      break;
      break;
    }
    }
 
 
  the_insn.opcode = opcode;
  the_insn.opcode = opcode;
}
}
 
 
/* Assemble a single instruction storing it into a frag.  */
/* Assemble a single instruction storing it into a frag.  */
 
 
void
void
md_assemble (char *str)
md_assemble (char *str)
{
{
  char *to;
  char *to;
 
 
  /* The had better be something to assemble.  */
  /* The had better be something to assemble.  */
  assert (str);
  assert (str);
 
 
  /* If we are within a procedure definition, make sure we've
  /* If we are within a procedure definition, make sure we've
     defined a label for the procedure; handle case where the
     defined a label for the procedure; handle case where the
     label was defined after the .PROC directive.
     label was defined after the .PROC directive.
 
 
     Note there's not need to diddle with the segment or fragment
     Note there's not need to diddle with the segment or fragment
     for the label symbol in this case.  We have already switched
     for the label symbol in this case.  We have already switched
     into the new $CODE$ subspace at this point.  */
     into the new $CODE$ subspace at this point.  */
  if (within_procedure && last_call_info->start_symbol == NULL)
  if (within_procedure && last_call_info->start_symbol == NULL)
    {
    {
      label_symbol_struct *label_symbol = pa_get_label ();
      label_symbol_struct *label_symbol = pa_get_label ();
 
 
      if (label_symbol)
      if (label_symbol)
        {
        {
          if (label_symbol->lss_label)
          if (label_symbol->lss_label)
            {
            {
              last_call_info->start_symbol = label_symbol->lss_label;
              last_call_info->start_symbol = label_symbol->lss_label;
              symbol_get_bfdsym (label_symbol->lss_label)->flags
              symbol_get_bfdsym (label_symbol->lss_label)->flags
                |= BSF_FUNCTION;
                |= BSF_FUNCTION;
#ifdef OBJ_SOM
#ifdef OBJ_SOM
              /* Also handle allocation of a fixup to hold the unwind
              /* Also handle allocation of a fixup to hold the unwind
                 information when the label appears after the proc/procend.  */
                 information when the label appears after the proc/procend.  */
              if (within_entry_exit)
              if (within_entry_exit)
                {
                {
                  char *where;
                  char *where;
                  unsigned int u;
                  unsigned int u;
 
 
                  where = frag_more (0);
                  where = frag_more (0);
                  u = UNWIND_LOW32 (&last_call_info->ci_unwind.descriptor);
                  u = UNWIND_LOW32 (&last_call_info->ci_unwind.descriptor);
                  fix_new_hppa (frag_now, where - frag_now->fr_literal, 0,
                  fix_new_hppa (frag_now, where - frag_now->fr_literal, 0,
                                NULL, (offsetT) 0, NULL,
                                NULL, (offsetT) 0, NULL,
                                0, R_HPPA_ENTRY, e_fsel, 0, 0, u);
                                0, R_HPPA_ENTRY, e_fsel, 0, 0, u);
                }
                }
#endif
#endif
            }
            }
          else
          else
            as_bad (_("Missing function name for .PROC (corrupted label chain)"));
            as_bad (_("Missing function name for .PROC (corrupted label chain)"));
        }
        }
      else
      else
        as_bad (_("Missing function name for .PROC"));
        as_bad (_("Missing function name for .PROC"));
    }
    }
 
 
  /* Assemble the instruction.  Results are saved into "the_insn".  */
  /* Assemble the instruction.  Results are saved into "the_insn".  */
  pa_ip (str);
  pa_ip (str);
 
 
  /* Get somewhere to put the assembled instruction.  */
  /* Get somewhere to put the assembled instruction.  */
  to = frag_more (4);
  to = frag_more (4);
 
 
  /* Output the opcode.  */
  /* Output the opcode.  */
  md_number_to_chars (to, the_insn.opcode, 4);
  md_number_to_chars (to, the_insn.opcode, 4);
 
 
  /* If necessary output more stuff.  */
  /* If necessary output more stuff.  */
  if (the_insn.reloc != R_HPPA_NONE)
  if (the_insn.reloc != R_HPPA_NONE)
    fix_new_hppa (frag_now, (to - frag_now->fr_literal), 4, NULL,
    fix_new_hppa (frag_now, (to - frag_now->fr_literal), 4, NULL,
                  (offsetT) 0, &the_insn.exp, the_insn.pcrel,
                  (offsetT) 0, &the_insn.exp, the_insn.pcrel,
                  the_insn.reloc, the_insn.field_selector,
                  the_insn.reloc, the_insn.field_selector,
                  the_insn.format, the_insn.arg_reloc, 0);
                  the_insn.format, the_insn.arg_reloc, 0);
 
 
#ifdef OBJ_ELF
#ifdef OBJ_ELF
  dwarf2_emit_insn (4);
  dwarf2_emit_insn (4);
#endif
#endif
}
}
 
 
#ifdef OBJ_SOM
#ifdef OBJ_SOM
/* Handle an alignment directive.  Special so that we can update the
/* Handle an alignment directive.  Special so that we can update the
   alignment of the subspace if necessary.  */
   alignment of the subspace if necessary.  */
static void
static void
pa_align (int bytes)
pa_align (int bytes)
{
{
  /* We must have a valid space and subspace.  */
  /* We must have a valid space and subspace.  */
  pa_check_current_space_and_subspace ();
  pa_check_current_space_and_subspace ();
 
 
  /* Let the generic gas code do most of the work.  */
  /* Let the generic gas code do most of the work.  */
  s_align_bytes (bytes);
  s_align_bytes (bytes);
 
 
  /* If bytes is a power of 2, then update the current subspace's
  /* If bytes is a power of 2, then update the current subspace's
     alignment if necessary.  */
     alignment if necessary.  */
  if (exact_log2 (bytes) != -1)
  if (exact_log2 (bytes) != -1)
    record_alignment (current_subspace->ssd_seg, exact_log2 (bytes));
    record_alignment (current_subspace->ssd_seg, exact_log2 (bytes));
}
}
#endif
#endif
 
 
/* Handle a .BLOCK type pseudo-op.  */
/* Handle a .BLOCK type pseudo-op.  */
 
 
static void
static void
pa_block (int z ATTRIBUTE_UNUSED)
pa_block (int z ATTRIBUTE_UNUSED)
{
{
  unsigned int temp_size;
  unsigned int temp_size;
 
 
#ifdef OBJ_SOM
#ifdef OBJ_SOM
  /* We must have a valid space and subspace.  */
  /* We must have a valid space and subspace.  */
  pa_check_current_space_and_subspace ();
  pa_check_current_space_and_subspace ();
#endif
#endif
 
 
  temp_size = get_absolute_expression ();
  temp_size = get_absolute_expression ();
 
 
  if (temp_size > 0x3FFFFFFF)
  if (temp_size > 0x3FFFFFFF)
    {
    {
      as_bad (_("Argument to .BLOCK/.BLOCKZ must be between 0 and 0x3fffffff"));
      as_bad (_("Argument to .BLOCK/.BLOCKZ must be between 0 and 0x3fffffff"));
      temp_size = 0;
      temp_size = 0;
    }
    }
  else
  else
    {
    {
      /* Always fill with zeros, that's what the HP assembler does.  */
      /* Always fill with zeros, that's what the HP assembler does.  */
      char *p = frag_var (rs_fill, 1, 1, 0, NULL, temp_size, NULL);
      char *p = frag_var (rs_fill, 1, 1, 0, NULL, temp_size, NULL);
      *p = 0;
      *p = 0;
    }
    }
 
 
  pa_undefine_label ();
  pa_undefine_label ();
  demand_empty_rest_of_line ();
  demand_empty_rest_of_line ();
}
}
 
 
/* Handle a .begin_brtab and .end_brtab pseudo-op.  */
/* Handle a .begin_brtab and .end_brtab pseudo-op.  */
 
 
static void
static void
pa_brtab (int begin ATTRIBUTE_UNUSED)
pa_brtab (int begin ATTRIBUTE_UNUSED)
{
{
 
 
#ifdef OBJ_SOM
#ifdef OBJ_SOM
  /* The BRTAB relocations are only available in SOM (to denote
  /* The BRTAB relocations are only available in SOM (to denote
     the beginning and end of branch tables).  */
     the beginning and end of branch tables).  */
  char *where = frag_more (0);
  char *where = frag_more (0);
 
 
  fix_new_hppa (frag_now, where - frag_now->fr_literal, 0,
  fix_new_hppa (frag_now, where - frag_now->fr_literal, 0,
                NULL, (offsetT) 0, NULL,
                NULL, (offsetT) 0, NULL,
                0, begin ? R_HPPA_BEGIN_BRTAB : R_HPPA_END_BRTAB,
                0, begin ? R_HPPA_BEGIN_BRTAB : R_HPPA_END_BRTAB,
                e_fsel, 0, 0, 0);
                e_fsel, 0, 0, 0);
#endif
#endif
 
 
  demand_empty_rest_of_line ();
  demand_empty_rest_of_line ();
}
}
 
 
/* Handle a .begin_try and .end_try pseudo-op.  */
/* Handle a .begin_try and .end_try pseudo-op.  */
 
 
static void
static void
pa_try (int begin ATTRIBUTE_UNUSED)
pa_try (int begin ATTRIBUTE_UNUSED)
{
{
#ifdef OBJ_SOM
#ifdef OBJ_SOM
  expressionS exp;
  expressionS exp;
  char *where = frag_more (0);
  char *where = frag_more (0);
 
 
  if (! begin)
  if (! begin)
    expression (&exp);
    expression (&exp);
 
 
  /* The TRY relocations are only available in SOM (to denote
  /* The TRY relocations are only available in SOM (to denote
     the beginning and end of exception handling regions).  */
     the beginning and end of exception handling regions).  */
 
 
  fix_new_hppa (frag_now, where - frag_now->fr_literal, 0,
  fix_new_hppa (frag_now, where - frag_now->fr_literal, 0,
                NULL, (offsetT) 0, begin ? NULL : &exp,
                NULL, (offsetT) 0, begin ? NULL : &exp,
                0, begin ? R_HPPA_BEGIN_TRY : R_HPPA_END_TRY,
                0, begin ? R_HPPA_BEGIN_TRY : R_HPPA_END_TRY,
                e_fsel, 0, 0, 0);
                e_fsel, 0, 0, 0);
#endif
#endif
 
 
  demand_empty_rest_of_line ();
  demand_empty_rest_of_line ();
}
}
 
 
/* Do the dirty work of building a call descriptor which describes
/* Do the dirty work of building a call descriptor which describes
   where the caller placed arguments to a function call.  */
   where the caller placed arguments to a function call.  */
 
 
static void
static void
pa_call_args (struct call_desc *call_desc)
pa_call_args (struct call_desc *call_desc)
{
{
  char *name, c, *p;
  char *name, c, *p;
  unsigned int temp, arg_reloc;
  unsigned int temp, arg_reloc;
 
 
  while (!is_end_of_statement ())
  while (!is_end_of_statement ())
    {
    {
      name = input_line_pointer;
      name = input_line_pointer;
      c = get_symbol_end ();
      c = get_symbol_end ();
      /* Process a source argument.  */
      /* Process a source argument.  */
      if ((strncasecmp (name, "argw", 4) == 0))
      if ((strncasecmp (name, "argw", 4) == 0))
        {
        {
          temp = atoi (name + 4);
          temp = atoi (name + 4);
          p = input_line_pointer;
          p = input_line_pointer;
          *p = c;
          *p = c;
          input_line_pointer++;
          input_line_pointer++;
          name = input_line_pointer;
          name = input_line_pointer;
          c = get_symbol_end ();
          c = get_symbol_end ();
          arg_reloc = pa_build_arg_reloc (name);
          arg_reloc = pa_build_arg_reloc (name);
          call_desc->arg_reloc |= pa_align_arg_reloc (temp, arg_reloc);
          call_desc->arg_reloc |= pa_align_arg_reloc (temp, arg_reloc);
        }
        }
      /* Process a return value.  */
      /* Process a return value.  */
      else if ((strncasecmp (name, "rtnval", 6) == 0))
      else if ((strncasecmp (name, "rtnval", 6) == 0))
        {
        {
          p = input_line_pointer;
          p = input_line_pointer;
          *p = c;
          *p = c;
          input_line_pointer++;
          input_line_pointer++;
          name = input_line_pointer;
          name = input_line_pointer;
          c = get_symbol_end ();
          c = get_symbol_end ();
          arg_reloc = pa_build_arg_reloc (name);
          arg_reloc = pa_build_arg_reloc (name);
          call_desc->arg_reloc |= (arg_reloc & 0x3);
          call_desc->arg_reloc |= (arg_reloc & 0x3);
        }
        }
      else
      else
        {
        {
          as_bad (_("Invalid .CALL argument: %s"), name);
          as_bad (_("Invalid .CALL argument: %s"), name);
        }
        }
      p = input_line_pointer;
      p = input_line_pointer;
      *p = c;
      *p = c;
      if (!is_end_of_statement ())
      if (!is_end_of_statement ())
        input_line_pointer++;
        input_line_pointer++;
    }
    }
}
}
 
 
/* Handle a .CALL pseudo-op.  This involves storing away information
/* Handle a .CALL pseudo-op.  This involves storing away information
   about where arguments are to be found so the linker can detect
   about where arguments are to be found so the linker can detect
   (and correct) argument location mismatches between caller and callee.  */
   (and correct) argument location mismatches between caller and callee.  */
 
 
static void
static void
pa_call (int unused ATTRIBUTE_UNUSED)
pa_call (int unused ATTRIBUTE_UNUSED)
{
{
#ifdef OBJ_SOM
#ifdef OBJ_SOM
  /* We must have a valid space and subspace.  */
  /* We must have a valid space and subspace.  */
  pa_check_current_space_and_subspace ();
  pa_check_current_space_and_subspace ();
#endif
#endif
 
 
  pa_call_args (&last_call_desc);
  pa_call_args (&last_call_desc);
  demand_empty_rest_of_line ();
  demand_empty_rest_of_line ();
}
}
 
 
#ifdef OBJ_ELF
#ifdef OBJ_ELF
/* Build an entry in the UNWIND subspace from the given function
/* Build an entry in the UNWIND subspace from the given function
   attributes in CALL_INFO.  This is not needed for SOM as using
   attributes in CALL_INFO.  This is not needed for SOM as using
   R_ENTRY and R_EXIT relocations allow the linker to handle building
   R_ENTRY and R_EXIT relocations allow the linker to handle building
   of the unwind spaces.  */
   of the unwind spaces.  */
 
 
static void
static void
pa_build_unwind_subspace (struct call_info *call_info)
pa_build_unwind_subspace (struct call_info *call_info)
{
{
  asection *seg, *save_seg;
  asection *seg, *save_seg;
  subsegT save_subseg;
  subsegT save_subseg;
  unsigned int unwind;
  unsigned int unwind;
  int reloc;
  int reloc;
  char *p;
  char *p;
 
 
  if ((bfd_get_section_flags (stdoutput, now_seg)
  if ((bfd_get_section_flags (stdoutput, now_seg)
       & (SEC_ALLOC | SEC_LOAD | SEC_READONLY))
       & (SEC_ALLOC | SEC_LOAD | SEC_READONLY))
      != (SEC_ALLOC | SEC_LOAD | SEC_READONLY))
      != (SEC_ALLOC | SEC_LOAD | SEC_READONLY))
    return;
    return;
 
 
  reloc = R_PARISC_SEGREL32;
  reloc = R_PARISC_SEGREL32;
  save_seg = now_seg;
  save_seg = now_seg;
  save_subseg = now_subseg;
  save_subseg = now_subseg;
  /* Get into the right seg/subseg.  This may involve creating
  /* Get into the right seg/subseg.  This may involve creating
     the seg the first time through.  Make sure to have the
     the seg the first time through.  Make sure to have the
     old seg/subseg so that we can reset things when we are done.  */
     old seg/subseg so that we can reset things when we are done.  */
  seg = bfd_get_section_by_name (stdoutput, UNWIND_SECTION_NAME);
  seg = bfd_get_section_by_name (stdoutput, UNWIND_SECTION_NAME);
  if (seg == ASEC_NULL)
  if (seg == ASEC_NULL)
    {
    {
      seg = subseg_new (UNWIND_SECTION_NAME, 0);
      seg = subseg_new (UNWIND_SECTION_NAME, 0);
      bfd_set_section_flags (stdoutput, seg,
      bfd_set_section_flags (stdoutput, seg,
                             SEC_READONLY | SEC_HAS_CONTENTS
                             SEC_READONLY | SEC_HAS_CONTENTS
                             | SEC_LOAD | SEC_RELOC | SEC_ALLOC | SEC_DATA);
                             | SEC_LOAD | SEC_RELOC | SEC_ALLOC | SEC_DATA);
      bfd_set_section_alignment (stdoutput, seg, 2);
      bfd_set_section_alignment (stdoutput, seg, 2);
    }
    }
 
 
  subseg_set (seg, 0);
  subseg_set (seg, 0);
 
 
  /* Get some space to hold relocation information for the unwind
  /* Get some space to hold relocation information for the unwind
     descriptor.  */
     descriptor.  */
  p = frag_more (16);
  p = frag_more (16);
 
 
  /* Relocation info. for start offset of the function.  */
  /* Relocation info. for start offset of the function.  */
  md_number_to_chars (p, 0, 4);
  md_number_to_chars (p, 0, 4);
  fix_new_hppa (frag_now, p - frag_now->fr_literal, 4,
  fix_new_hppa (frag_now, p - frag_now->fr_literal, 4,
                call_info->start_symbol, (offsetT) 0,
                call_info->start_symbol, (offsetT) 0,
                (expressionS *) NULL, 0, reloc,
                (expressionS *) NULL, 0, reloc,
                e_fsel, 32, 0, 0);
                e_fsel, 32, 0, 0);
 
 
  /* Relocation info. for end offset of the function.
  /* Relocation info. for end offset of the function.
 
 
     Because we allow reductions of 32bit relocations for ELF, this will be
     Because we allow reductions of 32bit relocations for ELF, this will be
     reduced to section_sym + offset which avoids putting the temporary
     reduced to section_sym + offset which avoids putting the temporary
     symbol into the symbol table.  It (should) end up giving the same
     symbol into the symbol table.  It (should) end up giving the same
     value as call_info->start_symbol + function size once the linker is
     value as call_info->start_symbol + function size once the linker is
     finished with its work.  */
     finished with its work.  */
  md_number_to_chars (p + 4, 0, 4);
  md_number_to_chars (p + 4, 0, 4);
  fix_new_hppa (frag_now, p + 4 - frag_now->fr_literal, 4,
  fix_new_hppa (frag_now, p + 4 - frag_now->fr_literal, 4,
                call_info->end_symbol, (offsetT) 0,
                call_info->end_symbol, (offsetT) 0,
                (expressionS *) NULL, 0, reloc,
                (expressionS *) NULL, 0, reloc,
                e_fsel, 32, 0, 0);
                e_fsel, 32, 0, 0);
 
 
  /* Dump the descriptor.  */
  /* Dump the descriptor.  */
  unwind = UNWIND_LOW32 (&call_info->ci_unwind.descriptor);
  unwind = UNWIND_LOW32 (&call_info->ci_unwind.descriptor);
  md_number_to_chars (p + 8, unwind, 4);
  md_number_to_chars (p + 8, unwind, 4);
 
 
  unwind = UNWIND_HIGH32 (&call_info->ci_unwind.descriptor);
  unwind = UNWIND_HIGH32 (&call_info->ci_unwind.descriptor);
  md_number_to_chars (p + 12, unwind, 4);
  md_number_to_chars (p + 12, unwind, 4);
 
 
  /* Return back to the original segment/subsegment.  */
  /* Return back to the original segment/subsegment.  */
  subseg_set (save_seg, save_subseg);
  subseg_set (save_seg, save_subseg);
}
}
#endif
#endif
 
 
/* Process a .CALLINFO pseudo-op.  This information is used later
/* Process a .CALLINFO pseudo-op.  This information is used later
   to build unwind descriptors and maybe one day to support
   to build unwind descriptors and maybe one day to support
   .ENTER and .LEAVE.  */
   .ENTER and .LEAVE.  */
 
 
static void
static void
pa_callinfo (int unused ATTRIBUTE_UNUSED)
pa_callinfo (int unused ATTRIBUTE_UNUSED)
{
{
  char *name, c, *p;
  char *name, c, *p;
  int temp;
  int temp;
 
 
#ifdef OBJ_SOM
#ifdef OBJ_SOM
  /* We must have a valid space and subspace.  */
  /* We must have a valid space and subspace.  */
  pa_check_current_space_and_subspace ();
  pa_check_current_space_and_subspace ();
#endif
#endif
 
 
  /* .CALLINFO must appear within a procedure definition.  */
  /* .CALLINFO must appear within a procedure definition.  */
  if (!within_procedure)
  if (!within_procedure)
    as_bad (_(".callinfo is not within a procedure definition"));
    as_bad (_(".callinfo is not within a procedure definition"));
 
 
  /* Mark the fact that we found the .CALLINFO for the
  /* Mark the fact that we found the .CALLINFO for the
     current procedure.  */
     current procedure.  */
  callinfo_found = TRUE;
  callinfo_found = TRUE;
 
 
  /* Iterate over the .CALLINFO arguments.  */
  /* Iterate over the .CALLINFO arguments.  */
  while (!is_end_of_statement ())
  while (!is_end_of_statement ())
    {
    {
      name = input_line_pointer;
      name = input_line_pointer;
      c = get_symbol_end ();
      c = get_symbol_end ();
      /* Frame size specification.  */
      /* Frame size specification.  */
      if ((strncasecmp (name, "frame", 5) == 0))
      if ((strncasecmp (name, "frame", 5) == 0))
        {
        {
          p = input_line_pointer;
          p = input_line_pointer;
          *p = c;
          *p = c;
          input_line_pointer++;
          input_line_pointer++;
          temp = get_absolute_expression ();
          temp = get_absolute_expression ();
          if ((temp & 0x3) != 0)
          if ((temp & 0x3) != 0)
            {
            {
              as_bad (_("FRAME parameter must be a multiple of 8: %d\n"), temp);
              as_bad (_("FRAME parameter must be a multiple of 8: %d\n"), temp);
              temp = 0;
              temp = 0;
            }
            }
 
 
          /* callinfo is in bytes and unwind_desc is in 8 byte units.  */
          /* callinfo is in bytes and unwind_desc is in 8 byte units.  */
          last_call_info->ci_unwind.descriptor.frame_size = temp / 8;
          last_call_info->ci_unwind.descriptor.frame_size = temp / 8;
 
 
        }
        }
      /* Entry register (GR, GR and SR) specifications.  */
      /* Entry register (GR, GR and SR) specifications.  */
      else if ((strncasecmp (name, "entry_gr", 8) == 0))
      else if ((strncasecmp (name, "entry_gr", 8) == 0))
        {
        {
          p = input_line_pointer;
          p = input_line_pointer;
          *p = c;
          *p = c;
          input_line_pointer++;
          input_line_pointer++;
          temp = get_absolute_expression ();
          temp = get_absolute_expression ();
          /* The HP assembler accepts 19 as the high bound for ENTRY_GR
          /* The HP assembler accepts 19 as the high bound for ENTRY_GR
             even though %r19 is caller saved.  I think this is a bug in
             even though %r19 is caller saved.  I think this is a bug in
             the HP assembler, and we are not going to emulate it.  */
             the HP assembler, and we are not going to emulate it.  */
          if (temp < 3 || temp > 18)
          if (temp < 3 || temp > 18)
            as_bad (_("Value for ENTRY_GR must be in the range 3..18\n"));
            as_bad (_("Value for ENTRY_GR must be in the range 3..18\n"));
          last_call_info->ci_unwind.descriptor.entry_gr = temp - 2;
          last_call_info->ci_unwind.descriptor.entry_gr = temp - 2;
        }
        }
      else if ((strncasecmp (name, "entry_fr", 8) == 0))
      else if ((strncasecmp (name, "entry_fr", 8) == 0))
        {
        {
          p = input_line_pointer;
          p = input_line_pointer;
          *p = c;
          *p = c;
          input_line_pointer++;
          input_line_pointer++;
          temp = get_absolute_expression ();
          temp = get_absolute_expression ();
          /* Similarly the HP assembler takes 31 as the high bound even
          /* Similarly the HP assembler takes 31 as the high bound even
             though %fr21 is the last callee saved floating point register.  */
             though %fr21 is the last callee saved floating point register.  */
          if (temp < 12 || temp > 21)
          if (temp < 12 || temp > 21)
            as_bad (_("Value for ENTRY_FR must be in the range 12..21\n"));
            as_bad (_("Value for ENTRY_FR must be in the range 12..21\n"));
          last_call_info->ci_unwind.descriptor.entry_fr = temp - 11;
          last_call_info->ci_unwind.descriptor.entry_fr = temp - 11;
        }
        }
      else if ((strncasecmp (name, "entry_sr", 8) == 0))
      else if ((strncasecmp (name, "entry_sr", 8) == 0))
        {
        {
          p = input_line_pointer;
          p = input_line_pointer;
          *p = c;
          *p = c;
          input_line_pointer++;
          input_line_pointer++;
          temp = get_absolute_expression ();
          temp = get_absolute_expression ();
          if (temp != 3)
          if (temp != 3)
            as_bad (_("Value for ENTRY_SR must be 3\n"));
            as_bad (_("Value for ENTRY_SR must be 3\n"));
        }
        }
      /* Note whether or not this function performs any calls.  */
      /* Note whether or not this function performs any calls.  */
      else if ((strncasecmp (name, "calls", 5) == 0) ||
      else if ((strncasecmp (name, "calls", 5) == 0) ||
               (strncasecmp (name, "caller", 6) == 0))
               (strncasecmp (name, "caller", 6) == 0))
        {
        {
          p = input_line_pointer;
          p = input_line_pointer;
          *p = c;
          *p = c;
        }
        }
      else if ((strncasecmp (name, "no_calls", 8) == 0))
      else if ((strncasecmp (name, "no_calls", 8) == 0))
        {
        {
          p = input_line_pointer;
          p = input_line_pointer;
          *p = c;
          *p = c;
        }
        }
      /* Should RP be saved into the stack.  */
      /* Should RP be saved into the stack.  */
      else if ((strncasecmp (name, "save_rp", 7) == 0))
      else if ((strncasecmp (name, "save_rp", 7) == 0))
        {
        {
          p = input_line_pointer;
          p = input_line_pointer;
          *p = c;
          *p = c;
          last_call_info->ci_unwind.descriptor.save_rp = 1;
          last_call_info->ci_unwind.descriptor.save_rp = 1;
        }
        }
      /* Likewise for SP.  */
      /* Likewise for SP.  */
      else if ((strncasecmp (name, "save_sp", 7) == 0))
      else if ((strncasecmp (name, "save_sp", 7) == 0))
        {
        {
          p = input_line_pointer;
          p = input_line_pointer;
          *p = c;
          *p = c;
          last_call_info->ci_unwind.descriptor.save_sp = 1;
          last_call_info->ci_unwind.descriptor.save_sp = 1;
        }
        }
      /* Is this an unwindable procedure.  If so mark it so
      /* Is this an unwindable procedure.  If so mark it so
         in the unwind descriptor.  */
         in the unwind descriptor.  */
      else if ((strncasecmp (name, "no_unwind", 9) == 0))
      else if ((strncasecmp (name, "no_unwind", 9) == 0))
        {
        {
          p = input_line_pointer;
          p = input_line_pointer;
          *p = c;
          *p = c;
          last_call_info->ci_unwind.descriptor.cannot_unwind = 1;
          last_call_info->ci_unwind.descriptor.cannot_unwind = 1;
        }
        }
      /* Is this an interrupt routine.  If so mark it in the
      /* Is this an interrupt routine.  If so mark it in the
         unwind descriptor.  */
         unwind descriptor.  */
      else if ((strncasecmp (name, "hpux_int", 7) == 0))
      else if ((strncasecmp (name, "hpux_int", 7) == 0))
        {
        {
          p = input_line_pointer;
          p = input_line_pointer;
          *p = c;
          *p = c;
          last_call_info->ci_unwind.descriptor.hpux_interrupt_marker = 1;
          last_call_info->ci_unwind.descriptor.hpux_interrupt_marker = 1;
        }
        }
      /* Is this a millicode routine.  "millicode" isn't in my
      /* Is this a millicode routine.  "millicode" isn't in my
         assembler manual, but my copy is old.  The HP assembler
         assembler manual, but my copy is old.  The HP assembler
         accepts it, and there's a place in the unwind descriptor
         accepts it, and there's a place in the unwind descriptor
         to drop the information, so we'll accept it too.  */
         to drop the information, so we'll accept it too.  */
      else if ((strncasecmp (name, "millicode", 9) == 0))
      else if ((strncasecmp (name, "millicode", 9) == 0))
        {
        {
          p = input_line_pointer;
          p = input_line_pointer;
          *p = c;
          *p = c;
          last_call_info->ci_unwind.descriptor.millicode = 1;
          last_call_info->ci_unwind.descriptor.millicode = 1;
        }
        }
      else
      else
        {
        {
          as_bad (_("Invalid .CALLINFO argument: %s"), name);
          as_bad (_("Invalid .CALLINFO argument: %s"), name);
          *input_line_pointer = c;
          *input_line_pointer = c;
        }
        }
      if (!is_end_of_statement ())
      if (!is_end_of_statement ())
        input_line_pointer++;
        input_line_pointer++;
    }
    }
 
 
  demand_empty_rest_of_line ();
  demand_empty_rest_of_line ();
}
}
 
 
#if !(defined (OBJ_ELF) && (defined (TE_LINUX) || defined (TE_NetBSD)))
#if !(defined (OBJ_ELF) && (defined (TE_LINUX) || defined (TE_NetBSD)))
/* Switch to the text space.  Like s_text, but delete our
/* Switch to the text space.  Like s_text, but delete our
   label when finished.  */
   label when finished.  */
 
 
static void
static void
pa_text (int unused ATTRIBUTE_UNUSED)
pa_text (int unused ATTRIBUTE_UNUSED)
{
{
#ifdef OBJ_SOM
#ifdef OBJ_SOM
  current_space = is_defined_space ("$TEXT$");
  current_space = is_defined_space ("$TEXT$");
  current_subspace
  current_subspace
    = pa_subsegment_to_subspace (current_space->sd_seg, 0);
    = pa_subsegment_to_subspace (current_space->sd_seg, 0);
#endif
#endif
 
 
  s_text (0);
  s_text (0);
  pa_undefine_label ();
  pa_undefine_label ();
}
}
 
 
/* Switch to the data space.  As usual delete our label.  */
/* Switch to the data space.  As usual delete our label.  */
 
 
static void
static void
pa_data (int unused ATTRIBUTE_UNUSED)
pa_data (int unused ATTRIBUTE_UNUSED)
{
{
#ifdef OBJ_SOM
#ifdef OBJ_SOM
  current_space = is_defined_space ("$PRIVATE$");
  current_space = is_defined_space ("$PRIVATE$");
  current_subspace
  current_subspace
    = pa_subsegment_to_subspace (current_space->sd_seg, 0);
    = pa_subsegment_to_subspace (current_space->sd_seg, 0);
#endif
#endif
  s_data (0);
  s_data (0);
  pa_undefine_label ();
  pa_undefine_label ();
}
}
 
 
/* This is different than the standard GAS s_comm(). On HP9000/800 machines,
/* This is different than the standard GAS s_comm(). On HP9000/800 machines,
   the .comm pseudo-op has the following syntax:
   the .comm pseudo-op has the following syntax:
 
 
   <label> .comm <length>
   <label> .comm <length>
 
 
   where <label> is optional and is a symbol whose address will be the start of
   where <label> is optional and is a symbol whose address will be the start of
   a block of memory <length> bytes long. <length> must be an absolute
   a block of memory <length> bytes long. <length> must be an absolute
   expression.  <length> bytes will be allocated in the current space
   expression.  <length> bytes will be allocated in the current space
   and subspace.
   and subspace.
 
 
   Also note the label may not even be on the same line as the .comm.
   Also note the label may not even be on the same line as the .comm.
 
 
   This difference in syntax means the colon function will be called
   This difference in syntax means the colon function will be called
   on the symbol before we arrive in pa_comm.  colon will set a number
   on the symbol before we arrive in pa_comm.  colon will set a number
   of attributes of the symbol that need to be fixed here.  In particular
   of attributes of the symbol that need to be fixed here.  In particular
   the value, section pointer, fragment pointer, flags, etc.  What
   the value, section pointer, fragment pointer, flags, etc.  What
   a pain.
   a pain.
 
 
   This also makes error detection all but impossible.  */
   This also makes error detection all but impossible.  */
 
 
static void
static void
pa_comm (int unused ATTRIBUTE_UNUSED)
pa_comm (int unused ATTRIBUTE_UNUSED)
{
{
  unsigned int size;
  unsigned int size;
  symbolS *symbol;
  symbolS *symbol;
  label_symbol_struct *label_symbol = pa_get_label ();
  label_symbol_struct *label_symbol = pa_get_label ();
 
 
  if (label_symbol)
  if (label_symbol)
    symbol = label_symbol->lss_label;
    symbol = label_symbol->lss_label;
  else
  else
    symbol = NULL;
    symbol = NULL;
 
 
  SKIP_WHITESPACE ();
  SKIP_WHITESPACE ();
  size = get_absolute_expression ();
  size = get_absolute_expression ();
 
 
  if (symbol)
  if (symbol)
    {
    {
      symbol_get_bfdsym (symbol)->flags |= BSF_OBJECT;
      symbol_get_bfdsym (symbol)->flags |= BSF_OBJECT;
      S_SET_VALUE (symbol, size);
      S_SET_VALUE (symbol, size);
      S_SET_SEGMENT (symbol, bfd_com_section_ptr);
      S_SET_SEGMENT (symbol, bfd_com_section_ptr);
      S_SET_EXTERNAL (symbol);
      S_SET_EXTERNAL (symbol);
 
 
      /* colon() has already set the frag to the current location in the
      /* colon() has already set the frag to the current location in the
         current subspace; we need to reset the fragment to the zero address
         current subspace; we need to reset the fragment to the zero address
         fragment.  We also need to reset the segment pointer.  */
         fragment.  We also need to reset the segment pointer.  */
      symbol_set_frag (symbol, &zero_address_frag);
      symbol_set_frag (symbol, &zero_address_frag);
    }
    }
  demand_empty_rest_of_line ();
  demand_empty_rest_of_line ();
}
}
#endif /* !(defined (OBJ_ELF) && (defined (TE_LINUX) || defined (TE_NetBSD))) */
#endif /* !(defined (OBJ_ELF) && (defined (TE_LINUX) || defined (TE_NetBSD))) */
 
 
/* Process a .END pseudo-op.  */
/* Process a .END pseudo-op.  */
 
 
static void
static void
pa_end (int unused ATTRIBUTE_UNUSED)
pa_end (int unused ATTRIBUTE_UNUSED)
{
{
  demand_empty_rest_of_line ();
  demand_empty_rest_of_line ();
}
}
 
 
/* Process a .ENTER pseudo-op.  This is not supported.  */
/* Process a .ENTER pseudo-op.  This is not supported.  */
 
 
static void
static void
pa_enter (int unused ATTRIBUTE_UNUSED)
pa_enter (int unused ATTRIBUTE_UNUSED)
{
{
#ifdef OBJ_SOM
#ifdef OBJ_SOM
  /* We must have a valid space and subspace.  */
  /* We must have a valid space and subspace.  */
  pa_check_current_space_and_subspace ();
  pa_check_current_space_and_subspace ();
#endif
#endif
 
 
  as_bad (_("The .ENTER pseudo-op is not supported"));
  as_bad (_("The .ENTER pseudo-op is not supported"));
  demand_empty_rest_of_line ();
  demand_empty_rest_of_line ();
}
}
 
 
/* Process a .ENTRY pseudo-op.  .ENTRY marks the beginning of the
/* Process a .ENTRY pseudo-op.  .ENTRY marks the beginning of the
   procedure.  */
   procedure.  */
 
 
static void
static void
pa_entry (int unused ATTRIBUTE_UNUSED)
pa_entry (int unused ATTRIBUTE_UNUSED)
{
{
#ifdef OBJ_SOM
#ifdef OBJ_SOM
  /* We must have a valid space and subspace.  */
  /* We must have a valid space and subspace.  */
  pa_check_current_space_and_subspace ();
  pa_check_current_space_and_subspace ();
#endif
#endif
 
 
  if (!within_procedure)
  if (!within_procedure)
    as_bad (_("Misplaced .entry. Ignored."));
    as_bad (_("Misplaced .entry. Ignored."));
  else
  else
    {
    {
      if (!callinfo_found)
      if (!callinfo_found)
        as_bad (_("Missing .callinfo."));
        as_bad (_("Missing .callinfo."));
    }
    }
  demand_empty_rest_of_line ();
  demand_empty_rest_of_line ();
  within_entry_exit = TRUE;
  within_entry_exit = TRUE;
 
 
#ifdef OBJ_SOM
#ifdef OBJ_SOM
  /* SOM defers building of unwind descriptors until the link phase.
  /* SOM defers building of unwind descriptors until the link phase.
     The assembler is responsible for creating an R_ENTRY relocation
     The assembler is responsible for creating an R_ENTRY relocation
     to mark the beginning of a region and hold the unwind bits, and
     to mark the beginning of a region and hold the unwind bits, and
     for creating an R_EXIT relocation to mark the end of the region.
     for creating an R_EXIT relocation to mark the end of the region.
 
 
     FIXME.  ELF should be using the same conventions!  The problem
     FIXME.  ELF should be using the same conventions!  The problem
     is an unwind requires too much relocation space.  Hmmm.  Maybe
     is an unwind requires too much relocation space.  Hmmm.  Maybe
     if we split the unwind bits up between the relocations which
     if we split the unwind bits up between the relocations which
     denote the entry and exit points.  */
     denote the entry and exit points.  */
  if (last_call_info->start_symbol != NULL)
  if (last_call_info->start_symbol != NULL)
    {
    {
      char *where;
      char *where;
      unsigned int u;
      unsigned int u;
 
 
      where = frag_more (0);
      where = frag_more (0);
      u = UNWIND_LOW32 (&last_call_info->ci_unwind.descriptor);
      u = UNWIND_LOW32 (&last_call_info->ci_unwind.descriptor);
      fix_new_hppa (frag_now, where - frag_now->fr_literal, 0,
      fix_new_hppa (frag_now, where - frag_now->fr_literal, 0,
                    NULL, (offsetT) 0, NULL,
                    NULL, (offsetT) 0, NULL,
                    0, R_HPPA_ENTRY, e_fsel, 0, 0, u);
                    0, R_HPPA_ENTRY, e_fsel, 0, 0, u);
    }
    }
#endif
#endif
}
}
 
 
/* Silly nonsense for pa_equ.  The only half-sensible use for this is
/* Silly nonsense for pa_equ.  The only half-sensible use for this is
   being able to subtract two register symbols that specify a range of
   being able to subtract two register symbols that specify a range of
   registers, to get the size of the range.  */
   registers, to get the size of the range.  */
static int fudge_reg_expressions;
static int fudge_reg_expressions;
 
 
int
int
hppa_force_reg_syms_absolute (expressionS *resultP,
hppa_force_reg_syms_absolute (expressionS *resultP,
                              operatorT op ATTRIBUTE_UNUSED,
                              operatorT op ATTRIBUTE_UNUSED,
                              expressionS *rightP)
                              expressionS *rightP)
{
{
  if (fudge_reg_expressions
  if (fudge_reg_expressions
      && rightP->X_op == O_register
      && rightP->X_op == O_register
      && resultP->X_op == O_register)
      && resultP->X_op == O_register)
    {
    {
      rightP->X_op = O_constant;
      rightP->X_op = O_constant;
      resultP->X_op = O_constant;
      resultP->X_op = O_constant;
    }
    }
  return 0;  /* Continue normal expr handling.  */
  return 0;  /* Continue normal expr handling.  */
}
}
 
 
/* Handle a .EQU pseudo-op.  */
/* Handle a .EQU pseudo-op.  */
 
 
static void
static void
pa_equ (int reg)
pa_equ (int reg)
{
{
  label_symbol_struct *label_symbol = pa_get_label ();
  label_symbol_struct *label_symbol = pa_get_label ();
  symbolS *symbol;
  symbolS *symbol;
 
 
  if (label_symbol)
  if (label_symbol)
    {
    {
      symbol = label_symbol->lss_label;
      symbol = label_symbol->lss_label;
      if (reg)
      if (reg)
        {
        {
          strict = 1;
          strict = 1;
          if (!pa_parse_number (&input_line_pointer, 0))
          if (!pa_parse_number (&input_line_pointer, 0))
            as_bad (_(".REG expression must be a register"));
            as_bad (_(".REG expression must be a register"));
          S_SET_VALUE (symbol, pa_number);
          S_SET_VALUE (symbol, pa_number);
          S_SET_SEGMENT (symbol, reg_section);
          S_SET_SEGMENT (symbol, reg_section);
        }
        }
      else
      else
        {
        {
          expressionS exp;
          expressionS exp;
          segT seg;
          segT seg;
 
 
          fudge_reg_expressions = 1;
          fudge_reg_expressions = 1;
          seg = expression (&exp);
          seg = expression (&exp);
          fudge_reg_expressions = 0;
          fudge_reg_expressions = 0;
          if (exp.X_op != O_constant
          if (exp.X_op != O_constant
              && exp.X_op != O_register)
              && exp.X_op != O_register)
            {
            {
              if (exp.X_op != O_absent)
              if (exp.X_op != O_absent)
                as_bad (_("bad or irreducible absolute expression; zero assumed"));
                as_bad (_("bad or irreducible absolute expression; zero assumed"));
              exp.X_add_number = 0;
              exp.X_add_number = 0;
              seg = absolute_section;
              seg = absolute_section;
            }
            }
          S_SET_VALUE (symbol, (unsigned int) exp.X_add_number);
          S_SET_VALUE (symbol, (unsigned int) exp.X_add_number);
          S_SET_SEGMENT (symbol, seg);
          S_SET_SEGMENT (symbol, seg);
        }
        }
    }
    }
  else
  else
    {
    {
      if (reg)
      if (reg)
        as_bad (_(".REG must use a label"));
        as_bad (_(".REG must use a label"));
      else
      else
        as_bad (_(".EQU must use a label"));
        as_bad (_(".EQU must use a label"));
    }
    }
 
 
  pa_undefine_label ();
  pa_undefine_label ();
  demand_empty_rest_of_line ();
  demand_empty_rest_of_line ();
}
}
 
 
#ifdef OBJ_ELF
#ifdef OBJ_ELF
/* Mark the end of a function so that it's possible to compute
/* Mark the end of a function so that it's possible to compute
   the size of the function in elf_hppa_final_processing.  */
   the size of the function in elf_hppa_final_processing.  */
 
 
static void
static void
hppa_elf_mark_end_of_function (void)
hppa_elf_mark_end_of_function (void)
{
{
  /* ELF does not have EXIT relocations.  All we do is create a
  /* ELF does not have EXIT relocations.  All we do is create a
     temporary symbol marking the end of the function.  */
     temporary symbol marking the end of the function.  */
  char *name;
  char *name;
 
 
  if (last_call_info == NULL || last_call_info->start_symbol == NULL)
  if (last_call_info == NULL || last_call_info->start_symbol == NULL)
    {
    {
      /* We have already warned about a missing label,
      /* We have already warned about a missing label,
         or other problems.  */
         or other problems.  */
      return;
      return;
    }
    }
 
 
  name = xmalloc (strlen ("L$\001end_")
  name = xmalloc (strlen ("L$\001end_")
                  + strlen (S_GET_NAME (last_call_info->start_symbol))
                  + strlen (S_GET_NAME (last_call_info->start_symbol))
                  + 1);
                  + 1);
  if (name)
  if (name)
    {
    {
      symbolS *symbolP;
      symbolS *symbolP;
 
 
      strcpy (name, "L$\001end_");
      strcpy (name, "L$\001end_");
      strcat (name, S_GET_NAME (last_call_info->start_symbol));
      strcat (name, S_GET_NAME (last_call_info->start_symbol));
 
 
      /* If we have a .exit followed by a .procend, then the
      /* If we have a .exit followed by a .procend, then the
         symbol will have already been defined.  */
         symbol will have already been defined.  */
      symbolP = symbol_find (name);
      symbolP = symbol_find (name);
      if (symbolP)
      if (symbolP)
        {
        {
          /* The symbol has already been defined!  This can
          /* The symbol has already been defined!  This can
             happen if we have a .exit followed by a .procend.
             happen if we have a .exit followed by a .procend.
 
 
             This is *not* an error.  All we want to do is free
             This is *not* an error.  All we want to do is free
             the memory we just allocated for the name and continue.  */
             the memory we just allocated for the name and continue.  */
          xfree (name);
          xfree (name);
        }
        }
      else
      else
        {
        {
          /* symbol value should be the offset of the
          /* symbol value should be the offset of the
             last instruction of the function */
             last instruction of the function */
          symbolP = symbol_new (name, now_seg, (valueT) (frag_now_fix () - 4),
          symbolP = symbol_new (name, now_seg, (valueT) (frag_now_fix () - 4),
                                frag_now);
                                frag_now);
 
 
          assert (symbolP);
          assert (symbolP);
          S_CLEAR_EXTERNAL (symbolP);
          S_CLEAR_EXTERNAL (symbolP);
          symbol_table_insert (symbolP);
          symbol_table_insert (symbolP);
        }
        }
 
 
      if (symbolP)
      if (symbolP)
        last_call_info->end_symbol = symbolP;
        last_call_info->end_symbol = symbolP;
      else
      else
        as_bad (_("Symbol '%s' could not be created."), name);
        as_bad (_("Symbol '%s' could not be created."), name);
 
 
    }
    }
  else
  else
    as_bad (_("No memory for symbol name."));
    as_bad (_("No memory for symbol name."));
}
}
#endif
#endif
 
 
/* Helper function.  Does processing for the end of a function.  This
/* Helper function.  Does processing for the end of a function.  This
   usually involves creating some relocations or building special
   usually involves creating some relocations or building special
   symbols to mark the end of the function.  */
   symbols to mark the end of the function.  */
 
 
static void
static void
process_exit (void)
process_exit (void)
{
{
  char *where;
  char *where;
 
 
  where = frag_more (0);
  where = frag_more (0);
 
 
#ifdef OBJ_ELF
#ifdef OBJ_ELF
  /* Mark the end of the function, stuff away the location of the frag
  /* Mark the end of the function, stuff away the location of the frag
     for the end of the function, and finally call pa_build_unwind_subspace
     for the end of the function, and finally call pa_build_unwind_subspace
     to add an entry in the unwind table.  */
     to add an entry in the unwind table.  */
  hppa_elf_mark_end_of_function ();
  hppa_elf_mark_end_of_function ();
  pa_build_unwind_subspace (last_call_info);
  pa_build_unwind_subspace (last_call_info);
#else
#else
  /* SOM defers building of unwind descriptors until the link phase.
  /* SOM defers building of unwind descriptors until the link phase.
     The assembler is responsible for creating an R_ENTRY relocation
     The assembler is responsible for creating an R_ENTRY relocation
     to mark the beginning of a region and hold the unwind bits, and
     to mark the beginning of a region and hold the unwind bits, and
     for creating an R_EXIT relocation to mark the end of the region.
     for creating an R_EXIT relocation to mark the end of the region.
 
 
     FIXME.  ELF should be using the same conventions!  The problem
     FIXME.  ELF should be using the same conventions!  The problem
     is an unwind requires too much relocation space.  Hmmm.  Maybe
     is an unwind requires too much relocation space.  Hmmm.  Maybe
     if we split the unwind bits up between the relocations which
     if we split the unwind bits up between the relocations which
     denote the entry and exit points.  */
     denote the entry and exit points.  */
  fix_new_hppa (frag_now, where - frag_now->fr_literal, 0,
  fix_new_hppa (frag_now, where - frag_now->fr_literal, 0,
                NULL, (offsetT) 0,
                NULL, (offsetT) 0,
                NULL, 0, R_HPPA_EXIT, e_fsel, 0, 0,
                NULL, 0, R_HPPA_EXIT, e_fsel, 0, 0,
                UNWIND_HIGH32 (&last_call_info->ci_unwind.descriptor));
                UNWIND_HIGH32 (&last_call_info->ci_unwind.descriptor));
#endif
#endif
}
}
 
 
/* Process a .EXIT pseudo-op.  */
/* Process a .EXIT pseudo-op.  */
 
 
static void
static void
pa_exit (int unused ATTRIBUTE_UNUSED)
pa_exit (int unused ATTRIBUTE_UNUSED)
{
{
#ifdef OBJ_SOM
#ifdef OBJ_SOM
  /* We must have a valid space and subspace.  */
  /* We must have a valid space and subspace.  */
  pa_check_current_space_and_subspace ();
  pa_check_current_space_and_subspace ();
#endif
#endif
 
 
  if (!within_procedure)
  if (!within_procedure)
    as_bad (_(".EXIT must appear within a procedure"));
    as_bad (_(".EXIT must appear within a procedure"));
  else
  else
    {
    {
      if (!callinfo_found)
      if (!callinfo_found)
        as_bad (_("Missing .callinfo"));
        as_bad (_("Missing .callinfo"));
      else
      else
        {
        {
          if (!within_entry_exit)
          if (!within_entry_exit)
            as_bad (_("No .ENTRY for this .EXIT"));
            as_bad (_("No .ENTRY for this .EXIT"));
          else
          else
            {
            {
              within_entry_exit = FALSE;
              within_entry_exit = FALSE;
              process_exit ();
              process_exit ();
            }
            }
        }
        }
    }
    }
  demand_empty_rest_of_line ();
  demand_empty_rest_of_line ();
}
}
 
 
/* Helper function to process arguments to a .EXPORT pseudo-op.  */
/* Helper function to process arguments to a .EXPORT pseudo-op.  */
 
 
static void
static void
pa_type_args (symbolS *symbolP, int is_export)
pa_type_args (symbolS *symbolP, int is_export)
{
{
  char *name, c, *p;
  char *name, c, *p;
  unsigned int temp, arg_reloc;
  unsigned int temp, arg_reloc;
  pa_symbol_type type = SYMBOL_TYPE_UNKNOWN;
  pa_symbol_type type = SYMBOL_TYPE_UNKNOWN;
  asymbol *bfdsym = symbol_get_bfdsym (symbolP);
  asymbol *bfdsym = symbol_get_bfdsym (symbolP);
 
 
  if (strncasecmp (input_line_pointer, "absolute", 8) == 0)
  if (strncasecmp (input_line_pointer, "absolute", 8) == 0)
    {
    {
      input_line_pointer += 8;
      input_line_pointer += 8;
      bfdsym->flags &= ~BSF_FUNCTION;
      bfdsym->flags &= ~BSF_FUNCTION;
      S_SET_SEGMENT (symbolP, bfd_abs_section_ptr);
      S_SET_SEGMENT (symbolP, bfd_abs_section_ptr);
      type = SYMBOL_TYPE_ABSOLUTE;
      type = SYMBOL_TYPE_ABSOLUTE;
    }
    }
  else if (strncasecmp (input_line_pointer, "code", 4) == 0)
  else if (strncasecmp (input_line_pointer, "code", 4) == 0)
    {
    {
      input_line_pointer += 4;
      input_line_pointer += 4;
      /* IMPORTing/EXPORTing CODE types for functions is meaningless for SOM,
      /* IMPORTing/EXPORTing CODE types for functions is meaningless for SOM,
         instead one should be IMPORTing/EXPORTing ENTRY types.
         instead one should be IMPORTing/EXPORTing ENTRY types.
 
 
         Complain if one tries to EXPORT a CODE type since that's never
         Complain if one tries to EXPORT a CODE type since that's never
         done.  Both GCC and HP C still try to IMPORT CODE types, so
         done.  Both GCC and HP C still try to IMPORT CODE types, so
         silently fix them to be ENTRY types.  */
         silently fix them to be ENTRY types.  */
      if (S_IS_FUNCTION (symbolP))
      if (S_IS_FUNCTION (symbolP))
        {
        {
          if (is_export)
          if (is_export)
            as_tsktsk (_("Using ENTRY rather than CODE in export directive for %s"),
            as_tsktsk (_("Using ENTRY rather than CODE in export directive for %s"),
                       S_GET_NAME (symbolP));
                       S_GET_NAME (symbolP));
 
 
          bfdsym->flags |= BSF_FUNCTION;
          bfdsym->flags |= BSF_FUNCTION;
          type = SYMBOL_TYPE_ENTRY;
          type = SYMBOL_TYPE_ENTRY;
        }
        }
      else
      else
        {
        {
          bfdsym->flags &= ~BSF_FUNCTION;
          bfdsym->flags &= ~BSF_FUNCTION;
          type = SYMBOL_TYPE_CODE;
          type = SYMBOL_TYPE_CODE;
        }
        }
    }
    }
  else if (strncasecmp (input_line_pointer, "data", 4) == 0)
  else if (strncasecmp (input_line_pointer, "data", 4) == 0)
    {
    {
      input_line_pointer += 4;
      input_line_pointer += 4;
      bfdsym->flags &= ~BSF_FUNCTION;
      bfdsym->flags &= ~BSF_FUNCTION;
      bfdsym->flags |= BSF_OBJECT;
      bfdsym->flags |= BSF_OBJECT;
      type = SYMBOL_TYPE_DATA;
      type = SYMBOL_TYPE_DATA;
    }
    }
  else if ((strncasecmp (input_line_pointer, "entry", 5) == 0))
  else if ((strncasecmp (input_line_pointer, "entry", 5) == 0))
    {
    {
      input_line_pointer += 5;
      input_line_pointer += 5;
      bfdsym->flags |= BSF_FUNCTION;
      bfdsym->flags |= BSF_FUNCTION;
      type = SYMBOL_TYPE_ENTRY;
      type = SYMBOL_TYPE_ENTRY;
    }
    }
  else if (strncasecmp (input_line_pointer, "millicode", 9) == 0)
  else if (strncasecmp (input_line_pointer, "millicode", 9) == 0)
    {
    {
      input_line_pointer += 9;
      input_line_pointer += 9;
      bfdsym->flags |= BSF_FUNCTION;
      bfdsym->flags |= BSF_FUNCTION;
#ifdef OBJ_ELF
#ifdef OBJ_ELF
      {
      {
        elf_symbol_type *elfsym = (elf_symbol_type *) bfdsym;
        elf_symbol_type *elfsym = (elf_symbol_type *) bfdsym;
        elfsym->internal_elf_sym.st_info =
        elfsym->internal_elf_sym.st_info =
          ELF_ST_INFO (ELF_ST_BIND (elfsym->internal_elf_sym.st_info),
          ELF_ST_INFO (ELF_ST_BIND (elfsym->internal_elf_sym.st_info),
                       STT_PARISC_MILLI);
                       STT_PARISC_MILLI);
      }
      }
#endif
#endif
      type = SYMBOL_TYPE_MILLICODE;
      type = SYMBOL_TYPE_MILLICODE;
    }
    }
  else if (strncasecmp (input_line_pointer, "plabel", 6) == 0)
  else if (strncasecmp (input_line_pointer, "plabel", 6) == 0)
    {
    {
      input_line_pointer += 6;
      input_line_pointer += 6;
      bfdsym->flags &= ~BSF_FUNCTION;
      bfdsym->flags &= ~BSF_FUNCTION;
      type = SYMBOL_TYPE_PLABEL;
      type = SYMBOL_TYPE_PLABEL;
    }
    }
  else if (strncasecmp (input_line_pointer, "pri_prog", 8) == 0)
  else if (strncasecmp (input_line_pointer, "pri_prog", 8) == 0)
    {
    {
      input_line_pointer += 8;
      input_line_pointer += 8;
      bfdsym->flags |= BSF_FUNCTION;
      bfdsym->flags |= BSF_FUNCTION;
      type = SYMBOL_TYPE_PRI_PROG;
      type = SYMBOL_TYPE_PRI_PROG;
    }
    }
  else if (strncasecmp (input_line_pointer, "sec_prog", 8) == 0)
  else if (strncasecmp (input_line_pointer, "sec_prog", 8) == 0)
    {
    {
      input_line_pointer += 8;
      input_line_pointer += 8;
      bfdsym->flags |= BSF_FUNCTION;
      bfdsym->flags |= BSF_FUNCTION;
      type = SYMBOL_TYPE_SEC_PROG;
      type = SYMBOL_TYPE_SEC_PROG;
    }
    }
 
 
  /* SOM requires much more information about symbol types
  /* SOM requires much more information about symbol types
     than BFD understands.  This is how we get this information
     than BFD understands.  This is how we get this information
     to the SOM BFD backend.  */
     to the SOM BFD backend.  */
#ifdef obj_set_symbol_type
#ifdef obj_set_symbol_type
  obj_set_symbol_type (bfdsym, (int) type);
  obj_set_symbol_type (bfdsym, (int) type);
#endif
#endif
 
 
  /* Now that the type of the exported symbol has been handled,
  /* Now that the type of the exported symbol has been handled,
     handle any argument relocation information.  */
     handle any argument relocation information.  */
  while (!is_end_of_statement ())
  while (!is_end_of_statement ())
    {
    {
      if (*input_line_pointer == ',')
      if (*input_line_pointer == ',')
        input_line_pointer++;
        input_line_pointer++;
      name = input_line_pointer;
      name = input_line_pointer;
      c = get_symbol_end ();
      c = get_symbol_end ();
      /* Argument sources.  */
      /* Argument sources.  */
      if ((strncasecmp (name, "argw", 4) == 0))
      if ((strncasecmp (name, "argw", 4) == 0))
        {
        {
          p = input_line_pointer;
          p = input_line_pointer;
          *p = c;
          *p = c;
          input_line_pointer++;
          input_line_pointer++;
          temp = atoi (name + 4);
          temp = atoi (name + 4);
          name = input_line_pointer;
          name = input_line_pointer;
          c = get_symbol_end ();
          c = get_symbol_end ();
          arg_reloc = pa_align_arg_reloc (temp, pa_build_arg_reloc (name));
          arg_reloc = pa_align_arg_reloc (temp, pa_build_arg_reloc (name));
#if defined (OBJ_SOM) || defined (ELF_ARG_RELOC)
#if defined (OBJ_SOM) || defined (ELF_ARG_RELOC)
          symbol_arg_reloc_info (symbolP) |= arg_reloc;
          symbol_arg_reloc_info (symbolP) |= arg_reloc;
#endif
#endif
          *input_line_pointer = c;
          *input_line_pointer = c;
        }
        }
      /* The return value.  */
      /* The return value.  */
      else if ((strncasecmp (name, "rtnval", 6)) == 0)
      else if ((strncasecmp (name, "rtnval", 6)) == 0)
        {
        {
          p = input_line_pointer;
          p = input_line_pointer;
          *p = c;
          *p = c;
          input_line_pointer++;
          input_line_pointer++;
          name = input_line_pointer;
          name = input_line_pointer;
          c = get_symbol_end ();
          c = get_symbol_end ();
          arg_reloc = pa_build_arg_reloc (name);
          arg_reloc = pa_build_arg_reloc (name);
#if defined (OBJ_SOM) || defined (ELF_ARG_RELOC)
#if defined (OBJ_SOM) || defined (ELF_ARG_RELOC)
          symbol_arg_reloc_info (symbolP) |= arg_reloc;
          symbol_arg_reloc_info (symbolP) |= arg_reloc;
#endif
#endif
          *input_line_pointer = c;
          *input_line_pointer = c;
        }
        }
      /* Privilege level.  */
      /* Privilege level.  */
      else if ((strncasecmp (name, "priv_lev", 8)) == 0)
      else if ((strncasecmp (name, "priv_lev", 8)) == 0)
        {
        {
          p = input_line_pointer;
          p = input_line_pointer;
          *p = c;
          *p = c;
          input_line_pointer++;
          input_line_pointer++;
          temp = atoi (input_line_pointer);
          temp = atoi (input_line_pointer);
#ifdef OBJ_SOM
#ifdef OBJ_SOM
          ((obj_symbol_type *) bfdsym)->tc_data.ap.hppa_priv_level = temp;
          ((obj_symbol_type *) bfdsym)->tc_data.ap.hppa_priv_level = temp;
#endif
#endif
          c = get_symbol_end ();
          c = get_symbol_end ();
          *input_line_pointer = c;
          *input_line_pointer = c;
        }
        }
      else
      else
        {
        {
          as_bad (_("Undefined .EXPORT/.IMPORT argument (ignored): %s"), name);
          as_bad (_("Undefined .EXPORT/.IMPORT argument (ignored): %s"), name);
          p = input_line_pointer;
          p = input_line_pointer;
          *p = c;
          *p = c;
        }
        }
      if (!is_end_of_statement ())
      if (!is_end_of_statement ())
        input_line_pointer++;
        input_line_pointer++;
    }
    }
}
}
 
 
/* Process a .EXPORT directive.  This makes functions external
/* Process a .EXPORT directive.  This makes functions external
   and provides information such as argument relocation entries
   and provides information such as argument relocation entries
   to callers.  */
   to callers.  */
 
 
static void
static void
pa_export (int unused ATTRIBUTE_UNUSED)
pa_export (int unused ATTRIBUTE_UNUSED)
{
{
  char *name, c, *p;
  char *name, c, *p;
  symbolS *symbol;
  symbolS *symbol;
 
 
  name = input_line_pointer;
  name = input_line_pointer;
  c = get_symbol_end ();
  c = get_symbol_end ();
  /* Make sure the given symbol exists.  */
  /* Make sure the given symbol exists.  */
  if ((symbol = symbol_find_or_make (name)) == NULL)
  if ((symbol = symbol_find_or_make (name)) == NULL)
    {
    {
      as_bad (_("Cannot define export symbol: %s\n"), name);
      as_bad (_("Cannot define export symbol: %s\n"), name);
      p = input_line_pointer;
      p = input_line_pointer;
      *p = c;
      *p = c;
      input_line_pointer++;
      input_line_pointer++;
    }
    }
  else
  else
    {
    {
      /* OK.  Set the external bits and process argument relocations.
      /* OK.  Set the external bits and process argument relocations.
         For the HP, weak and global are not mutually exclusive.
         For the HP, weak and global are not mutually exclusive.
         S_SET_EXTERNAL will not set BSF_GLOBAL if WEAK is set.
         S_SET_EXTERNAL will not set BSF_GLOBAL if WEAK is set.
         Call S_SET_EXTERNAL to get the other processing.  Manually
         Call S_SET_EXTERNAL to get the other processing.  Manually
         set BSF_GLOBAL when we get back.  */
         set BSF_GLOBAL when we get back.  */
      S_SET_EXTERNAL (symbol);
      S_SET_EXTERNAL (symbol);
      symbol_get_bfdsym (symbol)->flags |= BSF_GLOBAL;
      symbol_get_bfdsym (symbol)->flags |= BSF_GLOBAL;
      p = input_line_pointer;
      p = input_line_pointer;
      *p = c;
      *p = c;
      if (!is_end_of_statement ())
      if (!is_end_of_statement ())
        {
        {
          input_line_pointer++;
          input_line_pointer++;
          pa_type_args (symbol, 1);
          pa_type_args (symbol, 1);
        }
        }
    }
    }
 
 
  demand_empty_rest_of_line ();
  demand_empty_rest_of_line ();
}
}
 
 
/* Handle an .IMPORT pseudo-op.  Any symbol referenced in a given
/* Handle an .IMPORT pseudo-op.  Any symbol referenced in a given
   assembly file must either be defined in the assembly file, or
   assembly file must either be defined in the assembly file, or
   explicitly IMPORTED from another.  */
   explicitly IMPORTED from another.  */
 
 
static void
static void
pa_import (int unused ATTRIBUTE_UNUSED)
pa_import (int unused ATTRIBUTE_UNUSED)
{
{
  char *name, c, *p;
  char *name, c, *p;
  symbolS *symbol;
  symbolS *symbol;
 
 
  name = input_line_pointer;
  name = input_line_pointer;
  c = get_symbol_end ();
  c = get_symbol_end ();
 
 
  symbol = symbol_find (name);
  symbol = symbol_find (name);
  /* Ugh.  We might be importing a symbol defined earlier in the file,
  /* Ugh.  We might be importing a symbol defined earlier in the file,
     in which case all the code below will really screw things up
     in which case all the code below will really screw things up
     (set the wrong segment, symbol flags & type, etc).  */
     (set the wrong segment, symbol flags & type, etc).  */
  if (symbol == NULL || !S_IS_DEFINED (symbol))
  if (symbol == NULL || !S_IS_DEFINED (symbol))
    {
    {
      symbol = symbol_find_or_make (name);
      symbol = symbol_find_or_make (name);
      p = input_line_pointer;
      p = input_line_pointer;
      *p = c;
      *p = c;
 
 
      if (!is_end_of_statement ())
      if (!is_end_of_statement ())
        {
        {
          input_line_pointer++;
          input_line_pointer++;
          pa_type_args (symbol, 0);
          pa_type_args (symbol, 0);
        }
        }
      else
      else
        {
        {
          /* Sigh.  To be compatible with the HP assembler and to help
          /* Sigh.  To be compatible with the HP assembler and to help
             poorly written assembly code, we assign a type based on
             poorly written assembly code, we assign a type based on
             the current segment.  Note only BSF_FUNCTION really
             the current segment.  Note only BSF_FUNCTION really
             matters, we do not need to set the full SYMBOL_TYPE_* info.  */
             matters, we do not need to set the full SYMBOL_TYPE_* info.  */
          if (now_seg == text_section)
          if (now_seg == text_section)
            symbol_get_bfdsym (symbol)->flags |= BSF_FUNCTION;
            symbol_get_bfdsym (symbol)->flags |= BSF_FUNCTION;
 
 
          /* If the section is undefined, then the symbol is undefined
          /* If the section is undefined, then the symbol is undefined
             Since this is an import, leave the section undefined.  */
             Since this is an import, leave the section undefined.  */
          S_SET_SEGMENT (symbol, bfd_und_section_ptr);
          S_SET_SEGMENT (symbol, bfd_und_section_ptr);
        }
        }
    }
    }
  else
  else
    {
    {
      /* The symbol was already defined.  Just eat everything up to
      /* The symbol was already defined.  Just eat everything up to
         the end of the current statement.  */
         the end of the current statement.  */
      while (!is_end_of_statement ())
      while (!is_end_of_statement ())
        input_line_pointer++;
        input_line_pointer++;
    }
    }
 
 
  demand_empty_rest_of_line ();
  demand_empty_rest_of_line ();
}
}
 
 
/* Handle a .LABEL pseudo-op.  */
/* Handle a .LABEL pseudo-op.  */
 
 
static void
static void
pa_label (int unused ATTRIBUTE_UNUSED)
pa_label (int unused ATTRIBUTE_UNUSED)
{
{
  char *name, c, *p;
  char *name, c, *p;
 
 
  name = input_line_pointer;
  name = input_line_pointer;
  c = get_symbol_end ();
  c = get_symbol_end ();
 
 
  if (strlen (name) > 0)
  if (strlen (name) > 0)
    {
    {
      colon (name);
      colon (name);
      p = input_line_pointer;
      p = input_line_pointer;
      *p = c;
      *p = c;
    }
    }
  else
  else
    {
    {
      as_warn (_("Missing label name on .LABEL"));
      as_warn (_("Missing label name on .LABEL"));
    }
    }
 
 
  if (!is_end_of_statement ())
  if (!is_end_of_statement ())
    {
    {
      as_warn (_("extra .LABEL arguments ignored."));
      as_warn (_("extra .LABEL arguments ignored."));
      ignore_rest_of_line ();
      ignore_rest_of_line ();
    }
    }
  demand_empty_rest_of_line ();
  demand_empty_rest_of_line ();
}
}
 
 
/* Handle a .LEAVE pseudo-op.  This is not supported yet.  */
/* Handle a .LEAVE pseudo-op.  This is not supported yet.  */
 
 
static void
static void
pa_leave (int unused ATTRIBUTE_UNUSED)
pa_leave (int unused ATTRIBUTE_UNUSED)
{
{
#ifdef OBJ_SOM
#ifdef OBJ_SOM
  /* We must have a valid space and subspace.  */
  /* We must have a valid space and subspace.  */
  pa_check_current_space_and_subspace ();
  pa_check_current_space_and_subspace ();
#endif
#endif
 
 
  as_bad (_("The .LEAVE pseudo-op is not supported"));
  as_bad (_("The .LEAVE pseudo-op is not supported"));
  demand_empty_rest_of_line ();
  demand_empty_rest_of_line ();
}
}
 
 
/* Handle a .LEVEL pseudo-op.  */
/* Handle a .LEVEL pseudo-op.  */
 
 
static void
static void
pa_level (int unused ATTRIBUTE_UNUSED)
pa_level (int unused ATTRIBUTE_UNUSED)
{
{
  char *level;
  char *level;
 
 
  level = input_line_pointer;
  level = input_line_pointer;
  if (strncmp (level, "1.0", 3) == 0)
  if (strncmp (level, "1.0", 3) == 0)
    {
    {
      input_line_pointer += 3;
      input_line_pointer += 3;
      if (!bfd_set_arch_mach (stdoutput, bfd_arch_hppa, 10))
      if (!bfd_set_arch_mach (stdoutput, bfd_arch_hppa, 10))
        as_warn (_("could not set architecture and machine"));
        as_warn (_("could not set architecture and machine"));
    }
    }
  else if (strncmp (level, "1.1", 3) == 0)
  else if (strncmp (level, "1.1", 3) == 0)
    {
    {
      input_line_pointer += 3;
      input_line_pointer += 3;
      if (!bfd_set_arch_mach (stdoutput, bfd_arch_hppa, 11))
      if (!bfd_set_arch_mach (stdoutput, bfd_arch_hppa, 11))
        as_warn (_("could not set architecture and machine"));
        as_warn (_("could not set architecture and machine"));
    }
    }
  else if (strncmp (level, "2.0w", 4) == 0)
  else if (strncmp (level, "2.0w", 4) == 0)
    {
    {
      input_line_pointer += 4;
      input_line_pointer += 4;
      if (!bfd_set_arch_mach (stdoutput, bfd_arch_hppa, 25))
      if (!bfd_set_arch_mach (stdoutput, bfd_arch_hppa, 25))
        as_warn (_("could not set architecture and machine"));
        as_warn (_("could not set architecture and machine"));
    }
    }
  else if (strncmp (level, "2.0", 3) == 0)
  else if (strncmp (level, "2.0", 3) == 0)
    {
    {
      input_line_pointer += 3;
      input_line_pointer += 3;
      if (!bfd_set_arch_mach (stdoutput, bfd_arch_hppa, 20))
      if (!bfd_set_arch_mach (stdoutput, bfd_arch_hppa, 20))
        as_warn (_("could not set architecture and machine"));
        as_warn (_("could not set architecture and machine"));
    }
    }
  else
  else
    {
    {
      as_bad (_("Unrecognized .LEVEL argument\n"));
      as_bad (_("Unrecognized .LEVEL argument\n"));
      ignore_rest_of_line ();
      ignore_rest_of_line ();
    }
    }
  demand_empty_rest_of_line ();
  demand_empty_rest_of_line ();
}
}
 
 
/* Handle a .ORIGIN pseudo-op.  */
/* Handle a .ORIGIN pseudo-op.  */
 
 
static void
static void
pa_origin (int unused ATTRIBUTE_UNUSED)
pa_origin (int unused ATTRIBUTE_UNUSED)
{
{
#ifdef OBJ_SOM
#ifdef OBJ_SOM
  /* We must have a valid space and subspace.  */
  /* We must have a valid space and subspace.  */
  pa_check_current_space_and_subspace ();
  pa_check_current_space_and_subspace ();
#endif
#endif
 
 
  s_org (0);
  s_org (0);
  pa_undefine_label ();
  pa_undefine_label ();
}
}
 
 
/* Handle a .PARAM pseudo-op.  This is much like a .EXPORT, except it
/* Handle a .PARAM pseudo-op.  This is much like a .EXPORT, except it
   is for static functions.  FIXME.  Should share more code with .EXPORT.  */
   is for static functions.  FIXME.  Should share more code with .EXPORT.  */
 
 
static void
static void
pa_param (int unused ATTRIBUTE_UNUSED)
pa_param (int unused ATTRIBUTE_UNUSED)
{
{
  char *name, c, *p;
  char *name, c, *p;
  symbolS *symbol;
  symbolS *symbol;
 
 
  name = input_line_pointer;
  name = input_line_pointer;
  c = get_symbol_end ();
  c = get_symbol_end ();
 
 
  if ((symbol = symbol_find_or_make (name)) == NULL)
  if ((symbol = symbol_find_or_make (name)) == NULL)
    {
    {
      as_bad (_("Cannot define static symbol: %s\n"), name);
      as_bad (_("Cannot define static symbol: %s\n"), name);
      p = input_line_pointer;
      p = input_line_pointer;
      *p = c;
      *p = c;
      input_line_pointer++;
      input_line_pointer++;
    }
    }
  else
  else
    {
    {
      S_CLEAR_EXTERNAL (symbol);
      S_CLEAR_EXTERNAL (symbol);
      p = input_line_pointer;
      p = input_line_pointer;
      *p = c;
      *p = c;
      if (!is_end_of_statement ())
      if (!is_end_of_statement ())
        {
        {
          input_line_pointer++;
          input_line_pointer++;
          pa_type_args (symbol, 0);
          pa_type_args (symbol, 0);
        }
        }
    }
    }
 
 
  demand_empty_rest_of_line ();
  demand_empty_rest_of_line ();
}
}
 
 
/* Handle a .PROC pseudo-op.  It is used to mark the beginning
/* Handle a .PROC pseudo-op.  It is used to mark the beginning
   of a procedure from a syntactical point of view.  */
   of a procedure from a syntactical point of view.  */
 
 
static void
static void
pa_proc (int unused ATTRIBUTE_UNUSED)
pa_proc (int unused ATTRIBUTE_UNUSED)
{
{
  struct call_info *call_info;
  struct call_info *call_info;
 
 
#ifdef OBJ_SOM
#ifdef OBJ_SOM
  /* We must have a valid space and subspace.  */
  /* We must have a valid space and subspace.  */
  pa_check_current_space_and_subspace ();
  pa_check_current_space_and_subspace ();
#endif
#endif
 
 
  if (within_procedure)
  if (within_procedure)
    as_fatal (_("Nested procedures"));
    as_fatal (_("Nested procedures"));
 
 
  /* Reset global variables for new procedure.  */
  /* Reset global variables for new procedure.  */
  callinfo_found = FALSE;
  callinfo_found = FALSE;
  within_procedure = TRUE;
  within_procedure = TRUE;
 
 
  /* Create another call_info structure.  */
  /* Create another call_info structure.  */
  call_info = xmalloc (sizeof (struct call_info));
  call_info = xmalloc (sizeof (struct call_info));
 
 
  if (!call_info)
  if (!call_info)
    as_fatal (_("Cannot allocate unwind descriptor\n"));
    as_fatal (_("Cannot allocate unwind descriptor\n"));
 
 
  memset (call_info, 0, sizeof (struct call_info));
  memset (call_info, 0, sizeof (struct call_info));
 
 
  call_info->ci_next = NULL;
  call_info->ci_next = NULL;
 
 
  if (call_info_root == NULL)
  if (call_info_root == NULL)
    {
    {
      call_info_root = call_info;
      call_info_root = call_info;
      last_call_info = call_info;
      last_call_info = call_info;
    }
    }
  else
  else
    {
    {
      last_call_info->ci_next = call_info;
      last_call_info->ci_next = call_info;
      last_call_info = call_info;
      last_call_info = call_info;
    }
    }
 
 
  /* set up defaults on call_info structure */
  /* set up defaults on call_info structure */
 
 
  call_info->ci_unwind.descriptor.cannot_unwind = 0;
  call_info->ci_unwind.descriptor.cannot_unwind = 0;
  call_info->ci_unwind.descriptor.region_desc = 1;
  call_info->ci_unwind.descriptor.region_desc = 1;
  call_info->ci_unwind.descriptor.hpux_interrupt_marker = 0;
  call_info->ci_unwind.descriptor.hpux_interrupt_marker = 0;
 
 
  /* If we got a .PROC pseudo-op, we know that the function is defined
  /* If we got a .PROC pseudo-op, we know that the function is defined
     locally.  Make sure it gets into the symbol table.  */
     locally.  Make sure it gets into the symbol table.  */
  {
  {
    label_symbol_struct *label_symbol = pa_get_label ();
    label_symbol_struct *label_symbol = pa_get_label ();
 
 
    if (label_symbol)
    if (label_symbol)
      {
      {
        if (label_symbol->lss_label)
        if (label_symbol->lss_label)
          {
          {
            last_call_info->start_symbol = label_symbol->lss_label;
            last_call_info->start_symbol = label_symbol->lss_label;
            symbol_get_bfdsym (label_symbol->lss_label)->flags |= BSF_FUNCTION;
            symbol_get_bfdsym (label_symbol->lss_label)->flags |= BSF_FUNCTION;
          }
          }
        else
        else
          as_bad (_("Missing function name for .PROC (corrupted label chain)"));
          as_bad (_("Missing function name for .PROC (corrupted label chain)"));
      }
      }
    else
    else
      last_call_info->start_symbol = NULL;
      last_call_info->start_symbol = NULL;
  }
  }
 
 
  demand_empty_rest_of_line ();
  demand_empty_rest_of_line ();
}
}
 
 
/* Process the syntactical end of a procedure.  Make sure all the
/* Process the syntactical end of a procedure.  Make sure all the
   appropriate pseudo-ops were found within the procedure.  */
   appropriate pseudo-ops were found within the procedure.  */
 
 
static void
static void
pa_procend (int unused ATTRIBUTE_UNUSED)
pa_procend (int unused ATTRIBUTE_UNUSED)
{
{
#ifdef OBJ_SOM
#ifdef OBJ_SOM
  /* We must have a valid space and subspace.  */
  /* We must have a valid space and subspace.  */
  pa_check_current_space_and_subspace ();
  pa_check_current_space_and_subspace ();
#endif
#endif
 
 
  /* If we are within a procedure definition, make sure we've
  /* If we are within a procedure definition, make sure we've
     defined a label for the procedure; handle case where the
     defined a label for the procedure; handle case where the
     label was defined after the .PROC directive.
     label was defined after the .PROC directive.
 
 
     Note there's not need to diddle with the segment or fragment
     Note there's not need to diddle with the segment or fragment
     for the label symbol in this case.  We have already switched
     for the label symbol in this case.  We have already switched
     into the new $CODE$ subspace at this point.  */
     into the new $CODE$ subspace at this point.  */
  if (within_procedure && last_call_info->start_symbol == NULL)
  if (within_procedure && last_call_info->start_symbol == NULL)
    {
    {
      label_symbol_struct *label_symbol = pa_get_label ();
      label_symbol_struct *label_symbol = pa_get_label ();
 
 
      if (label_symbol)
      if (label_symbol)
        {
        {
          if (label_symbol->lss_label)
          if (label_symbol->lss_label)
            {
            {
              last_call_info->start_symbol = label_symbol->lss_label;
              last_call_info->start_symbol = label_symbol->lss_label;
              symbol_get_bfdsym (label_symbol->lss_label)->flags
              symbol_get_bfdsym (label_symbol->lss_label)->flags
                |= BSF_FUNCTION;
                |= BSF_FUNCTION;
#ifdef OBJ_SOM
#ifdef OBJ_SOM
              /* Also handle allocation of a fixup to hold the unwind
              /* Also handle allocation of a fixup to hold the unwind
                 information when the label appears after the proc/procend.  */
                 information when the label appears after the proc/procend.  */
              if (within_entry_exit)
              if (within_entry_exit)
                {
                {
                  char *where;
                  char *where;
                  unsigned int u;
                  unsigned int u;
 
 
                  where = frag_more (0);
                  where = frag_more (0);
                  u = UNWIND_LOW32 (&last_call_info->ci_unwind.descriptor);
                  u = UNWIND_LOW32 (&last_call_info->ci_unwind.descriptor);
                  fix_new_hppa (frag_now, where - frag_now->fr_literal, 0,
                  fix_new_hppa (frag_now, where - frag_now->fr_literal, 0,
                                NULL, (offsetT) 0, NULL,
                                NULL, (offsetT) 0, NULL,
                                0, R_HPPA_ENTRY, e_fsel, 0, 0, u);
                                0, R_HPPA_ENTRY, e_fsel, 0, 0, u);
                }
                }
#endif
#endif
            }
            }
          else
          else
            as_bad (_("Missing function name for .PROC (corrupted label chain)"));
            as_bad (_("Missing function name for .PROC (corrupted label chain)"));
        }
        }
      else
      else
        as_bad (_("Missing function name for .PROC"));
        as_bad (_("Missing function name for .PROC"));
    }
    }
 
 
  if (!within_procedure)
  if (!within_procedure)
    as_bad (_("misplaced .procend"));
    as_bad (_("misplaced .procend"));
 
 
  if (!callinfo_found)
  if (!callinfo_found)
    as_bad (_("Missing .callinfo for this procedure"));
    as_bad (_("Missing .callinfo for this procedure"));
 
 
  if (within_entry_exit)
  if (within_entry_exit)
    as_bad (_("Missing .EXIT for a .ENTRY"));
    as_bad (_("Missing .EXIT for a .ENTRY"));
 
 
#ifdef OBJ_ELF
#ifdef OBJ_ELF
  /* ELF needs to mark the end of each function so that it can compute
  /* ELF needs to mark the end of each function so that it can compute
     the size of the function (apparently its needed in the symbol table).  */
     the size of the function (apparently its needed in the symbol table).  */
  hppa_elf_mark_end_of_function ();
  hppa_elf_mark_end_of_function ();
#endif
#endif
 
 
  within_procedure = FALSE;
  within_procedure = FALSE;
  demand_empty_rest_of_line ();
  demand_empty_rest_of_line ();
  pa_undefine_label ();
  pa_undefine_label ();
}
}
 
 
#ifdef OBJ_SOM
#ifdef OBJ_SOM
/* If VALUE is an exact power of two between zero and 2^31, then
/* If VALUE is an exact power of two between zero and 2^31, then
   return log2 (VALUE).  Else return -1.  */
   return log2 (VALUE).  Else return -1.  */
 
 
static int
static int
exact_log2 (int value)
exact_log2 (int value)
{
{
  int shift = 0;
  int shift = 0;
 
 
  while ((1 << shift) != value && shift < 32)
  while ((1 << shift) != value && shift < 32)
    shift++;
    shift++;
 
 
  if (shift >= 32)
  if (shift >= 32)
    return -1;
    return -1;
  else
  else
    return shift;
    return shift;
}
}
 
 
/* Check to make sure we have a valid space and subspace.  */
/* Check to make sure we have a valid space and subspace.  */
 
 
static void
static void
pa_check_current_space_and_subspace (void)
pa_check_current_space_and_subspace (void)
{
{
  if (current_space == NULL)
  if (current_space == NULL)
    as_fatal (_("Not in a space.\n"));
    as_fatal (_("Not in a space.\n"));
 
 
  if (current_subspace == NULL)
  if (current_subspace == NULL)
    as_fatal (_("Not in a subspace.\n"));
    as_fatal (_("Not in a subspace.\n"));
}
}
 
 
/* Parse the parameters to a .SPACE directive; if CREATE_FLAG is nonzero,
/* Parse the parameters to a .SPACE directive; if CREATE_FLAG is nonzero,
   then create a new space entry to hold the information specified
   then create a new space entry to hold the information specified
   by the parameters to the .SPACE directive.  */
   by the parameters to the .SPACE directive.  */
 
 
static sd_chain_struct *
static sd_chain_struct *
pa_parse_space_stmt (char *space_name, int create_flag)
pa_parse_space_stmt (char *space_name, int create_flag)
{
{
  char *name, *ptemp, c;
  char *name, *ptemp, c;
  char loadable, defined, private, sort;
  char loadable, defined, private, sort;
  int spnum;
  int spnum;
  asection *seg = NULL;
  asection *seg = NULL;
  sd_chain_struct *space;
  sd_chain_struct *space;
 
 
  /* Load default values.  */
  /* Load default values.  */
  spnum = 0;
  spnum = 0;
  sort = 0;
  sort = 0;
  loadable = TRUE;
  loadable = TRUE;
  defined = TRUE;
  defined = TRUE;
  private = FALSE;
  private = FALSE;
  if (strcmp (space_name, "$TEXT$") == 0)
  if (strcmp (space_name, "$TEXT$") == 0)
    {
    {
      seg = pa_def_spaces[0].segment;
      seg = pa_def_spaces[0].segment;
      defined = pa_def_spaces[0].defined;
      defined = pa_def_spaces[0].defined;
      private = pa_def_spaces[0].private;
      private = pa_def_spaces[0].private;
      sort = pa_def_spaces[0].sort;
      sort = pa_def_spaces[0].sort;
      spnum = pa_def_spaces[0].spnum;
      spnum = pa_def_spaces[0].spnum;
    }
    }
  else if (strcmp (space_name, "$PRIVATE$") == 0)
  else if (strcmp (space_name, "$PRIVATE$") == 0)
    {
    {
      seg = pa_def_spaces[1].segment;
      seg = pa_def_spaces[1].segment;
      defined = pa_def_spaces[1].defined;
      defined = pa_def_spaces[1].defined;
      private = pa_def_spaces[1].private;
      private = pa_def_spaces[1].private;
      sort = pa_def_spaces[1].sort;
      sort = pa_def_spaces[1].sort;
      spnum = pa_def_spaces[1].spnum;
      spnum = pa_def_spaces[1].spnum;
    }
    }
 
 
  if (!is_end_of_statement ())
  if (!is_end_of_statement ())
    {
    {
      print_errors = FALSE;
      print_errors = FALSE;
      ptemp = input_line_pointer + 1;
      ptemp = input_line_pointer + 1;
      /* First see if the space was specified as a number rather than
      /* First see if the space was specified as a number rather than
         as a name.  According to the PA assembly manual the rest of
         as a name.  According to the PA assembly manual the rest of
         the line should be ignored.  */
         the line should be ignored.  */
      strict = 0;
      strict = 0;
      pa_parse_number (&ptemp, 0);
      pa_parse_number (&ptemp, 0);
      if (pa_number >= 0)
      if (pa_number >= 0)
        {
        {
          spnum = pa_number;
          spnum = pa_number;
          input_line_pointer = ptemp;
          input_line_pointer = ptemp;
        }
        }
      else
      else
        {
        {
          while (!is_end_of_statement ())
          while (!is_end_of_statement ())
            {
            {
              input_line_pointer++;
              input_line_pointer++;
              name = input_line_pointer;
              name = input_line_pointer;
              c = get_symbol_end ();
              c = get_symbol_end ();
              if ((strncasecmp (name, "spnum", 5) == 0))
              if ((strncasecmp (name, "spnum", 5) == 0))
                {
                {
                  *input_line_pointer = c;
                  *input_line_pointer = c;
                  input_line_pointer++;
                  input_line_pointer++;
                  spnum = get_absolute_expression ();
                  spnum = get_absolute_expression ();
                }
                }
              else if ((strncasecmp (name, "sort", 4) == 0))
              else if ((strncasecmp (name, "sort", 4) == 0))
                {
                {
                  *input_line_pointer = c;
                  *input_line_pointer = c;
                  input_line_pointer++;
                  input_line_pointer++;
                  sort = get_absolute_expression ();
                  sort = get_absolute_expression ();
                }
                }
              else if ((strncasecmp (name, "unloadable", 10) == 0))
              else if ((strncasecmp (name, "unloadable", 10) == 0))
                {
                {
                  *input_line_pointer = c;
                  *input_line_pointer = c;
                  loadable = FALSE;
                  loadable = FALSE;
                }
                }
              else if ((strncasecmp (name, "notdefined", 10) == 0))
              else if ((strncasecmp (name, "notdefined", 10) == 0))
                {
                {
                  *input_line_pointer = c;
                  *input_line_pointer = c;
                  defined = FALSE;
                  defined = FALSE;
                }
                }
              else if ((strncasecmp (name, "private", 7) == 0))
              else if ((strncasecmp (name, "private", 7) == 0))
                {
                {
                  *input_line_pointer = c;
                  *input_line_pointer = c;
                  private = TRUE;
                  private = TRUE;
                }
                }
              else
              else
                {
                {
                  as_bad (_("Invalid .SPACE argument"));
                  as_bad (_("Invalid .SPACE argument"));
                  *input_line_pointer = c;
                  *input_line_pointer = c;
                  if (!is_end_of_statement ())
                  if (!is_end_of_statement ())
                    input_line_pointer++;
                    input_line_pointer++;
                }
                }
            }
            }
        }
        }
      print_errors = TRUE;
      print_errors = TRUE;
    }
    }
 
 
  if (create_flag && seg == NULL)
  if (create_flag && seg == NULL)
    seg = subseg_new (space_name, 0);
    seg = subseg_new (space_name, 0);
 
 
  /* If create_flag is nonzero, then create the new space with
  /* If create_flag is nonzero, then create the new space with
     the attributes computed above.  Else set the values in
     the attributes computed above.  Else set the values in
     an already existing space -- this can only happen for
     an already existing space -- this can only happen for
     the first occurrence of a built-in space.  */
     the first occurrence of a built-in space.  */
  if (create_flag)
  if (create_flag)
    space = create_new_space (space_name, spnum, loadable, defined,
    space = create_new_space (space_name, spnum, loadable, defined,
                              private, sort, seg, 1);
                              private, sort, seg, 1);
  else
  else
    {
    {
      space = is_defined_space (space_name);
      space = is_defined_space (space_name);
      SPACE_SPNUM (space) = spnum;
      SPACE_SPNUM (space) = spnum;
      SPACE_DEFINED (space) = defined & 1;
      SPACE_DEFINED (space) = defined & 1;
      SPACE_USER_DEFINED (space) = 1;
      SPACE_USER_DEFINED (space) = 1;
    }
    }
 
 
#ifdef obj_set_section_attributes
#ifdef obj_set_section_attributes
  obj_set_section_attributes (seg, defined, private, sort, spnum);
  obj_set_section_attributes (seg, defined, private, sort, spnum);
#endif
#endif
 
 
  return space;
  return space;
}
}
 
 
/* Handle a .SPACE pseudo-op; this switches the current space to the
/* Handle a .SPACE pseudo-op; this switches the current space to the
   given space, creating the new space if necessary.  */
   given space, creating the new space if necessary.  */
 
 
static void
static void
pa_space (int unused ATTRIBUTE_UNUSED)
pa_space (int unused ATTRIBUTE_UNUSED)
{
{
  char *name, c, *space_name, *save_s;
  char *name, c, *space_name, *save_s;
  sd_chain_struct *sd_chain;
  sd_chain_struct *sd_chain;
 
 
  if (within_procedure)
  if (within_procedure)
    {
    {
      as_bad (_("Can\'t change spaces within a procedure definition. Ignored"));
      as_bad (_("Can\'t change spaces within a procedure definition. Ignored"));
      ignore_rest_of_line ();
      ignore_rest_of_line ();
    }
    }
  else
  else
    {
    {
      /* Check for some of the predefined spaces.   FIXME: most of the code
      /* Check for some of the predefined spaces.   FIXME: most of the code
         below is repeated several times, can we extract the common parts
         below is repeated several times, can we extract the common parts
         and place them into a subroutine or something similar?  */
         and place them into a subroutine or something similar?  */
      /* FIXME Is this (and the next IF stmt) really right?
      /* FIXME Is this (and the next IF stmt) really right?
         What if INPUT_LINE_POINTER points to "$TEXT$FOO"?  */
         What if INPUT_LINE_POINTER points to "$TEXT$FOO"?  */
      if (strncmp (input_line_pointer, "$TEXT$", 6) == 0)
      if (strncmp (input_line_pointer, "$TEXT$", 6) == 0)
        {
        {
          input_line_pointer += 6;
          input_line_pointer += 6;
          sd_chain = is_defined_space ("$TEXT$");
          sd_chain = is_defined_space ("$TEXT$");
          if (sd_chain == NULL)
          if (sd_chain == NULL)
            sd_chain = pa_parse_space_stmt ("$TEXT$", 1);
            sd_chain = pa_parse_space_stmt ("$TEXT$", 1);
          else if (SPACE_USER_DEFINED (sd_chain) == 0)
          else if (SPACE_USER_DEFINED (sd_chain) == 0)
            sd_chain = pa_parse_space_stmt ("$TEXT$", 0);
            sd_chain = pa_parse_space_stmt ("$TEXT$", 0);
 
 
          current_space = sd_chain;
          current_space = sd_chain;
          subseg_set (text_section, sd_chain->sd_last_subseg);
          subseg_set (text_section, sd_chain->sd_last_subseg);
          current_subspace
          current_subspace
            = pa_subsegment_to_subspace (text_section,
            = pa_subsegment_to_subspace (text_section,
                                         sd_chain->sd_last_subseg);
                                         sd_chain->sd_last_subseg);
          demand_empty_rest_of_line ();
          demand_empty_rest_of_line ();
          return;
          return;
        }
        }
      if (strncmp (input_line_pointer, "$PRIVATE$", 9) == 0)
      if (strncmp (input_line_pointer, "$PRIVATE$", 9) == 0)
        {
        {
          input_line_pointer += 9;
          input_line_pointer += 9;
          sd_chain = is_defined_space ("$PRIVATE$");
          sd_chain = is_defined_space ("$PRIVATE$");
          if (sd_chain == NULL)
          if (sd_chain == NULL)
            sd_chain = pa_parse_space_stmt ("$PRIVATE$", 1);
            sd_chain = pa_parse_space_stmt ("$PRIVATE$", 1);
          else if (SPACE_USER_DEFINED (sd_chain) == 0)
          else if (SPACE_USER_DEFINED (sd_chain) == 0)
            sd_chain = pa_parse_space_stmt ("$PRIVATE$", 0);
            sd_chain = pa_parse_space_stmt ("$PRIVATE$", 0);
 
 
          current_space = sd_chain;
          current_space = sd_chain;
          subseg_set (data_section, sd_chain->sd_last_subseg);
          subseg_set (data_section, sd_chain->sd_last_subseg);
          current_subspace
          current_subspace
            = pa_subsegment_to_subspace (data_section,
            = pa_subsegment_to_subspace (data_section,
                                         sd_chain->sd_last_subseg);
                                         sd_chain->sd_last_subseg);
          demand_empty_rest_of_line ();
          demand_empty_rest_of_line ();
          return;
          return;
        }
        }
      if (!strncasecmp (input_line_pointer,
      if (!strncasecmp (input_line_pointer,
                        GDB_DEBUG_SPACE_NAME,
                        GDB_DEBUG_SPACE_NAME,
                        strlen (GDB_DEBUG_SPACE_NAME)))
                        strlen (GDB_DEBUG_SPACE_NAME)))
        {
        {
          input_line_pointer += strlen (GDB_DEBUG_SPACE_NAME);
          input_line_pointer += strlen (GDB_DEBUG_SPACE_NAME);
          sd_chain = is_defined_space (GDB_DEBUG_SPACE_NAME);
          sd_chain = is_defined_space (GDB_DEBUG_SPACE_NAME);
          if (sd_chain == NULL)
          if (sd_chain == NULL)
            sd_chain = pa_parse_space_stmt (GDB_DEBUG_SPACE_NAME, 1);
            sd_chain = pa_parse_space_stmt (GDB_DEBUG_SPACE_NAME, 1);
          else if (SPACE_USER_DEFINED (sd_chain) == 0)
          else if (SPACE_USER_DEFINED (sd_chain) == 0)
            sd_chain = pa_parse_space_stmt (GDB_DEBUG_SPACE_NAME, 0);
            sd_chain = pa_parse_space_stmt (GDB_DEBUG_SPACE_NAME, 0);
 
 
          current_space = sd_chain;
          current_space = sd_chain;
 
 
          {
          {
            asection *gdb_section
            asection *gdb_section
            = bfd_make_section_old_way (stdoutput, GDB_DEBUG_SPACE_NAME);
            = bfd_make_section_old_way (stdoutput, GDB_DEBUG_SPACE_NAME);
 
 
            subseg_set (gdb_section, sd_chain->sd_last_subseg);
            subseg_set (gdb_section, sd_chain->sd_last_subseg);
            current_subspace
            current_subspace
              = pa_subsegment_to_subspace (gdb_section,
              = pa_subsegment_to_subspace (gdb_section,
                                           sd_chain->sd_last_subseg);
                                           sd_chain->sd_last_subseg);
          }
          }
          demand_empty_rest_of_line ();
          demand_empty_rest_of_line ();
          return;
          return;
        }
        }
 
 
      /* It could be a space specified by number.  */
      /* It could be a space specified by number.  */
      print_errors = 0;
      print_errors = 0;
      save_s = input_line_pointer;
      save_s = input_line_pointer;
      strict = 0;
      strict = 0;
      pa_parse_number (&input_line_pointer, 0);
      pa_parse_number (&input_line_pointer, 0);
      if (pa_number >= 0)
      if (pa_number >= 0)
        {
        {
          if ((sd_chain = pa_find_space_by_number (pa_number)))
          if ((sd_chain = pa_find_space_by_number (pa_number)))
            {
            {
              current_space = sd_chain;
              current_space = sd_chain;
 
 
              subseg_set (sd_chain->sd_seg, sd_chain->sd_last_subseg);
              subseg_set (sd_chain->sd_seg, sd_chain->sd_last_subseg);
              current_subspace
              current_subspace
                = pa_subsegment_to_subspace (sd_chain->sd_seg,
                = pa_subsegment_to_subspace (sd_chain->sd_seg,
                                             sd_chain->sd_last_subseg);
                                             sd_chain->sd_last_subseg);
              demand_empty_rest_of_line ();
              demand_empty_rest_of_line ();
              return;
              return;
            }
            }
        }
        }
 
 
      /* Not a number, attempt to create a new space.  */
      /* Not a number, attempt to create a new space.  */
      print_errors = 1;
      print_errors = 1;
      input_line_pointer = save_s;
      input_line_pointer = save_s;
      name = input_line_pointer;
      name = input_line_pointer;
      c = get_symbol_end ();
      c = get_symbol_end ();
      space_name = xmalloc (strlen (name) + 1);
      space_name = xmalloc (strlen (name) + 1);
      strcpy (space_name, name);
      strcpy (space_name, name);
      *input_line_pointer = c;
      *input_line_pointer = c;
 
 
      sd_chain = pa_parse_space_stmt (space_name, 1);
      sd_chain = pa_parse_space_stmt (space_name, 1);
      current_space = sd_chain;
      current_space = sd_chain;
 
 
      subseg_set (sd_chain->sd_seg, sd_chain->sd_last_subseg);
      subseg_set (sd_chain->sd_seg, sd_chain->sd_last_subseg);
      current_subspace = pa_subsegment_to_subspace (sd_chain->sd_seg,
      current_subspace = pa_subsegment_to_subspace (sd_chain->sd_seg,
                                                  sd_chain->sd_last_subseg);
                                                  sd_chain->sd_last_subseg);
      demand_empty_rest_of_line ();
      demand_empty_rest_of_line ();
    }
    }
}
}
 
 
/* Switch to a new space.  (I think).  FIXME.  */
/* Switch to a new space.  (I think).  FIXME.  */
 
 
static void
static void
pa_spnum (int unused ATTRIBUTE_UNUSED)
pa_spnum (int unused ATTRIBUTE_UNUSED)
{
{
  char *name;
  char *name;
  char c;
  char c;
  char *p;
  char *p;
  sd_chain_struct *space;
  sd_chain_struct *space;
 
 
  name = input_line_pointer;
  name = input_line_pointer;
  c = get_symbol_end ();
  c = get_symbol_end ();
  space = is_defined_space (name);
  space = is_defined_space (name);
  if (space)
  if (space)
    {
    {
      p = frag_more (4);
      p = frag_more (4);
      md_number_to_chars (p, SPACE_SPNUM (space), 4);
      md_number_to_chars (p, SPACE_SPNUM (space), 4);
    }
    }
  else
  else
    as_warn (_("Undefined space: '%s' Assuming space number = 0."), name);
    as_warn (_("Undefined space: '%s' Assuming space number = 0."), name);
 
 
  *input_line_pointer = c;
  *input_line_pointer = c;
  demand_empty_rest_of_line ();
  demand_empty_rest_of_line ();
}
}
 
 
/* Handle a .SUBSPACE pseudo-op; this switches the current subspace to the
/* Handle a .SUBSPACE pseudo-op; this switches the current subspace to the
   given subspace, creating the new subspace if necessary.
   given subspace, creating the new subspace if necessary.
 
 
   FIXME.  Should mirror pa_space more closely, in particular how
   FIXME.  Should mirror pa_space more closely, in particular how
   they're broken up into subroutines.  */
   they're broken up into subroutines.  */
 
 
static void
static void
pa_subspace (int create_new)
pa_subspace (int create_new)
{
{
  char *name, *ss_name, c;
  char *name, *ss_name, c;
  char loadable, code_only, comdat, common, dup_common, zero, sort;
  char loadable, code_only, comdat, common, dup_common, zero, sort;
  int i, access, space_index, alignment, quadrant, applicable, flags;
  int i, access, space_index, alignment, quadrant, applicable, flags;
  sd_chain_struct *space;
  sd_chain_struct *space;
  ssd_chain_struct *ssd;
  ssd_chain_struct *ssd;
  asection *section;
  asection *section;
 
 
  if (current_space == NULL)
  if (current_space == NULL)
    as_fatal (_("Must be in a space before changing or declaring subspaces.\n"));
    as_fatal (_("Must be in a space before changing or declaring subspaces.\n"));
 
 
  if (within_procedure)
  if (within_procedure)
    {
    {
      as_bad (_("Can\'t change subspaces within a procedure definition. Ignored"));
      as_bad (_("Can\'t change subspaces within a procedure definition. Ignored"));
      ignore_rest_of_line ();
      ignore_rest_of_line ();
    }
    }
  else
  else
    {
    {
      name = input_line_pointer;
      name = input_line_pointer;
      c = get_symbol_end ();
      c = get_symbol_end ();
      ss_name = xmalloc (strlen (name) + 1);
      ss_name = xmalloc (strlen (name) + 1);
      strcpy (ss_name, name);
      strcpy (ss_name, name);
      *input_line_pointer = c;
      *input_line_pointer = c;
 
 
      /* Load default values.  */
      /* Load default values.  */
      sort = 0;
      sort = 0;
      access = 0x7f;
      access = 0x7f;
      loadable = 1;
      loadable = 1;
      comdat = 0;
      comdat = 0;
      common = 0;
      common = 0;
      dup_common = 0;
      dup_common = 0;
      code_only = 0;
      code_only = 0;
      zero = 0;
      zero = 0;
      space_index = ~0;
      space_index = ~0;
      alignment = 1;
      alignment = 1;
      quadrant = 0;
      quadrant = 0;
 
 
      space = current_space;
      space = current_space;
      if (create_new)
      if (create_new)
        ssd = NULL;
        ssd = NULL;
      else
      else
        ssd = is_defined_subspace (ss_name);
        ssd = is_defined_subspace (ss_name);
      /* Allow user to override the builtin attributes of subspaces.  But
      /* Allow user to override the builtin attributes of subspaces.  But
         only allow the attributes to be changed once!  */
         only allow the attributes to be changed once!  */
      if (ssd && SUBSPACE_DEFINED (ssd))
      if (ssd && SUBSPACE_DEFINED (ssd))
        {
        {
          subseg_set (ssd->ssd_seg, ssd->ssd_subseg);
          subseg_set (ssd->ssd_seg, ssd->ssd_subseg);
          current_subspace = ssd;
          current_subspace = ssd;
          if (!is_end_of_statement ())
          if (!is_end_of_statement ())
            as_warn (_("Parameters of an existing subspace can\'t be modified"));
            as_warn (_("Parameters of an existing subspace can\'t be modified"));
          demand_empty_rest_of_line ();
          demand_empty_rest_of_line ();
          return;
          return;
        }
        }
      else
      else
        {
        {
          /* A new subspace.  Load default values if it matches one of
          /* A new subspace.  Load default values if it matches one of
             the builtin subspaces.  */
             the builtin subspaces.  */
          i = 0;
          i = 0;
          while (pa_def_subspaces[i].name)
          while (pa_def_subspaces[i].name)
            {
            {
              if (strcasecmp (pa_def_subspaces[i].name, ss_name) == 0)
              if (strcasecmp (pa_def_subspaces[i].name, ss_name) == 0)
                {
                {
                  loadable = pa_def_subspaces[i].loadable;
                  loadable = pa_def_subspaces[i].loadable;
                  comdat = pa_def_subspaces[i].comdat;
                  comdat = pa_def_subspaces[i].comdat;
                  common = pa_def_subspaces[i].common;
                  common = pa_def_subspaces[i].common;
                  dup_common = pa_def_subspaces[i].dup_common;
                  dup_common = pa_def_subspaces[i].dup_common;
                  code_only = pa_def_subspaces[i].code_only;
                  code_only = pa_def_subspaces[i].code_only;
                  zero = pa_def_subspaces[i].zero;
                  zero = pa_def_subspaces[i].zero;
                  space_index = pa_def_subspaces[i].space_index;
                  space_index = pa_def_subspaces[i].space_index;
                  alignment = pa_def_subspaces[i].alignment;
                  alignment = pa_def_subspaces[i].alignment;
                  quadrant = pa_def_subspaces[i].quadrant;
                  quadrant = pa_def_subspaces[i].quadrant;
                  access = pa_def_subspaces[i].access;
                  access = pa_def_subspaces[i].access;
                  sort = pa_def_subspaces[i].sort;
                  sort = pa_def_subspaces[i].sort;
                  break;
                  break;
                }
                }
              i++;
              i++;
            }
            }
        }
        }
 
 
      /* We should be working with a new subspace now.  Fill in
      /* We should be working with a new subspace now.  Fill in
         any information as specified by the user.  */
         any information as specified by the user.  */
      if (!is_end_of_statement ())
      if (!is_end_of_statement ())
        {
        {
          input_line_pointer++;
          input_line_pointer++;
          while (!is_end_of_statement ())
          while (!is_end_of_statement ())
            {
            {
              name = input_line_pointer;
              name = input_line_pointer;
              c = get_symbol_end ();
              c = get_symbol_end ();
              if ((strncasecmp (name, "quad", 4) == 0))
              if ((strncasecmp (name, "quad", 4) == 0))
                {
                {
                  *input_line_pointer = c;
                  *input_line_pointer = c;
                  input_line_pointer++;
                  input_line_pointer++;
                  quadrant = get_absolute_expression ();
                  quadrant = get_absolute_expression ();
                }
                }
              else if ((strncasecmp (name, "align", 5) == 0))
              else if ((strncasecmp (name, "align", 5) == 0))
                {
                {
                  *input_line_pointer = c;
                  *input_line_pointer = c;
                  input_line_pointer++;
                  input_line_pointer++;
                  alignment = get_absolute_expression ();
                  alignment = get_absolute_expression ();
                  if (exact_log2 (alignment) == -1)
                  if (exact_log2 (alignment) == -1)
                    {
                    {
                      as_bad (_("Alignment must be a power of 2"));
                      as_bad (_("Alignment must be a power of 2"));
                      alignment = 1;
                      alignment = 1;
                    }
                    }
                }
                }
              else if ((strncasecmp (name, "access", 6) == 0))
              else if ((strncasecmp (name, "access", 6) == 0))
                {
                {
                  *input_line_pointer = c;
                  *input_line_pointer = c;
                  input_line_pointer++;
                  input_line_pointer++;
                  access = get_absolute_expression ();
                  access = get_absolute_expression ();
                }
                }
              else if ((strncasecmp (name, "sort", 4) == 0))
              else if ((strncasecmp (name, "sort", 4) == 0))
                {
                {
                  *input_line_pointer = c;
                  *input_line_pointer = c;
                  input_line_pointer++;
                  input_line_pointer++;
                  sort = get_absolute_expression ();
                  sort = get_absolute_expression ();
                }
                }
              else if ((strncasecmp (name, "code_only", 9) == 0))
              else if ((strncasecmp (name, "code_only", 9) == 0))
                {
                {
                  *input_line_pointer = c;
                  *input_line_pointer = c;
                  code_only = 1;
                  code_only = 1;
                }
                }
              else if ((strncasecmp (name, "unloadable", 10) == 0))
              else if ((strncasecmp (name, "unloadable", 10) == 0))
                {
                {
                  *input_line_pointer = c;
                  *input_line_pointer = c;
                  loadable = 0;
                  loadable = 0;
                }
                }
              else if ((strncasecmp (name, "comdat", 6) == 0))
              else if ((strncasecmp (name, "comdat", 6) == 0))
                {
                {
                  *input_line_pointer = c;
                  *input_line_pointer = c;
                  comdat = 1;
                  comdat = 1;
                }
                }
              else if ((strncasecmp (name, "common", 6) == 0))
              else if ((strncasecmp (name, "common", 6) == 0))
                {
                {
                  *input_line_pointer = c;
                  *input_line_pointer = c;
                  common = 1;
                  common = 1;
                }
                }
              else if ((strncasecmp (name, "dup_comm", 8) == 0))
              else if ((strncasecmp (name, "dup_comm", 8) == 0))
                {
                {
                  *input_line_pointer = c;
                  *input_line_pointer = c;
                  dup_common = 1;
                  dup_common = 1;
                }
                }
              else if ((strncasecmp (name, "zero", 4) == 0))
              else if ((strncasecmp (name, "zero", 4) == 0))
                {
                {
                  *input_line_pointer = c;
                  *input_line_pointer = c;
                  zero = 1;
                  zero = 1;
                }
                }
              else if ((strncasecmp (name, "first", 5) == 0))
              else if ((strncasecmp (name, "first", 5) == 0))
                as_bad (_("FIRST not supported as a .SUBSPACE argument"));
                as_bad (_("FIRST not supported as a .SUBSPACE argument"));
              else
              else
                as_bad (_("Invalid .SUBSPACE argument"));
                as_bad (_("Invalid .SUBSPACE argument"));
              if (!is_end_of_statement ())
              if (!is_end_of_statement ())
                input_line_pointer++;
                input_line_pointer++;
            }
            }
        }
        }
 
 
      /* Compute a reasonable set of BFD flags based on the information
      /* Compute a reasonable set of BFD flags based on the information
         in the .subspace directive.  */
         in the .subspace directive.  */
      applicable = bfd_applicable_section_flags (stdoutput);
      applicable = bfd_applicable_section_flags (stdoutput);
      flags = 0;
      flags = 0;
      if (loadable)
      if (loadable)
        flags |= (SEC_ALLOC | SEC_LOAD);
        flags |= (SEC_ALLOC | SEC_LOAD);
      if (code_only)
      if (code_only)
        flags |= SEC_CODE;
        flags |= SEC_CODE;
 
 
      /* These flags are used to implement various flavors of initialized
      /* These flags are used to implement various flavors of initialized
         common.  The SOM linker discards duplicate subspaces when they
         common.  The SOM linker discards duplicate subspaces when they
         have the same "key" symbol name.  This support is more like
         have the same "key" symbol name.  This support is more like
         GNU linkonce than BFD common.  Further, pc-relative relocations
         GNU linkonce than BFD common.  Further, pc-relative relocations
         are converted to section relative relocations in BFD common
         are converted to section relative relocations in BFD common
         sections.  This complicates the handling of relocations in
         sections.  This complicates the handling of relocations in
         common sections containing text and isn't currently supported
         common sections containing text and isn't currently supported
         correctly in the SOM BFD backend.  */
         correctly in the SOM BFD backend.  */
      if (comdat || common || dup_common)
      if (comdat || common || dup_common)
        flags |= SEC_LINK_ONCE;
        flags |= SEC_LINK_ONCE;
 
 
      flags |= SEC_RELOC | SEC_HAS_CONTENTS;
      flags |= SEC_RELOC | SEC_HAS_CONTENTS;
 
 
      /* This is a zero-filled subspace (eg BSS).  */
      /* This is a zero-filled subspace (eg BSS).  */
      if (zero)
      if (zero)
        flags &= ~(SEC_LOAD | SEC_HAS_CONTENTS);
        flags &= ~(SEC_LOAD | SEC_HAS_CONTENTS);
 
 
      applicable &= flags;
      applicable &= flags;
 
 
      /* If this is an existing subspace, then we want to use the
      /* If this is an existing subspace, then we want to use the
         segment already associated with the subspace.
         segment already associated with the subspace.
 
 
         FIXME NOW!  ELF BFD doesn't appear to be ready to deal with
         FIXME NOW!  ELF BFD doesn't appear to be ready to deal with
         lots of sections.  It might be a problem in the PA ELF
         lots of sections.  It might be a problem in the PA ELF
         code, I do not know yet.  For now avoid creating anything
         code, I do not know yet.  For now avoid creating anything
         but the "standard" sections for ELF.  */
         but the "standard" sections for ELF.  */
      if (create_new)
      if (create_new)
        section = subseg_force_new (ss_name, 0);
        section = subseg_force_new (ss_name, 0);
      else if (ssd)
      else if (ssd)
        section = ssd->ssd_seg;
        section = ssd->ssd_seg;
      else
      else
        section = subseg_new (ss_name, 0);
        section = subseg_new (ss_name, 0);
 
 
      if (zero)
      if (zero)
        seg_info (section)->bss = 1;
        seg_info (section)->bss = 1;
 
 
      /* Now set the flags.  */
      /* Now set the flags.  */
      bfd_set_section_flags (stdoutput, section, applicable);
      bfd_set_section_flags (stdoutput, section, applicable);
 
 
      /* Record any alignment request for this section.  */
      /* Record any alignment request for this section.  */
      record_alignment (section, exact_log2 (alignment));
      record_alignment (section, exact_log2 (alignment));
 
 
      /* Set the starting offset for this section.  */
      /* Set the starting offset for this section.  */
      bfd_set_section_vma (stdoutput, section,
      bfd_set_section_vma (stdoutput, section,
                           pa_subspace_start (space, quadrant));
                           pa_subspace_start (space, quadrant));
 
 
      /* Now that all the flags are set, update an existing subspace,
      /* Now that all the flags are set, update an existing subspace,
         or create a new one.  */
         or create a new one.  */
      if (ssd)
      if (ssd)
 
 
        current_subspace = update_subspace (space, ss_name, loadable,
        current_subspace = update_subspace (space, ss_name, loadable,
                                            code_only, comdat, common,
                                            code_only, comdat, common,
                                            dup_common, sort, zero, access,
                                            dup_common, sort, zero, access,
                                            space_index, alignment, quadrant,
                                            space_index, alignment, quadrant,
                                            section);
                                            section);
      else
      else
        current_subspace = create_new_subspace (space, ss_name, loadable,
        current_subspace = create_new_subspace (space, ss_name, loadable,
                                                code_only, comdat, common,
                                                code_only, comdat, common,
                                                dup_common, zero, sort,
                                                dup_common, zero, sort,
                                                access, space_index,
                                                access, space_index,
                                                alignment, quadrant, section);
                                                alignment, quadrant, section);
 
 
      demand_empty_rest_of_line ();
      demand_empty_rest_of_line ();
      current_subspace->ssd_seg = section;
      current_subspace->ssd_seg = section;
      subseg_set (current_subspace->ssd_seg, current_subspace->ssd_subseg);
      subseg_set (current_subspace->ssd_seg, current_subspace->ssd_subseg);
    }
    }
  SUBSPACE_DEFINED (current_subspace) = 1;
  SUBSPACE_DEFINED (current_subspace) = 1;
}
}
 
 
/* Create default space and subspace dictionaries.  */
/* Create default space and subspace dictionaries.  */
 
 
static void
static void
pa_spaces_begin (void)
pa_spaces_begin (void)
{
{
  int i;
  int i;
 
 
  space_dict_root = NULL;
  space_dict_root = NULL;
  space_dict_last = NULL;
  space_dict_last = NULL;
 
 
  i = 0;
  i = 0;
  while (pa_def_spaces[i].name)
  while (pa_def_spaces[i].name)
    {
    {
      char *name;
      char *name;
 
 
      /* Pick the right name to use for the new section.  */
      /* Pick the right name to use for the new section.  */
      name = pa_def_spaces[i].name;
      name = pa_def_spaces[i].name;
 
 
      pa_def_spaces[i].segment = subseg_new (name, 0);
      pa_def_spaces[i].segment = subseg_new (name, 0);
      create_new_space (pa_def_spaces[i].name, pa_def_spaces[i].spnum,
      create_new_space (pa_def_spaces[i].name, pa_def_spaces[i].spnum,
                        pa_def_spaces[i].loadable, pa_def_spaces[i].defined,
                        pa_def_spaces[i].loadable, pa_def_spaces[i].defined,
                        pa_def_spaces[i].private, pa_def_spaces[i].sort,
                        pa_def_spaces[i].private, pa_def_spaces[i].sort,
                        pa_def_spaces[i].segment, 0);
                        pa_def_spaces[i].segment, 0);
      i++;
      i++;
    }
    }
 
 
  i = 0;
  i = 0;
  while (pa_def_subspaces[i].name)
  while (pa_def_subspaces[i].name)
    {
    {
      char *name;
      char *name;
      int applicable, subsegment;
      int applicable, subsegment;
      asection *segment = NULL;
      asection *segment = NULL;
      sd_chain_struct *space;
      sd_chain_struct *space;
 
 
      /* Pick the right name for the new section and pick the right
      /* Pick the right name for the new section and pick the right
         subsegment number.  */
         subsegment number.  */
      name = pa_def_subspaces[i].name;
      name = pa_def_subspaces[i].name;
      subsegment = 0;
      subsegment = 0;
 
 
      /* Create the new section.  */
      /* Create the new section.  */
      segment = subseg_new (name, subsegment);
      segment = subseg_new (name, subsegment);
 
 
      /* For SOM we want to replace the standard .text, .data, and .bss
      /* For SOM we want to replace the standard .text, .data, and .bss
         sections with our own.   We also want to set BFD flags for
         sections with our own.   We also want to set BFD flags for
         all the built-in subspaces.  */
         all the built-in subspaces.  */
      if (!strcmp (pa_def_subspaces[i].name, "$CODE$"))
      if (!strcmp (pa_def_subspaces[i].name, "$CODE$"))
        {
        {
          text_section = segment;
          text_section = segment;
          applicable = bfd_applicable_section_flags (stdoutput);
          applicable = bfd_applicable_section_flags (stdoutput);
          bfd_set_section_flags (stdoutput, segment,
          bfd_set_section_flags (stdoutput, segment,
                                 applicable & (SEC_ALLOC | SEC_LOAD
                                 applicable & (SEC_ALLOC | SEC_LOAD
                                               | SEC_RELOC | SEC_CODE
                                               | SEC_RELOC | SEC_CODE
                                               | SEC_READONLY
                                               | SEC_READONLY
                                               | SEC_HAS_CONTENTS));
                                               | SEC_HAS_CONTENTS));
        }
        }
      else if (!strcmp (pa_def_subspaces[i].name, "$DATA$"))
      else if (!strcmp (pa_def_subspaces[i].name, "$DATA$"))
        {
        {
          data_section = segment;
          data_section = segment;
          applicable = bfd_applicable_section_flags (stdoutput);
          applicable = bfd_applicable_section_flags (stdoutput);
          bfd_set_section_flags (stdoutput, segment,
          bfd_set_section_flags (stdoutput, segment,
                                 applicable & (SEC_ALLOC | SEC_LOAD
                                 applicable & (SEC_ALLOC | SEC_LOAD
                                               | SEC_RELOC
                                               | SEC_RELOC
                                               | SEC_HAS_CONTENTS));
                                               | SEC_HAS_CONTENTS));
 
 
        }
        }
      else if (!strcmp (pa_def_subspaces[i].name, "$BSS$"))
      else if (!strcmp (pa_def_subspaces[i].name, "$BSS$"))
        {
        {
          bss_section = segment;
          bss_section = segment;
          applicable = bfd_applicable_section_flags (stdoutput);
          applicable = bfd_applicable_section_flags (stdoutput);
          bfd_set_section_flags (stdoutput, segment,
          bfd_set_section_flags (stdoutput, segment,
                                 applicable & SEC_ALLOC);
                                 applicable & SEC_ALLOC);
        }
        }
      else if (!strcmp (pa_def_subspaces[i].name, "$LIT$"))
      else if (!strcmp (pa_def_subspaces[i].name, "$LIT$"))
        {
        {
          applicable = bfd_applicable_section_flags (stdoutput);
          applicable = bfd_applicable_section_flags (stdoutput);
          bfd_set_section_flags (stdoutput, segment,
          bfd_set_section_flags (stdoutput, segment,
                                 applicable & (SEC_ALLOC | SEC_LOAD
                                 applicable & (SEC_ALLOC | SEC_LOAD
                                               | SEC_RELOC
                                               | SEC_RELOC
                                               | SEC_READONLY
                                               | SEC_READONLY
                                               | SEC_HAS_CONTENTS));
                                               | SEC_HAS_CONTENTS));
        }
        }
      else if (!strcmp (pa_def_subspaces[i].name, "$MILLICODE$"))
      else if (!strcmp (pa_def_subspaces[i].name, "$MILLICODE$"))
        {
        {
          applicable = bfd_applicable_section_flags (stdoutput);
          applicable = bfd_applicable_section_flags (stdoutput);
          bfd_set_section_flags (stdoutput, segment,
          bfd_set_section_flags (stdoutput, segment,
                                 applicable & (SEC_ALLOC | SEC_LOAD
                                 applicable & (SEC_ALLOC | SEC_LOAD
                                               | SEC_RELOC
                                               | SEC_RELOC
                                               | SEC_READONLY
                                               | SEC_READONLY
                                               | SEC_HAS_CONTENTS));
                                               | SEC_HAS_CONTENTS));
        }
        }
      else if (!strcmp (pa_def_subspaces[i].name, "$UNWIND$"))
      else if (!strcmp (pa_def_subspaces[i].name, "$UNWIND$"))
        {
        {
          applicable = bfd_applicable_section_flags (stdoutput);
          applicable = bfd_applicable_section_flags (stdoutput);
          bfd_set_section_flags (stdoutput, segment,
          bfd_set_section_flags (stdoutput, segment,
                                 applicable & (SEC_ALLOC | SEC_LOAD
                                 applicable & (SEC_ALLOC | SEC_LOAD
                                               | SEC_RELOC
                                               | SEC_RELOC
                                               | SEC_READONLY
                                               | SEC_READONLY
                                               | SEC_HAS_CONTENTS));
                                               | SEC_HAS_CONTENTS));
        }
        }
 
 
      /* Find the space associated with this subspace.  */
      /* Find the space associated with this subspace.  */
      space = pa_segment_to_space (pa_def_spaces[pa_def_subspaces[i].
      space = pa_segment_to_space (pa_def_spaces[pa_def_subspaces[i].
                                                 def_space_index].segment);
                                                 def_space_index].segment);
      if (space == NULL)
      if (space == NULL)
        {
        {
          as_fatal (_("Internal error: Unable to find containing space for %s."),
          as_fatal (_("Internal error: Unable to find containing space for %s."),
                    pa_def_subspaces[i].name);
                    pa_def_subspaces[i].name);
        }
        }
 
 
      create_new_subspace (space, name,
      create_new_subspace (space, name,
                           pa_def_subspaces[i].loadable,
                           pa_def_subspaces[i].loadable,
                           pa_def_subspaces[i].code_only,
                           pa_def_subspaces[i].code_only,
                           pa_def_subspaces[i].comdat,
                           pa_def_subspaces[i].comdat,
                           pa_def_subspaces[i].common,
                           pa_def_subspaces[i].common,
                           pa_def_subspaces[i].dup_common,
                           pa_def_subspaces[i].dup_common,
                           pa_def_subspaces[i].zero,
                           pa_def_subspaces[i].zero,
                           pa_def_subspaces[i].sort,
                           pa_def_subspaces[i].sort,
                           pa_def_subspaces[i].access,
                           pa_def_subspaces[i].access,
                           pa_def_subspaces[i].space_index,
                           pa_def_subspaces[i].space_index,
                           pa_def_subspaces[i].alignment,
                           pa_def_subspaces[i].alignment,
                           pa_def_subspaces[i].quadrant,
                           pa_def_subspaces[i].quadrant,
                           segment);
                           segment);
      i++;
      i++;
    }
    }
}
}
 
 
/* Create a new space NAME, with the appropriate flags as defined
/* Create a new space NAME, with the appropriate flags as defined
   by the given parameters.  */
   by the given parameters.  */
 
 
static sd_chain_struct *
static sd_chain_struct *
create_new_space (char *name,
create_new_space (char *name,
                  int spnum,
                  int spnum,
                  int loadable ATTRIBUTE_UNUSED,
                  int loadable ATTRIBUTE_UNUSED,
                  int defined,
                  int defined,
                  int private,
                  int private,
                  int sort,
                  int sort,
                  asection *seg,
                  asection *seg,
                  int user_defined)
                  int user_defined)
{
{
  sd_chain_struct *chain_entry;
  sd_chain_struct *chain_entry;
 
 
  chain_entry = xmalloc (sizeof (sd_chain_struct));
  chain_entry = xmalloc (sizeof (sd_chain_struct));
  if (!chain_entry)
  if (!chain_entry)
    as_fatal (_("Out of memory: could not allocate new space chain entry: %s\n"),
    as_fatal (_("Out of memory: could not allocate new space chain entry: %s\n"),
              name);
              name);
 
 
  SPACE_NAME (chain_entry) = xmalloc (strlen (name) + 1);
  SPACE_NAME (chain_entry) = xmalloc (strlen (name) + 1);
  strcpy (SPACE_NAME (chain_entry), name);
  strcpy (SPACE_NAME (chain_entry), name);
  SPACE_DEFINED (chain_entry) = defined;
  SPACE_DEFINED (chain_entry) = defined;
  SPACE_USER_DEFINED (chain_entry) = user_defined;
  SPACE_USER_DEFINED (chain_entry) = user_defined;
  SPACE_SPNUM (chain_entry) = spnum;
  SPACE_SPNUM (chain_entry) = spnum;
 
 
  chain_entry->sd_seg = seg;
  chain_entry->sd_seg = seg;
  chain_entry->sd_last_subseg = -1;
  chain_entry->sd_last_subseg = -1;
  chain_entry->sd_subspaces = NULL;
  chain_entry->sd_subspaces = NULL;
  chain_entry->sd_next = NULL;
  chain_entry->sd_next = NULL;
 
 
  /* Find spot for the new space based on its sort key.  */
  /* Find spot for the new space based on its sort key.  */
  if (!space_dict_last)
  if (!space_dict_last)
    space_dict_last = chain_entry;
    space_dict_last = chain_entry;
 
 
  if (space_dict_root == NULL)
  if (space_dict_root == NULL)
    space_dict_root = chain_entry;
    space_dict_root = chain_entry;
  else
  else
    {
    {
      sd_chain_struct *chain_pointer;
      sd_chain_struct *chain_pointer;
      sd_chain_struct *prev_chain_pointer;
      sd_chain_struct *prev_chain_pointer;
 
 
      chain_pointer = space_dict_root;
      chain_pointer = space_dict_root;
      prev_chain_pointer = NULL;
      prev_chain_pointer = NULL;
 
 
      while (chain_pointer)
      while (chain_pointer)
        {
        {
          prev_chain_pointer = chain_pointer;
          prev_chain_pointer = chain_pointer;
          chain_pointer = chain_pointer->sd_next;
          chain_pointer = chain_pointer->sd_next;
        }
        }
 
 
      /* At this point we've found the correct place to add the new
      /* At this point we've found the correct place to add the new
         entry.  So add it and update the linked lists as appropriate.  */
         entry.  So add it and update the linked lists as appropriate.  */
      if (prev_chain_pointer)
      if (prev_chain_pointer)
        {
        {
          chain_entry->sd_next = chain_pointer;
          chain_entry->sd_next = chain_pointer;
          prev_chain_pointer->sd_next = chain_entry;
          prev_chain_pointer->sd_next = chain_entry;
        }
        }
      else
      else
        {
        {
          space_dict_root = chain_entry;
          space_dict_root = chain_entry;
          chain_entry->sd_next = chain_pointer;
          chain_entry->sd_next = chain_pointer;
        }
        }
 
 
      if (chain_entry->sd_next == NULL)
      if (chain_entry->sd_next == NULL)
        space_dict_last = chain_entry;
        space_dict_last = chain_entry;
    }
    }
 
 
  /* This is here to catch predefined spaces which do not get
  /* This is here to catch predefined spaces which do not get
     modified by the user's input.  Another call is found at
     modified by the user's input.  Another call is found at
     the bottom of pa_parse_space_stmt to handle cases where
     the bottom of pa_parse_space_stmt to handle cases where
     the user modifies a predefined space.  */
     the user modifies a predefined space.  */
#ifdef obj_set_section_attributes
#ifdef obj_set_section_attributes
  obj_set_section_attributes (seg, defined, private, sort, spnum);
  obj_set_section_attributes (seg, defined, private, sort, spnum);
#endif
#endif
 
 
  return chain_entry;
  return chain_entry;
}
}
 
 
/* Create a new subspace NAME, with the appropriate flags as defined
/* Create a new subspace NAME, with the appropriate flags as defined
   by the given parameters.
   by the given parameters.
 
 
   Add the new subspace to the subspace dictionary chain in numerical
   Add the new subspace to the subspace dictionary chain in numerical
   order as defined by the SORT entries.  */
   order as defined by the SORT entries.  */
 
 
static ssd_chain_struct *
static ssd_chain_struct *
create_new_subspace (sd_chain_struct *space,
create_new_subspace (sd_chain_struct *space,
                     char *name,
                     char *name,
                     int loadable ATTRIBUTE_UNUSED,
                     int loadable ATTRIBUTE_UNUSED,
                     int code_only ATTRIBUTE_UNUSED,
                     int code_only ATTRIBUTE_UNUSED,
                     int comdat,
                     int comdat,
                     int common,
                     int common,
                     int dup_common,
                     int dup_common,
                     int is_zero ATTRIBUTE_UNUSED,
                     int is_zero ATTRIBUTE_UNUSED,
                     int sort,
                     int sort,
                     int access,
                     int access,
                     int space_index ATTRIBUTE_UNUSED,
                     int space_index ATTRIBUTE_UNUSED,
                     int alignment ATTRIBUTE_UNUSED,
                     int alignment ATTRIBUTE_UNUSED,
                     int quadrant,
                     int quadrant,
                     asection *seg)
                     asection *seg)
{
{
  ssd_chain_struct *chain_entry;
  ssd_chain_struct *chain_entry;
 
 
  chain_entry = xmalloc (sizeof (ssd_chain_struct));
  chain_entry = xmalloc (sizeof (ssd_chain_struct));
  if (!chain_entry)
  if (!chain_entry)
    as_fatal (_("Out of memory: could not allocate new subspace chain entry: %s\n"), name);
    as_fatal (_("Out of memory: could not allocate new subspace chain entry: %s\n"), name);
 
 
  SUBSPACE_NAME (chain_entry) = xmalloc (strlen (name) + 1);
  SUBSPACE_NAME (chain_entry) = xmalloc (strlen (name) + 1);
  strcpy (SUBSPACE_NAME (chain_entry), name);
  strcpy (SUBSPACE_NAME (chain_entry), name);
 
 
  /* Initialize subspace_defined.  When we hit a .subspace directive
  /* Initialize subspace_defined.  When we hit a .subspace directive
     we'll set it to 1 which "locks-in" the subspace attributes.  */
     we'll set it to 1 which "locks-in" the subspace attributes.  */
  SUBSPACE_DEFINED (chain_entry) = 0;
  SUBSPACE_DEFINED (chain_entry) = 0;
 
 
  chain_entry->ssd_subseg = 0;
  chain_entry->ssd_subseg = 0;
  chain_entry->ssd_seg = seg;
  chain_entry->ssd_seg = seg;
  chain_entry->ssd_next = NULL;
  chain_entry->ssd_next = NULL;
 
 
  /* Find spot for the new subspace based on its sort key.  */
  /* Find spot for the new subspace based on its sort key.  */
  if (space->sd_subspaces == NULL)
  if (space->sd_subspaces == NULL)
    space->sd_subspaces = chain_entry;
    space->sd_subspaces = chain_entry;
  else
  else
    {
    {
      ssd_chain_struct *chain_pointer;
      ssd_chain_struct *chain_pointer;
      ssd_chain_struct *prev_chain_pointer;
      ssd_chain_struct *prev_chain_pointer;
 
 
      chain_pointer = space->sd_subspaces;
      chain_pointer = space->sd_subspaces;
      prev_chain_pointer = NULL;
      prev_chain_pointer = NULL;
 
 
      while (chain_pointer)
      while (chain_pointer)
        {
        {
          prev_chain_pointer = chain_pointer;
          prev_chain_pointer = chain_pointer;
          chain_pointer = chain_pointer->ssd_next;
          chain_pointer = chain_pointer->ssd_next;
        }
        }
 
 
      /* Now we have somewhere to put the new entry.  Insert it and update
      /* Now we have somewhere to put the new entry.  Insert it and update
         the links.  */
         the links.  */
      if (prev_chain_pointer)
      if (prev_chain_pointer)
        {
        {
          chain_entry->ssd_next = chain_pointer;
          chain_entry->ssd_next = chain_pointer;
          prev_chain_pointer->ssd_next = chain_entry;
          prev_chain_pointer->ssd_next = chain_entry;
        }
        }
      else
      else
        {
        {
          space->sd_subspaces = chain_entry;
          space->sd_subspaces = chain_entry;
          chain_entry->ssd_next = chain_pointer;
          chain_entry->ssd_next = chain_pointer;
        }
        }
    }
    }
 
 
#ifdef obj_set_subsection_attributes
#ifdef obj_set_subsection_attributes
  obj_set_subsection_attributes (seg, space->sd_seg, access, sort,
  obj_set_subsection_attributes (seg, space->sd_seg, access, sort,
                                 quadrant, comdat, common, dup_common);
                                 quadrant, comdat, common, dup_common);
#endif
#endif
 
 
  return chain_entry;
  return chain_entry;
}
}
 
 
/* Update the information for the given subspace based upon the
/* Update the information for the given subspace based upon the
   various arguments.   Return the modified subspace chain entry.  */
   various arguments.   Return the modified subspace chain entry.  */
 
 
static ssd_chain_struct *
static ssd_chain_struct *
update_subspace (sd_chain_struct *space,
update_subspace (sd_chain_struct *space,
                 char *name,
                 char *name,
                 int loadable ATTRIBUTE_UNUSED,
                 int loadable ATTRIBUTE_UNUSED,
                 int code_only ATTRIBUTE_UNUSED,
                 int code_only ATTRIBUTE_UNUSED,
                 int comdat,
                 int comdat,
                 int common,
                 int common,
                 int dup_common,
                 int dup_common,
                 int sort,
                 int sort,
                 int zero ATTRIBUTE_UNUSED,
                 int zero ATTRIBUTE_UNUSED,
                 int access,
                 int access,
                 int space_index ATTRIBUTE_UNUSED,
                 int space_index ATTRIBUTE_UNUSED,
                 int alignment ATTRIBUTE_UNUSED,
                 int alignment ATTRIBUTE_UNUSED,
                 int quadrant,
                 int quadrant,
                 asection *section)
                 asection *section)
{
{
  ssd_chain_struct *chain_entry;
  ssd_chain_struct *chain_entry;
 
 
  chain_entry = is_defined_subspace (name);
  chain_entry = is_defined_subspace (name);
 
 
#ifdef obj_set_subsection_attributes
#ifdef obj_set_subsection_attributes
  obj_set_subsection_attributes (section, space->sd_seg, access, sort,
  obj_set_subsection_attributes (section, space->sd_seg, access, sort,
                                 quadrant, comdat, common, dup_common);
                                 quadrant, comdat, common, dup_common);
#endif
#endif
 
 
  return chain_entry;
  return chain_entry;
}
}
 
 
/* Return the space chain entry for the space with the name NAME or
/* Return the space chain entry for the space with the name NAME or
   NULL if no such space exists.  */
   NULL if no such space exists.  */
 
 
static sd_chain_struct *
static sd_chain_struct *
is_defined_space (char *name)
is_defined_space (char *name)
{
{
  sd_chain_struct *chain_pointer;
  sd_chain_struct *chain_pointer;
 
 
  for (chain_pointer = space_dict_root;
  for (chain_pointer = space_dict_root;
       chain_pointer;
       chain_pointer;
       chain_pointer = chain_pointer->sd_next)
       chain_pointer = chain_pointer->sd_next)
    if (strcmp (SPACE_NAME (chain_pointer), name) == 0)
    if (strcmp (SPACE_NAME (chain_pointer), name) == 0)
      return chain_pointer;
      return chain_pointer;
 
 
  /* No mapping from segment to space was found.  Return NULL.  */
  /* No mapping from segment to space was found.  Return NULL.  */
  return NULL;
  return NULL;
}
}
 
 
/* Find and return the space associated with the given seg.  If no mapping
/* Find and return the space associated with the given seg.  If no mapping
   from the given seg to a space is found, then return NULL.
   from the given seg to a space is found, then return NULL.
 
 
   Unlike subspaces, the number of spaces is not expected to grow much,
   Unlike subspaces, the number of spaces is not expected to grow much,
   so a linear exhaustive search is OK here.  */
   so a linear exhaustive search is OK here.  */
 
 
static sd_chain_struct *
static sd_chain_struct *
pa_segment_to_space (asection *seg)
pa_segment_to_space (asection *seg)
{
{
  sd_chain_struct *space_chain;
  sd_chain_struct *space_chain;
 
 
  /* Walk through each space looking for the correct mapping.  */
  /* Walk through each space looking for the correct mapping.  */
  for (space_chain = space_dict_root;
  for (space_chain = space_dict_root;
       space_chain;
       space_chain;
       space_chain = space_chain->sd_next)
       space_chain = space_chain->sd_next)
    if (space_chain->sd_seg == seg)
    if (space_chain->sd_seg == seg)
      return space_chain;
      return space_chain;
 
 
  /* Mapping was not found.  Return NULL.  */
  /* Mapping was not found.  Return NULL.  */
  return NULL;
  return NULL;
}
}
 
 
/* Return the first space chain entry for the subspace with the name
/* Return the first space chain entry for the subspace with the name
   NAME or NULL if no such subspace exists.
   NAME or NULL if no such subspace exists.
 
 
   When there are multiple subspaces with the same name, switching to
   When there are multiple subspaces with the same name, switching to
   the first (i.e., default) subspace is preferable in most situations.
   the first (i.e., default) subspace is preferable in most situations.
   For example, it wouldn't be desirable to merge COMDAT data with non
   For example, it wouldn't be desirable to merge COMDAT data with non
   COMDAT data.
   COMDAT data.
 
 
   Uses a linear search through all the spaces and subspaces, this may
   Uses a linear search through all the spaces and subspaces, this may
   not be appropriate if we ever being placing each function in its
   not be appropriate if we ever being placing each function in its
   own subspace.  */
   own subspace.  */
 
 
static ssd_chain_struct *
static ssd_chain_struct *
is_defined_subspace (char *name)
is_defined_subspace (char *name)
{
{
  sd_chain_struct *space_chain;
  sd_chain_struct *space_chain;
  ssd_chain_struct *subspace_chain;
  ssd_chain_struct *subspace_chain;
 
 
  /* Walk through each space.  */
  /* Walk through each space.  */
  for (space_chain = space_dict_root;
  for (space_chain = space_dict_root;
       space_chain;
       space_chain;
       space_chain = space_chain->sd_next)
       space_chain = space_chain->sd_next)
    {
    {
      /* Walk through each subspace looking for a name which matches.  */
      /* Walk through each subspace looking for a name which matches.  */
      for (subspace_chain = space_chain->sd_subspaces;
      for (subspace_chain = space_chain->sd_subspaces;
           subspace_chain;
           subspace_chain;
           subspace_chain = subspace_chain->ssd_next)
           subspace_chain = subspace_chain->ssd_next)
        if (strcmp (SUBSPACE_NAME (subspace_chain), name) == 0)
        if (strcmp (SUBSPACE_NAME (subspace_chain), name) == 0)
          return subspace_chain;
          return subspace_chain;
    }
    }
 
 
  /* Subspace wasn't found.  Return NULL.  */
  /* Subspace wasn't found.  Return NULL.  */
  return NULL;
  return NULL;
}
}
 
 
/* Find and return the subspace associated with the given seg.  If no
/* Find and return the subspace associated with the given seg.  If no
   mapping from the given seg to a subspace is found, then return NULL.
   mapping from the given seg to a subspace is found, then return NULL.
 
 
   If we ever put each procedure/function within its own subspace
   If we ever put each procedure/function within its own subspace
   (to make life easier on the compiler and linker), then this will have
   (to make life easier on the compiler and linker), then this will have
   to become more efficient.  */
   to become more efficient.  */
 
 
static ssd_chain_struct *
static ssd_chain_struct *
pa_subsegment_to_subspace (asection *seg, subsegT subseg)
pa_subsegment_to_subspace (asection *seg, subsegT subseg)
{
{
  sd_chain_struct *space_chain;
  sd_chain_struct *space_chain;
  ssd_chain_struct *subspace_chain;
  ssd_chain_struct *subspace_chain;
 
 
  /* Walk through each space.  */
  /* Walk through each space.  */
  for (space_chain = space_dict_root;
  for (space_chain = space_dict_root;
       space_chain;
       space_chain;
       space_chain = space_chain->sd_next)
       space_chain = space_chain->sd_next)
    {
    {
      if (space_chain->sd_seg == seg)
      if (space_chain->sd_seg == seg)
        {
        {
          /* Walk through each subspace within each space looking for
          /* Walk through each subspace within each space looking for
             the correct mapping.  */
             the correct mapping.  */
          for (subspace_chain = space_chain->sd_subspaces;
          for (subspace_chain = space_chain->sd_subspaces;
               subspace_chain;
               subspace_chain;
               subspace_chain = subspace_chain->ssd_next)
               subspace_chain = subspace_chain->ssd_next)
            if (subspace_chain->ssd_subseg == (int) subseg)
            if (subspace_chain->ssd_subseg == (int) subseg)
              return subspace_chain;
              return subspace_chain;
        }
        }
    }
    }
 
 
  /* No mapping from subsegment to subspace found.  Return NULL.  */
  /* No mapping from subsegment to subspace found.  Return NULL.  */
  return NULL;
  return NULL;
}
}
 
 
/* Given a number, try and find a space with the name number.
/* Given a number, try and find a space with the name number.
 
 
   Return a pointer to a space dictionary chain entry for the space
   Return a pointer to a space dictionary chain entry for the space
   that was found or NULL on failure.  */
   that was found or NULL on failure.  */
 
 
static sd_chain_struct *
static sd_chain_struct *
pa_find_space_by_number (int number)
pa_find_space_by_number (int number)
{
{
  sd_chain_struct *space_chain;
  sd_chain_struct *space_chain;
 
 
  for (space_chain = space_dict_root;
  for (space_chain = space_dict_root;
       space_chain;
       space_chain;
       space_chain = space_chain->sd_next)
       space_chain = space_chain->sd_next)
    {
    {
      if (SPACE_SPNUM (space_chain) == (unsigned int) number)
      if (SPACE_SPNUM (space_chain) == (unsigned int) number)
        return space_chain;
        return space_chain;
    }
    }
 
 
  /* No appropriate space found.  Return NULL.  */
  /* No appropriate space found.  Return NULL.  */
  return NULL;
  return NULL;
}
}
 
 
/* Return the starting address for the given subspace.  If the starting
/* Return the starting address for the given subspace.  If the starting
   address is unknown then return zero.  */
   address is unknown then return zero.  */
 
 
static unsigned int
static unsigned int
pa_subspace_start (sd_chain_struct *space, int quadrant)
pa_subspace_start (sd_chain_struct *space, int quadrant)
{
{
  /* FIXME.  Assumes everyone puts read/write data at 0x4000000, this
  /* FIXME.  Assumes everyone puts read/write data at 0x4000000, this
     is not correct for the PA OSF1 port.  */
     is not correct for the PA OSF1 port.  */
  if ((strcmp (SPACE_NAME (space), "$PRIVATE$") == 0) && quadrant == 1)
  if ((strcmp (SPACE_NAME (space), "$PRIVATE$") == 0) && quadrant == 1)
    return 0x40000000;
    return 0x40000000;
  else if (space->sd_seg == data_section && quadrant == 1)
  else if (space->sd_seg == data_section && quadrant == 1)
    return 0x40000000;
    return 0x40000000;
  else
  else
    return 0;
    return 0;
  return 0;
  return 0;
}
}
#endif
#endif
 
 
/* Helper function for pa_stringer.  Used to find the end of
/* Helper function for pa_stringer.  Used to find the end of
   a string.  */
   a string.  */
 
 
static unsigned int
static unsigned int
pa_stringer_aux (char *s)
pa_stringer_aux (char *s)
{
{
  unsigned int c = *s & CHAR_MASK;
  unsigned int c = *s & CHAR_MASK;
 
 
  switch (c)
  switch (c)
    {
    {
    case '\"':
    case '\"':
      c = NOT_A_CHAR;
      c = NOT_A_CHAR;
      break;
      break;
    default:
    default:
      break;
      break;
    }
    }
  return c;
  return c;
}
}
 
 
/* Handle a .STRING type pseudo-op.  */
/* Handle a .STRING type pseudo-op.  */
 
 
static void
static void
pa_stringer (int append_zero)
pa_stringer (int append_zero)
{
{
  char *s, num_buf[4];
  char *s, num_buf[4];
  unsigned int c;
  unsigned int c;
  int i;
  int i;
 
 
  /* Preprocess the string to handle PA-specific escape sequences.
  /* Preprocess the string to handle PA-specific escape sequences.
     For example, \xDD where DD is a hexadecimal number should be
     For example, \xDD where DD is a hexadecimal number should be
     changed to \OOO where OOO is an octal number.  */
     changed to \OOO where OOO is an octal number.  */
 
 
#ifdef OBJ_SOM
#ifdef OBJ_SOM
  /* We must have a valid space and subspace.  */
  /* We must have a valid space and subspace.  */
  pa_check_current_space_and_subspace ();
  pa_check_current_space_and_subspace ();
#endif
#endif
 
 
  /* Skip the opening quote.  */
  /* Skip the opening quote.  */
  s = input_line_pointer + 1;
  s = input_line_pointer + 1;
 
 
  while (is_a_char (c = pa_stringer_aux (s++)))
  while (is_a_char (c = pa_stringer_aux (s++)))
    {
    {
      if (c == '\\')
      if (c == '\\')
        {
        {
          c = *s;
          c = *s;
          switch (c)
          switch (c)
            {
            {
              /* Handle \x<num>.  */
              /* Handle \x<num>.  */
            case 'x':
            case 'x':
              {
              {
                unsigned int number;
                unsigned int number;
                int num_digit;
                int num_digit;
                char dg;
                char dg;
                char *s_start = s;
                char *s_start = s;
 
 
                /* Get past the 'x'.  */
                /* Get past the 'x'.  */
                s++;
                s++;
                for (num_digit = 0, number = 0, dg = *s;
                for (num_digit = 0, number = 0, dg = *s;
                     num_digit < 2
                     num_digit < 2
                     && (ISDIGIT (dg) || (dg >= 'a' && dg <= 'f')
                     && (ISDIGIT (dg) || (dg >= 'a' && dg <= 'f')
                         || (dg >= 'A' && dg <= 'F'));
                         || (dg >= 'A' && dg <= 'F'));
                     num_digit++)
                     num_digit++)
                  {
                  {
                    if (ISDIGIT (dg))
                    if (ISDIGIT (dg))
                      number = number * 16 + dg - '0';
                      number = number * 16 + dg - '0';
                    else if (dg >= 'a' && dg <= 'f')
                    else if (dg >= 'a' && dg <= 'f')
                      number = number * 16 + dg - 'a' + 10;
                      number = number * 16 + dg - 'a' + 10;
                    else
                    else
                      number = number * 16 + dg - 'A' + 10;
                      number = number * 16 + dg - 'A' + 10;
 
 
                    s++;
                    s++;
                    dg = *s;
                    dg = *s;
                  }
                  }
                if (num_digit > 0)
                if (num_digit > 0)
                  {
                  {
                    switch (num_digit)
                    switch (num_digit)
                      {
                      {
                      case 1:
                      case 1:
                        sprintf (num_buf, "%02o", number);
                        sprintf (num_buf, "%02o", number);
                        break;
                        break;
                      case 2:
                      case 2:
                        sprintf (num_buf, "%03o", number);
                        sprintf (num_buf, "%03o", number);
                        break;
                        break;
                      }
                      }
                    for (i = 0; i <= num_digit; i++)
                    for (i = 0; i <= num_digit; i++)
                      s_start[i] = num_buf[i];
                      s_start[i] = num_buf[i];
                  }
                  }
                break;
                break;
              }
              }
            /* This might be a "\"", skip over the escaped char.  */
            /* This might be a "\"", skip over the escaped char.  */
            default:
            default:
              s++;
              s++;
              break;
              break;
            }
            }
        }
        }
    }
    }
  stringer (8 + append_zero);
  stringer (8 + append_zero);
  pa_undefine_label ();
  pa_undefine_label ();
}
}
 
 
/* Handle a .VERSION pseudo-op.  */
/* Handle a .VERSION pseudo-op.  */
 
 
static void
static void
pa_version (int unused ATTRIBUTE_UNUSED)
pa_version (int unused ATTRIBUTE_UNUSED)
{
{
  obj_version (0);
  obj_version (0);
  pa_undefine_label ();
  pa_undefine_label ();
}
}
 
 
#ifdef OBJ_SOM
#ifdef OBJ_SOM
 
 
/* Handle a .COMPILER pseudo-op.  */
/* Handle a .COMPILER pseudo-op.  */
 
 
static void
static void
pa_compiler (int unused ATTRIBUTE_UNUSED)
pa_compiler (int unused ATTRIBUTE_UNUSED)
{
{
  obj_som_compiler (0);
  obj_som_compiler (0);
  pa_undefine_label ();
  pa_undefine_label ();
}
}
 
 
#endif
#endif
 
 
/* Handle a .COPYRIGHT pseudo-op.  */
/* Handle a .COPYRIGHT pseudo-op.  */
 
 
static void
static void
pa_copyright (int unused ATTRIBUTE_UNUSED)
pa_copyright (int unused ATTRIBUTE_UNUSED)
{
{
  obj_copyright (0);
  obj_copyright (0);
  pa_undefine_label ();
  pa_undefine_label ();
}
}
 
 
/* Just like a normal cons, but when finished we have to undefine
/* Just like a normal cons, but when finished we have to undefine
   the latest space label.  */
   the latest space label.  */
 
 
static void
static void
pa_cons (int nbytes)
pa_cons (int nbytes)
{
{
  cons (nbytes);
  cons (nbytes);
  pa_undefine_label ();
  pa_undefine_label ();
}
}
 
 
/* Like float_cons, but we need to undefine our label.  */
/* Like float_cons, but we need to undefine our label.  */
 
 
static void
static void
pa_float_cons (int float_type)
pa_float_cons (int float_type)
{
{
  float_cons (float_type);
  float_cons (float_type);
  pa_undefine_label ();
  pa_undefine_label ();
}
}
 
 
/* Like s_fill, but delete our label when finished.  */
/* Like s_fill, but delete our label when finished.  */
 
 
static void
static void
pa_fill (int unused ATTRIBUTE_UNUSED)
pa_fill (int unused ATTRIBUTE_UNUSED)
{
{
#ifdef OBJ_SOM
#ifdef OBJ_SOM
  /* We must have a valid space and subspace.  */
  /* We must have a valid space and subspace.  */
  pa_check_current_space_and_subspace ();
  pa_check_current_space_and_subspace ();
#endif
#endif
 
 
  s_fill (0);
  s_fill (0);
  pa_undefine_label ();
  pa_undefine_label ();
}
}
 
 
/* Like lcomm, but delete our label when finished.  */
/* Like lcomm, but delete our label when finished.  */
 
 
static void
static void
pa_lcomm (int needs_align)
pa_lcomm (int needs_align)
{
{
#ifdef OBJ_SOM
#ifdef OBJ_SOM
  /* We must have a valid space and subspace.  */
  /* We must have a valid space and subspace.  */
  pa_check_current_space_and_subspace ();
  pa_check_current_space_and_subspace ();
#endif
#endif
 
 
  s_lcomm (needs_align);
  s_lcomm (needs_align);
  pa_undefine_label ();
  pa_undefine_label ();
}
}
 
 
/* Like lsym, but delete our label when finished.  */
/* Like lsym, but delete our label when finished.  */
 
 
static void
static void
pa_lsym (int unused ATTRIBUTE_UNUSED)
pa_lsym (int unused ATTRIBUTE_UNUSED)
{
{
#ifdef OBJ_SOM
#ifdef OBJ_SOM
  /* We must have a valid space and subspace.  */
  /* We must have a valid space and subspace.  */
  pa_check_current_space_and_subspace ();
  pa_check_current_space_and_subspace ();
#endif
#endif
 
 
  s_lsym (0);
  s_lsym (0);
  pa_undefine_label ();
  pa_undefine_label ();
}
}
 
 
/* This function is called once, at assembler startup time.  It should
/* This function is called once, at assembler startup time.  It should
   set up all the tables, etc. that the MD part of the assembler will need.  */
   set up all the tables, etc. that the MD part of the assembler will need.  */
 
 
void
void
md_begin (void)
md_begin (void)
{
{
  const char *retval = NULL;
  const char *retval = NULL;
  int lose = 0;
  int lose = 0;
  unsigned int i = 0;
  unsigned int i = 0;
 
 
  last_call_info = NULL;
  last_call_info = NULL;
  call_info_root = NULL;
  call_info_root = NULL;
 
 
  /* Set the default machine type.  */
  /* Set the default machine type.  */
  if (!bfd_set_arch_mach (stdoutput, bfd_arch_hppa, DEFAULT_LEVEL))
  if (!bfd_set_arch_mach (stdoutput, bfd_arch_hppa, DEFAULT_LEVEL))
    as_warn (_("could not set architecture and machine"));
    as_warn (_("could not set architecture and machine"));
 
 
  /* Folding of text and data segments fails miserably on the PA.
  /* Folding of text and data segments fails miserably on the PA.
     Warn user and disable "-R" option.  */
     Warn user and disable "-R" option.  */
  if (flag_readonly_data_in_text)
  if (flag_readonly_data_in_text)
    {
    {
      as_warn (_("-R option not supported on this target."));
      as_warn (_("-R option not supported on this target."));
      flag_readonly_data_in_text = 0;
      flag_readonly_data_in_text = 0;
    }
    }
 
 
#ifdef OBJ_SOM
#ifdef OBJ_SOM
  pa_spaces_begin ();
  pa_spaces_begin ();
#endif
#endif
 
 
  op_hash = hash_new ();
  op_hash = hash_new ();
 
 
  while (i < NUMOPCODES)
  while (i < NUMOPCODES)
    {
    {
      const char *name = pa_opcodes[i].name;
      const char *name = pa_opcodes[i].name;
 
 
      retval = hash_insert (op_hash, name, (struct pa_opcode *) &pa_opcodes[i]);
      retval = hash_insert (op_hash, name, (struct pa_opcode *) &pa_opcodes[i]);
      if (retval != NULL && *retval != '\0')
      if (retval != NULL && *retval != '\0')
        {
        {
          as_fatal (_("Internal error: can't hash `%s': %s\n"), name, retval);
          as_fatal (_("Internal error: can't hash `%s': %s\n"), name, retval);
          lose = 1;
          lose = 1;
        }
        }
 
 
      do
      do
        {
        {
          if ((pa_opcodes[i].match & pa_opcodes[i].mask)
          if ((pa_opcodes[i].match & pa_opcodes[i].mask)
              != pa_opcodes[i].match)
              != pa_opcodes[i].match)
            {
            {
              fprintf (stderr, _("internal error: losing opcode: `%s' \"%s\"\n"),
              fprintf (stderr, _("internal error: losing opcode: `%s' \"%s\"\n"),
                       pa_opcodes[i].name, pa_opcodes[i].args);
                       pa_opcodes[i].name, pa_opcodes[i].args);
              lose = 1;
              lose = 1;
            }
            }
          ++i;
          ++i;
        }
        }
      while (i < NUMOPCODES && !strcmp (pa_opcodes[i].name, name));
      while (i < NUMOPCODES && !strcmp (pa_opcodes[i].name, name));
    }
    }
 
 
  if (lose)
  if (lose)
    as_fatal (_("Broken assembler.  No assembly attempted."));
    as_fatal (_("Broken assembler.  No assembly attempted."));
 
 
#ifdef OBJ_SOM
#ifdef OBJ_SOM
  /* SOM will change text_section.  To make sure we never put
  /* SOM will change text_section.  To make sure we never put
     anything into the old one switch to the new one now.  */
     anything into the old one switch to the new one now.  */
  subseg_set (text_section, 0);
  subseg_set (text_section, 0);
#endif
#endif
 
 
#ifdef OBJ_SOM
#ifdef OBJ_SOM
  dummy_symbol = symbol_find_or_make ("L$dummy");
  dummy_symbol = symbol_find_or_make ("L$dummy");
  S_SET_SEGMENT (dummy_symbol, text_section);
  S_SET_SEGMENT (dummy_symbol, text_section);
  /* Force the symbol to be converted to a real symbol.  */
  /* Force the symbol to be converted to a real symbol.  */
  (void) symbol_get_bfdsym (dummy_symbol);
  (void) symbol_get_bfdsym (dummy_symbol);
#endif
#endif
}
}
 
 
/* On the PA relocations which involve function symbols must not be
/* On the PA relocations which involve function symbols must not be
   adjusted.  This so that the linker can know when/how to create argument
   adjusted.  This so that the linker can know when/how to create argument
   relocation stubs for indirect calls and calls to static functions.
   relocation stubs for indirect calls and calls to static functions.
 
 
   "T" field selectors create DLT relative fixups for accessing
   "T" field selectors create DLT relative fixups for accessing
   globals and statics in PIC code; each DLT relative fixup creates
   globals and statics in PIC code; each DLT relative fixup creates
   an entry in the DLT table.  The entries contain the address of
   an entry in the DLT table.  The entries contain the address of
   the final target (eg accessing "foo" would create a DLT entry
   the final target (eg accessing "foo" would create a DLT entry
   with the address of "foo").
   with the address of "foo").
 
 
   Unfortunately, the HP linker doesn't take into account any addend
   Unfortunately, the HP linker doesn't take into account any addend
   when generating the DLT; so accessing $LIT$+8 puts the address of
   when generating the DLT; so accessing $LIT$+8 puts the address of
   $LIT$ into the DLT rather than the address of $LIT$+8.
   $LIT$ into the DLT rather than the address of $LIT$+8.
 
 
   The end result is we can't perform relocation symbol reductions for
   The end result is we can't perform relocation symbol reductions for
   any fixup which creates entries in the DLT (eg they use "T" field
   any fixup which creates entries in the DLT (eg they use "T" field
   selectors).
   selectors).
 
 
   ??? Reject reductions involving symbols with external scope; such
   ??? Reject reductions involving symbols with external scope; such
   reductions make life a living hell for object file editors.  */
   reductions make life a living hell for object file editors.  */
 
 
int
int
hppa_fix_adjustable (fixS *fixp)
hppa_fix_adjustable (fixS *fixp)
{
{
#ifdef OBJ_ELF
#ifdef OBJ_ELF
  reloc_type code;
  reloc_type code;
#endif
#endif
  struct hppa_fix_struct *hppa_fix;
  struct hppa_fix_struct *hppa_fix;
 
 
  hppa_fix = (struct hppa_fix_struct *) fixp->tc_fix_data;
  hppa_fix = (struct hppa_fix_struct *) fixp->tc_fix_data;
 
 
#ifdef OBJ_ELF
#ifdef OBJ_ELF
  /* LR/RR selectors are implicitly used for a number of different relocation
  /* LR/RR selectors are implicitly used for a number of different relocation
     types.  We must ensure that none of these types are adjusted (see below)
     types.  We must ensure that none of these types are adjusted (see below)
     even if they occur with a different selector.  */
     even if they occur with a different selector.  */
  code = elf_hppa_reloc_final_type (stdoutput, fixp->fx_r_type,
  code = elf_hppa_reloc_final_type (stdoutput, fixp->fx_r_type,
                                    hppa_fix->fx_r_format,
                                    hppa_fix->fx_r_format,
                                    hppa_fix->fx_r_field);
                                    hppa_fix->fx_r_field);
 
 
  switch (code)
  switch (code)
    {
    {
    /* Relocation types which use e_lrsel.  */
    /* Relocation types which use e_lrsel.  */
    case R_PARISC_DIR21L:
    case R_PARISC_DIR21L:
    case R_PARISC_DLTREL21L:
    case R_PARISC_DLTREL21L:
    case R_PARISC_DPREL21L:
    case R_PARISC_DPREL21L:
    case R_PARISC_PLTOFF21L:
    case R_PARISC_PLTOFF21L:
 
 
    /* Relocation types which use e_rrsel.  */
    /* Relocation types which use e_rrsel.  */
    case R_PARISC_DIR14R:
    case R_PARISC_DIR14R:
    case R_PARISC_DIR14DR:
    case R_PARISC_DIR14DR:
    case R_PARISC_DIR14WR:
    case R_PARISC_DIR14WR:
    case R_PARISC_DIR17R:
    case R_PARISC_DIR17R:
    case R_PARISC_DLTREL14R:
    case R_PARISC_DLTREL14R:
    case R_PARISC_DLTREL14DR:
    case R_PARISC_DLTREL14DR:
    case R_PARISC_DLTREL14WR:
    case R_PARISC_DLTREL14WR:
    case R_PARISC_DPREL14R:
    case R_PARISC_DPREL14R:
    case R_PARISC_DPREL14DR:
    case R_PARISC_DPREL14DR:
    case R_PARISC_DPREL14WR:
    case R_PARISC_DPREL14WR:
    case R_PARISC_PLTOFF14R:
    case R_PARISC_PLTOFF14R:
    case R_PARISC_PLTOFF14DR:
    case R_PARISC_PLTOFF14DR:
    case R_PARISC_PLTOFF14WR:
    case R_PARISC_PLTOFF14WR:
 
 
    /* Other types that we reject for reduction.  */
    /* Other types that we reject for reduction.  */
    case R_PARISC_GNU_VTENTRY:
    case R_PARISC_GNU_VTENTRY:
    case R_PARISC_GNU_VTINHERIT:
    case R_PARISC_GNU_VTINHERIT:
      return 0;
      return 0;
    default:
    default:
      break;
      break;
    }
    }
#endif
#endif
 
 
  /* Reject reductions of symbols in sym1-sym2 expressions when
  /* Reject reductions of symbols in sym1-sym2 expressions when
     the fixup will occur in a CODE subspace.
     the fixup will occur in a CODE subspace.
 
 
     XXX FIXME: Long term we probably want to reject all of these;
     XXX FIXME: Long term we probably want to reject all of these;
     for example reducing in the debug section would lose if we ever
     for example reducing in the debug section would lose if we ever
     supported using the optimizing hp linker.  */
     supported using the optimizing hp linker.  */
  if (fixp->fx_addsy
  if (fixp->fx_addsy
      && fixp->fx_subsy
      && fixp->fx_subsy
      && (hppa_fix->segment->flags & SEC_CODE))
      && (hppa_fix->segment->flags & SEC_CODE))
    return 0;
    return 0;
 
 
  /* We can't adjust any relocs that use LR% and RR% field selectors.
  /* We can't adjust any relocs that use LR% and RR% field selectors.
 
 
     If a symbol is reduced to a section symbol, the assembler will
     If a symbol is reduced to a section symbol, the assembler will
     adjust the addend unless the symbol happens to reside right at
     adjust the addend unless the symbol happens to reside right at
     the start of the section.  Additionally, the linker has no choice
     the start of the section.  Additionally, the linker has no choice
     but to manipulate the addends when coalescing input sections for
     but to manipulate the addends when coalescing input sections for
     "ld -r".  Since an LR% field selector is defined to round the
     "ld -r".  Since an LR% field selector is defined to round the
     addend, we can't change the addend without risking that a LR% and
     addend, we can't change the addend without risking that a LR% and
     it's corresponding (possible multiple) RR% field will no longer
     it's corresponding (possible multiple) RR% field will no longer
     sum to the right value.
     sum to the right value.
 
 
     eg. Suppose we have
     eg. Suppose we have
     .          ldil    LR%foo+0,%r21
     .          ldil    LR%foo+0,%r21
     .          ldw     RR%foo+0(%r21),%r26
     .          ldw     RR%foo+0(%r21),%r26
     .          ldw     RR%foo+4(%r21),%r25
     .          ldw     RR%foo+4(%r21),%r25
 
 
     If foo is at address 4092 (decimal) in section `sect', then after
     If foo is at address 4092 (decimal) in section `sect', then after
     reducing to the section symbol we get
     reducing to the section symbol we get
     .                  LR%sect+4092 == (L%sect)+0
     .                  LR%sect+4092 == (L%sect)+0
     .                  RR%sect+4092 == (R%sect)+4092
     .                  RR%sect+4092 == (R%sect)+4092
     .                  RR%sect+4096 == (R%sect)-4096
     .                  RR%sect+4096 == (R%sect)-4096
     and the last address loses because rounding the addend to 8k
     and the last address loses because rounding the addend to 8k
     multiples takes us up to 8192 with an offset of -4096.
     multiples takes us up to 8192 with an offset of -4096.
 
 
     In cases where the LR% expression is identical to the RR% one we
     In cases where the LR% expression is identical to the RR% one we
     will never have a problem, but is so happens that gcc rounds
     will never have a problem, but is so happens that gcc rounds
     addends involved in LR% field selectors to work around a HP
     addends involved in LR% field selectors to work around a HP
     linker bug.  ie. We often have addresses like the last case
     linker bug.  ie. We often have addresses like the last case
     above where the LR% expression is offset from the RR% one.  */
     above where the LR% expression is offset from the RR% one.  */
 
 
  if (hppa_fix->fx_r_field == e_lrsel
  if (hppa_fix->fx_r_field == e_lrsel
      || hppa_fix->fx_r_field == e_rrsel
      || hppa_fix->fx_r_field == e_rrsel
      || hppa_fix->fx_r_field == e_nlrsel)
      || hppa_fix->fx_r_field == e_nlrsel)
    return 0;
    return 0;
 
 
  /* Reject reductions of symbols in DLT relative relocs,
  /* Reject reductions of symbols in DLT relative relocs,
     relocations with plabels.  */
     relocations with plabels.  */
  if (hppa_fix->fx_r_field == e_tsel
  if (hppa_fix->fx_r_field == e_tsel
      || hppa_fix->fx_r_field == e_ltsel
      || hppa_fix->fx_r_field == e_ltsel
      || hppa_fix->fx_r_field == e_rtsel
      || hppa_fix->fx_r_field == e_rtsel
      || hppa_fix->fx_r_field == e_psel
      || hppa_fix->fx_r_field == e_psel
      || hppa_fix->fx_r_field == e_rpsel
      || hppa_fix->fx_r_field == e_rpsel
      || hppa_fix->fx_r_field == e_lpsel)
      || hppa_fix->fx_r_field == e_lpsel)
    return 0;
    return 0;
 
 
  /* Reject absolute calls (jumps).  */
  /* Reject absolute calls (jumps).  */
  if (hppa_fix->fx_r_type == R_HPPA_ABS_CALL)
  if (hppa_fix->fx_r_type == R_HPPA_ABS_CALL)
    return 0;
    return 0;
 
 
  /* Reject reductions of function symbols.  */
  /* Reject reductions of function symbols.  */
  if (fixp->fx_addsy != 0 && S_IS_FUNCTION (fixp->fx_addsy))
  if (fixp->fx_addsy != 0 && S_IS_FUNCTION (fixp->fx_addsy))
    return 0;
    return 0;
 
 
  return 1;
  return 1;
}
}
 
 
/* Return nonzero if the fixup in FIXP will require a relocation,
/* Return nonzero if the fixup in FIXP will require a relocation,
   even it if appears that the fixup could be completely handled
   even it if appears that the fixup could be completely handled
   within GAS.  */
   within GAS.  */
 
 
int
int
hppa_force_relocation (struct fix *fixp)
hppa_force_relocation (struct fix *fixp)
{
{
  struct hppa_fix_struct *hppa_fixp;
  struct hppa_fix_struct *hppa_fixp;
 
 
  hppa_fixp = (struct hppa_fix_struct *) fixp->tc_fix_data;
  hppa_fixp = (struct hppa_fix_struct *) fixp->tc_fix_data;
#ifdef OBJ_SOM
#ifdef OBJ_SOM
  if (fixp->fx_r_type == (int) R_HPPA_ENTRY
  if (fixp->fx_r_type == (int) R_HPPA_ENTRY
      || fixp->fx_r_type == (int) R_HPPA_EXIT
      || fixp->fx_r_type == (int) R_HPPA_EXIT
      || fixp->fx_r_type == (int) R_HPPA_BEGIN_BRTAB
      || fixp->fx_r_type == (int) R_HPPA_BEGIN_BRTAB
      || fixp->fx_r_type == (int) R_HPPA_END_BRTAB
      || fixp->fx_r_type == (int) R_HPPA_END_BRTAB
      || fixp->fx_r_type == (int) R_HPPA_BEGIN_TRY
      || fixp->fx_r_type == (int) R_HPPA_BEGIN_TRY
      || fixp->fx_r_type == (int) R_HPPA_END_TRY
      || fixp->fx_r_type == (int) R_HPPA_END_TRY
      || (fixp->fx_addsy != NULL && fixp->fx_subsy != NULL
      || (fixp->fx_addsy != NULL && fixp->fx_subsy != NULL
          && (hppa_fixp->segment->flags & SEC_CODE) != 0))
          && (hppa_fixp->segment->flags & SEC_CODE) != 0))
    return 1;
    return 1;
#endif
#endif
#ifdef OBJ_ELF
#ifdef OBJ_ELF
  if (fixp->fx_r_type == (int) R_PARISC_GNU_VTINHERIT
  if (fixp->fx_r_type == (int) R_PARISC_GNU_VTINHERIT
      || fixp->fx_r_type == (int) R_PARISC_GNU_VTENTRY)
      || fixp->fx_r_type == (int) R_PARISC_GNU_VTENTRY)
    return 1;
    return 1;
#endif
#endif
 
 
  assert (fixp->fx_addsy != NULL);
  assert (fixp->fx_addsy != NULL);
 
 
  /* Ensure we emit a relocation for global symbols so that dynamic
  /* Ensure we emit a relocation for global symbols so that dynamic
     linking works.  */
     linking works.  */
  if (S_FORCE_RELOC (fixp->fx_addsy, 1))
  if (S_FORCE_RELOC (fixp->fx_addsy, 1))
    return 1;
    return 1;
 
 
  /* It is necessary to force PC-relative calls/jumps to have a relocation
  /* It is necessary to force PC-relative calls/jumps to have a relocation
     entry if they're going to need either an argument relocation or long
     entry if they're going to need either an argument relocation or long
     call stub.  */
     call stub.  */
  if (fixp->fx_pcrel
  if (fixp->fx_pcrel
      && arg_reloc_stub_needed (symbol_arg_reloc_info (fixp->fx_addsy),
      && arg_reloc_stub_needed (symbol_arg_reloc_info (fixp->fx_addsy),
                                hppa_fixp->fx_arg_reloc))
                                hppa_fixp->fx_arg_reloc))
    return 1;
    return 1;
 
 
  /* Now check to see if we're going to need a long-branch stub.  */
  /* Now check to see if we're going to need a long-branch stub.  */
  if (fixp->fx_r_type == (int) R_HPPA_PCREL_CALL)
  if (fixp->fx_r_type == (int) R_HPPA_PCREL_CALL)
    {
    {
      long pc = md_pcrel_from (fixp);
      long pc = md_pcrel_from (fixp);
      valueT distance, min_stub_distance;
      valueT distance, min_stub_distance;
 
 
      distance = fixp->fx_offset + S_GET_VALUE (fixp->fx_addsy) - pc - 8;
      distance = fixp->fx_offset + S_GET_VALUE (fixp->fx_addsy) - pc - 8;
 
 
      /* Distance to the closest possible stub.  This will detect most
      /* Distance to the closest possible stub.  This will detect most
         but not all circumstances where a stub will not work.  */
         but not all circumstances where a stub will not work.  */
      min_stub_distance = pc + 16;
      min_stub_distance = pc + 16;
#ifdef OBJ_SOM
#ifdef OBJ_SOM
      if (last_call_info != NULL)
      if (last_call_info != NULL)
        min_stub_distance -= S_GET_VALUE (last_call_info->start_symbol);
        min_stub_distance -= S_GET_VALUE (last_call_info->start_symbol);
#endif
#endif
 
 
      if ((distance + 8388608 >= 16777216
      if ((distance + 8388608 >= 16777216
           && min_stub_distance <= 8388608)
           && min_stub_distance <= 8388608)
          || (hppa_fixp->fx_r_format == 17
          || (hppa_fixp->fx_r_format == 17
              && distance + 262144 >= 524288
              && distance + 262144 >= 524288
              && min_stub_distance <= 262144)
              && min_stub_distance <= 262144)
          || (hppa_fixp->fx_r_format == 12
          || (hppa_fixp->fx_r_format == 12
              && distance + 8192 >= 16384
              && distance + 8192 >= 16384
              && min_stub_distance <= 8192)
              && min_stub_distance <= 8192)
          )
          )
        return 1;
        return 1;
    }
    }
 
 
  if (fixp->fx_r_type == (int) R_HPPA_ABS_CALL)
  if (fixp->fx_r_type == (int) R_HPPA_ABS_CALL)
    return 1;
    return 1;
 
 
  /* No need (yet) to force another relocations to be emitted.  */
  /* No need (yet) to force another relocations to be emitted.  */
  return 0;
  return 0;
}
}
 
 
/* Now for some ELF specific code.  FIXME.  */
/* Now for some ELF specific code.  FIXME.  */
#ifdef OBJ_ELF
#ifdef OBJ_ELF
/* For ELF, this function serves one purpose:  to setup the st_size
/* For ELF, this function serves one purpose:  to setup the st_size
   field of STT_FUNC symbols.  To do this, we need to scan the
   field of STT_FUNC symbols.  To do this, we need to scan the
   call_info structure list, determining st_size in by taking the
   call_info structure list, determining st_size in by taking the
   difference in the address of the beginning/end marker symbols.  */
   difference in the address of the beginning/end marker symbols.  */
 
 
void
void
elf_hppa_final_processing (void)
elf_hppa_final_processing (void)
{
{
  struct call_info *call_info_pointer;
  struct call_info *call_info_pointer;
 
 
  for (call_info_pointer = call_info_root;
  for (call_info_pointer = call_info_root;
       call_info_pointer;
       call_info_pointer;
       call_info_pointer = call_info_pointer->ci_next)
       call_info_pointer = call_info_pointer->ci_next)
    {
    {
      elf_symbol_type *esym
      elf_symbol_type *esym
        = ((elf_symbol_type *)
        = ((elf_symbol_type *)
           symbol_get_bfdsym (call_info_pointer->start_symbol));
           symbol_get_bfdsym (call_info_pointer->start_symbol));
      esym->internal_elf_sym.st_size =
      esym->internal_elf_sym.st_size =
        S_GET_VALUE (call_info_pointer->end_symbol)
        S_GET_VALUE (call_info_pointer->end_symbol)
        - S_GET_VALUE (call_info_pointer->start_symbol) + 4;
        - S_GET_VALUE (call_info_pointer->start_symbol) + 4;
    }
    }
}
}
 
 
static void
static void
pa_vtable_entry (int ignore ATTRIBUTE_UNUSED)
pa_vtable_entry (int ignore ATTRIBUTE_UNUSED)
{
{
  struct fix *new_fix;
  struct fix *new_fix;
 
 
  new_fix = obj_elf_vtable_entry (0);
  new_fix = obj_elf_vtable_entry (0);
 
 
  if (new_fix)
  if (new_fix)
    {
    {
      struct hppa_fix_struct * hppa_fix = obstack_alloc (&notes, sizeof (struct hppa_fix_struct));
      struct hppa_fix_struct * hppa_fix = obstack_alloc (&notes, sizeof (struct hppa_fix_struct));
 
 
      hppa_fix->fx_r_type = R_HPPA;
      hppa_fix->fx_r_type = R_HPPA;
      hppa_fix->fx_r_field = e_fsel;
      hppa_fix->fx_r_field = e_fsel;
      hppa_fix->fx_r_format = 32;
      hppa_fix->fx_r_format = 32;
      hppa_fix->fx_arg_reloc = 0;
      hppa_fix->fx_arg_reloc = 0;
      hppa_fix->segment = now_seg;
      hppa_fix->segment = now_seg;
      new_fix->tc_fix_data = (void *) hppa_fix;
      new_fix->tc_fix_data = (void *) hppa_fix;
      new_fix->fx_r_type = (int) R_PARISC_GNU_VTENTRY;
      new_fix->fx_r_type = (int) R_PARISC_GNU_VTENTRY;
    }
    }
}
}
 
 
static void
static void
pa_vtable_inherit (int ignore ATTRIBUTE_UNUSED)
pa_vtable_inherit (int ignore ATTRIBUTE_UNUSED)
{
{
  struct fix *new_fix;
  struct fix *new_fix;
 
 
  new_fix = obj_elf_vtable_inherit (0);
  new_fix = obj_elf_vtable_inherit (0);
 
 
  if (new_fix)
  if (new_fix)
    {
    {
      struct hppa_fix_struct * hppa_fix = obstack_alloc (&notes, sizeof (struct hppa_fix_struct));
      struct hppa_fix_struct * hppa_fix = obstack_alloc (&notes, sizeof (struct hppa_fix_struct));
 
 
      hppa_fix->fx_r_type = R_HPPA;
      hppa_fix->fx_r_type = R_HPPA;
      hppa_fix->fx_r_field = e_fsel;
      hppa_fix->fx_r_field = e_fsel;
      hppa_fix->fx_r_format = 32;
      hppa_fix->fx_r_format = 32;
      hppa_fix->fx_arg_reloc = 0;
      hppa_fix->fx_arg_reloc = 0;
      hppa_fix->segment = now_seg;
      hppa_fix->segment = now_seg;
      new_fix->tc_fix_data = (void *) hppa_fix;
      new_fix->tc_fix_data = (void *) hppa_fix;
      new_fix->fx_r_type = (int) R_PARISC_GNU_VTINHERIT;
      new_fix->fx_r_type = (int) R_PARISC_GNU_VTINHERIT;
    }
    }
}
}
#endif
#endif
 
 
/* Table of pseudo ops for the PA.  FIXME -- how many of these
/* Table of pseudo ops for the PA.  FIXME -- how many of these
   are now redundant with the overall GAS and the object file
   are now redundant with the overall GAS and the object file
   dependent tables?  */
   dependent tables?  */
const pseudo_typeS md_pseudo_table[] =
const pseudo_typeS md_pseudo_table[] =
{
{
  /* align pseudo-ops on the PA specify the actual alignment requested,
  /* align pseudo-ops on the PA specify the actual alignment requested,
     not the log2 of the requested alignment.  */
     not the log2 of the requested alignment.  */
#ifdef OBJ_SOM
#ifdef OBJ_SOM
  {"align", pa_align, 8},
  {"align", pa_align, 8},
#endif
#endif
#ifdef OBJ_ELF
#ifdef OBJ_ELF
  {"align", s_align_bytes, 8},
  {"align", s_align_bytes, 8},
#endif
#endif
  {"begin_brtab", pa_brtab, 1},
  {"begin_brtab", pa_brtab, 1},
  {"begin_try", pa_try, 1},
  {"begin_try", pa_try, 1},
  {"block", pa_block, 1},
  {"block", pa_block, 1},
  {"blockz", pa_block, 0},
  {"blockz", pa_block, 0},
  {"byte", pa_cons, 1},
  {"byte", pa_cons, 1},
  {"call", pa_call, 0},
  {"call", pa_call, 0},
  {"callinfo", pa_callinfo, 0},
  {"callinfo", pa_callinfo, 0},
#if defined (OBJ_ELF) && (defined (TE_LINUX) || defined (TE_NetBSD))
#if defined (OBJ_ELF) && (defined (TE_LINUX) || defined (TE_NetBSD))
  {"code", obj_elf_text, 0},
  {"code", obj_elf_text, 0},
#else
#else
  {"code", pa_text, 0},
  {"code", pa_text, 0},
  {"comm", pa_comm, 0},
  {"comm", pa_comm, 0},
#endif
#endif
#ifdef OBJ_SOM
#ifdef OBJ_SOM
  {"compiler", pa_compiler, 0},
  {"compiler", pa_compiler, 0},
#endif
#endif
  {"copyright", pa_copyright, 0},
  {"copyright", pa_copyright, 0},
#if !(defined (OBJ_ELF) && (defined (TE_LINUX) || defined (TE_NetBSD)))
#if !(defined (OBJ_ELF) && (defined (TE_LINUX) || defined (TE_NetBSD)))
  {"data", pa_data, 0},
  {"data", pa_data, 0},
#endif
#endif
  {"double", pa_float_cons, 'd'},
  {"double", pa_float_cons, 'd'},
  {"dword", pa_cons, 8},
  {"dword", pa_cons, 8},
  {"end", pa_end, 0},
  {"end", pa_end, 0},
  {"end_brtab", pa_brtab, 0},
  {"end_brtab", pa_brtab, 0},
#if !(defined (OBJ_ELF) && (defined (TE_LINUX) || defined (TE_NetBSD)))
#if !(defined (OBJ_ELF) && (defined (TE_LINUX) || defined (TE_NetBSD)))
  {"end_try", pa_try, 0},
  {"end_try", pa_try, 0},
#endif
#endif
  {"enter", pa_enter, 0},
  {"enter", pa_enter, 0},
  {"entry", pa_entry, 0},
  {"entry", pa_entry, 0},
  {"equ", pa_equ, 0},
  {"equ", pa_equ, 0},
  {"exit", pa_exit, 0},
  {"exit", pa_exit, 0},
  {"export", pa_export, 0},
  {"export", pa_export, 0},
  {"fill", pa_fill, 0},
  {"fill", pa_fill, 0},
  {"float", pa_float_cons, 'f'},
  {"float", pa_float_cons, 'f'},
  {"half", pa_cons, 2},
  {"half", pa_cons, 2},
  {"import", pa_import, 0},
  {"import", pa_import, 0},
  {"int", pa_cons, 4},
  {"int", pa_cons, 4},
  {"label", pa_label, 0},
  {"label", pa_label, 0},
  {"lcomm", pa_lcomm, 0},
  {"lcomm", pa_lcomm, 0},
  {"leave", pa_leave, 0},
  {"leave", pa_leave, 0},
  {"level", pa_level, 0},
  {"level", pa_level, 0},
  {"long", pa_cons, 4},
  {"long", pa_cons, 4},
  {"lsym", pa_lsym, 0},
  {"lsym", pa_lsym, 0},
#ifdef OBJ_SOM
#ifdef OBJ_SOM
  {"nsubspa", pa_subspace, 1},
  {"nsubspa", pa_subspace, 1},
#endif
#endif
  {"octa", pa_cons, 16},
  {"octa", pa_cons, 16},
  {"org", pa_origin, 0},
  {"org", pa_origin, 0},
  {"origin", pa_origin, 0},
  {"origin", pa_origin, 0},
  {"param", pa_param, 0},
  {"param", pa_param, 0},
  {"proc", pa_proc, 0},
  {"proc", pa_proc, 0},
  {"procend", pa_procend, 0},
  {"procend", pa_procend, 0},
  {"quad", pa_cons, 8},
  {"quad", pa_cons, 8},
  {"reg", pa_equ, 1},
  {"reg", pa_equ, 1},
  {"short", pa_cons, 2},
  {"short", pa_cons, 2},
  {"single", pa_float_cons, 'f'},
  {"single", pa_float_cons, 'f'},
#ifdef OBJ_SOM
#ifdef OBJ_SOM
  {"space", pa_space, 0},
  {"space", pa_space, 0},
  {"spnum", pa_spnum, 0},
  {"spnum", pa_spnum, 0},
#endif
#endif
  {"string", pa_stringer, 0},
  {"string", pa_stringer, 0},
  {"stringz", pa_stringer, 1},
  {"stringz", pa_stringer, 1},
#ifdef OBJ_SOM
#ifdef OBJ_SOM
  {"subspa", pa_subspace, 0},
  {"subspa", pa_subspace, 0},
#endif
#endif
#if !(defined (OBJ_ELF) && (defined (TE_LINUX) || defined (TE_NetBSD)))
#if !(defined (OBJ_ELF) && (defined (TE_LINUX) || defined (TE_NetBSD)))
  {"text", pa_text, 0},
  {"text", pa_text, 0},
#endif
#endif
  {"version", pa_version, 0},
  {"version", pa_version, 0},
#ifdef OBJ_ELF
#ifdef OBJ_ELF
  {"vtable_entry", pa_vtable_entry, 0},
  {"vtable_entry", pa_vtable_entry, 0},
  {"vtable_inherit", pa_vtable_inherit, 0},
  {"vtable_inherit", pa_vtable_inherit, 0},
#endif
#endif
  {"word", pa_cons, 4},
  {"word", pa_cons, 4},
  {NULL, 0, 0}
  {NULL, 0, 0}
};
};
 
 
#ifdef OBJ_ELF
#ifdef OBJ_ELF
void
void
hppa_cfi_frame_initial_instructions (void)
hppa_cfi_frame_initial_instructions (void)
{
{
  cfi_add_CFA_def_cfa (30, 0);
  cfi_add_CFA_def_cfa (30, 0);
}
}
 
 
int
int
hppa_regname_to_dw2regnum (char *regname)
hppa_regname_to_dw2regnum (char *regname)
{
{
  unsigned int regnum = -1;
  unsigned int regnum = -1;
  unsigned int i;
  unsigned int i;
  const char *p;
  const char *p;
  char *q;
  char *q;
  static struct { char *name; int dw2regnum; } regnames[] =
  static struct { char *name; int dw2regnum; } regnames[] =
    {
    {
      { "sp", 30 }, { "rp", 2 },
      { "sp", 30 }, { "rp", 2 },
    };
    };
 
 
  for (i = 0; i < ARRAY_SIZE (regnames); ++i)
  for (i = 0; i < ARRAY_SIZE (regnames); ++i)
    if (strcmp (regnames[i].name, regname) == 0)
    if (strcmp (regnames[i].name, regname) == 0)
      return regnames[i].dw2regnum;
      return regnames[i].dw2regnum;
 
 
  if (regname[0] == 'r')
  if (regname[0] == 'r')
    {
    {
      p = regname + 1;
      p = regname + 1;
      regnum = strtoul (p, &q, 10);
      regnum = strtoul (p, &q, 10);
      if (p == q || *q || regnum >= 32)
      if (p == q || *q || regnum >= 32)
        return -1;
        return -1;
    }
    }
  else if (regname[0] == 'f' && regname[1] == 'r')
  else if (regname[0] == 'f' && regname[1] == 'r')
    {
    {
      p = regname + 2;
      p = regname + 2;
      regnum = strtoul (p, &q, 10);
      regnum = strtoul (p, &q, 10);
      if (p == q || *q || regnum <= 4 || regnum >= 32)
      if (p == q || *q || regnum <= 4 || regnum >= 32)
        return -1;
        return -1;
      regnum += 32 - 4;
      regnum += 32 - 4;
    }
    }
  return regnum;
  return regnum;
}
}
#endif
#endif
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.