* config/tc-hppa.c (pa_ip): Put strict register checks before
[deliverable/binutils-gdb.git] / gas / config / tc-hppa.c
index 498f40e3ea2364d53609ec8ebb2eef14fda5d39f..5f938c5df44c91a029a8af59757326094cdc76dc 100644 (file)
@@ -1,11 +1,12 @@
 /* tc-hppa.c -- Assemble for the PA
 /* tc-hppa.c -- Assemble for the PA
-   Copyright (C) 1989 Free Software Foundation, Inc.
+   Copyright (C) 1989, 93, 94, 95, 96, 97, 98, 1999
+   Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
 
    GAS is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
 
    This file is part of GAS, the GNU Assembler.
 
    GAS is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 1, or (at your option)
+   the Free Software Foundation; either version 2, or (at your option)
    any later version.
 
    GAS is distributed in the hope that it will be useful,
    any later version.
 
    GAS is distributed in the hope that it will be useful,
@@ -14,8 +15,9 @@
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
-   along with GAS; see the file COPYING.  If not, write to
-   the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+   along with GAS; see the file COPYING.  If not, write to the Free
+   Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+   02111-1307, USA.  */
 
 
 /* HP PA-RISC support was contributed by the Center for Software Science
 
 
 /* HP PA-RISC support was contributed by the Center for Software Science
 #include "as.h"
 #include "subsegs.h"
 
 #include "as.h"
 #include "subsegs.h"
 
-#include "../bfd/libhppa.h"
-#include "../bfd/libbfd.h"
+#include "bfd/libhppa.h"
+#include "bfd/libbfd.h"
 
 /* Be careful, this file includes data *declarations*.  */
 #include "opcode/hppa.h"
 
 
 /* Be careful, this file includes data *declarations*.  */
 #include "opcode/hppa.h"
 
+#if defined (OBJ_ELF) && defined (OBJ_SOM)
+error only one of OBJ_ELF and OBJ_SOM can be defined
+#endif
+
 /* A "convient" place to put object file dependencies which do
    not need to be seen outside of tc-hppa.c.  */
 #ifdef OBJ_ELF
 /* A "convient" place to put object file dependencies which do
    not need to be seen outside of tc-hppa.c.  */
 #ifdef OBJ_ELF
-/* Names of various debugging spaces/subspaces.  */
-#define GDB_DEBUG_SPACE_NAME ".stab"
-#define GDB_STRINGS_SUBSPACE_NAME ".stabstr"
-#define GDB_SYMBOLS_SUBSPACE_NAME ".stab"
-#define UNWIND_SECTION_NAME ".PARISC.unwind"
-/* Nonzero if CODE is a fixup code needing further processing.  */
-
 /* Object file formats specify relocation types.  */
 /* Object file formats specify relocation types.  */
-typedef elf32_hppa_reloc_type reloc_type;
+typedef elf_hppa_reloc_type reloc_type;
 
 /* Object file formats specify BFD symbol types.  */
 typedef elf_symbol_type obj_symbol_type;
 
 
 /* Object file formats specify BFD symbol types.  */
 typedef elf_symbol_type obj_symbol_type;
 
+#ifdef BFD64
 /* How to generate a relocation.  */
 /* How to generate a relocation.  */
-#define hppa_gen_reloc_type hppa_elf_gen_reloc_type
+#define hppa_gen_reloc_type _bfd_elf64_hppa_gen_reloc_type
+#else
+#define hppa_gen_reloc_type _bfd_elf32_hppa_gen_reloc_type
+#endif
 
 /* ELF objects can have versions, but apparently do not have anywhere
    to store a copyright string.  */
 #define obj_version obj_elf_version
 #define obj_copyright obj_elf_version
 
 
 /* ELF objects can have versions, but apparently do not have anywhere
    to store a copyright string.  */
 #define obj_version obj_elf_version
 #define obj_copyright obj_elf_version
 
-/* Use space aliases.  */
-#define USE_ALIASES 1
+#define UNWIND_SECTION_NAME ".PARISC.unwind"
 #endif
 
 #ifdef OBJ_SOM
 #endif
 
 #ifdef OBJ_SOM
@@ -75,9 +77,6 @@ typedef int reloc_type;
 #define obj_version obj_som_version
 #define obj_copyright obj_som_copyright
 
 #define obj_version obj_som_version
 #define obj_copyright obj_som_copyright
 
-/* Do not use space aliases.  */
-#define USE_ALIASES 0
-
 /* How to generate a relocation.  */
 #define hppa_gen_reloc_type hppa_som_gen_reloc_type
 
 /* How to generate a relocation.  */
 #define hppa_gen_reloc_type hppa_som_gen_reloc_type
 
@@ -90,6 +89,14 @@ typedef som_symbol_type obj_symbol_type;
 #endif
 #endif
 
 #endif
 #endif
 
+#ifndef R_N0SEL
+#define R_N0SEL 0xd8
+#endif
+
+#ifndef R_N1SEL
+#define R_N1SEL 0xd9
+#endif
+
 /* Various structures and types used internally in tc-hppa.c.  */
 
 /* Unwind table and descriptor.  FIXME: Sync this with GDB version.  */
 /* Various structures and types used internally in tc-hppa.c.  */
 
 /* Unwind table and descriptor.  FIXME: Sync this with GDB version.  */
@@ -157,7 +164,7 @@ struct call_info
    SGL and DBL).  */
 typedef enum
   {
    SGL and DBL).  */
 typedef enum
   {
-    SGL, DBL, ILLEGAL_FMT, QUAD
+    SGL, DBL, ILLEGAL_FMT, QUAD, W, UW, DW, UDW, QW, UQW
   }
 fp_operand_format;
 
   }
 fp_operand_format;
 
@@ -195,6 +202,7 @@ struct pa_it
     fp_operand_format fpof1;
     fp_operand_format fpof2;
 
     fp_operand_format fpof1;
     fp_operand_format fpof2;
 
+
     /* Holds the field selector for this instruction
        (for example L%, LR%, etc).  */
     long field_selector;
     /* Holds the field selector for this instruction
        (for example L%, LR%, etc).  */
     long field_selector;
@@ -236,9 +244,9 @@ struct pa_it
    handles the L/R notation and returns the correct
    value to put into the instruction register field.
    The correct value to put into the instruction is
    handles the L/R notation and returns the correct
    value to put into the instruction register field.
    The correct value to put into the instruction is
-   encoded in the structure 'pa_89_fp_reg_struct'.  */
+   encoded in the structure 'pa_11_fp_reg_struct'.  */
 
 
-struct pa_89_fp_reg_struct
+struct pa_11_fp_reg_struct
   {
     /* The register number.  */
     char number_part;
   {
     /* The register number.  */
     char number_part;
@@ -257,6 +265,7 @@ struct call_desc
     unsigned int arg_count;
   };
 
     unsigned int arg_count;
   };
 
+#ifdef OBJ_SOM
 /* This structure defines an entry in the subspace dictionary
    chain.  */
 
 /* This structure defines an entry in the subspace dictionary
    chain.  */
 
@@ -311,17 +320,6 @@ struct space_dictionary_chain
 
 typedef struct space_dictionary_chain sd_chain_struct;
 
 
 typedef struct space_dictionary_chain sd_chain_struct;
 
-/* Structure for previous label tracking.  Needed so that alignments,
-   callinfo declarations, etc can be easily attached to a particular
-   label.  */
-typedef struct label_symbol_struct
-  {
-    struct symbol *lss_label;
-    sd_chain_struct *lss_space;
-    struct label_symbol_struct *lss_next;
-  }
-label_symbol_struct;
-
 /* This structure defines attributes of the default subspace
    dictionary entries.  */
 
 /* This structure defines attributes of the default subspace
    dictionary entries.  */
 
@@ -368,9 +366,6 @@ struct default_subspace_dict
     /* An index into the default spaces array.  */
     int def_space_index;
 
     /* An index into the default spaces array.  */
     int def_space_index;
 
-    /* An alias for this section (or NULL if no alias exists).  */
-    char *alias;
-
     /* Subsegment associated with this subspace.  */
     subsegT subsegment;
   };
     /* Subsegment associated with this subspace.  */
     subsegT subsegment;
   };
@@ -401,16 +396,30 @@ struct default_space_dict
 
     /* Segment associated with this space.  */
     asection *segment;
 
     /* Segment associated with this space.  */
     asection *segment;
-
-    /* An alias for this section (or NULL if no alias exists).  */
-    char *alias;
   };
   };
+#endif
+
+/* Structure for previous label tracking.  Needed so that alignments,
+   callinfo declarations, etc can be easily attached to a particular
+   label.  */
+typedef struct label_symbol_struct
+  {
+    struct symbol *lss_label;
+#ifdef OBJ_SOM
+    sd_chain_struct *lss_space;
+#endif
+#ifdef OBJ_ELF
+    segT lss_segment;
+#endif
+    struct label_symbol_struct *lss_next;
+  }
+label_symbol_struct;
 
 /* Extra information needed to perform fixups (relocations) on the PA.  */
 struct hppa_fix_struct
   {
     /* The field selector.  */
 
 /* Extra information needed to perform fixups (relocations) on the PA.  */
 struct hppa_fix_struct
   {
     /* The field selector.  */
-    enum hppa_reloc_field_selector_type fx_r_field;
+    enum hppa_reloc_field_selector_type_alt fx_r_field;
 
     /* Type of fixup.  */
     int fx_r_type;
 
     /* Type of fixup.  */
     int fx_r_type;
@@ -451,6 +460,10 @@ struct selector_entry
 
 /* Prototypes for functions local to tc-hppa.c.  */
 
 
 /* Prototypes for functions local to tc-hppa.c.  */
 
+#ifdef OBJ_SOM
+static void pa_check_current_space_and_subspace PARAMS ((void));
+#endif
+
 static fp_operand_format pa_parse_fp_format PARAMS ((char **s));
 static void pa_cons PARAMS ((int));
 static void pa_data PARAMS ((int));
 static fp_operand_format pa_parse_fp_format PARAMS ((char **s));
 static void pa_cons PARAMS ((int));
 static void pa_data PARAMS ((int));
@@ -472,8 +485,9 @@ static int pa_parse_nonneg_cmpsub_cmpltr PARAMS ((char **, int));
 static int pa_parse_neg_cmpsub_cmpltr PARAMS ((char **, int));
 static int pa_parse_neg_add_cmpltr PARAMS ((char **, int));
 static int pa_parse_nonneg_add_cmpltr PARAMS ((char **, int));
 static int pa_parse_neg_cmpsub_cmpltr PARAMS ((char **, int));
 static int pa_parse_neg_add_cmpltr PARAMS ((char **, int));
 static int pa_parse_nonneg_add_cmpltr PARAMS ((char **, int));
-static void pa_align PARAMS ((int));
 static void pa_block PARAMS ((int));
 static void pa_block PARAMS ((int));
+static void pa_brtab PARAMS ((int));
+static void pa_try PARAMS ((int));
 static void pa_call PARAMS ((int));
 static void pa_call_args PARAMS ((struct call_desc *));
 static void pa_callinfo PARAMS ((int));
 static void pa_call PARAMS ((int));
 static void pa_call_args PARAMS ((struct call_desc *));
 static void pa_callinfo PARAMS ((int));
@@ -490,18 +504,22 @@ static void pa_type_args PARAMS ((symbolS *, int));
 static void pa_import PARAMS ((int));
 static void pa_label PARAMS ((int));
 static void pa_leave PARAMS ((int));
 static void pa_import PARAMS ((int));
 static void pa_label PARAMS ((int));
 static void pa_leave PARAMS ((int));
+static void pa_level PARAMS ((int));
 static void pa_origin PARAMS ((int));
 static void pa_proc PARAMS ((int));
 static void pa_procend PARAMS ((int));
 static void pa_origin PARAMS ((int));
 static void pa_proc PARAMS ((int));
 static void pa_procend PARAMS ((int));
-static void pa_space PARAMS ((int));
-static void pa_spnum PARAMS ((int));
-static void pa_subspace PARAMS ((int));
 static void pa_param PARAMS ((int));
 static void pa_undefine_label PARAMS ((void));
 static void pa_param PARAMS ((int));
 static void pa_undefine_label PARAMS ((void));
-static int need_89_opcode PARAMS ((struct pa_it *,
-                                  struct pa_89_fp_reg_struct *));
-static int pa_parse_number PARAMS ((char **, struct pa_89_fp_reg_struct *));
+static int need_pa11_opcode PARAMS ((struct pa_it *,
+                                    struct pa_11_fp_reg_struct *));
+static int pa_parse_number PARAMS ((char **, struct pa_11_fp_reg_struct *));
 static label_symbol_struct *pa_get_label PARAMS ((void));
 static label_symbol_struct *pa_get_label PARAMS ((void));
+#ifdef OBJ_SOM
+static void pa_compiler PARAMS ((int));
+static void pa_align PARAMS ((int));
+static void pa_space PARAMS ((int));
+static void pa_spnum PARAMS ((int));
+static void pa_subspace PARAMS ((int));
 static sd_chain_struct *create_new_space PARAMS ((char *, int, int,
                                                  int, int, int,
                                                  asection *, int));
 static sd_chain_struct *create_new_space PARAMS ((char *, int, int,
                                                  int, int, int,
                                                  asection *, int));
@@ -522,27 +540,32 @@ static ssd_chain_struct *pa_subsegment_to_subspace PARAMS ((asection *,
                                                            subsegT));
 static sd_chain_struct *pa_find_space_by_number PARAMS ((int));
 static unsigned int pa_subspace_start PARAMS ((sd_chain_struct *, int));
                                                            subsegT));
 static sd_chain_struct *pa_find_space_by_number PARAMS ((int));
 static unsigned int pa_subspace_start PARAMS ((sd_chain_struct *, int));
+static sd_chain_struct *pa_parse_space_stmt PARAMS ((char *, int));
+static int pa_next_subseg PARAMS ((sd_chain_struct *));
+static void pa_spaces_begin PARAMS ((void));
+#endif
 static void pa_ip PARAMS ((char *));
 static void fix_new_hppa PARAMS ((fragS *, int, int, symbolS *,
                                  long, expressionS *, int,
                                  bfd_reloc_code_real_type,
 static void pa_ip PARAMS ((char *));
 static void fix_new_hppa PARAMS ((fragS *, int, int, symbolS *,
                                  long, expressionS *, int,
                                  bfd_reloc_code_real_type,
-                                 enum hppa_reloc_field_selector_type,
+                                 enum hppa_reloc_field_selector_type_alt,
                                  int, long, int *));
 static int is_end_of_statement PARAMS ((void));
 static int reg_name_search PARAMS ((char *));
 static int pa_chk_field_selector PARAMS ((char **));
 static int is_same_frag PARAMS ((fragS *, fragS *));
                                  int, long, int *));
 static int is_end_of_statement PARAMS ((void));
 static int reg_name_search PARAMS ((char *));
 static int pa_chk_field_selector PARAMS ((char **));
 static int is_same_frag PARAMS ((fragS *, fragS *));
-static void pa_build_unwind_subspace PARAMS ((struct call_info *));
 static void process_exit PARAMS ((void));
 static void process_exit PARAMS ((void));
-static sd_chain_struct *pa_parse_space_stmt PARAMS ((char *, int));
 static int log2 PARAMS ((int));
 static int log2 PARAMS ((int));
-static int pa_next_subseg PARAMS ((sd_chain_struct *));
 static unsigned int pa_stringer_aux PARAMS ((char *));
 static unsigned int pa_stringer_aux PARAMS ((char *));
-static void pa_spaces_begin PARAMS ((void));
+
+#ifdef OBJ_ELF
 static void hppa_elf_mark_end_of_function PARAMS ((void));
 static void hppa_elf_mark_end_of_function PARAMS ((void));
+static void pa_build_unwind_subspace PARAMS ((struct call_info *));
+#endif
 
 /* File and gloally scoped variable declarations.  */
 
 
 /* File and gloally scoped variable declarations.  */
 
+#ifdef OBJ_SOM
 /* Root and final entry in the space chain.  */
 static sd_chain_struct *space_dict_root;
 static sd_chain_struct *space_dict_last;
 /* Root and final entry in the space chain.  */
 static sd_chain_struct *space_dict_root;
 static sd_chain_struct *space_dict_last;
@@ -550,6 +573,7 @@ static sd_chain_struct *space_dict_last;
 /* The current space and subspace.  */
 static sd_chain_struct *current_space;
 static ssd_chain_struct *current_subspace;
 /* The current space and subspace.  */
 static sd_chain_struct *current_space;
 static ssd_chain_struct *current_subspace;
+#endif
 
 /* Root of the call_info chain.  */
 static struct call_info *call_info_root;
 
 /* Root of the call_info chain.  */
 static struct call_info *call_info_root;
@@ -562,14 +586,6 @@ static struct call_info *last_call_info;
 /* The last call description (for actual calls).  */
 static struct call_desc last_call_desc;
 
 /* The last call description (for actual calls).  */
 static struct call_desc last_call_desc;
 
-/* Relaxation isn't supported for the PA yet.  */
-const relax_typeS md_relax_table[] =
-{0};
-
-/* Jumps are always the same size -- one instruction.  */
-int md_short_jump_size = 4;
-int md_long_jump_size = 4;
-
 /* handle of the OPCODE hash table */
 static struct hash_control *op_hash = NULL;
 
 /* handle of the OPCODE hash table */
 static struct hash_control *op_hash = NULL;
 
@@ -584,7 +600,14 @@ const pseudo_typeS md_pseudo_table[] =
 {
   /* align pseudo-ops on the PA specify the actual alignment requested,
      not the log2 of the requested alignment.  */
 {
   /* align pseudo-ops on the PA specify the actual alignment requested,
      not the log2 of the requested alignment.  */
+#ifdef OBJ_SOM
   {"align", pa_align, 8},
   {"align", pa_align, 8},
+#endif
+#ifdef OBJ_ELF
+  {"align", s_align_bytes, 8},
+#endif
+  {"begin_brtab", pa_brtab, 1},
+  {"begin_try", pa_try, 1},
   {"block", pa_block, 1},
   {"blockz", pa_block, 0},
   {"byte", pa_cons, 1},
   {"block", pa_block, 1},
   {"blockz", pa_block, 0},
   {"byte", pa_cons, 1},
@@ -592,10 +615,16 @@ const pseudo_typeS md_pseudo_table[] =
   {"callinfo", pa_callinfo, 0},
   {"code", pa_code, 0},
   {"comm", pa_comm, 0},
   {"callinfo", pa_callinfo, 0},
   {"code", pa_code, 0},
   {"comm", pa_comm, 0},
+#ifdef OBJ_SOM
+  {"compiler", pa_compiler, 0},
+#endif
   {"copyright", pa_copyright, 0},
   {"data", pa_data, 0},
   {"double", pa_float_cons, 'd'},
   {"copyright", pa_copyright, 0},
   {"data", pa_data, 0},
   {"double", pa_float_cons, 'd'},
+  {"dword", pa_cons, 8},
   {"end", pa_end, 0},
   {"end", pa_end, 0},
+  {"end_brtab", pa_brtab, 0},
+  {"end_try", pa_try, 0},
   {"enter", pa_enter, 0},
   {"entry", pa_entry, 0},
   {"equ", pa_equ, 0},
   {"enter", pa_enter, 0},
   {"entry", pa_entry, 0},
   {"equ", pa_equ, 0},
@@ -609,8 +638,12 @@ const pseudo_typeS md_pseudo_table[] =
   {"label", pa_label, 0},
   {"lcomm", pa_lcomm, 0},
   {"leave", pa_leave, 0},
   {"label", pa_label, 0},
   {"lcomm", pa_lcomm, 0},
   {"leave", pa_leave, 0},
+  {"level", pa_level, 0},
   {"long", pa_cons, 4},
   {"lsym", pa_lsym, 0},
   {"long", pa_cons, 4},
   {"lsym", pa_lsym, 0},
+#ifdef OBJ_SOM
+  {"nsubspa", pa_subspace, 1},
+#endif
   {"octa", pa_cons, 16},
   {"org", pa_origin, 0},
   {"origin", pa_origin, 0},
   {"octa", pa_cons, 16},
   {"org", pa_origin, 0},
   {"origin", pa_origin, 0},
@@ -621,11 +654,15 @@ const pseudo_typeS md_pseudo_table[] =
   {"reg", pa_equ, 1},
   {"short", pa_cons, 2},
   {"single", pa_float_cons, 'f'},
   {"reg", pa_equ, 1},
   {"short", pa_cons, 2},
   {"single", pa_float_cons, 'f'},
+#ifdef OBJ_SOM
   {"space", pa_space, 0},
   {"spnum", pa_spnum, 0},
   {"space", pa_space, 0},
   {"spnum", pa_spnum, 0},
+#endif
   {"string", pa_stringer, 0},
   {"stringz", pa_stringer, 1},
   {"string", pa_stringer, 0},
   {"stringz", pa_stringer, 1},
+#ifdef OBJ_SOM
   {"subspa", pa_subspace, 0},
   {"subspa", pa_subspace, 0},
+#endif
   {"text", pa_text, 0},
   {"version", pa_version, 0},
   {"word", pa_cons, 4},
   {"text", pa_text, 0},
   {"version", pa_version, 0},
   {"word", pa_cons, 4},
@@ -640,7 +677,7 @@ const pseudo_typeS md_pseudo_table[] =
    first line of the input file.  This is because the compiler outputs
    #NO_APP at the beginning of its output.
 
    first line of the input file.  This is because the compiler outputs
    #NO_APP at the beginning of its output.
 
-   Also note that '/*' will always start a comment.  */
+   Also note that C style comments will always work. */
 const char line_comment_chars[] = "#";
 
 /* This array holds the characters which act as line separators.  */
 const char line_comment_chars[] = "#";
 
 /* This array holds the characters which act as line separators.  */
@@ -680,8 +717,16 @@ static label_symbol_struct *label_symbols_rootp = NULL;
 /* Holds the last field selector.  */
 static int hppa_field_selector;
 
 /* Holds the last field selector.  */
 static int hppa_field_selector;
 
+/* Nonzero when strict syntax checking is enabled.  Zero otherwise.
+
+   Each opcode in the table has a flag which indicates whether or not
+   strict syntax checking should be enabled for that instruction.  */
+static int strict = 0;
+
+#ifdef OBJ_SOM
 /* A dummy bfd symbol so that all relocations have symbols of some kind.  */
 static symbolS *dummy_symbol;
 /* A dummy bfd symbol so that all relocations have symbols of some kind.  */
 static symbolS *dummy_symbol;
+#endif
 
 /* Nonzero if errors are to be printed.  */
 static int print_errors = 1;
 
 /* Nonzero if errors are to be printed.  */
 static int print_errors = 1;
@@ -960,6 +1005,10 @@ static const struct selector_entry selector_table[] =
   {"lr", e_lrsel},
   {"ls", e_lssel},
   {"lt", e_ltsel},
   {"lr", e_lrsel},
   {"ls", e_lssel},
   {"lt", e_ltsel},
+  {"ltp", e_ltpsel},
+  {"n", e_nsel},
+  {"nl", e_nlsel},
+  {"nlr", e_nlrsel},
   {"p", e_psel},
   {"r", e_rsel},
   {"rd", e_rdsel},
   {"p", e_psel},
   {"r", e_rsel},
   {"rd", e_rdsel},
@@ -967,9 +1016,11 @@ static const struct selector_entry selector_table[] =
   {"rr", e_rrsel},
   {"rs", e_rssel},
   {"rt", e_rtsel},
   {"rr", e_rrsel},
   {"rs", e_rssel},
   {"rt", e_rtsel},
+  {"rtp", e_rtpsel},
   {"t", e_tsel},
 };
 
   {"t", e_tsel},
 };
 
+#ifdef OBJ_SOM
 /* default space and subspace dictionaries */
 
 #define GDB_SYMBOLS          GDB_SYMBOLS_SUBSPACE_NAME
 /* default space and subspace dictionaries */
 
 #define GDB_SYMBOLS          GDB_SYMBOLS_SUBSPACE_NAME
@@ -977,8 +1028,9 @@ static const struct selector_entry selector_table[] =
 
 /* pre-defined subsegments (subspaces) for the HPPA.  */
 #define SUBSEG_CODE   0
 
 /* pre-defined subsegments (subspaces) for the HPPA.  */
 #define SUBSEG_CODE   0
-#define SUBSEG_DATA   0
 #define SUBSEG_LIT    1
 #define SUBSEG_LIT    1
+#define SUBSEG_MILLI  2
+#define SUBSEG_DATA   0
 #define SUBSEG_BSS    2
 #define SUBSEG_UNWIND 3
 #define SUBSEG_GDB_STRINGS 0
 #define SUBSEG_BSS    2
 #define SUBSEG_UNWIND 3
 #define SUBSEG_GDB_STRINGS 0
@@ -986,30 +1038,23 @@ static const struct selector_entry selector_table[] =
 
 static struct default_subspace_dict pa_def_subspaces[] =
 {
 
 static struct default_subspace_dict pa_def_subspaces[] =
 {
-  {"$CODE$", 1, 1, 1, 0, 0, 0, 24, 0x2c, 0, 8, 0, 0, ".text", SUBSEG_CODE},
-  {"$DATA$", 1, 1, 0, 0, 0, 0, 24, 0x1f, 1, 8, 1, 1, ".data", SUBSEG_DATA},
-  {"$LIT$", 1, 1, 0, 0, 0, 0, 16, 0x2c, 0, 8, 0, 0, ".text", SUBSEG_LIT},
-  {"$BSS$", 1, 1, 0, 0, 0, 1, 80, 0x1f, 1, 8, 1, 1, ".bss", SUBSEG_BSS},
-#ifdef OBJ_ELF
-  {"$UNWIND$", 1, 1, 0, 0, 0, 0, 64, 0x2c, 0, 4, 0, 0, ".PARISC.unwind", SUBSEG_UNWIND},
-#endif
+  {"$CODE$", 1, 1, 1, 0, 0, 0, 24, 0x2c, 0, 8, 0, 0, SUBSEG_CODE},
+  {"$DATA$", 1, 1, 0, 0, 0, 0, 24, 0x1f, 1, 8, 1, 1, SUBSEG_DATA},
+  {"$LIT$", 1, 1, 0, 0, 0, 0, 16, 0x2c, 0, 8, 0, 0, SUBSEG_LIT},
+  {"$MILLICODE$", 1, 1, 0, 0, 0, 0, 8, 0x2c, 0, 8, 0, 0, SUBSEG_MILLI},
+  {"$BSS$", 1, 1, 0, 0, 0, 1, 80, 0x1f, 1, 8, 1, 1, SUBSEG_BSS},
   {NULL, 0, 1, 0, 0, 0, 0, 255, 0x1f, 0, 4, 0, 0, 0}
 };
 
 static struct default_space_dict pa_def_spaces[] =
 {
   {NULL, 0, 1, 0, 0, 0, 0, 255, 0x1f, 0, 4, 0, 0, 0}
 };
 
 static struct default_space_dict pa_def_spaces[] =
 {
-  {"$TEXT$", 0, 1, 1, 0, 8, ASEC_NULL, ".text"},
-  {"$PRIVATE$", 1, 1, 1, 1, 16, ASEC_NULL, ".data"},
-  {NULL, 0, 0, 0, 0, 0, ASEC_NULL, NULL}
+  {"$TEXT$", 0, 1, 1, 0, 8, ASEC_NULL},
+  {"$PRIVATE$", 1, 1, 1, 1, 16, ASEC_NULL},
+  {NULL, 0, 0, 0, 0, 0, ASEC_NULL}
 };
 
 /* Misc local definitions used by the assembler.  */
 
 };
 
 /* Misc local definitions used by the assembler.  */
 
-/* Return nonzero if the string pointed to by S potentially represents
-   a right or left half of a FP register  */
-#define IS_R_SELECT(S)   (*(S) == 'R' || *(S) == 'r')
-#define IS_L_SELECT(S)   (*(S) == 'L' || *(S) == 'l')
-
 /* These macros are used to maintain spaces/subspaces.  */
 #define SPACE_DEFINED(space_chain)     (space_chain)->sd_defined
 #define SPACE_USER_DEFINED(space_chain) (space_chain)->sd_user_defined
 /* These macros are used to maintain spaces/subspaces.  */
 #define SPACE_DEFINED(space_chain)     (space_chain)->sd_defined
 #define SPACE_USER_DEFINED(space_chain) (space_chain)->sd_user_defined
@@ -1018,6 +1063,12 @@ static struct default_space_dict pa_def_spaces[] =
 
 #define SUBSPACE_DEFINED(ss_chain)     (ss_chain)->ssd_defined
 #define SUBSPACE_NAME(ss_chain)                (ss_chain)->ssd_name
 
 #define SUBSPACE_DEFINED(ss_chain)     (ss_chain)->ssd_defined
 #define SUBSPACE_NAME(ss_chain)                (ss_chain)->ssd_name
+#endif
+
+/* Return nonzero if the string pointed to by S potentially represents
+   a right or left half of a FP register  */
+#define IS_R_SELECT(S)   (*(S) == 'R' || *(S) == 'r')
+#define IS_L_SELECT(S)   (*(S) == 'L' || *(S) == 'l')
 
 /* Insert FIELD into OPCODE starting at bit START.  Continue pa_ip
    main loop after insertion.  */
 
 /* Insert FIELD into OPCODE starting at bit START.  Continue pa_ip
    main loop after insertion.  */
@@ -1036,7 +1087,7 @@ static struct default_space_dict pa_def_spaces[] =
     if ((FIELD) > (HIGH) || (FIELD) < (LOW)) \
       { \
        if (! IGNORE) \
     if ((FIELD) > (HIGH) || (FIELD) < (LOW)) \
       { \
        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));\
         break; \
       } \
                  (int) (FIELD));\
         break; \
       } \
@@ -1044,11 +1095,11 @@ static struct default_space_dict pa_def_spaces[] =
 
 #define is_DP_relative(exp)                    \
   ((exp).X_op == O_subtract                    \
 
 #define is_DP_relative(exp)                    \
   ((exp).X_op == O_subtract                    \
-   && strcmp((exp).X_op_symbol->bsym->name, "$global$") == 0)
+   && strcmp (S_GET_NAME ((exp).X_op_symbol), "$global$") == 0)
 
 #define is_PC_relative(exp)                    \
   ((exp).X_op == O_subtract                    \
 
 #define is_PC_relative(exp)                    \
   ((exp).X_op == O_subtract                    \
-   && strcmp((exp).X_op_symbol->bsym->name, "$PIC_pcrel$0") == 0)
+   && strcmp (S_GET_NAME ((exp).X_op_symbol), "$PIC_pcrel$0") == 0)
 
 /* 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
 
 /* 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
@@ -1058,6 +1109,19 @@ static struct default_space_dict pa_def_spaces[] =
 
 /* 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
+   proc/procend pairs match.  */
+
+void
+pa_check_eof ()
+{
+  if (within_entry_exit)
+    as_fatal (_("Missing .exit\n"));
+
+  if (within_procedure)
+    as_fatal (_("Missing .procend\n"));
+}
+
 /* Returns a pointer to the label_symbol_struct for the current space.
    or NULL if no label_symbol_struct exists 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.  */
 
@@ -1065,13 +1129,20 @@ static label_symbol_struct *
 pa_get_label ()
 {
   label_symbol_struct *label_chain;
 pa_get_label ()
 {
   label_symbol_struct *label_chain;
-  sd_chain_struct *space_chain = current_space;
 
   for (label_chain = label_symbols_rootp;
        label_chain;
        label_chain = label_chain->lss_next)
 
   for (label_chain = label_symbols_rootp;
        label_chain;
        label_chain = label_chain->lss_next)
-    if (space_chain == label_chain->lss_space && label_chain->lss_label)
+    {
+#ifdef OBJ_SOM
+    if (current_space == label_chain->lss_space && label_chain->lss_label)
+      return label_chain;
+#endif
+#ifdef OBJ_ELF
+    if (now_seg == label_chain->lss_segment && label_chain->lss_label)
       return label_chain;
       return label_chain;
+#endif
+    }
 
   return NULL;
 }
 
   return NULL;
 }
@@ -1084,7 +1155,6 @@ pa_define_label (symbol)
      symbolS *symbol;
 {
   label_symbol_struct *label_chain = pa_get_label ();
      symbolS *symbol;
 {
   label_symbol_struct *label_chain = pa_get_label ();
-  sd_chain_struct *space_chain = current_space;
 
   if (label_chain)
     label_chain->lss_label = symbol;
 
   if (label_chain)
     label_chain->lss_label = symbol;
@@ -1094,7 +1164,12 @@ pa_define_label (symbol)
       label_chain
        = (label_symbol_struct *) xmalloc (sizeof (label_symbol_struct));
       label_chain->lss_label = symbol;
       label_chain
        = (label_symbol_struct *) xmalloc (sizeof (label_symbol_struct));
       label_chain->lss_label = symbol;
-      label_chain->lss_space = space_chain;
+#ifdef OBJ_SOM
+      label_chain->lss_space = current_space;
+#endif
+#ifdef OBJ_ELF
+      label_chain->lss_segment = now_seg;
+#endif
       label_chain->lss_next = NULL;
 
       if (label_symbols_rootp)
       label_chain->lss_next = NULL;
 
       if (label_symbols_rootp)
@@ -1112,13 +1187,19 @@ pa_undefine_label ()
 {
   label_symbol_struct *label_chain;
   label_symbol_struct *prev_label_chain = NULL;
 {
   label_symbol_struct *label_chain;
   label_symbol_struct *prev_label_chain = NULL;
-  sd_chain_struct *space_chain = current_space;
 
   for (label_chain = label_symbols_rootp;
        label_chain;
        label_chain = label_chain->lss_next)
     {
 
   for (label_chain = label_symbols_rootp;
        label_chain;
        label_chain = label_chain->lss_next)
     {
-      if (space_chain == label_chain->lss_space && label_chain->lss_label)
+      if (1
+#ifdef OBJ_SOM
+         && current_space == label_chain->lss_space && label_chain->lss_label
+#endif
+#ifdef OBJ_ELF
+         && now_seg == label_chain->lss_segment && label_chain->lss_label
+#endif
+         )
        {
          /* Remove the label from the chain and free its memory.  */
          if (prev_label_chain)
        {
          /* Remove the label from the chain and free its memory.  */
          if (prev_label_chain)
@@ -1152,7 +1233,7 @@ fix_new_hppa (frag, where, size, add_symbol, offset, exp, pcrel,
      expressionS *exp;
      int pcrel;
      bfd_reloc_code_real_type r_type;
      expressionS *exp;
      int pcrel;
      bfd_reloc_code_real_type r_type;
-     enum hppa_reloc_field_selector_type r_field;
+     enum hppa_reloc_field_selector_type_alt r_field;
      int r_format;
      long arg_reloc;
      int* unwind_bits;
      int r_format;
      long arg_reloc;
      int* unwind_bits;
@@ -1217,11 +1298,11 @@ cons_fix_new_hppa (frag, where, size, exp)
     rel_type = R_HPPA;
 
   if (hppa_field_selector != e_psel && hppa_field_selector != e_fsel)
     rel_type = R_HPPA;
 
   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%%."));
 
   fix_new_hppa (frag, where, size,
                (symbolS *) NULL, (offsetT) 0, exp, 0, rel_type,
 
   fix_new_hppa (frag, where, size,
                (symbolS *) NULL, (offsetT) 0, exp, 0, rel_type,
-               hppa_field_selector, 32, 0, NULL);
+               hppa_field_selector, size * 8, 0, NULL);
 
   /* Reset field selector to its default state.  */
   hppa_field_selector = 0;
 
   /* Reset field selector to its default state.  */
   hppa_field_selector = 0;
@@ -1240,15 +1321,21 @@ md_begin ()
   last_call_info = NULL;
   call_info_root = NULL;
 
   last_call_info = NULL;
   call_info_root = NULL;
 
+  /* Set the default machine type.  */
+  if (!bfd_set_arch_mach (stdoutput, bfd_arch_hppa, 10))
+    as_warn (_("could not set architecture and machine"));
+
   /* Folding of text and data segments fails miserably on the PA.
      Warn user and disable "-R" option.  */
   if (flag_readonly_data_in_text)
     {
   /* Folding of text and data segments fails miserably on the PA.
      Warn user and disable "-R" option.  */
   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
   pa_spaces_begin ();
   pa_spaces_begin ();
+#endif
 
   op_hash = hash_new ();
 
 
   op_hash = hash_new ();
 
@@ -1258,7 +1345,7 @@ md_begin ()
       retval = hash_insert (op_hash, name, (struct pa_opcode *) &pa_opcodes[i]);
       if (retval != NULL && *retval != '\0')
        {
       retval = hash_insert (op_hash, name, (struct pa_opcode *) &pa_opcodes[i]);
       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;
        }
       do
          lose = 1;
        }
       do
@@ -1266,7 +1353,7 @@ md_begin ()
          if ((pa_opcodes[i].match & pa_opcodes[i].mask)
              != pa_opcodes[i].match)
            {
          if ((pa_opcodes[i].match & pa_opcodes[i].mask)
              != 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);
              lose = 1;
            }
                       pa_opcodes[i].name, pa_opcodes[i].args);
              lose = 1;
            }
@@ -1276,14 +1363,20 @@ md_begin ()
     }
 
   if (lose)
     }
 
   if (lose)
-    as_fatal ("Broken assembler.  No assembly attempted.");
+    as_fatal (_("Broken assembler.  No assembly attempted."));
 
 
+#ifdef OBJ_SOM
   /* SOM will change text_section.  To make sure we never put
      anything into the old one switch to the new one now.  */
   subseg_set (text_section, 0);
   /* SOM will change text_section.  To make sure we never put
      anything into the old one switch to the new one now.  */
   subseg_set (text_section, 0);
+#endif
 
 
+#ifdef OBJ_SOM
   dummy_symbol = symbol_find_or_make ("L$dummy");
   S_SET_SEGMENT (dummy_symbol, text_section);
   dummy_symbol = symbol_find_or_make ("L$dummy");
   S_SET_SEGMENT (dummy_symbol, text_section);
+  /* Force the symbol to be converted to a real symbol. */
+  (void) symbol_get_bfdsym (dummy_symbol); 
+#endif
 }
 
 /* Assemble a single instruction storing it into a frag.  */
 }
 
 /* Assemble a single instruction storing it into a frag.  */
@@ -1312,7 +1405,8 @@ md_assemble (str)
          if (label_symbol->lss_label)
            {
              last_call_info->start_symbol = label_symbol->lss_label;
          if (label_symbol->lss_label)
            {
              last_call_info->start_symbol = label_symbol->lss_label;
-             label_symbol->lss_label->bsym->flags |= BSF_FUNCTION;
+             symbol_get_bfdsym (label_symbol->lss_label)->flags
+               |= BSF_FUNCTION;
 #ifdef OBJ_SOM
              /* Also handle allocation of a fixup to hold the unwind
                 information when the label appears after the proc/procend.  */
 #ifdef OBJ_SOM
              /* Also handle allocation of a fixup to hold the unwind
                 information when the label appears after the proc/procend.  */
@@ -1328,10 +1422,10 @@ md_assemble (str)
 #endif
            }
          else
 #endif
            }
          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".  */
@@ -1367,6 +1461,17 @@ pa_ip (str)
   unsigned long opcode;
   struct pa_opcode *insn;
 
   unsigned long opcode;
   struct pa_opcode *insn;
 
+#ifdef OBJ_SOM
+  /* We must have a valid space and subspace.  */
+  pa_check_current_space_and_subspace ();
+#endif
+
+  /* Convert everything up to the first whitespace character into lower
+     case.  */
+  for (s = str; *s != ' ' && *s != '\t' && *s != '\n' && *s != '\0'; s++)
+    if (isupper (*s))
+      *s = tolower (*s);
+
   /* Skip to something interesting.  */
   for (s = str; isupper (*s) || islower (*s) || (*s >= '0' && *s <= '3'); ++s)
     ;
   /* Skip to something interesting.  */
   for (s = str; isupper (*s) || islower (*s) || (*s >= '0' && *s <= '3'); ++s)
     ;
@@ -1387,19 +1492,11 @@ pa_ip (str)
       break;
 
     default:
       break;
 
     default:
-      as_fatal ("Unknown opcode: `%s'", str);
+      as_fatal (_("Unknown opcode: `%s'"), str);
     }
 
   save_s = str;
 
     }
 
   save_s = str;
 
-  /* Convert everything into lower case.  */
-  while (*save_s)
-    {
-      if (isupper (*save_s))
-       *save_s = tolower (*save_s);
-      save_s++;
-    }
-
   /* Look up the opcode in the has table.  */
   if ((insn = (struct pa_opcode *) hash_find (op_hash, str)) == NULL)
     {
   /* Look up the opcode in the has table.  */
   if ((insn = (struct pa_opcode *) hash_find (op_hash, str)) == NULL)
     {
@@ -1419,14 +1516,35 @@ pa_ip (str)
     {
       /* Do some initialization.  */
       opcode = insn->match;
     {
       /* Do some initialization.  */
       opcode = insn->match;
-      bzero (&the_insn, sizeof (the_insn));
+      strict = (insn->flags & FLAG_STRICT);
+      memset (&the_insn, 0, sizeof (the_insn));
 
       the_insn.reloc = R_HPPA_NONE;
 
 
       the_insn.reloc = R_HPPA_NONE;
 
+      /* If this instruction is specific to a particular architecture,
+        then set a new architecture.  */
+      /* But do not automatically promote to pa2.0.  The automatic promotion
+        crud is for compatability with HP's old assemblers only.  */
+      if (insn->arch < 20
+         && bfd_get_mach (stdoutput) < insn->arch)
+       {
+         if (!bfd_set_arch_mach (stdoutput, bfd_arch_hppa, insn->arch))
+           as_warn (_("could not update architecture and machine"));
+       }
+      else if (bfd_get_mach (stdoutput) < insn->arch)
+       {
+         match = FALSE;
+         goto failed;
+       }
+
       /* Build the opcode, checking as we go to make
          sure that the operands match.  */
       for (args = insn->args;; ++args)
        {
       /* Build the opcode, checking as we go to make
          sure that the operands match.  */
       for (args = insn->args;; ++args)
        {
+         /* Absorb white space in instruction.  */
+         while (*s == ' ' || *s == '\t')
+           s++;
+
          switch (*args)
            {
 
          switch (*args)
            {
 
@@ -1458,26 +1576,65 @@ pa_ip (str)
            /* Handle a 5 bit register or control register field at 10.  */
            case 'b':
            case '^':
            /* Handle a 5 bit register or control register field at 10.  */
            case 'b':
            case '^':
+             /* This should be more strict.  Small steps.  */
+             if (strict && *s != '%')
+               break;
              num = pa_parse_number (&s, 0);
              CHECK_FIELD (num, 31, 0, 0);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 21);
 
              num = pa_parse_number (&s, 0);
              CHECK_FIELD (num, 31, 0, 0);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 21);
 
+           /* Handle %sar or %cr11.  No bits get set, we just verify that it
+              is there.  */
+           case '!':
+             /* Skip whitespace before register.  */
+             while (*s == ' ' || *s == '\t')
+               s = s + 1;
+
+             if (!strncasecmp(s, "%sar", 4))
+               {
+                 s += 4;
+                 continue;
+               }
+             else if (!strncasecmp(s, "%cr11", 5))
+               {
+                 s += 5;
+                 continue;
+               }
+             break;
+
            /* Handle a 5 bit register field at 15.  */
            case 'x':
            /* Handle a 5 bit register field at 15.  */
            case 'x':
+             /* This should be more strict.  Small steps.  */
+             if (strict && *s != '%')
+               break;
              num = pa_parse_number (&s, 0);
              CHECK_FIELD (num, 31, 0, 0);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 16);
 
            /* Handle a 5 bit register field at 31.  */
              num = pa_parse_number (&s, 0);
              CHECK_FIELD (num, 31, 0, 0);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 16);
 
            /* Handle a 5 bit register field at 31.  */
-           case 'y':
            case 't':
            case 't':
+             /* This should be more strict.  Small steps.  */
+             if (strict && *s != '%')
+               break;
              num = pa_parse_number (&s, 0);
              CHECK_FIELD (num, 31, 0, 0);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
 
              num = pa_parse_number (&s, 0);
              CHECK_FIELD (num, 31, 0, 0);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
 
+           /* Handle a 5 bit register field at 10 and 15.  */
+           case 'a':
+             /* This should be more strict.  Small steps.  */
+             if (strict && *s != '%')
+               break;
+             num = pa_parse_number (&s, 0);
+             CHECK_FIELD (num, 31, 0, 0);
+             opcode |= num << 16;
+             INSERT_FIELD_AND_CONTINUE (opcode, num, 21);
+
            /* Handle a 5 bit field length at 31.  */
            case 'T':
              num = pa_get_absolute_expression (&the_insn, &s);
            /* Handle a 5 bit field length at 31.  */
            case 'T':
              num = pa_get_absolute_expression (&the_insn, &s);
+             if (strict && the_insn.exp.X_op != O_constant)
+               break;
              s = expr_end;
              CHECK_FIELD (num, 32, 1, 0);
              INSERT_FIELD_AND_CONTINUE (opcode, 32 - num, 0);
              s = expr_end;
              CHECK_FIELD (num, 32, 1, 0);
              INSERT_FIELD_AND_CONTINUE (opcode, 32 - num, 0);
@@ -1485,489 +1642,1004 @@ pa_ip (str)
            /* Handle a 5 bit immediate at 15.  */
            case '5':
              num = pa_get_absolute_expression (&the_insn, &s);
            /* Handle a 5 bit immediate at 15.  */
            case '5':
              num = pa_get_absolute_expression (&the_insn, &s);
+             if (strict && the_insn.exp.X_op != O_constant)
+               break;
              s = expr_end;
              s = expr_end;
-             CHECK_FIELD (num, 15, -16, 0);
+             /* When in strict mode, we want to just reject this
+                match instead of giving an out of range error.  */
+             CHECK_FIELD (num, 15, -16, strict);
              low_sign_unext (num, 5, &num);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 16);
 
            /* Handle a 5 bit immediate at 31.  */
            case 'V':
              num = pa_get_absolute_expression (&the_insn, &s);
              low_sign_unext (num, 5, &num);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 16);
 
            /* Handle a 5 bit immediate at 31.  */
            case 'V':
              num = pa_get_absolute_expression (&the_insn, &s);
+             if (strict && the_insn.exp.X_op != O_constant)
+               break;
              s = expr_end;
              s = expr_end;
-             CHECK_FIELD (num, 15, -16, 0)
-               low_sign_unext (num, 5, &num);
+             /* When in strict mode, we want to just reject this
+                match instead of giving an out of range error.  */
+             CHECK_FIELD (num, 15, -16, strict)
+             low_sign_unext (num, 5, &num);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
 
            /* Handle an unsigned 5 bit immediate at 31.  */
            case 'r':
              num = pa_get_absolute_expression (&the_insn, &s);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
 
            /* Handle an unsigned 5 bit immediate at 31.  */
            case 'r':
              num = pa_get_absolute_expression (&the_insn, &s);
+             if (strict && the_insn.exp.X_op != O_constant)
+               break;
              s = expr_end;
              CHECK_FIELD (num, 31, 0, 0);
              s = expr_end;
              CHECK_FIELD (num, 31, 0, 0);
-             INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
+             INSERT_FIELD_AND_CONTINUE (opcode, num, strict);
 
            /* Handle an unsigned 5 bit immediate at 15.  */
            case 'R':
              num = pa_get_absolute_expression (&the_insn, &s);
 
            /* Handle an unsigned 5 bit immediate at 15.  */
            case 'R':
              num = pa_get_absolute_expression (&the_insn, &s);
+             if (strict && the_insn.exp.X_op != O_constant)
+               break;
              s = expr_end;
              s = expr_end;
-             CHECK_FIELD (num, 31, 0, 0);
+             CHECK_FIELD (num, 31, 0, strict);
+             INSERT_FIELD_AND_CONTINUE (opcode, num, 16);
+
+           /* Handle an unsigned 10 bit immediate at 15.  */
+           case 'U':
+             num = pa_get_absolute_expression (&the_insn, &s);
+             if (strict && the_insn.exp.X_op != O_constant)
+               break;
+             s = expr_end;
+             CHECK_FIELD (num, 1023, 0, strict);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 16);
 
            /* Handle a 2 bit space identifier at 17.  */
            case 's':
              INSERT_FIELD_AND_CONTINUE (opcode, num, 16);
 
            /* Handle a 2 bit space identifier at 17.  */
            case 's':
+             /* This should be more strict.  Small steps.  */
+             if (strict && *s != '%')
+               break;
              num = pa_parse_number (&s, 0);
              CHECK_FIELD (num, 3, 0, 1);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 14);
 
            /* Handle a 3 bit space identifier at 18.  */
            case 'S':
              num = pa_parse_number (&s, 0);
              CHECK_FIELD (num, 3, 0, 1);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 14);
 
            /* Handle a 3 bit space identifier at 18.  */
            case 'S':
+             /* This should be more strict.  Small steps.  */
+             if (strict && *s != '%')
+               break;
              num = pa_parse_number (&s, 0);
              CHECK_FIELD (num, 7, 0, 1);
              dis_assemble_3 (num, &num);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 13);
 
              num = pa_parse_number (&s, 0);
              CHECK_FIELD (num, 7, 0, 1);
              dis_assemble_3 (num, &num);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 13);
 
-           /* Handle a completer for an indexing load or store.  */
+           /* Handle all completers.  */
            case 'c':
            case 'c':
-             {
-               int uu = 0;
-               int m = 0;
-               int i = 0;
-               while (*s == ',' && i < 2)
+             switch (*++args)
+               {
+
+               /* Handle a completer for an indexing load or store.  */
+               case 'x':
                  {
                  {
-                   s++;
-                   if (strncasecmp (s, "sm", 2) == 0)
+                   int uu = 0;
+                   int m = 0;
+                   int i = 0;
+                   while (*s == ',' && i < 2)
                      {
                      {
-                       uu = 1;
-                       m = 1;
+                       s++;
+                       if (strncasecmp (s, "sm", 2) == 0)
+                         {
+                           uu = 1;
+                           m = 1;
+                           s++;
+                           i++;
+                         }
+                       else if (strncasecmp (s, "m", 1) == 0)
+                         m = 1;
+                       else if (strncasecmp (s, "s", 1) == 0)
+                         uu = 1;
+                       /* When in strict mode this is a match failure.  */
+                       else if (strict)
+                         break;
+                       else
+                         as_bad (_("Invalid Indexed Load Completer."));
                        s++;
                        i++;
                      }
                        s++;
                        i++;
                      }
-                   else if (strncasecmp (s, "m", 1) == 0)
-                     m = 1;
-                   else if (strncasecmp (s, "s", 1) == 0)
-                     uu = 1;
-                   else
-                     as_bad ("Invalid Indexed Load Completer.");
-                   s++;
-                   i++;
+                   if (i > 2)
+                     as_bad (_("Invalid Indexed Load Completer Syntax."));
+                   opcode |= m << 5;
+                   INSERT_FIELD_AND_CONTINUE (opcode, uu, 13);
                  }
                  }
-               if (i > 2)
-                 as_bad ("Invalid Indexed Load Completer Syntax.");
-               opcode |= m << 5;
-               INSERT_FIELD_AND_CONTINUE (opcode, uu, 13);
-             }
 
 
-           /* Handle a short load/store completer.  */
-           case 'C':
-             {
-               int a = 0;
-               int m = 0;
-               if (*s == ',')
+               /* Handle a short load/store completer.  */
+               case 'm':
                  {
                  {
-                   s++;
-                   if (strncasecmp (s, "ma", 2) == 0)
-                     {
-                       a = 0;
-                       m = 1;
-                     }
-                   else if (strncasecmp (s, "mb", 2) == 0)
+                   int a = 0;
+                   int m = 0;
+                   if (*s == ',')
                      {
                      {
-                       a = 1;
-                       m = 1;
+                       s++;
+                       if (strncasecmp (s, "ma", 2) == 0)
+                         {
+                           a = 0;
+                           m = 1;
+                         }
+                       else if (strncasecmp (s, "mb", 2) == 0)
+                         {
+                           a = 1;
+                           m = 1;
+                         }
+                       /* When in strict mode this is a match failure.  */
+                       else if (strict)
+                         break;
+                       else
+                         as_bad (_("Invalid Short Load/Store Completer."));
+                       s += 2;
                      }
                      }
-                   else
-                     as_bad ("Invalid Short Load/Store Completer.");
-                   s += 2;
+
+                   opcode |= m << 5;
+                   INSERT_FIELD_AND_CONTINUE (opcode, a, 13);
                  }
                  }
-               opcode |= m << 5;
-               INSERT_FIELD_AND_CONTINUE (opcode, a, 13);
-             }
 
 
-           /* Handle a stbys completer.  */
-           case 'Y':
-             {
-               int a = 0;
-               int m = 0;
-               int i = 0;
-               while (*s == ',' && i < 2)
+               /* Handle a stbys completer.  */
+               case 's':
                  {
                  {
-                   s++;
-                   if (strncasecmp (s, "m", 1) == 0)
-                     m = 1;
-                   else if (strncasecmp (s, "b", 1) == 0)
-                     a = 0;
-                   else if (strncasecmp (s, "e", 1) == 0)
-                     a = 1;
-                   else
-                     as_bad ("Invalid Store Bytes Short Completer");
-                   s++;
-                   i++;
+                   int a = 0;
+                   int m = 0;
+                   int i = 0;
+                   while (*s == ',' && i < 2)
+                     {
+                       s++;
+                       if (strncasecmp (s, "m", 1) == 0)
+                         m = 1;
+                       else if (strncasecmp (s, "b", 1) == 0)
+                         a = 0;
+                       else if (strncasecmp (s, "e", 1) == 0)
+                         a = 1;
+                       /* When in strict mode this is a match failure.  */
+                       else if (strict)
+                         break;
+                       else
+                         as_bad (_("Invalid Store Bytes Short Completer"));
+                       s++;
+                       i++;
+                     }
+                   if (i > 2)
+                     as_bad (_("Invalid Store Bytes Short Completer"));
+                   opcode |= m << 5;
+                   INSERT_FIELD_AND_CONTINUE (opcode, a, 13);
                  }
                  }
-               if (i > 2)
-                 as_bad ("Invalid Store Bytes Short Completer");
-               opcode |= m << 5;
-               INSERT_FIELD_AND_CONTINUE (opcode, a, 13);
-             }
 
 
-           /* Handle a non-negated compare/stubtract condition.  */
-           case '<':
-             cmpltr = pa_parse_nonneg_cmpsub_cmpltr (&s, 1);
-             if (cmpltr < 0)
-               {
-                 as_bad ("Invalid Compare/Subtract Condition: %c", *s);
-                 cmpltr = 0;
-               }
-             INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 13);
+               /* Handle a local processor completer.  */
+               case 'L':
+                 if (strncasecmp (s, ",l", 2) != 0)
+                   break;
+                 s += 2;
+                 continue;
 
 
-           /* Handle a negated or non-negated compare/subtract condition.  */
-           case '?':
-             save_s = s;
-             cmpltr = pa_parse_nonneg_cmpsub_cmpltr (&s, 1);
-             if (cmpltr < 0)
-               {
-                 s = save_s;
-                 cmpltr = pa_parse_neg_cmpsub_cmpltr (&s, 1);
-                 if (cmpltr < 0)
+               /* Handle a PROBE read/write completer.  */
+               case 'w':
+                 flag = 0;
+                 if (!strncasecmp (s, ",w", 2))
                    {
                    {
-                     as_bad ("Invalid Compare/Subtract Condition.");
-                     cmpltr = 0;
+                     flag = 1;
+                     s += 2;
                    }
                    }
-                 else
+                 else if (!strncasecmp (s, ",r", 2))
                    {
                    {
-                     /* Negated condition requires an opcode change.  */
-                     opcode |= 1 << 27;
+                     flag = 0;
+                     s += 2;
                    }
                    }
-               }
-             INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 13);
 
 
-           /* Handle non-negated add condition.  */
-           case '!':
-             cmpltr = pa_parse_nonneg_add_cmpltr (&s, 1);
-             if (cmpltr < 0)
-               {
-                 as_bad ("Invalid Compare/Subtract Condition: %c", *s);
-                 cmpltr = 0;
-               }
-             INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 13);
+                 INSERT_FIELD_AND_CONTINUE (opcode, flag, 6);
 
 
-           /* Handle a negated or non-negated add condition.  */
-           case '@':
-             save_s = s;
-             cmpltr = pa_parse_nonneg_add_cmpltr (&s, 1);
-             if (cmpltr < 0)
-               {
-                 s = save_s;
-                 cmpltr = pa_parse_neg_add_cmpltr (&s, 1);
-                 if (cmpltr < 0)
-                   {
-                     as_bad ("Invalid Compare/Subtract Condition");
-                     cmpltr = 0;
-                   }
-                 else
+               /* Handle MFCTL wide completer.  */
+               case 'W':       
+                 if (strncasecmp (s, ",w", 2) != 0)
+                   break;
+                 s += 2;
+                 continue;
+
+               /* Handle an RFI restore completer.  */
+               case 'r':
+                 flag = 0;
+                 if (!strncasecmp (s, ",r", 2))
                    {
                    {
-                     /* Negated condition requires an opcode change.  */
-                     opcode |= 1 << 27;
+                     flag = 5;
+                     s += 2;
                    }
                    }
-               }
-             INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 13);
 
 
-           /* Handle a compare/subtract condition.  */
-           case 'a':
-             cmpltr = 0;
-             flag = 0;
-             save_s = s;
-             if (*s == ',')
-               {
-                 cmpltr = pa_parse_nonneg_cmpsub_cmpltr (&s, 0);
-                 if (cmpltr < 0)
+                 INSERT_FIELD_AND_CONTINUE (opcode, flag, 5);
+
+               /* Handle a system control completer.  */
+               case 'Z':
+                 if (*s == ',' && (*(s + 1) == 'm' || *(s + 1) == 'M'))
                    {
                      flag = 1;
                    {
                      flag = 1;
-                     s = save_s;
-                     cmpltr = pa_parse_neg_cmpsub_cmpltr (&s, 0);
-                     if (cmpltr < 0)
-                       {
-                         as_bad ("Invalid Compare/Subtract Condition");
-                       }
+                     s += 2;
                    }
                    }
-               }
-             opcode |= cmpltr << 13;
-             INSERT_FIELD_AND_CONTINUE (opcode, flag, 12);
+                 else
+                   flag = 0;
 
 
-           /* Handle a non-negated add condition.  */
-           case 'd':
-             cmpltr = 0;
-             nullif = 0;
-             flag = 0;
-             if (*s == ',')
-               {
-                 s++;
-                 name = s;
-                 while (*s != ',' && *s != ' ' && *s != '\t')
-                   s += 1;
-                 c = *s;
-                 *s = 0x00;
-                 if (strcmp (name, "=") == 0)
-                   cmpltr = 1;
-                 else if (strcmp (name, "<") == 0)
-                   cmpltr = 2;
-                 else if (strcmp (name, "<=") == 0)
-                   cmpltr = 3;
-                 else if (strcasecmp (name, "nuv") == 0)
-                   cmpltr = 4;
-                 else if (strcasecmp (name, "znv") == 0)
-                   cmpltr = 5;
-                 else if (strcasecmp (name, "sv") == 0)
-                   cmpltr = 6;
-                 else if (strcasecmp (name, "od") == 0)
-                   cmpltr = 7;
-                 else if (strcasecmp (name, "n") == 0)
-                   nullif = 1;
-                 else if (strcasecmp (name, "tr") == 0)
+                 INSERT_FIELD_AND_CONTINUE (opcode, flag, 5);
+
+               /* Handle intermediate/final completer for DCOR.  */
+               case 'i':
+                 flag = 0;
+                 if (!strncasecmp (s, ",i", 2))
                    {
                    {
-                     cmpltr = 0;
                      flag = 1;
                      flag = 1;
+                     s += 2;
                    }
                    }
-                 else if (strcmp (name, "<>") == 0)
+
+                 INSERT_FIELD_AND_CONTINUE (opcode, flag, 6);
+
+               /* Handle zero/sign extension completer.  */
+               case 'z':
+                 flag = 1;
+                 if (!strncasecmp (s, ",z", 2))
                    {
                    {
-                     cmpltr = 1;
-                     flag = 1;
+                     flag = 0;
+                     s += 2;
                    }
                    }
-                 else if (strcmp (name, ">=") == 0)
+
+                 INSERT_FIELD_AND_CONTINUE (opcode, flag, 10);
+
+               /* Handle add completer.  */
+               case 'a':
+                 flag = 1;
+                 if (!strncasecmp (s, ",l", 2))
                    {
                    {
-                     cmpltr = 2;
-                     flag = 1;
+                     flag = 2;
+                     s += 2;
                    }
                    }
-                 else if (strcmp (name, ">") == 0)
+                 else if (!strncasecmp (s, ",tsv", 4))
                    {
                    {
-                     cmpltr = 3;
-                     flag = 1;
+                     flag = 3;
+                     s += 4;
                    }
                    }
-                 else if (strcasecmp (name, "uv") == 0)
+                 
+                 INSERT_FIELD_AND_CONTINUE (opcode, flag, 10);
+
+               /* Handle 64 bit carry for ADD.  */
+               case 'Y':
+                 flag = 0;
+                 if (!strncasecmp (s, ",dc,tsv", 7) ||
+                     !strncasecmp (s, ",tsv,dc", 7))
                    {
                    {
-                     cmpltr = 4;
                      flag = 1;
                      flag = 1;
+                     s += 7;
                    }
                    }
-                 else if (strcasecmp (name, "vnz") == 0)
+                 else if (!strncasecmp (s, ",dc", 3))
                    {
                    {
-                     cmpltr = 5;
-                     flag = 1;
-                   }
-                 else if (strcasecmp (name, "nsv") == 0)
-                   {
-                     cmpltr = 6;
-                     flag = 1;
-                   }
-                 else if (strcasecmp (name, "ev") == 0)
-                   {
-                     cmpltr = 7;
-                     flag = 1;
+                     flag = 0;
+                     s += 3;
                    }
                  else
                    }
                  else
-                   as_bad ("Invalid Add Condition: %s", name);
-                 *s = c;
-               }
-             nullif = pa_parse_nullif (&s);
-             opcode |= nullif << 1;
-             opcode |= cmpltr << 13;
-             INSERT_FIELD_AND_CONTINUE (opcode, flag, 12);
+                   break;
 
 
-           /* HANDLE a logical instruction condition.  */
-           case '&':
-             cmpltr = 0;
-             flag = 0;
-             if (*s == ',')
-               {
-                 s++;
-                 name = s;
-                 while (*s != ',' && *s != ' ' && *s != '\t')
-                   s += 1;
-                 c = *s;
-                 *s = 0x00;
-                 if (strcmp (name, "=") == 0)
-                   cmpltr = 1;
-                 else if (strcmp (name, "<") == 0)
-                   cmpltr = 2;
-                 else if (strcmp (name, "<=") == 0)
-                   cmpltr = 3;
-                 else if (strcasecmp (name, "od") == 0)
-                   cmpltr = 7;
-                 else if (strcasecmp (name, "tr") == 0)
+                 INSERT_FIELD_AND_CONTINUE (opcode, flag, 11);
+
+               /* Handle 32 bit carry for ADD.  */
+               case 'y':
+                 flag = 0;
+                 if (!strncasecmp (s, ",c,tsv", 6) ||
+                     !strncasecmp (s, ",tsv,c", 6))
                    {
                    {
-                     cmpltr = 0;
                      flag = 1;
                      flag = 1;
+                     s += 6;
                    }
                    }
-                 else if (strcmp (name, "<>") == 0)
+                 else if (!strncasecmp (s, ",c", 2))
                    {
                    {
-                     cmpltr = 1;
-                     flag = 1;
+                     flag = 0;
+                     s += 2;
                    }
                    }
-                 else if (strcmp (name, ">=") == 0)
+                 else
+                   break;
+
+                 INSERT_FIELD_AND_CONTINUE (opcode, flag, 11);
+
+               /* Handle trap on signed overflow.  */
+               case 'v':
+                 flag = 0;
+                 if (!strncasecmp (s, ",tsv", 4))
                    {
                    {
-                     cmpltr = 2;
                      flag = 1;
                      flag = 1;
+                     s += 4;
                    }
                    }
-                 else if (strcmp (name, ">") == 0)
+
+                 INSERT_FIELD_AND_CONTINUE (opcode, flag, 11);
+
+               /* Handle trap on condition and overflow.  */
+               case 't':
+                 flag = 0;
+                 if (!strncasecmp (s, ",tc,tsv", 7) ||
+                     !strncasecmp (s, ",tsv,tc", 7))
                    {
                    {
-                     cmpltr = 3;
                      flag = 1;
                      flag = 1;
+                     s += 7;
                    }
                    }
-                 else if (strcasecmp (name, "ev") == 0)
+                 else if (!strncasecmp (s, ",tc", 3))
                    {
                    {
-                     cmpltr = 7;
-                     flag = 1;
+                     flag = 0;
+                     s += 3;
                    }
                  else
                    }
                  else
-                   as_bad ("Invalid Logical Instruction Condition.");
-                 *s = c;
-               }
-             opcode |= cmpltr << 13;
-             INSERT_FIELD_AND_CONTINUE (opcode, flag, 12);
+                   break;
 
 
-           /* Handle a unit instruction condition.  */
-           case 'U':
-             cmpltr = 0;
-             flag = 0;
-             if (*s == ',')
-               {
-                 s++;
-                 if (strncasecmp (s, "sbz", 3) == 0)
-                   {
-                     cmpltr = 2;
-                     s += 3;
-                   }
-                 else if (strncasecmp (s, "shz", 3) == 0)
-                   {
-                     cmpltr = 3;
-                     s += 3;
-                   }
-                 else if (strncasecmp (s, "sdc", 3) == 0)
-                   {
-                     cmpltr = 4;
-                     s += 3;
-                   }
-                 else if (strncasecmp (s, "sbc", 3) == 0)
-                   {
-                     cmpltr = 6;
-                     s += 3;
-                   }
-                 else if (strncasecmp (s, "shc", 3) == 0)
-                   {
-                     cmpltr = 7;
-                     s += 3;
-                   }
-                 else if (strncasecmp (s, "tr", 2) == 0)
+                 INSERT_FIELD_AND_CONTINUE (opcode, flag, 11);
+
+               /* Handle 64 bit borrow for SUB.  */
+               case 'B':
+                 flag = 0;
+                 if (!strncasecmp (s, ",db,tsv", 7) ||
+                     !strncasecmp (s, ",tsv,db", 7))
                    {
                    {
-                     cmpltr = 0;
                      flag = 1;
                      flag = 1;
-                     s += 2;
+                     s += 7;
                    }
                    }
-                 else if (strncasecmp (s, "nbz", 3) == 0)
+                 else if (!strncasecmp (s, ",db", 3))
                    {
                    {
-                     cmpltr = 2;
-                     flag = 1;
+                     flag = 0;
                      s += 3;
                    }
                      s += 3;
                    }
-                 else if (strncasecmp (s, "nhz", 3) == 0)
+                 else
+                   break;
+
+                 INSERT_FIELD_AND_CONTINUE (opcode, flag, 11);
+
+               /* Handle 32 bit borrow for SUB.  */
+               case 'b':
+                 flag = 0;
+                 if (!strncasecmp (s, ",b,tsv", 6) ||
+                     !strncasecmp (s, ",tsv,b", 6))
                    {
                    {
-                     cmpltr = 3;
                      flag = 1;
                      flag = 1;
-                     s += 3;
+                     s += 6;
                    }
                    }
-                 else if (strncasecmp (s, "ndc", 3) == 0)
+                 else if (!strncasecmp (s, ",b", 2))
                    {
                    {
-                     cmpltr = 4;
-                     flag = 1;
-                     s += 3;
+                     flag = 0;
+                     s += 2;
                    }
                    }
-                 else if (strncasecmp (s, "nbc", 3) == 0)
+                 else
+                   break;
+
+                 INSERT_FIELD_AND_CONTINUE (opcode, flag, 11);
+
+               /* Handle trap condition completer for UADDCM.  */
+               case 'T':
+                 flag = 0;
+                 if (!strncasecmp (s, ",tc", 3))
                    {
                    {
-                     cmpltr = 6;
                      flag = 1;
                      s += 3;
                    }
                      flag = 1;
                      s += 3;
                    }
-                 else if (strncasecmp (s, "nhc", 3) == 0)
+
+                 INSERT_FIELD_AND_CONTINUE (opcode, flag, 6);
+
+               /* Handle signed/unsigned at 21.  */
+               case 'S':
+                 {
+                   int sign = 1;
+                   if (strncasecmp (s, ",s", 2) == 0)
+                     {
+                       sign = 1;
+                       s += 2;
+                     }
+                   else if (strncasecmp (s, ",u", 2) == 0)
+                     {
+                       sign = 0;
+                       s += 2;
+                     }
+
+                   INSERT_FIELD_AND_CONTINUE (opcode, sign, 10);
+                 }
+
+               /* Handle left/right combination at 17:18.  */
+               case 'h':
+                 if (*s++ == ',')
                    {
                    {
-                     cmpltr = 7;
-                     flag = 1;
-                     s += 3;
+                     int lr = 0;
+                     if (*s == 'r')
+                       lr = 2;
+                     else if (*s == 'l')
+                       lr = 0;
+                     else
+                       as_bad(_("Invalid left/right combination completer"));
+
+                     s++;
+                     INSERT_FIELD_AND_CONTINUE (opcode, lr, 13);
                    }
                  else
                    }
                  else
-                   as_bad ("Invalid Logical Instruction Condition.");
-               }
-             opcode |= cmpltr << 13;
-             INSERT_FIELD_AND_CONTINUE (opcode, flag, 12);
+                   as_bad(_("Invalid left/right combination completer"));
+                 break;
 
 
-           /* Handle a shift/extract/deposit condition.  */
-           case '|':
-           case '>':
-             cmpltr = 0;
-             if (*s == ',')
-               {
-                 save_s = s++;
-                 name = s;
-                 while (*s != ',' && *s != ' ' && *s != '\t')
-                   s += 1;
-                 c = *s;
-                 *s = 0x00;
-                 if (strcmp (name, "=") == 0)
-                   cmpltr = 1;
-                 else if (strcmp (name, "<") == 0)
-                   cmpltr = 2;
-                 else if (strcasecmp (name, "od") == 0)
-                   cmpltr = 3;
-                 else if (strcasecmp (name, "tr") == 0)
-                   cmpltr = 4;
-                 else if (strcmp (name, "<>") == 0)
-                   cmpltr = 5;
-                 else if (strcmp (name, ">=") == 0)
-                   cmpltr = 6;
-                 else if (strcasecmp (name, "ev") == 0)
-                   cmpltr = 7;
-                 /* Handle movb,n.  Put things back the way they were.
-                    This includes moving s back to where it started.  */
-                 else if (strcasecmp (name, "n") == 0 && *args == '|')
+               /* Handle saturation at 24:25.  */
+               case 'H':
+                 {
+                   int sat = 3;
+                   if (strncasecmp (s, ",ss", 3) == 0)
+                     {
+                       sat = 1;
+                       s += 3;
+                     }
+                   else if (strncasecmp (s, ",us", 3) == 0)
+                     {
+                       sat = 0;
+                       s += 3;
+                     }
+
+                   INSERT_FIELD_AND_CONTINUE (opcode, sat, 6);
+                 }
+
+               /* Handle permutation completer.  */
+               case '*':
+                 if (*s++ == ',')
                    {
                    {
-                     *s = c;
-                     s = save_s;
+                     int permloc[4] = {13,10,8,6};
+                     int perm = 0;
+                     int i = 0;
+                     for (; i < 4; i++)
+                       {
+                         switch (*s++)
+                           {
+                           case '0':
+                             perm = 0;
+                             break;
+                           case '1':
+                             perm = 1;
+                             break;
+                           case '2':
+                             perm = 2;
+                             break;
+                           case '3':
+                             perm = 3;
+                             break;
+                           default:
+                             as_bad(_("Invalid permutation completer"));
+                           }
+                         opcode |= perm << permloc[i];
+                       }
                      continue;
                    }
                  else
                      continue;
                    }
                  else
-                   as_bad ("Invalid Shift/Extract/Deposit Condition.");
-                 *s = c;
-               }
-             INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 13);
+                   as_bad(_("Invalid permutation completer"));
+                 break;
 
 
-           /* Handle bvb and bb conditions.  */
-           case '~':
-             cmpltr = 0;
-             if (*s == ',')
-               {
-                 s++;
-                 if (strncmp (s, "<", 1) == 0)
-                   {
-                     cmpltr = 2;
-                     s++;
-                   }
-                 else if (strncmp (s, ">=", 2) == 0)
-                   {
-                     cmpltr = 6;
-                     s += 2;
-                   }
-                 else
-                   as_bad ("Invalid Bit Branch Condition: %c", *s);
+               default:
+                 abort ();
                }
                }
-             INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 13);
+             break;
 
 
-           /* Handle a system control completer.  */
-           case 'Z':
-             if (*s == ',' && (*(s + 1) == 'm' || *(s + 1) == 'M'))
-               {
-                 flag = 1;
-                 s += 2;
-               }
-             else
-               flag = 0;
+           /* Handle all conditions.  */
+           case '?':
+             {
+               args++;
+               switch (*args)
+                 {
+                 /* Handle FP compare conditions.  */
+                 case 'f':
+                   cond = pa_parse_fp_cmp_cond (&s);
+                   INSERT_FIELD_AND_CONTINUE (opcode, cond, 0);
+
+                 /* Handle an add condition.  */
+                 case 'A':
+                 case 'a':
+                   cmpltr = 0;
+                   flag = 0;
+                   if (*s == ',')
+                     {
+                       s++;
+
+                       /* 64 bit conditions.  */
+                       if (*args == 'A')
+                         {
+                           if (*s == '*')
+                             s++;
+                           else
+                             break;
+                         }
+                       else if (*s == '*')
+                         break;
+                       name = s;
+
+                       name = s;
+                       while (*s != ',' && *s != ' ' && *s != '\t')
+                         s += 1;
+                       c = *s;
+                       *s = 0x00;
+                       if (strcmp (name, "=") == 0)
+                         cmpltr = 1;
+                       else if (strcmp (name, "<") == 0)
+                         cmpltr = 2;
+                       else if (strcmp (name, "<=") == 0)
+                         cmpltr = 3;
+                       else if (strcasecmp (name, "nuv") == 0)
+                         cmpltr = 4;
+                       else if (strcasecmp (name, "znv") == 0)
+                         cmpltr = 5;
+                       else if (strcasecmp (name, "sv") == 0)
+                         cmpltr = 6;
+                       else if (strcasecmp (name, "od") == 0)
+                         cmpltr = 7;
+                       else if (strcasecmp (name, "tr") == 0)
+                         {
+                           cmpltr = 0;
+                           flag = 1;
+                         }
+                       else if (strcmp (name, "<>") == 0)
+                         {
+                           cmpltr = 1;
+                           flag = 1;
+                         }
+                       else if (strcmp (name, ">=") == 0)
+                         {
+                           cmpltr = 2;
+                           flag = 1;
+                         }
+                       else if (strcmp (name, ">") == 0)
+                         {
+                           cmpltr = 3;
+                           flag = 1;
+                         }
+                       else if (strcasecmp (name, "uv") == 0)
+                         {
+                           cmpltr = 4;
+                           flag = 1;
+                         }
+                       else if (strcasecmp (name, "vnz") == 0)
+                         {
+                           cmpltr = 5;
+                           flag = 1;
+                         }
+                       else if (strcasecmp (name, "nsv") == 0)
+                         {
+                           cmpltr = 6;
+                           flag = 1;
+                         }
+                       else if (strcasecmp (name, "ev") == 0)
+                         {
+                           cmpltr = 7;
+                           flag = 1;
+                         }
+                       /* ",*" is a valid condition.  */
+                       else if (*args == 'a')
+                         as_bad (_("Invalid Add Condition: %s"), name);
+                       *s = c;
+                     }
+                   opcode |= cmpltr << 13;
+                   INSERT_FIELD_AND_CONTINUE (opcode, flag, 12);
+
+                 /* Handle non-negated add and branch condition.  */
+                 case 'd':
+                   cmpltr = pa_parse_nonneg_add_cmpltr (&s, 1);
+                   if (cmpltr < 0)
+                     {
+                       as_bad (_("Invalid Compare/Subtract Condition: %c"), *s);
+                       cmpltr = 0;
+                     }
+                   INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 13);
+
+                 /* Handle negated add and branch condition.  */
+                 case 'D':
+                   abort ();
+
+                 /* Handle wide-mode non-negated add and branch condition.  */
+                 case 'w':
+                   abort ();
+
+                 /* Handle wide-mode negated add and branch condition.  */
+                 case 'W':
+                   abort();
+
+                 /* Handle a negated or non-negated add and branch 
+                    condition.  */
+                 case '@':
+                   save_s = s;
+                   cmpltr = pa_parse_nonneg_add_cmpltr (&s, 1);
+                   if (cmpltr < 0)
+                     {
+                       s = save_s;
+                       cmpltr = pa_parse_neg_add_cmpltr (&s, 1);
+                       if (cmpltr < 0)
+                         {
+                           as_bad (_("Invalid Compare/Subtract Condition"));
+                           cmpltr = 0;
+                         }
+                       else
+                         {
+                           /* Negated condition requires an opcode change. */
+                           opcode |= 1 << 27;
+                         }
+                     }
+                   INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 13);
+
+                 /* Handle branch on bit conditions.  */
+                 case 'B':
+                 case 'b':
+                   cmpltr = 0;
+                   if (*s == ',')
+                     {
+                       s++;
 
 
-             INSERT_FIELD_AND_CONTINUE (opcode, flag, 5);
+                       if (*args == 'B')
+                         {
+                           if (*s == '*')
+                             s++;
+                           else
+                             break;
+                         }
+                       else if (*s == '*')
+                         break;
+
+                       if (strncmp (s, "<", 1) == 0)
+                         {
+                           cmpltr = 0;
+                           s++;
+                         }
+                       else if (strncmp (s, ">=", 2) == 0)
+                         {
+                           cmpltr = 1;
+                           s += 2;
+                         }
+                       else
+                         as_bad (_("Invalid Bit Branch Condition: %c"), *s);
+                     }
+                   INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 15);
+
+                 /* Handle a compare/subtract condition.  */
+                 case 'S':
+                 case 's':
+                   cmpltr = 0;
+                   flag = 0;
+                   if (*s == ',')
+                     {
+                       s++;
+
+                       /* 64 bit conditions.  */
+                       if (*args == 'S')
+                         { 
+                           if (*s == '*')
+                             s++;
+                           else
+                             break;
+                         } 
+                       else if (*s == '*')
+                         break;
+                       name = s;
+                           
+                       name = s;
+                       while (*s != ',' && *s != ' ' && *s != '\t')
+                         s += 1;
+                       c = *s;
+                       *s = 0x00;
+                       if (strcmp (name, "=") == 0)
+                         cmpltr = 1;
+                       else if (strcmp (name, "<") == 0)
+                         cmpltr = 2;
+                       else if (strcmp (name, "<=") == 0)
+                         cmpltr = 3;
+                       else if (strcasecmp (name, "<<") == 0)
+                         cmpltr = 4;
+                       else if (strcasecmp (name, "<<=") == 0)
+                         cmpltr = 5;
+                       else if (strcasecmp (name, "sv") == 0)
+                         cmpltr = 6;
+                       else if (strcasecmp (name, "od") == 0)
+                         cmpltr = 7;
+                       else if (strcasecmp (name, "tr") == 0)
+                         {
+                           cmpltr = 0;
+                           flag = 1;
+                         }
+                       else if (strcmp (name, "<>") == 0)
+                         {
+                           cmpltr = 1;
+                           flag = 1;
+                         }
+                       else if (strcmp (name, ">=") == 0)
+                         {
+                           cmpltr = 2;
+                           flag = 1;
+                         }
+                       else if (strcmp (name, ">") == 0)
+                         {
+                           cmpltr = 3;
+                           flag = 1;
+                         }
+                       else if (strcasecmp (name, ">>=") == 0)
+                         {
+                           cmpltr = 4;
+                           flag = 1;
+                         }
+                       else if (strcasecmp (name, ">>") == 0)
+                         {
+                           cmpltr = 5;
+                           flag = 1;
+                         }
+                       else if (strcasecmp (name, "nsv") == 0)
+                         {
+                           cmpltr = 6;
+                           flag = 1;
+                         }
+                       else if (strcasecmp (name, "ev") == 0)
+                         {
+                           cmpltr = 7;
+                           flag = 1;
+                         }
+                       /* ",*" is a valid condition.  */
+                       else if (*args != 'S')
+                         as_bad (_("Invalid Compare/Subtract Condition: %s"),
+                                 name);
+                       *s = c;
+                     }
+                   opcode |= cmpltr << 13;
+                   INSERT_FIELD_AND_CONTINUE (opcode, flag, 12);
+
+                 /* Handle a non-negated compare condition.  */
+                 case 't':
+                   cmpltr = pa_parse_nonneg_cmpsub_cmpltr (&s, 1);
+                   if (cmpltr < 0)
+                     {
+                       as_bad (_("Invalid Compare/Subtract Condition: %c"), *s);
+                       cmpltr = 0;
+                     }
+                   INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 13);
+
+                 /* Handle a negated compare condition.  */
+                 case 'T':
+                   abort ();
+  
+                 /* Handle a 64 bit non-negated compare condition.  */
+                 case 'r':
+                   abort ();
+  
+                 /* Handle a 64 bit negated compare condition.  */
+                 case 'R':
+                   abort ();
+  
+                 /* Handle a 64 bit cmpib condition.  */
+                 case 'Q':
+                   abort ();
+  
+                 /* Handle a negated or non-negated compare/subtract
+                    condition.  */
+                 case 'n':
+                   save_s = s;
+                   cmpltr = pa_parse_nonneg_cmpsub_cmpltr (&s, 1);
+                   if (cmpltr < 0)
+                     {
+                       s = save_s;
+                       cmpltr = pa_parse_neg_cmpsub_cmpltr (&s, 1);
+                       if (cmpltr < 0)
+                         {
+                           as_bad (_("Invalid Compare/Subtract Condition."));
+                           cmpltr = 0;
+                         }
+                       else
+                         {
+                           /* Negated condition requires an opcode change. */
+                           opcode |= 1 << 27;
+                         }
+                     }
+           
+                   INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 13);
+
+                   /* Handle a logical instruction condition.  */
+                 case 'L':
+                 case 'l':
+                   cmpltr = 0;
+                   flag = 0;
+                   if (*s == ',')
+                     {
+                       s++;
+
+                       /* 64 bit conditions.  */
+                       if (*args == 'L')
+                         {
+                           if (*s == '*')
+                             s++;
+                           else
+                             break;
+                         }
+                       else if (*s == '*')
+                         break;
+                       name = s;
+                           
+                       name = s;
+                       while (*s != ',' && *s != ' ' && *s != '\t')
+                         s += 1;
+                       c = *s;
+                       *s = 0x00;
+           
+           
+                       if (strcmp (name, "=") == 0)
+                         cmpltr = 1;
+                       else if (strcmp (name, "<") == 0)
+                         cmpltr = 2;
+                       else if (strcmp (name, "<=") == 0)
+                         cmpltr = 3;
+                       else if (strcasecmp (name, "od") == 0)
+                         cmpltr = 7;
+                       else if (strcasecmp (name, "tr") == 0)
+                         {
+                           cmpltr = 0;
+                           flag = 1;
+                         }
+                       else if (strcmp (name, "<>") == 0)
+                         {
+                           cmpltr = 1;
+                           flag = 1;
+                         }
+                       else if (strcmp (name, ">=") == 0)
+                         {
+                           cmpltr = 2;
+                           flag = 1;
+                         }
+                       else if (strcmp (name, ">") == 0)
+                         {
+                           cmpltr = 3;
+                           flag = 1;
+                         }
+                       else if (strcasecmp (name, "ev") == 0)
+                         {
+                           cmpltr = 7;
+                           flag = 1;
+                         }
+                       /* ",*" is a valid condition.  */
+                       else if (*args != 'L')
+                         as_bad (_("Invalid Logical Instruction Condition."));
+                       *s = c;
+                     }
+                   opcode |= cmpltr << 13;
+                   INSERT_FIELD_AND_CONTINUE (opcode, flag, 12);
+
+                 /* Handle a shift/extract/deposit condition.  */
+                 case 'X':
+                 case 'x':
+                 case 'y':
+                   cmpltr = 0;
+                   if (*s == ',')
+                     {
+                       save_s = s++;
+
+                       /* 64 bit conditions.  */
+                       if (*args == 'X')
+                         {
+                           if (*s == '*')
+                             s++;
+                           else
+                             break;
+                         }
+                       else if (*s == '*')
+                         break;
+                       name = s;
+                           
+                       name = s;
+                       while (*s != ',' && *s != ' ' && *s != '\t')
+                         s += 1;
+                       c = *s;
+                       *s = 0x00;
+                       if (strcmp (name, "=") == 0)
+                         cmpltr = 1;
+                       else if (strcmp (name, "<") == 0)
+                         cmpltr = 2;
+                       else if (strcasecmp (name, "od") == 0)
+                         cmpltr = 3;
+                       else if (strcasecmp (name, "tr") == 0)
+                         cmpltr = 4;
+                       else if (strcmp (name, "<>") == 0)
+                         cmpltr = 5;
+                       else if (strcmp (name, ">=") == 0)
+                         cmpltr = 6;
+                       else if (strcasecmp (name, "ev") == 0)
+                         cmpltr = 7;
+                       /* Handle movb,n.  Put things back the way they were.
+                          This includes moving s back to where it started.  */
+                       else if (strcasecmp (name, "n") == 0 && *args == 'y')
+                         {
+                           *s = c;
+                           s = save_s;
+                           continue;
+                         }
+                       /* ",*" is a valid condition.  */
+                       else if (*args != 'X')
+                         as_bad (_("Invalid Shift/Extract/Deposit Condition."));
+                       *s = c;
+                     }
+                   INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 13);
+
+                 /* Handle a unit instruction condition.  */
+                 case 'U':
+                 case 'u':
+                   cmpltr = 0;
+                   flag = 0;
+                   if (*s == ',')
+                     {
+                       s++;
+           
+                       /* 64 bit conditions.  */
+                       if (*args == 'U')
+                         {
+                           if (*s == '*')
+                             s++;
+                           else
+                             break;
+                         }
+                       else if (*s == '*')
+                         break;
+                           
+                       if (strncasecmp (s, "sbz", 3) == 0)
+                         {
+                           cmpltr = 2;
+                           s += 3;
+                         }
+                       else if (strncasecmp (s, "shz", 3) == 0)
+                         {
+                           cmpltr = 3;
+                           s += 3;
+                         }
+                       else if (strncasecmp (s, "sdc", 3) == 0)
+                         {
+                           cmpltr = 4;
+                           s += 3;
+                         }
+                       else if (strncasecmp (s, "sbc", 3) == 0)
+                         {
+                           cmpltr = 6;
+                           s += 3;
+                         }
+                       else if (strncasecmp (s, "shc", 3) == 0)
+                         {
+                           cmpltr = 7;
+                           s += 3;
+                         }
+                       else if (strncasecmp (s, "tr", 2) == 0)
+                         {
+                           cmpltr = 0;
+                           flag = 1;
+                           s += 2;
+                         }
+                       else if (strncasecmp (s, "nbz", 3) == 0)
+                         {
+                           cmpltr = 2;
+                           flag = 1;
+                           s += 3;
+                         }
+                       else if (strncasecmp (s, "nhz", 3) == 0)
+                         {
+                           cmpltr = 3;
+                           flag = 1;
+                           s += 3;
+                         }
+                       else if (strncasecmp (s, "ndc", 3) == 0)
+                         {
+                           cmpltr = 4;
+                           flag = 1;
+                           s += 3;
+                         }
+                       else if (strncasecmp (s, "nbc", 3) == 0)
+                         {
+                           cmpltr = 6;
+                           flag = 1;
+                           s += 3;
+                         }
+                       else if (strncasecmp (s, "nhc", 3) == 0)
+                         {
+                           cmpltr = 7;
+                           flag = 1;
+                           s += 3;
+                         }
+                       /* ",*" is a valid condition.  */
+                       else if (*args != 'U')
+                         as_bad (_("Invalid Unit Instruction Condition."));
+                     }
+                   opcode |= cmpltr << 13;
+                   INSERT_FIELD_AND_CONTINUE (opcode, flag, 12);
+
+                 default:
+                   abort ();
+                 }
+               break;
+             }
 
            /* Handle a nullification completer for branch instructions.  */
            case 'n':
 
            /* Handle a nullification completer for branch instructions.  */
            case 'n':
@@ -1979,6 +2651,7 @@ pa_ip (str)
              nullif = pa_parse_nullif (&s);
              INSERT_FIELD_AND_CONTINUE (opcode, nullif, 5);
 
              nullif = pa_parse_nullif (&s);
              INSERT_FIELD_AND_CONTINUE (opcode, nullif, 5);
 
+
            /* Handle a 11 bit immediate at 31.  */
            case 'i':
              the_insn.field_selector = pa_chk_field_selector (&s);
            /* Handle a 11 bit immediate at 31.  */
            case 'i':
              the_insn.field_selector = pa_chk_field_selector (&s);
@@ -2003,6 +2676,7 @@ pa_ip (str)
                  continue;
                }
 
                  continue;
                }
 
+
            /* Handle a 14 bit immediate at 31.  */
            case 'j':
              the_insn.field_selector = pa_chk_field_selector (&s);
            /* Handle a 14 bit immediate at 31.  */
            case 'j':
              the_insn.field_selector = pa_chk_field_selector (&s);
@@ -2064,10 +2738,10 @@ pa_ip (str)
                  num = evaluate_absolute (&the_insn);
                  if (num % 4)
                    {
                  num = evaluate_absolute (&the_insn);
                  if (num % 4)
                    {
-                     as_bad ("Branch to unaligned address");
+                     as_bad (_("Branch to unaligned address"));
                      break;
                    }
                      break;
                    }
-                 CHECK_FIELD (num, 8191, -8192, 0);
+                 CHECK_FIELD (num, 8199, -8184, 0);
                  sign_unext ((num - 8) >> 2, 12, &result);
                  dis_assemble_12 (result, &w1, &w);
                  INSERT_FIELD_AND_CONTINUE (opcode, ((w1 << 2) | w), 0);
                  sign_unext ((num - 8) >> 2, 12, &result);
                  dis_assemble_12 (result, &w1, &w);
                  INSERT_FIELD_AND_CONTINUE (opcode, ((w1 << 2) | w), 0);
@@ -2077,7 +2751,7 @@ pa_ip (str)
                  the_insn.reloc = R_HPPA_PCREL_CALL;
                  the_insn.format = 12;
                  the_insn.arg_reloc = last_call_desc.arg_reloc;
                  the_insn.reloc = R_HPPA_PCREL_CALL;
                  the_insn.format = 12;
                  the_insn.arg_reloc = last_call_desc.arg_reloc;
-                 bzero (&last_call_desc, sizeof (struct call_desc));
+                 memset (&last_call_desc, 0, sizeof (struct call_desc));
                  s = expr_end;
                  continue;
                }
                  s = expr_end;
                  continue;
                }
@@ -2097,7 +2771,7 @@ pa_ip (str)
                  num = evaluate_absolute (&the_insn);
                  if (num % 4)
                    {
                  num = evaluate_absolute (&the_insn);
                  if (num % 4)
                    {
-                     as_bad ("Branch to unaligned address");
+                     as_bad (_("Branch to unaligned address"));
                      break;
                    }
                  CHECK_FIELD (num, 262143, -262144, 0);
                      break;
                    }
                  CHECK_FIELD (num, 262143, -262144, 0);
@@ -2115,7 +2789,7 @@ pa_ip (str)
                  the_insn.reloc = R_HPPA_PCREL_CALL;
                  the_insn.format = 17;
                  the_insn.arg_reloc = last_call_desc.arg_reloc;
                  the_insn.reloc = R_HPPA_PCREL_CALL;
                  the_insn.format = 17;
                  the_insn.arg_reloc = last_call_desc.arg_reloc;
-                 bzero (&last_call_desc, sizeof (struct call_desc));
+                 memset (&last_call_desc, 0, sizeof (struct call_desc));
                  continue;
                }
 
                  continue;
                }
 
@@ -2134,7 +2808,7 @@ pa_ip (str)
                  num = evaluate_absolute (&the_insn);
                  if (num % 4)
                    {
                  num = evaluate_absolute (&the_insn);
                  if (num % 4)
                    {
-                     as_bad ("Branch to unaligned address");
+                     as_bad (_("Branch to unaligned address"));
                      break;
                    }
                  CHECK_FIELD (num, 262143, -262144, 0);
                      break;
                    }
                  CHECK_FIELD (num, 262143, -262144, 0);
@@ -2151,101 +2825,203 @@ pa_ip (str)
                {
                  the_insn.reloc = R_HPPA_ABS_CALL;
                  the_insn.format = 17;
                {
                  the_insn.reloc = R_HPPA_ABS_CALL;
                  the_insn.format = 17;
+                 the_insn.arg_reloc = last_call_desc.arg_reloc;
+                 memset (&last_call_desc, 0, sizeof (struct call_desc));
                  continue;
                }
 
                  continue;
                }
 
+           /* Handle a 2 bit shift count at 25.  */
+           case '.':
+             num = pa_get_absolute_expression (&the_insn, &s);
+             if (strict && the_insn.exp.X_op != O_constant)
+               break;
+             s = expr_end;
+             CHECK_FIELD (num, 3, 1, strict);
+             INSERT_FIELD_AND_CONTINUE (opcode, num, 6);
+
+           /* Handle a 4 bit shift count at 25.  */
+           case '*':
+             num = pa_get_absolute_expression (&the_insn, &s);
+             if (strict && the_insn.exp.X_op != O_constant)
+               break;
+             s = expr_end;
+             CHECK_FIELD (num, 15, 0, strict);
+             INSERT_FIELD_AND_CONTINUE (opcode, num, 6);
+
            /* Handle a 5 bit shift count at 26.  */
            case 'p':
              num = pa_get_absolute_expression (&the_insn, &s);
            /* Handle a 5 bit shift count at 26.  */
            case 'p':
              num = pa_get_absolute_expression (&the_insn, &s);
+             if (strict && the_insn.exp.X_op != O_constant)
+               break;
              s = expr_end;
              s = expr_end;
-             CHECK_FIELD (num, 31, 0, 0);
+             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.  */
+           case '~':
+             num = pa_get_absolute_expression (&the_insn, &s);
+             if (strict && the_insn.exp.X_op != O_constant)
+               break;
+             s = expr_end;
+             CHECK_FIELD (num, 63, 0, strict);
+             num = 63 - num;
+             opcode |= (num & 0x20) << 6;
+             INSERT_FIELD_AND_CONTINUE (opcode, num & 0x1f, 5);
+
+           /* Handle a 6 bit field length at 23,27:31.  */
+           case '%':
+             flag = 0;
+             num = pa_get_absolute_expression (&the_insn, &s);
+             if (strict && the_insn.exp.X_op != O_constant)
+               break;
+             s = expr_end;
+             CHECK_FIELD (num, 64, 1, strict);
+             num--;
+             opcode |= (num & 0x20) << 3;
+             num = 31 - (num & 0x1f);
+             INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
+
+           /* Handle a 6 bit field length at 19,27:31.  */
+           case '|':
+             num = pa_get_absolute_expression (&the_insn, &s);
+             if (strict && the_insn.exp.X_op != O_constant)
+               break;
+             s = expr_end;
+             CHECK_FIELD (num, 64, 1, strict);
+             num--;
+             opcode |= (num & 0x20) << 7;
+             num = 31 - (num & 0x1f);
+             INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
+
            /* Handle a 5 bit bit position at 26.  */
            case 'P':
              num = pa_get_absolute_expression (&the_insn, &s);
            /* Handle a 5 bit bit position at 26.  */
            case 'P':
              num = pa_get_absolute_expression (&the_insn, &s);
+             if (strict && the_insn.exp.X_op != O_constant)
+               break;
              s = expr_end;
              s = expr_end;
-             CHECK_FIELD (num, 31, 0, 0);
+             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.  */
+           case 'q':
+             num = pa_get_absolute_expression (&the_insn, &s);
+             if (strict && the_insn.exp.X_op != O_constant)
+               break;
+             s = expr_end;
+             CHECK_FIELD (num, 63, 0, strict);
+             opcode |= (num & 0x20) << 6;
+             INSERT_FIELD_AND_CONTINUE (opcode, num & 0x1f, 5);
+
            /* Handle a 5 bit immediate at 10.  */
            case 'Q':
              num = pa_get_absolute_expression (&the_insn, &s);
            /* Handle a 5 bit immediate at 10.  */
            case 'Q':
              num = pa_get_absolute_expression (&the_insn, &s);
+             if (strict && the_insn.exp.X_op != O_constant)
+               break;
+             if (the_insn.exp.X_op != O_constant)
+               break;
              s = expr_end;
              s = expr_end;
-             CHECK_FIELD (num, 31, 0, 0);
+             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.  */
+           case '$':
+             num = pa_get_absolute_expression (&the_insn, &s);
+             if (strict && the_insn.exp.X_op != O_constant)
+               break;
+             s = expr_end;
+             CHECK_FIELD (num, 511, 1, strict);
+             INSERT_FIELD_AND_CONTINUE (opcode, num, 3);
+  
            /* Handle a 13 bit immediate at 18.  */
            case 'A':
              num = pa_get_absolute_expression (&the_insn, &s);
            /* Handle a 13 bit immediate at 18.  */
            case 'A':
              num = pa_get_absolute_expression (&the_insn, &s);
+             if (strict && the_insn.exp.X_op != O_constant)
+               break;
              s = expr_end;
              s = expr_end;
-             CHECK_FIELD (num, 8191, 0, 0);
+             CHECK_FIELD (num, 8191, 0, strict);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 13);
 
            /* Handle a 26 bit immediate at 31.  */
            case 'D':
              num = pa_get_absolute_expression (&the_insn, &s);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 13);
 
            /* Handle a 26 bit immediate at 31.  */
            case 'D':
              num = pa_get_absolute_expression (&the_insn, &s);
+             if (strict && the_insn.exp.X_op != O_constant)
+               break;
              s = expr_end;
              s = expr_end;
-             CHECK_FIELD (num, 671108864, 0, 0);
-             INSERT_FIELD_AND_CONTINUE (opcode, num, 1);
+             CHECK_FIELD (num, 671108864, 0, strict);
+             INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
 
            /* Handle a 3 bit SFU identifier at 25.  */
 
            /* Handle a 3 bit SFU identifier at 25.  */
-           case 'f':
+           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)
+               break;
              s = expr_end;
              s = expr_end;
-             CHECK_FIELD (num, 7, 0, 0);
+             CHECK_FIELD (num, 7, 0, strict);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 6);
 
            /* Handle a 20 bit SOP field for spop0.  */
            case 'O':
              num = pa_get_absolute_expression (&the_insn, &s);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 6);
 
            /* Handle a 20 bit SOP field for spop0.  */
            case 'O':
              num = pa_get_absolute_expression (&the_insn, &s);
+             if (strict && the_insn.exp.X_op != O_constant)
+               break;
              s = expr_end;
              s = expr_end;
-             CHECK_FIELD (num, 1048575, 0, 0);
+             CHECK_FIELD (num, 1048575, 0, strict);
              num = (num & 0x1f) | ((num & 0x000fffe0) << 6);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
 
            /* Handle a 15bit SOP field for spop1.  */
            case 'o':
              num = pa_get_absolute_expression (&the_insn, &s);
              num = (num & 0x1f) | ((num & 0x000fffe0) << 6);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
 
            /* Handle a 15bit SOP field for spop1.  */
            case 'o':
              num = pa_get_absolute_expression (&the_insn, &s);
+             if (strict && the_insn.exp.X_op != O_constant)
+               break;
              s = expr_end;
              s = expr_end;
-             CHECK_FIELD (num, 32767, 0, 0);
+             CHECK_FIELD (num, 32767, 0, strict);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 11);
 
            /* Handle a 10bit SOP field for spop3.  */
            case '0':
              num = pa_get_absolute_expression (&the_insn, &s);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 11);
 
            /* Handle a 10bit SOP field for spop3.  */
            case '0':
              num = pa_get_absolute_expression (&the_insn, &s);
+             if (strict && the_insn.exp.X_op != O_constant)
+               break;
              s = expr_end;
              s = expr_end;
-             CHECK_FIELD (num, 1023, 0, 0);
+             CHECK_FIELD (num, 1023, 0, strict);
              num = (num & 0x1f) | ((num & 0x000003e0) << 6);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
 
            /* Handle a 15 bit SOP field for spop2.  */
            case '1':
              num = pa_get_absolute_expression (&the_insn, &s);
              num = (num & 0x1f) | ((num & 0x000003e0) << 6);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
 
            /* Handle a 15 bit SOP field for spop2.  */
            case '1':
              num = pa_get_absolute_expression (&the_insn, &s);
+             if (strict && the_insn.exp.X_op != O_constant)
+               break;
              s = expr_end;
              s = expr_end;
-             CHECK_FIELD (num, 32767, 0, 0);
+             CHECK_FIELD (num, 32767, 0, strict);
              num = (num & 0x1f) | ((num & 0x00007fe0) << 6);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
 
            /* Handle a 3-bit co-processor ID field.  */
            case 'u':
              if (*s++ != ',')
              num = (num & 0x1f) | ((num & 0x00007fe0) << 6);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
 
            /* Handle a 3-bit co-processor ID field.  */
            case 'u':
              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)
+               break;
              s = expr_end;
              s = expr_end;
-             CHECK_FIELD (num, 7, 0, 0);
+             CHECK_FIELD (num, 7, 0, strict);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 6);
 
            /* Handle a 22bit SOP field for copr.  */
            case '2':
              num = pa_get_absolute_expression (&the_insn, &s);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 6);
 
            /* Handle a 22bit SOP field for copr.  */
            case '2':
              num = pa_get_absolute_expression (&the_insn, &s);
+             if (strict && the_insn.exp.X_op != O_constant)
+               break;
              s = expr_end;
              s = expr_end;
-             CHECK_FIELD (num, 4194303, 0, 0);
+             CHECK_FIELD (num, 4194303, 0, strict);
              num = (num & 0x1f) | ((num & 0x003fffe0) << 4);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
 
              num = (num & 0x1f) | ((num & 0x003fffe0) << 4);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
 
+
            /* Handle a source FP operand format completer.  */
            case 'F':
              flag = pa_parse_fp_format (&s);
            /* Handle a source FP operand format completer.  */
            case 'F':
              flag = pa_parse_fp_format (&s);
@@ -2260,166 +3036,301 @@ pa_ip (str)
              the_insn.fpof2 = flag;
              INSERT_FIELD_AND_CONTINUE (opcode, flag, 13);
 
              the_insn.fpof2 = flag;
              INSERT_FIELD_AND_CONTINUE (opcode, flag, 13);
 
-           /* Handle FP compare conditions.  */
-           case 'M':
-             cond = pa_parse_fp_cmp_cond (&s);
-             INSERT_FIELD_AND_CONTINUE (opcode, cond, 0);
+           /* Handle a source FP operand format completer at 20.  */
+           case 'I':
+             flag = pa_parse_fp_format (&s);
+             the_insn.fpof1 = flag;
+             INSERT_FIELD_AND_CONTINUE (opcode, flag, 11);
 
 
-           /* Handle L/R register halves like 't'.  */
-           case 'v':
-             {
-               struct pa_89_fp_reg_struct result;
+           /* Handle a floating point operand format at 26.
+              Only allows single and double precision.  */
+           case 'H':
+             flag = pa_parse_fp_format (&s);
+             switch (flag)
+               {
+               case SGL:
+                 opcode |= 0x20;
+               case DBL:
+                 the_insn.fpof1 = flag;
+                 continue;
 
 
-               pa_parse_number (&s, &result);
-               CHECK_FIELD (result.number_part, 31, 0, 0);
-               opcode |= result.number_part;
+               case QUAD:
+               case ILLEGAL_FMT:
+               default:
+                 as_bad (_("Invalid Floating Point Operand Format."));
+               }
+             break;
 
 
-               /* 0x30 opcodes are FP arithmetic operation opcodes
-                  and need to be turned into 0x38 opcodes.  This
-                  is not necessary for loads/stores.  */
-               if (need_89_opcode (&the_insn, &result)
-                   && ((opcode & 0xfc000000) == 0x30000000))
-                 opcode |= 1 << 27;
+           /* Handle all floating point registers.  */
+           case 'f':
+             switch (*++args)
+               {
+               /* Float target register.  */
+               case 't':
+                 /* This should be more strict.  Small steps.  */
+                 if (strict && *s != '%')
+                   break;
+                 num = pa_parse_number (&s, 0);
+                 CHECK_FIELD (num, 31, 0, 0);
+                 INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
 
 
-               INSERT_FIELD_AND_CONTINUE (opcode, result.l_r_select & 1, 6);
-             }
+               /* Float target register with L/R selection.  */
+               case 'T':
+                 {
+                   struct pa_11_fp_reg_struct result;
 
 
-           /* Handle L/R register halves like 'b'.  */
-           case 'E':
-             {
-               struct pa_89_fp_reg_struct result;
+                   /* This should be more strict.  Small steps.  */
+                   if (strict && *s != '%')
+                     break;
+                   pa_parse_number (&s, &result);
+                   CHECK_FIELD (result.number_part, 31, 0, 0);
+                   opcode |= result.number_part;
+
+                   /* 0x30 opcodes are FP arithmetic operation opcodes
+                      and need to be turned into 0x38 opcodes.  This
+                      is not necessary for loads/stores.  */
+                   if (need_pa11_opcode (&the_insn, &result)
+                       && ((opcode & 0xfc000000) == 0x30000000))
+                     opcode |= 1 << 27;
 
 
-               pa_parse_number (&s, &result);
-               CHECK_FIELD (result.number_part, 31, 0, 0);
-               opcode |= result.number_part << 21;
-               if (need_89_opcode (&the_insn, &result))
+                   INSERT_FIELD_AND_CONTINUE (opcode, result.l_r_select & 1, 6);
+                 }
+
+               /* Float operand 1.  */
+               case 'a':
+                 {
+                   struct pa_11_fp_reg_struct result;
+
+                   /* This should be more strict.  Small steps.  */
+                   if (strict && *s != '%')
+                     break;
+                   pa_parse_number (&s, &result);
+                   CHECK_FIELD (result.number_part, 31, 0, 0);
+                   opcode |= result.number_part << 21;
+                   if (need_pa11_opcode (&the_insn, &result))
+                     {
+                       opcode |= (result.l_r_select & 1) << 7;
+                       opcode |= 1 << 27;
+                     }
+                   continue;
+                 }
+
+               /* Float operand 1 with L/R selection.  */
+               case 'A':
                  {
                  {
+                   struct pa_11_fp_reg_struct result;
+
+                   /* This should be more strict.  Small steps.  */
+                   if (strict && *s != '%')
+                     break;
+                   pa_parse_number (&s, &result);
+                   CHECK_FIELD (result.number_part, 31, 0, 0);
+                   opcode |= result.number_part << 21;
                    opcode |= (result.l_r_select & 1) << 7;
                    opcode |= (result.l_r_select & 1) << 7;
-                   opcode |= 1 << 27;
+                   continue;
                  }
                  }
-               continue;
-             }
 
 
-           /* Handle L/R register halves like 'x'.  */
-           case 'X':
-             {
-               struct pa_89_fp_reg_struct result;
+               /* Float operand 2.  */
+               case 'b':
+                 {
+                   struct pa_11_fp_reg_struct result;
 
 
-               pa_parse_number (&s, &result);
-               CHECK_FIELD (result.number_part, 31, 0, 0);
-               opcode |= (result.number_part & 0x1f) << 16;
-               if (need_89_opcode (&the_insn, &result))
+                   /* This should be more strict.  Small steps.  */
+                   if (strict && *s != '%')
+                     break;
+                   pa_parse_number (&s, &result);
+                   CHECK_FIELD (result.number_part, 31, 0, 0);
+                   opcode |= (result.number_part & 0x1f) << 16;
+                   if (need_pa11_opcode (&the_insn, &result))
+                     {
+                       opcode |= (result.l_r_select & 1) << 12;
+                       opcode |= 1 << 27;
+                     }
+                   continue;
+                 }
+
+               /* Float operand 2 with L/R selection.  */
+               case 'B':
                  {
                  {
+                   struct pa_11_fp_reg_struct result;
+
+                   /* This should be more strict.  Small steps.  */
+                   if (strict && *s != '%')
+                     break;
+                   pa_parse_number (&s, &result);
+                   CHECK_FIELD (result.number_part, 31, 0, 0);
+                   opcode |= (result.number_part & 0x1f) << 16;
                    opcode |= (result.l_r_select & 1) << 12;
                    opcode |= (result.l_r_select & 1) << 12;
-                   opcode |= 1 << 27;
+                   continue;
                  }
                  }
-               continue;
-             }
-
-           /* Handle a 5 bit register field at 10.  */
-           case '4':
-             {
-               struct pa_89_fp_reg_struct result;
 
 
-               pa_parse_number (&s, &result);
-               CHECK_FIELD (result.number_part, 31, 0, 0);
-               if (the_insn.fpof1 == SGL)
+               /* Float operand 3 for fmpyfadd, fmpynfadd.  */
+               case 'C':
                  {
                  {
-                   result.number_part &= 0xF;
-                   result.number_part |= (result.l_r_select & 1) << 4;
-                 }
-               INSERT_FIELD_AND_CONTINUE (opcode, result.number_part, 21);
-             }
+                   struct pa_11_fp_reg_struct result;
+                   int regnum;
 
 
-           /* Handle a 5 bit register field at 15.  */
-           case '6':
-             {
-               struct pa_89_fp_reg_struct result;
+                   /* This should be more strict.  Small steps.  */
+                   if (strict && *s != '%')
+                     break;
+                   pa_parse_number (&s, &result);
+                   CHECK_FIELD (result.number_part, 31, 0, 0);
+                   opcode |= (result.number_part & 0x1c) << 11;
+                   opcode |= (result.number_part & 0x3) << 9;
+                   opcode |= (result.l_r_select & 1) << 8;
+                   continue;
+                 }
 
 
-               pa_parse_number (&s, &result);
-               CHECK_FIELD (result.number_part, 31, 0, 0);
-               if (the_insn.fpof1 == SGL)
+               /* Float mult operand 1 for fmpyadd, fmpysub */
+               case 'i':
                  {
                  {
-                   result.number_part &= 0xF;
-                   result.number_part |= (result.l_r_select & 1) << 4;
+                   struct pa_11_fp_reg_struct result;
+
+                   /* This should be more strict.  Small steps.  */
+                   if (strict && *s != '%')
+                     break;
+                   pa_parse_number (&s, &result);
+                   CHECK_FIELD (result.number_part, 31, 0, 0);
+                   if (the_insn.fpof1 == SGL)
+                     {
+                       if (result.number_part < 16)
+                         {
+                           as_bad  (_("Invalid register for single precision fmpyadd or fmpysub"));
+                           break;
+                         }
+
+                       result.number_part &= 0xF;
+                       result.number_part |= (result.l_r_select & 1) << 4;
+                     }
+                   INSERT_FIELD_AND_CONTINUE (opcode, result.number_part, 21);
                  }
                  }
-               INSERT_FIELD_AND_CONTINUE (opcode, result.number_part, 16);
-             }
 
 
-           /* Handle a 5 bit register field at 31.  */
-           case '7':
-             {
-               struct pa_89_fp_reg_struct result;
+               /* Float mult operand 2 for fmpyadd, fmpysub */
+               case 'j':
+                 {
+                   struct pa_11_fp_reg_struct result;
+                 
+                   /* This should be more strict.  Small steps.  */
+                   if (strict && *s != '%')
+                     break;
+                   pa_parse_number (&s, &result);
+                   CHECK_FIELD (result.number_part, 31, 0, 0);
+                   if (the_insn.fpof1 == SGL)
+                     {
+                       if (result.number_part < 16)
+                         {
+                       as_bad  (_("Invalid register for single precision fmpyadd or fmpysub"));
+                       break;
+                         }
+                       result.number_part &= 0xF;
+                       result.number_part |= (result.l_r_select & 1) << 4;
+                     }
+                   INSERT_FIELD_AND_CONTINUE (opcode, result.number_part, 16);
+                 }
 
 
-               pa_parse_number (&s, &result);
-               CHECK_FIELD (result.number_part, 31, 0, 0);
-               if (the_insn.fpof1 == SGL)
+               /* Float mult target for fmpyadd, fmpysub */
+               case 'k':
                  {
                  {
-                   result.number_part &= 0xF;
-                   result.number_part |= (result.l_r_select & 1) << 4;
+                   struct pa_11_fp_reg_struct result;
+                 
+                   /* This should be more strict.  Small steps.  */
+                   if (strict && *s != '%')
+                     break;
+                   pa_parse_number (&s, &result);
+                   CHECK_FIELD (result.number_part, 31, 0, 0);
+                   if (the_insn.fpof1 == SGL)
+                     {
+                       if (result.number_part < 16)
+                         {
+                       as_bad  (_("Invalid register for single precision fmpyadd or fmpysub"));
+                       break;
+                         }
+                       result.number_part &= 0xF;
+                       result.number_part |= (result.l_r_select & 1) << 4;
+                     }
+                   INSERT_FIELD_AND_CONTINUE (opcode, result.number_part, 0);
                  }
                  }
-               INSERT_FIELD_AND_CONTINUE (opcode, result.number_part, 0);
-             }
 
 
-           /* Handle a 5 bit register field at 20.  */
-           case '8':
-             {
-               struct pa_89_fp_reg_struct result;
+               /* Float add operand 1 for fmpyadd, fmpysub */
+               case 'l':
+                 {
+                   struct pa_11_fp_reg_struct result;
+                 
+                   /* This should be more strict.  Small steps.  */
+                   if (strict && *s != '%')
+                     break;
+                   pa_parse_number (&s, &result);
+                   CHECK_FIELD (result.number_part, 31, 0, 0);
+                   if (the_insn.fpof1 == SGL)
+                     {
+                       if (result.number_part < 16)
+                         {
+                       as_bad  (_("Invalid register for single precision fmpyadd or fmpysub"));
+                       break;
+                         }
+                       result.number_part &= 0xF;
+                       result.number_part |= (result.l_r_select & 1) << 4;
+                     }
+                   INSERT_FIELD_AND_CONTINUE (opcode, result.number_part, 6);
+                 }
 
 
-               pa_parse_number (&s, &result);
-               CHECK_FIELD (result.number_part, 31, 0, 0);
-               if (the_insn.fpof1 == SGL)
+               /* Float add target for fmpyadd, fmpysub */
+               case 'm':
                  {
                  {
-                   result.number_part &= 0xF;
-                   result.number_part |= (result.l_r_select & 1) << 4;
+                   struct pa_11_fp_reg_struct result;
+                 
+                   /* This should be more strict.  Small steps.  */
+                   if (strict && *s != '%')
+                     break;
+                   pa_parse_number (&s, &result);
+                   CHECK_FIELD (result.number_part, 31, 0, 0);
+                   if (the_insn.fpof1 == SGL)
+                     {
+                       if (result.number_part < 16)
+                         {
+                       as_bad  (_("Invalid register for single precision fmpyadd or fmpysub"));
+                       break;
+                         }
+                       result.number_part &= 0xF;
+                       result.number_part |= (result.l_r_select & 1) << 4;
+                     }
+                   INSERT_FIELD_AND_CONTINUE (opcode, result.number_part, 11);
                  }
                  }
-               INSERT_FIELD_AND_CONTINUE (opcode, result.number_part, 11);
-             }
 
 
-           /* Handle a 5 bit register field at 25.  */
-           case '9':
+               default:
+                 abort ();
+               }
+             break;
+
+           /* Handle L/R register halves like 'x'.  */
+           case 'e':
              {
              {
-               struct pa_89_fp_reg_struct result;
+               struct pa_11_fp_reg_struct result;
 
 
+               /* This should be more strict.  Small steps.  */
+               if (strict && *s != '%')
+                 break;
                pa_parse_number (&s, &result);
                CHECK_FIELD (result.number_part, 31, 0, 0);
                pa_parse_number (&s, &result);
                CHECK_FIELD (result.number_part, 31, 0, 0);
-               if (the_insn.fpof1 == SGL)
+               opcode |= (result.number_part & 0x1f) << 16;
+               if (need_pa11_opcode (&the_insn, &result))
                  {
                  {
-                   result.number_part &= 0xF;
-                   result.number_part |= (result.l_r_select & 1) << 4;
+                   opcode |= (result.l_r_select & 1) << 1;
                  }
                  }
-               INSERT_FIELD_AND_CONTINUE (opcode, result.number_part, 6);
+               continue;
              }
 
              }
 
-           /* Handle a floating point operand format at 26.
-              Only allows single and double precision.  */
-           case 'H':
-             flag = pa_parse_fp_format (&s);
-             switch (flag)
-               {
-               case SGL:
-                 opcode |= 0x20;
-               case DBL:
-                 the_insn.fpof1 = flag;
-                 continue;
-
-               case QUAD:
-               case ILLEGAL_FMT:
-               default:
-                 as_bad ("Invalid Floating Point Operand Format.");
-               }
-             break;
-
            default:
              abort ();
            }
          break;
        }
 
            default:
              abort ();
            }
          break;
        }
 
+ failed:
       /* Check if the args matched.  */
       if (match == FALSE)
        {
       /* Check if the args matched.  */
       if (match == FALSE)
        {
-         if (&insn[1] - pa_opcodes < NUMOPCODES
+         if (&insn[1] - pa_opcodes < (int) NUMOPCODES
              && !strcmp (insn->name, insn[1].name))
            {
              ++insn;
              && !strcmp (insn->name, insn[1].name))
            {
              ++insn;
@@ -2428,7 +3339,7 @@ pa_ip (str)
            }
          else
            {
            }
          else
            {
-             as_bad ("Invalid operands %s", error_message);
+             as_bad (_("Invalid operands %s"), error_message);
              return;
            }
        }
              return;
            }
        }
@@ -2484,7 +3395,7 @@ md_atof (type, litP, sizeP)
 
     default:
       *sizeP = 0;
 
     default:
       *sizeP = 0;
-      return "Bad call to MD_ATOF()";
+      return _("Bad call to MD_ATOF()");
     }
   t = atof_ieee (input_line_pointer, type, words);
   if (t)
     }
   t = atof_ieee (input_line_pointer, type, words);
   if (t)
@@ -2532,27 +3443,25 @@ tc_gen_reloc (section, fixp)
   assert (hppa_fixp != 0);
   assert (section != 0);
 
   assert (hppa_fixp != 0);
   assert (section != 0);
 
-  reloc = (arelent *) bfd_alloc_by_size_t (stdoutput, sizeof (arelent));
-  assert (reloc != 0);
+  reloc = (arelent *) xmalloc (sizeof (arelent));
 
 
-  reloc->sym_ptr_ptr = &fixp->fx_addsy->bsym;
+  reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
+  *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
   codes = (bfd_reloc_code_real_type **) hppa_gen_reloc_type (stdoutput,
                               fixp->fx_r_type,
                               hppa_fixp->fx_r_format,
   codes = (bfd_reloc_code_real_type **) hppa_gen_reloc_type (stdoutput,
                               fixp->fx_r_type,
                               hppa_fixp->fx_r_format,
-                              hppa_fixp->fx_r_field);
+                              hppa_fixp->fx_r_field,
+                              fixp->fx_subsy != NULL,
+                              symbol_get_bfdsym (fixp->fx_addsy));
+
+  if (codes == NULL)
+    abort ();
 
   for (n_relocs = 0; codes[n_relocs]; n_relocs++)
     ;
 
 
   for (n_relocs = 0; codes[n_relocs]; n_relocs++)
     ;
 
-  relocs = (arelent **)
-    bfd_alloc_by_size_t (stdoutput, sizeof (arelent *) * n_relocs + 1);
-  assert (relocs != 0);
-
-  reloc = (arelent *) bfd_alloc_by_size_t (stdoutput,
-                                          sizeof (arelent) * n_relocs);
-  if (n_relocs > 0)
-    assert (reloc != 0);
-
+  relocs = (arelent **) xmalloc (sizeof (arelent *) * n_relocs + 1);
+  reloc = (arelent *) xmalloc (sizeof (arelent) * n_relocs);
   for (i = 0; i < n_relocs; i++)
     relocs[i] = &reloc[i];
 
   for (i = 0; i < n_relocs; i++)
     relocs[i] = &reloc[i];
 
@@ -2566,7 +3475,8 @@ tc_gen_reloc (section, fixp)
 
       code = *codes[0];
 
 
       code = *codes[0];
 
-      reloc->sym_ptr_ptr = &fixp->fx_addsy->bsym;
+      reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
+      *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
       reloc->howto = bfd_reloc_type_lookup (stdoutput, code);
       reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
       reloc->addend = 0;       /* default */
       reloc->howto = bfd_reloc_type_lookup (stdoutput, code);
       reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
       reloc->addend = 0;       /* default */
@@ -2616,12 +3526,41 @@ tc_gen_reloc (section, fixp)
     {
       code = *codes[i];
 
     {
       code = *codes[i];
 
-      relocs[i]->sym_ptr_ptr = &fixp->fx_addsy->bsym;
+      relocs[i]->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
+      *relocs[i]->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
       relocs[i]->howto = bfd_reloc_type_lookup (stdoutput, code);
       relocs[i]->address = fixp->fx_frag->fr_address + fixp->fx_where;
 
       switch (code)
        {
       relocs[i]->howto = bfd_reloc_type_lookup (stdoutput, code);
       relocs[i]->address = fixp->fx_frag->fr_address + fixp->fx_where;
 
       switch (code)
        {
+       case R_COMP2:
+         /* 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
+            relocs now and break out of the loop.  */
+         assert (i == 1);
+         relocs[0]->sym_ptr_ptr = (asymbol **) &(bfd_abs_symbol);
+         relocs[0]->howto = bfd_reloc_type_lookup (stdoutput, *codes[0]);
+         relocs[0]->address = fixp->fx_frag->fr_address + fixp->fx_where;
+         relocs[0]->addend = 0;
+         relocs[1]->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
+         *relocs[1]->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
+         relocs[1]->howto = bfd_reloc_type_lookup (stdoutput, *codes[1]);
+         relocs[1]->address = fixp->fx_frag->fr_address + fixp->fx_where;
+         relocs[1]->addend = 0;
+         relocs[2]->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
+         *relocs[2]->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_subsy);
+         relocs[2]->howto = bfd_reloc_type_lookup (stdoutput, *codes[2]);
+         relocs[2]->address = fixp->fx_frag->fr_address + fixp->fx_where;
+         relocs[2]->addend = 0;
+         relocs[3]->sym_ptr_ptr = (asymbol **) &(bfd_abs_symbol);
+         relocs[3]->howto = bfd_reloc_type_lookup (stdoutput, *codes[3]);
+         relocs[3]->address = fixp->fx_frag->fr_address + fixp->fx_where;
+         relocs[3]->addend = 0;
+         relocs[4]->sym_ptr_ptr = (asymbol **) &(bfd_abs_symbol);
+         relocs[4]->howto = bfd_reloc_type_lookup (stdoutput, *codes[4]);
+         relocs[4]->address = fixp->fx_frag->fr_address + fixp->fx_where;
+         relocs[4]->addend = 0;
+         goto done;
        case R_PCREL_CALL:
        case R_ABS_CALL:
          relocs[i]->addend = HPPA_R_ADDEND (hppa_fixp->fx_arg_reloc, 0);
        case R_PCREL_CALL:
        case R_ABS_CALL:
          relocs[i]->addend = HPPA_R_ADDEND (hppa_fixp->fx_arg_reloc, 0);
@@ -2649,15 +3588,23 @@ tc_gen_reloc (section, fixp)
        case R_FSEL:
        case R_LSEL:
        case R_RSEL:
        case R_FSEL:
        case R_LSEL:
        case R_RSEL:
+       case R_BEGIN_BRTAB:
+       case R_END_BRTAB:
+       case R_BEGIN_TRY:
+       case R_N0SEL:
+       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 = &dummy_symbol->bsym;
+          relocs[i]->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
+          *relocs[i]->sym_ptr_ptr = symbol_get_bfdsym (dummy_symbol);
          relocs[i]->addend = 0;
          break;
 
          relocs[i]->addend = 0;
          break;
 
+       case R_END_TRY:
        case R_ENTRY:
        case R_EXIT:
          /* There is no symbol associated with these fixups.  */
        case R_ENTRY:
        case R_EXIT:
          /* There is no symbol associated with these fixups.  */
-         relocs[i]->sym_ptr_ptr = &dummy_symbol->bsym;
+          relocs[i]->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
+          *relocs[i]->sym_ptr_ptr = symbol_get_bfdsym (dummy_symbol);
          relocs[i]->addend = fixp->fx_offset;
          break;
 
          relocs[i]->addend = fixp->fx_offset;
          break;
 
@@ -2665,6 +3612,8 @@ tc_gen_reloc (section, fixp)
          relocs[i]->addend = fixp->fx_offset;
        }
     }
          relocs[i]->addend = fixp->fx_offset;
        }
     }
+
+ done:
 #endif
 
   return relocs;
 #endif
 
   return relocs;
@@ -2716,30 +3665,6 @@ md_section_align (segment, size)
   return (size + align2) & ~align2;
 }
 
   return (size + align2) & ~align2;
 }
 
-/* Create a short jump from FROM_ADDR to TO_ADDR.  Not used on the PA.  */
-void
-md_create_short_jump (ptr, from_addr, to_addr, frag, to_symbol)
-     char *ptr;
-     addressT from_addr, to_addr;
-     fragS *frag;
-     symbolS *to_symbol;
-{
-  fprintf (stderr, "pa_create_short_jmp\n");
-  abort ();
-}
-
-/* Create a long jump from FROM_ADDR to TO_ADDR.  Not used on the PA.  */
-void
-md_create_long_jump (ptr, from_addr, to_addr, frag, to_symbol)
-     char *ptr;
-     addressT from_addr, to_addr;
-     fragS *frag;
-     symbolS *to_symbol;
-{
-  fprintf (stderr, "pa_create_long_jump\n");
-  abort ();
-}
-
 /* Return the approximate size of a frag before relaxation has occurred.  */
 int
 md_estimate_size_before_relax (fragP, segment)
 /* Return the approximate size of a frag before relaxation has occurred.  */
 int
 md_estimate_size_before_relax (fragP, segment)
@@ -2785,16 +3710,6 @@ md_undefined_symbol (name)
   return 0;
 }
 
   return 0;
 }
 
-/* Parse an operand that is machine-specific.
-   We just return without modifying the expression as we have nothing
-   to do on the PA.  */
-
-void
-md_operand (expressionP)
-     expressionS *expressionP;
-{
-}
-
 /* Apply a fixup to an instruction.  */
 
 int
 /* Apply a fixup to an instruction.  */
 
 int
@@ -2804,16 +3719,29 @@ md_apply_fix (fixP, valp)
 {
   char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
   struct hppa_fix_struct *hppa_fixP;
 {
   char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
   struct hppa_fix_struct *hppa_fixP;
-  long new_val, result;
-  unsigned int w1, w2, w;
+  long new_val, result = 0;
+  unsigned int w1, w2, w, resulti;
 
   hppa_fixP = (struct hppa_fix_struct *) fixP->tc_fix_data;
   /* SOM uses R_HPPA_ENTRY and R_HPPA_EXIT relocations which can
 
   hppa_fixP = (struct hppa_fix_struct *) fixP->tc_fix_data;
   /* SOM uses R_HPPA_ENTRY and R_HPPA_EXIT relocations which can
-     never be "applied" (they are just markers).  */
+     never be "applied" (they are just markers).  Likewise for
+     R_HPPA_BEGIN_BRTAB and R_HPPA_END_BRTAB.  */
 #ifdef OBJ_SOM
   if (fixP->fx_r_type == R_HPPA_ENTRY
 #ifdef OBJ_SOM
   if (fixP->fx_r_type == R_HPPA_ENTRY
-      || fixP->fx_r_type == R_HPPA_EXIT)
-    return;
+      || fixP->fx_r_type == R_HPPA_EXIT
+      || fixP->fx_r_type == R_HPPA_BEGIN_BRTAB
+      || fixP->fx_r_type == R_HPPA_END_BRTAB
+      || fixP->fx_r_type == R_HPPA_BEGIN_TRY)
+    return 1;
+
+  /* Disgusting.  We must set fx_offset ourselves -- R_HPPA_END_TRY
+     fixups are considered not adjustable, which in turn causes
+     adjust_reloc_syms to not set fx_offset.  Ugh.  */
+  if (fixP->fx_r_type == R_HPPA_END_TRY)
+    {
+      fixP->fx_offset = *valp;
+      return 1;
+    }
 #endif
 
   /* There should have been an HPPA specific fixup associated
 #endif
 
   /* There should have been an HPPA specific fixup associated
@@ -2827,27 +3755,51 @@ md_apply_fix (fixP, valp)
         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
         will be added in as needed from fx_offset in tc_gen_reloc.  */
         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
         will be added in as needed from fx_offset in tc_gen_reloc.  */
-      if (fixP->fx_addsy != NULL
-         || fixP->fx_r_type == R_HPPA_NONE)
-       new_val = ((fmt == 12 || fmt == 17) ? 8 : 0);
+      if ((fixP->fx_addsy != NULL
+          || fixP->fx_r_type == R_HPPA_NONE)
+#ifdef OBJ_SOM
+         && fmt != 32
+#endif
+         )
+       new_val = ((fmt == 12 || fmt == 17 || fmt == 22) ? 8 : 0);
+#ifdef OBJ_SOM
+      /* These field selectors imply that we do not want an addend.  */
+      else if (hppa_fixP->fx_r_field == e_psel
+              || hppa_fixP->fx_r_field == e_rpsel
+              || hppa_fixP->fx_r_field == e_lpsel
+              || hppa_fixP->fx_r_field == e_tsel
+              || hppa_fixP->fx_r_field == e_rtsel
+              || hppa_fixP->fx_r_field == e_ltsel)
+       new_val = ((fmt == 12 || fmt == 17 || fmt == 22) ? 8 : 0);
+      /* This is truely disgusting.  The machine independent code blindly
+        adds in the value of the symbol being relocated against.  Damn!  */
+      else if (fmt == 32
+              && fixP->fx_addsy != NULL
+              && S_GET_SEGMENT (fixP->fx_addsy) != bfd_com_section_ptr)
+       new_val = hppa_field_adjust (*valp - S_GET_VALUE (fixP->fx_addsy),
+                                    0, hppa_fixP->fx_r_field);
+#endif
       else
        new_val = hppa_field_adjust (*valp, 0, hppa_fixP->fx_r_field);
 
       /* Handle pc-relative exceptions from above.  */
       else
        new_val = hppa_field_adjust (*valp, 0, hppa_fixP->fx_r_field);
 
       /* Handle pc-relative exceptions from above.  */
-#define stub_needed(CALLER, CALLEE) \
+#define arg_reloc_stub_needed(CALLER, CALLEE) \
   ((CALLEE) && (CALLER) && ((CALLEE) != (CALLER)))
   ((CALLEE) && (CALLER) && ((CALLEE) != (CALLER)))
-      if ((fmt == 12 || fmt == 17)
+      if ((fmt == 12 || fmt == 17 || fmt == 22)
          && fixP->fx_addsy
          && fixP->fx_pcrel
          && fixP->fx_addsy
          && fixP->fx_pcrel
-         && !stub_needed (((obj_symbol_type *)
-                           fixP->fx_addsy->bsym)->tc_data.hppa_arg_reloc,
-                          hppa_fixP->fx_arg_reloc)
+#ifdef OBJ_SOM
+         && !arg_reloc_stub_needed ((long) ((obj_symbol_type *)
+               symbol_get_bfdsym (fixP->fx_addsy))->tc_data.ap.hppa_arg_reloc,
+               hppa_fixP->fx_arg_reloc)
+#endif
+         && (((int)(*valp) > -262144 && (int)(*valp) < 262143) && fmt != 22)
          && S_GET_SEGMENT (fixP->fx_addsy) == hppa_fixP->segment
          && !(fixP->fx_subsy
               && S_GET_SEGMENT (fixP->fx_subsy) != hppa_fixP->segment))
              
        new_val = hppa_field_adjust (*valp, 0, hppa_fixP->fx_r_field);
          && S_GET_SEGMENT (fixP->fx_addsy) == hppa_fixP->segment
          && !(fixP->fx_subsy
               && S_GET_SEGMENT (fixP->fx_subsy) != hppa_fixP->segment))
              
        new_val = hppa_field_adjust (*valp, 0, hppa_fixP->fx_r_field);
-#undef stub_needed
+#undef arg_reloc_stub_needed
        
       switch (fmt)
        {
        
       switch (fmt)
        {
@@ -2859,7 +3811,8 @@ md_apply_fix (fixP, valp)
          bfd_put_32 (stdoutput,
                      bfd_get_32 (stdoutput, buf) & 0xffffc000,
                      buf);
          bfd_put_32 (stdoutput,
                      bfd_get_32 (stdoutput, buf) & 0xffffc000,
                      buf);
-         low_sign_unext (new_val, 14, &result);
+         low_sign_unext (new_val, 14, &resulti);
+         result = resulti;
          break;
 
        /* Handle all opcodes with the 'k' operand type.  */
          break;
 
        /* Handle all opcodes with the 'k' operand type.  */
@@ -2870,7 +3823,8 @@ md_apply_fix (fixP, valp)
          bfd_put_32 (stdoutput,
                      bfd_get_32 (stdoutput, buf) & 0xffe00000,
                      buf);
          bfd_put_32 (stdoutput,
                      bfd_get_32 (stdoutput, buf) & 0xffe00000,
                      buf);
-         dis_assemble_21 (new_val, &result);
+         dis_assemble_21 (new_val, &resulti);
+         result = resulti;
          break;
 
        /* Handle all the opcodes with the 'i' operand type.  */
          break;
 
        /* Handle all the opcodes with the 'i' operand type.  */
@@ -2881,35 +3835,47 @@ md_apply_fix (fixP, valp)
          bfd_put_32 (stdoutput,
                      bfd_get_32 (stdoutput, buf) & 0xffff800,
                      buf);
          bfd_put_32 (stdoutput,
                      bfd_get_32 (stdoutput, buf) & 0xffff800,
                      buf);
-         low_sign_unext (new_val, 11, &result);
+         low_sign_unext (new_val, 11, &resulti);
+         result = resulti;
          break;
 
        /* Handle all the opcodes with the 'w' operand type.  */
        case 12:
          break;
 
        /* Handle all the opcodes with the 'w' operand type.  */
        case 12:
-         CHECK_FIELD (new_val, 8191, -8192, 0)
+         CHECK_FIELD (new_val, 8199, -8184, 0);
 
          /* Mask off 11 bits to be changed.  */
 
          /* Mask off 11 bits to be changed.  */
-           sign_unext ((new_val - 8) >> 2, 12, &result);
+         sign_unext ((new_val - 8) >> 2, 12, &resulti);
          bfd_put_32 (stdoutput,
                      bfd_get_32 (stdoutput, buf) & 0xffffe002,
                      buf);
 
          bfd_put_32 (stdoutput,
                      bfd_get_32 (stdoutput, buf) & 0xffffe002,
                      buf);
 
-         dis_assemble_12 (result, &w1, &w);
+         dis_assemble_12 (resulti, &w1, &w);
          result = ((w1 << 2) | w);
          break;
 
        /* Handle some of the opcodes with the 'W' operand type.  */
        case 17:
          result = ((w1 << 2) | w);
          break;
 
        /* Handle some of the opcodes with the 'W' operand type.  */
        case 17:
-         CHECK_FIELD (new_val, 262143, -262144, 0);
-
-         /* Mask off 17 bits to be changed.  */
-         bfd_put_32 (stdoutput,
-                     bfd_get_32 (stdoutput, buf) & 0xffe0e002,
-                     buf);
-         sign_unext ((new_val - 8) >> 2, 17, &result);
-         dis_assemble_17 (result, &w1, &w2, &w);
-         result = ((w2 << 2) | (w1 << 16) | w);
-         break;
+         {
+           int distance = *valp;
+
+           CHECK_FIELD (new_val, 262143, -262144, 0);
+
+           /* If this is an absolute branch (ie no link) with an out of
+              range target, then we want to complain.  */
+           if (fixP->fx_r_type == R_HPPA_PCREL_CALL
+               && (distance > 262143 || distance < -262144)
+               && (bfd_get_32 (stdoutput, buf) & 0xffe00000) == 0xe8000000)
+             CHECK_FIELD (distance, 262143, -262144, 0);
+
+           /* Mask off 17 bits to be changed.  */
+           bfd_put_32 (stdoutput,
+                       bfd_get_32 (stdoutput, buf) & 0xffe0e002,
+                       buf);
+           sign_unext ((new_val - 8) >> 2, 17, &resulti);
+           dis_assemble_17 (resulti, &w1, &w2, &w);
+           result = ((w2 << 2) | (w1 << 16) | w);
+           break;
+         }
 
        case 32:
          result = 0;
 
        case 32:
          result = 0;
@@ -2917,19 +3883,19 @@ md_apply_fix (fixP, valp)
          break;
 
        default:
          break;
 
        default:
-         as_bad ("Unknown relocation encountered in md_apply_fix.");
-         return;
+         as_bad (_("Unknown relocation encountered in md_apply_fix."));
+         return 0;
        }
 
       /* Insert the relocation.  */
       bfd_put_32 (stdoutput, bfd_get_32 (stdoutput, buf) | result, buf);
        }
 
       /* Insert the relocation.  */
       bfd_put_32 (stdoutput, bfd_get_32 (stdoutput, buf) | result, buf);
-      return;
+      return 1;
     }
   else
     {
     }
   else
     {
-      printf ("no hppa_fixup entry for this fixup (fixP = 0x%x, type = 0x%x)\n",
+      printf (_("no hppa_fixup entry for this fixup (fixP = 0x%x, type = 0x%x)\n"),
              (unsigned int) fixP, fixP->fx_r_type);
              (unsigned int) fixP, fixP->fx_r_type);
-      return;
+      return 0;
     }
 }
 
     }
 }
 
@@ -2970,7 +3936,7 @@ is_end_of_statement ()
 static int
 pa_parse_number (s, result)
      char **s;
 static int
 pa_parse_number (s, result)
      char **s;
-     struct pa_89_fp_reg_struct *result;
+     struct pa_11_fp_reg_struct *result;
 {
   int num;
   char *name;
 {
   int num;
   char *name;
@@ -3069,7 +4035,7 @@ pa_parse_number (s, result)
          else if (!isdigit (*p))
            {
              if (print_errors)
          else if (!isdigit (*p))
            {
              if (print_errors)
-               as_bad ("Undefined register: '%s'.", name);
+               as_bad (_("Undefined register: '%s'."), name);
              num = -1;
            }
          else
              num = -1;
            }
          else
@@ -3094,7 +4060,7 @@ pa_parse_number (s, result)
          else
            {
              if (print_errors)
          else
            {
              if (print_errors)
-               as_bad ("Undefined register: '%s'.", name);
+               as_bad (_("Undefined register: '%s'."), name);
              num = -1;
            }
          *p = c;
              num = -1;
            }
          *p = c;
@@ -3132,7 +4098,7 @@ pa_parse_number (s, result)
          else
            {
              if (print_errors)
          else
            {
              if (print_errors)
-               as_bad ("Non-absolute symbol: '%s'.", name);
+               as_bad (_("Non-absolute symbol: '%s'."), name);
              num = -1;
            }
        }
              num = -1;
            }
        }
@@ -3147,7 +4113,7 @@ pa_parse_number (s, result)
          else
            {
              if (print_errors)
          else
            {
              if (print_errors)
-               as_bad ("Undefined absolute constant: '%s'.", name);
+               as_bad (_("Undefined absolute constant: '%s'."), name);
              num = -1;
            }
        }
              num = -1;
            }
        }
@@ -3203,15 +4169,24 @@ reg_name_search (name)
 
 
 /* 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-89 opcode.  */
+   a new PA-1.1 opcode.  */
 
 static int
 
 static int
-need_89_opcode (insn, result)
+need_pa11_opcode (insn, result)
      struct pa_it *insn;
      struct pa_it *insn;
-     struct pa_89_fp_reg_struct *result;
+     struct pa_11_fp_reg_struct *result;
 {
   if (result->l_r_select == 1 && !(insn->fpof1 == DBL && insn->fpof2 == DBL))
 {
   if (result->l_r_select == 1 && !(insn->fpof1 == DBL && insn->fpof2 == DBL))
-    return TRUE;
+    {
+      /* If this instruction is specific to a particular architecture,
+        then set a new architecture.  */
+      if (bfd_get_mach (stdoutput) < pa11)
+       {
+         if (!bfd_set_arch_mach (stdoutput, bfd_arch_hppa, pa11))
+           as_warn (_("could not update architecture and machine"));
+       }
+      return TRUE;
+    }
   else
     return FALSE;
 }
   else
     return FALSE;
 }
@@ -3247,7 +4222,7 @@ pa_parse_fp_cmp_cond (s)
        }
     }
 
        }
     }
 
-  as_bad ("Invalid FP Compare Condition: %s", *s);
+  as_bad (_("Invalid FP Compare Condition: %s"), *s);
 
   /* Advance over the bogus completer.  */
   while (**s != ',' && **s != ' ' && **s != '\t')
 
   /* Advance over the bogus completer.  */
   while (**s != ',' && **s != ' ' && **s != '\t')
@@ -3256,6 +4231,7 @@ pa_parse_fp_cmp_cond (s)
   return 0;
 }
 
   return 0;
 }
 
+
 /* Parse an FP operand format completer returning the completer
    type.  */
 
 /* Parse an FP operand format completer returning the completer
    type.  */
 
@@ -3287,7 +4263,7 @@ pa_parse_fp_format (s)
       else
        {
          format = ILLEGAL_FMT;
       else
        {
          format = ILLEGAL_FMT;
-         as_bad ("Invalid FP Operand Format: %3s", *s);
+         as_bad (_("Invalid FP Operand Format: %3s"), *s);
        }
     }
 
        }
     }
 
@@ -3302,7 +4278,7 @@ pa_chk_field_selector (str)
 {
   int middle, low, high;
   int cmp;
 {
   int middle, low, high;
   int cmp;
-  char name[3];
+  char name[4];
 
   /* Read past any whitespace.  */
   /* FIXME: should we read past newlines and formfeeds??? */
 
   /* Read past any whitespace.  */
   /* FIXME: should we read past newlines and formfeeds??? */
@@ -3316,6 +4292,11 @@ pa_chk_field_selector (str)
     name[0] = tolower ((*str)[0]),
     name[1] = tolower ((*str)[1]),
     name[2] = 0;
     name[0] = tolower ((*str)[0]),
     name[1] = tolower ((*str)[1]),
     name[2] = 0;
+  else if ((*str)[3] == '\'' || (*str)[3] == '%')
+    name[0] = tolower ((*str)[0]),
+    name[1] = tolower ((*str)[1]),
+    name[2] = tolower ((*str)[2]),
+    name[3] = 0;
   else
     return e_fsel;
 
   else
     return e_fsel;
 
@@ -3333,6 +4314,10 @@ pa_chk_field_selector (str)
       else
        {
          *str += strlen (name) + 1;
       else
        {
          *str += strlen (name) + 1;
+#ifndef OBJ_SOM
+         if (selector_table[middle].field_selector == e_nsel)
+           return e_fsel;
+#endif
          return selector_table[middle].field_selector;
        }
     }
          return selector_table[middle].field_selector;
        }
     }
@@ -3357,7 +4342,7 @@ get_expression (str)
        || seg == undefined_section
        || SEG_NORMAL (seg)))
     {
        || seg == undefined_section
        || SEG_NORMAL (seg)))
     {
-      as_warn ("Bad segment in expression.");
+      as_warn (_("Bad segment in expression."));
       expr_end = input_line_pointer;
       input_line_pointer = save_in;
       return 1;
       expr_end = input_line_pointer;
       input_line_pointer = save_in;
       return 1;
@@ -3379,9 +4364,44 @@ pa_get_absolute_expression (insn, strp)
   save_in = input_line_pointer;
   input_line_pointer = *strp;
   expression (&insn->exp);
   save_in = input_line_pointer;
   input_line_pointer = *strp;
   expression (&insn->exp);
+  /* This is not perfect, but is a huge improvement over doing nothing.
+
+     The PA assembly syntax is ambigious in a variety of ways.  Consider
+     this string "4 %r5"  Is that the number 4 followed by the register
+     r5, or is that 4 MOD 5?
+
+     If we get a modulo expresion When looking for an absolute, we try
+     again cutting off the input string at the first whitespace character.  */
+  if (insn->exp.X_op == O_modulus)
+    {
+      char *s, c;
+      int retval;
+
+      input_line_pointer = *strp;
+      s = *strp;
+      while (*s != ',' && *s != ' ' && *s != '\t')
+        s++;
+
+      c = *s;
+      *s = 0;
+
+      retval = pa_get_absolute_expression (insn, strp);
+
+      input_line_pointer = save_in;
+      *s = c;
+      return evaluate_absolute (insn);
+    }
+  /* When in strict mode we have a non-match, fix up the pointers
+     and return to our caller.  */
+  if (insn->exp.X_op != O_constant && strict)
+    {
+      expr_end = input_line_pointer;
+      input_line_pointer = save_in;
+      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;
       input_line_pointer = save_in;
       return 0;
       expr_end = input_line_pointer;
       input_line_pointer = save_in;
       return 0;
@@ -3480,7 +4500,7 @@ pa_build_arg_reloc (type_name)
   else if (strncasecmp (type_name, "fu", 2) == 0)
     return 3;
   else
   else if (strncasecmp (type_name, "fu", 2) == 0)
     return 3;
   else
-    as_bad ("Invalid argument location: %s\n", type_name);
+    as_bad (_("Invalid argument location: %s\n"), type_name);
 
   return 0;
 }
 
   return 0;
 }
@@ -3511,7 +4531,7 @@ pa_align_arg_reloc (reg, arg_reloc)
       new_reloc <<= 2;
       break;
     default:
       new_reloc <<= 2;
       break;
     default:
-      as_bad ("Invalid argument description: %d", reg);
+      as_bad (_("Invalid argument description: %d"), reg);
     }
 
   return new_reloc;
     }
 
   return new_reloc;
@@ -3534,7 +4554,7 @@ pa_parse_nullif (s)
        nullif = 1;
       else
        {
        nullif = 1;
       else
        {
-         as_bad ("Invalid Nullification: (%c)", **s);
+         as_bad (_("Invalid Nullification: (%c)"), **s);
          nullif = 0;
        }
       *s = *s + 1;
          nullif = 0;
        }
       *s = *s + 1;
@@ -3559,6 +4579,7 @@ pa_parse_nonneg_cmpsub_cmpltr (s, isbranch)
   char *name = *s + 1;
   char c;
   char *save_s = *s;
   char *name = *s + 1;
   char c;
   char *save_s = *s;
+  int nullify = 0;
 
   cmpltr = 0;
   if (**s == ',')
 
   cmpltr = 0;
   if (**s == ',')
@@ -3568,6 +4589,8 @@ pa_parse_nonneg_cmpsub_cmpltr (s, isbranch)
        *s += 1;
       c = **s;
       **s = 0x00;
        *s += 1;
       c = **s;
       **s = 0x00;
+
+
       if (strcmp (name, "=") == 0)
        {
          cmpltr = 1;
       if (strcmp (name, "=") == 0)
        {
          cmpltr = 1;
@@ -3601,6 +4624,7 @@ pa_parse_nonneg_cmpsub_cmpltr (s, isbranch)
       else if (strcasecmp (name, "n") == 0 && isbranch)
        {
          cmpltr = 0;
       else if (strcasecmp (name, "n") == 0 && isbranch)
        {
          cmpltr = 0;
+         nullify = 1;
        }
       else
        {
        }
       else
        {
@@ -3610,9 +4634,10 @@ pa_parse_nonneg_cmpsub_cmpltr (s, isbranch)
     }
 
   /* 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 (cmpltr == 0 && *name == 'n' && isbranch)
+  if (nullify)
     *s = save_s;
 
     *s = save_s;
 
+
   return cmpltr;
 }
 
   return cmpltr;
 }
 
@@ -3632,6 +4657,7 @@ pa_parse_neg_cmpsub_cmpltr (s, isbranch)
   char *name = *s + 1;
   char c;
   char *save_s = *s;
   char *name = *s + 1;
   char c;
   char *save_s = *s;
+  int nullify = 0;
 
   cmpltr = 0;
   if (**s == ',')
 
   cmpltr = 0;
   if (**s == ',')
@@ -3641,6 +4667,8 @@ pa_parse_neg_cmpsub_cmpltr (s, isbranch)
        *s += 1;
       c = **s;
       **s = 0x00;
        *s += 1;
       c = **s;
       **s = 0x00;
+
+
       if (strcasecmp (name, "tr") == 0)
        {
          cmpltr = 0;
       if (strcasecmp (name, "tr") == 0)
        {
          cmpltr = 0;
@@ -3678,6 +4706,7 @@ pa_parse_neg_cmpsub_cmpltr (s, isbranch)
       else if (strcasecmp (name, "n") == 0 && isbranch)
        {
          cmpltr = 0;
       else if (strcasecmp (name, "n") == 0 && isbranch)
        {
          cmpltr = 0;
+         nullify = 1;
        }
       else
        {
        }
       else
        {
@@ -3687,12 +4716,14 @@ pa_parse_neg_cmpsub_cmpltr (s, isbranch)
     }
 
   /* 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 (cmpltr == 0 && *name == 'n' && isbranch)
+  if (nullify)
     *s = save_s;
 
     *s = save_s;
 
+
   return cmpltr;
 }
 
   return cmpltr;
 }
 
+
 /* Parse a non-negated addition completer returning the number
    (for encoding in instrutions) of the given completer.
 
 /* Parse a non-negated addition completer returning the number
    (for encoding in instrutions) of the given completer.
 
@@ -3771,7 +4802,7 @@ pa_parse_nonneg_add_cmpltr (s, isbranch)
 
    ISBRANCH specifies whether or not this is parsing a condition
    completer for a branch (vs a nullification completer for a
 
    ISBRANCH specifies whether or not this is parsing a condition
    completer for a branch (vs a nullification completer for a
-   computational instruction.  */
+   computational instruction).  */
 
 static int
 pa_parse_neg_add_cmpltr (s, isbranch)
 
 static int
 pa_parse_neg_add_cmpltr (s, isbranch)
@@ -3843,11 +4874,15 @@ pa_parse_neg_add_cmpltr (s, isbranch)
   return cmpltr;
 }
 
   return cmpltr;
 }
 
+#ifdef OBJ_SOM
 /* Handle an alignment directive.  Special so that we can update the
    alignment of the subspace if necessary.  */
 static void
 pa_align (bytes)
 {
 /* Handle an alignment directive.  Special so that we can update the
    alignment of the subspace if necessary.  */
 static void
 pa_align (bytes)
 {
+  /* We must have a valid space and subspace.  */
+  pa_check_current_space_and_subspace ();
+
   /* Let the generic gas code do most of the work.  */
   s_align_bytes (bytes);
 
   /* Let the generic gas code do most of the work.  */
   s_align_bytes (bytes);
 
@@ -3856,6 +4891,7 @@ pa_align (bytes)
   if (log2 (bytes) != -1)
     record_alignment (current_subspace->ssd_seg, log2 (bytes));
 }
   if (log2 (bytes) != -1)
     record_alignment (current_subspace->ssd_seg, log2 (bytes));
 }
+#endif
 
 /* Handle a .BLOCK type pseudo-op.  */
 
 
 /* Handle a .BLOCK type pseudo-op.  */
 
@@ -3866,7 +4902,12 @@ pa_block (z)
   char *p;
   long int temp_fill;
   unsigned int temp_size;
   char *p;
   long int temp_fill;
   unsigned int temp_size;
-  int i;
+  unsigned int i;
+
+#ifdef OBJ_SOM
+  /* We must have a valid space and subspace.  */
+  pa_check_current_space_and_subspace ();
+#endif
 
   temp_size = get_absolute_expression ();
 
 
   temp_size = get_absolute_expression ();
 
@@ -3874,8 +4915,8 @@ pa_block (z)
   temp_fill = 0;
 
   p = frag_var (rs_fill, (int) temp_size, (int) temp_size,
   temp_fill = 0;
 
   p = frag_var (rs_fill, (int) temp_size, (int) temp_size,
-               (relax_substateT) 0, (symbolS *) 0, 1, NULL);
-  bzero (p, temp_size);
+               (relax_substateT) 0, (symbolS *) 0, (offsetT) 1, NULL);
+  memset (p, 0, temp_size);
 
   /* Convert 2 bytes at a time.  */
 
 
   /* Convert 2 bytes at a time.  */
 
@@ -3890,6 +4931,52 @@ pa_block (z)
   demand_empty_rest_of_line ();
 }
 
   demand_empty_rest_of_line ();
 }
 
+/* Handle a .begin_brtab and .end_brtab pseudo-op.  */
+
+static void
+pa_brtab (begin)
+     int begin;
+{
+
+#ifdef OBJ_SOM
+  /* The BRTAB relocations are only availble in SOM (to denote
+     the beginning and end of branch tables).  */
+  char *where = frag_more (0);
+
+  fix_new_hppa (frag_now, where - frag_now->fr_literal, 0,
+               NULL, (offsetT) 0, NULL,
+               0, begin ? R_HPPA_BEGIN_BRTAB : R_HPPA_END_BRTAB,
+               e_fsel, 0, 0, NULL);
+#endif
+
+  demand_empty_rest_of_line ();
+}
+
+/* Handle a .begin_try and .end_try pseudo-op.  */
+
+static void
+pa_try (begin)
+     int begin;
+{
+#ifdef OBJ_SOM
+  expressionS exp;
+  char *where = frag_more (0);
+
+  if (! begin)
+    expression (&exp);
+
+  /* The TRY relocations are only availble in SOM (to denote
+     the beginning and end of exception handling regions).  */
+
+  fix_new_hppa (frag_now, where - frag_now->fr_literal, 0,
+               NULL, (offsetT) 0, begin ? NULL : &exp,
+               0, begin ? R_HPPA_BEGIN_TRY : R_HPPA_END_TRY,
+               e_fsel, 0, 0, NULL);
+#endif
+
+  demand_empty_rest_of_line ();
+}
+
 /* Handle a .CALL pseudo-op.  This involves storing away information
    about where arguments are to be found so the linker can detect
    (and correct) argument location mismatches between caller and callee.  */
 /* Handle a .CALL pseudo-op.  This involves storing away information
    about where arguments are to be found so the linker can detect
    (and correct) argument location mismatches between caller and callee.  */
@@ -3898,6 +4985,11 @@ static void
 pa_call (unused)
      int unused;
 {
 pa_call (unused)
      int unused;
 {
+#ifdef OBJ_SOM
+  /* We must have a valid space and subspace.  */
+  pa_check_current_space_and_subspace ();
+#endif
+
   pa_call_args (&last_call_desc);
   demand_empty_rest_of_line ();
 }
   pa_call_args (&last_call_desc);
   demand_empty_rest_of_line ();
 }
@@ -3941,7 +5033,7 @@ pa_call_args (call_desc)
        }
       else
        {
        }
       else
        {
-         as_bad ("Invalid .CALL argument: %s", name);
+         as_bad (_("Invalid .CALL argument: %s"), name);
        }
       p = input_line_pointer;
       *p = c;
        }
       p = input_line_pointer;
       *p = c;
@@ -3982,43 +5074,60 @@ pa_build_unwind_subspace (call_info)
 {
   char *unwind;
   asection *seg, *save_seg;
 {
   char *unwind;
   asection *seg, *save_seg;
+  asymbol *sym;
   subsegT subseg, save_subseg;
   subsegT subseg, save_subseg;
-  int i;
+  int i, reloc;
   char c, *p;
 
   char c, *p;
 
+  if (bfd_get_arch_info (stdoutput)->bits_per_address == 32)
+    reloc = R_PARISC_DIR32;
+  else
+    reloc = R_PARISC_SEGREL32;
+    
   /* Get into the right seg/subseg.  This may involve creating
      the seg the first time through.  Make sure to have the
      old seg/subseg so that we can reset things when we are done.  */
   /* Get into the right seg/subseg.  This may involve creating
      the seg the first time through.  Make sure to have the
      old seg/subseg so that we can reset things when we are done.  */
-  subseg = SUBSEG_UNWIND;
   seg = bfd_get_section_by_name (stdoutput, UNWIND_SECTION_NAME);
   if (seg == ASEC_NULL)
     {
       seg = bfd_make_section_old_way (stdoutput, UNWIND_SECTION_NAME);
       bfd_set_section_flags (stdoutput, seg,
                             SEC_READONLY | SEC_HAS_CONTENTS
   seg = bfd_get_section_by_name (stdoutput, UNWIND_SECTION_NAME);
   if (seg == ASEC_NULL)
     {
       seg = bfd_make_section_old_way (stdoutput, UNWIND_SECTION_NAME);
       bfd_set_section_flags (stdoutput, seg,
                             SEC_READONLY | SEC_HAS_CONTENTS
-                            | SEC_LOAD | SEC_RELOC);
+                            | SEC_LOAD | SEC_RELOC | SEC_ALLOC | SEC_DATA);
+      bfd_set_section_alignment (stdoutput, seg, 2);
     }
 
   save_seg = now_seg;
   save_subseg = now_subseg;
     }
 
   save_seg = now_seg;
   save_subseg = now_subseg;
-  subseg_set (seg, subseg);
+  subseg_set (seg, 0);
 
 
   /* Get some space to hold relocation information for the unwind
      descriptor.  */
   p = frag_more (4);
 
 
   /* Get some space to hold relocation information for the unwind
      descriptor.  */
   p = frag_more (4);
+  md_number_to_chars (p, 0, 4);
 
   /* Relocation info. for start offset of the function.  */
   fix_new_hppa (frag_now, p - frag_now->fr_literal, 4,
                call_info->start_symbol, (offsetT) 0,
 
   /* Relocation info. for start offset of the function.  */
   fix_new_hppa (frag_now, p - frag_now->fr_literal, 4,
                call_info->start_symbol, (offsetT) 0,
-               (expressionS *) NULL, 0, R_PARISC_DIR32, e_fsel, 32, 0, NULL);
+               (expressionS *) NULL, 0, reloc,
+               e_fsel, 32, 0, NULL);
 
   p = frag_more (4);
 
   p = frag_more (4);
+  md_number_to_chars (p, 0, 4);
+
+  /* Relocation info. for end offset of the function.
+
+     Because we allow reductions of 32bit relocations for ELF, this will be
+     reduced to section_sym + offset which avoids putting the temporary
+     symbol into the symbol table.  It (should) end up giving the same
+     value as call_info->start_symbol + function size once the linker is
+     finished with its work.  */
 
 
-  /* Relocation info. for end offset of the function.  */
   fix_new_hppa (frag_now, p - frag_now->fr_literal, 4,
                call_info->end_symbol, (offsetT) 0,
   fix_new_hppa (frag_now, p - frag_now->fr_literal, 4,
                call_info->end_symbol, (offsetT) 0,
-               (expressionS *) NULL, 0, R_PARISC_DIR32, e_fsel, 32, 0, NULL);
+               (expressionS *) NULL, 0, reloc,
+               e_fsel, 32, 0, NULL);
 
   /* Dump it. */
   unwind = (char *) &call_info->ci_unwind;
 
   /* Dump it. */
   unwind = (char *) &call_info->ci_unwind;
@@ -4046,9 +5155,14 @@ pa_callinfo (unused)
   char *name, c, *p;
   int temp;
 
   char *name, c, *p;
   int temp;
 
+#ifdef OBJ_SOM
+  /* We must have a valid space and subspace.  */
+  pa_check_current_space_and_subspace ();
+#endif
+
   /* .CALLINFO must appear within a procedure definition.  */
   if (!within_procedure)
   /* .CALLINFO must appear within a procedure definition.  */
   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
      current procedure.  */
 
   /* Mark the fact that we found the .CALLINFO for the
      current procedure.  */
@@ -4068,7 +5182,7 @@ pa_callinfo (unused)
          temp = get_absolute_expression ();
          if ((temp & 0x3) != 0)
            {
          temp = get_absolute_expression ();
          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;
            }
 
@@ -4087,7 +5201,7 @@ pa_callinfo (unused)
             even though %r19 is caller saved.  I think this is a bug in
             the HP assembler, and we are not going to emulate it.  */
          if (temp < 3 || temp > 18)
             even though %r19 is caller saved.  I think this is a bug in
             the HP assembler, and we are not going to emulate it.  */
          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;
        }
       else if ((strncasecmp (name, "entry_fr", 8) == 0))
          last_call_info->ci_unwind.descriptor.entry_gr = temp - 2;
        }
       else if ((strncasecmp (name, "entry_fr", 8) == 0))
@@ -4099,7 +5213,7 @@ pa_callinfo (unused)
          /* Similarly the HP assembler takes 31 as the high bound even
             though %fr21 is the last callee saved floating point register.  */
          if (temp < 12 || temp > 21)
          /* Similarly the HP assembler takes 31 as the high bound even
             though %fr21 is the last callee saved floating point register.  */
          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;
        }
       else if ((strncasecmp (name, "entry_sr", 8) == 0))
          last_call_info->ci_unwind.descriptor.entry_fr = temp - 11;
        }
       else if ((strncasecmp (name, "entry_sr", 8) == 0))
@@ -4109,7 +5223,7 @@ pa_callinfo (unused)
          input_line_pointer++;
          temp = get_absolute_expression ();
          if (temp != 3)
          input_line_pointer++;
          temp = get_absolute_expression ();
          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.  */
       else if ((strncasecmp (name, "calls", 5) == 0) ||
        }
       /* Note whether or not this function performs any calls.  */
       else if ((strncasecmp (name, "calls", 5) == 0) ||
@@ -4165,7 +5279,7 @@ pa_callinfo (unused)
        }
       else
        {
        }
       else
        {
-         as_bad ("Invalid .CALLINFO argument: %s", name);
+         as_bad (_("Invalid .CALLINFO argument: %s"), name);
          *input_line_pointer = c;
        }
       if (!is_end_of_statement ())
          *input_line_pointer = c;
        }
       if (!is_end_of_statement ())
@@ -4181,24 +5295,13 @@ static void
 pa_code (unused)
      int unused;
 {
 pa_code (unused)
      int unused;
 {
-  sd_chain_struct *sdchain;
-
-  /* First time through it might be necessary to create the
-     $TEXT$ space.  */
-  if ((sdchain = is_defined_space ("$TEXT$")) == NULL)
-    {
-      sdchain = create_new_space (pa_def_spaces[0].name,
-                                 pa_def_spaces[0].spnum,
-                                 pa_def_spaces[0].loadable,
-                                 pa_def_spaces[0].defined,
-                                 pa_def_spaces[0].private,
-                                 pa_def_spaces[0].sort,
-                                 pa_def_spaces[0].segment, 0);
-    }
-
-  SPACE_DEFINED (sdchain) = 1;
-  subseg_set (text_section, SUBSEG_CODE);
-  demand_empty_rest_of_line ();
+#ifdef OBJ_SOM
+  current_space = is_defined_space ("$TEXT$");
+  current_subspace
+    = pa_subsegment_to_subspace (current_space->sd_seg, 0);
+#endif
+  s_text (0);
+  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,
@@ -4209,7 +5312,17 @@ pa_code (unused)
    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
    expression.  <length> bytes will be allocated in the current space
    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
    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.
+
+   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
+   of attributes of the symbol that need to be fixed here.  In particular
+   the value, section pointer, fragment pointer, flags, etc.  What
+   a pain.
+
+   This also makes error detection all but impossible.  */
 
 static void
 pa_comm (unused)
 
 static void
 pa_comm (unused)
@@ -4229,30 +5342,14 @@ pa_comm (unused)
 
   if (symbol)
     {
 
   if (symbol)
     {
-      /* It is incorrect to check S_IS_DEFINED at this point as
-         the symbol will *always* be defined.  FIXME.  How to
-         correctly determine when this label really as been
-         defined before.  */
-      if (S_GET_VALUE (symbol))
-       {
-         if (S_GET_VALUE (symbol) != size)
-           {
-             as_warn ("Length of .comm \"%s\" is already %ld. Not changed.",
-                      S_GET_NAME (symbol), S_GET_VALUE (symbol));
-             return;
-           }
-       }
-      else
-       {
-         S_SET_VALUE (symbol, size);
-         S_SET_SEGMENT (symbol, bfd_und_section_ptr);
-         S_SET_EXTERNAL (symbol);
+      S_SET_VALUE (symbol, size);
+      S_SET_SEGMENT (symbol, bfd_und_section_ptr);
+      S_SET_EXTERNAL (symbol);
 
 
-         /* colon() has already set the frag to the current location in the
-            $BSS$ subspace; we need to reset the fragment to the zero address
-            fragment.  */
-         symbol->sy_frag = &zero_address_frag;
-       }
+      /* colon() has already set the frag to the current location in the
+         current subspace; we need to reset the fragment to the zero address
+         fragment.  We also need to reset the segment pointer.  */
+      symbol_set_frag (symbol, &zero_address_frag);
     }
   demand_empty_rest_of_line ();
 }
     }
   demand_empty_rest_of_line ();
 }
@@ -4271,7 +5368,13 @@ static void
 pa_enter (unused)
      int unused;
 {
 pa_enter (unused)
      int unused;
 {
-  abort ();
+#ifdef OBJ_SOM
+  /* We must have a valid space and subspace.  */
+  pa_check_current_space_and_subspace ();
+#endif
+
+  as_bad (_("The .ENTER pseudo-op is not supported"));
+  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
@@ -4280,12 +5383,17 @@ static void
 pa_entry (unused)
      int unused;
 {
 pa_entry (unused)
      int unused;
 {
+#ifdef OBJ_SOM
+  /* We must have a valid space and subspace.  */
+  pa_check_current_space_and_subspace ();
+#endif
+
   if (!within_procedure)
   if (!within_procedure)
-    as_bad ("Misplaced .entry. Ignored.");
+    as_bad (_("Misplaced .entry. Ignored."));
   else
     {
       if (!callinfo_found)
   else
     {
       if (!callinfo_found)
-       as_bad ("Missing .callinfo.");
+       as_bad (_("Missing .callinfo."));
     }
   demand_empty_rest_of_line ();
   within_entry_exit = TRUE;
     }
   demand_empty_rest_of_line ();
   within_entry_exit = TRUE;
@@ -4333,9 +5441,9 @@ pa_equ (reg)
   else
     {
       if (reg)
   else
     {
       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 ();
@@ -4382,16 +5490,21 @@ static void
 pa_exit (unused)
      int unused;
 {
 pa_exit (unused)
      int unused;
 {
+#ifdef OBJ_SOM
+  /* We must have a valid space and subspace.  */
+  pa_check_current_space_and_subspace ();
+#endif
+
   if (!within_procedure)
   if (!within_procedure)
-    as_bad (".EXIT must appear within a procedure");
+    as_bad (_(".EXIT must appear within a procedure"));
   else
     {
       if (!callinfo_found)
   else
     {
       if (!callinfo_found)
-       as_bad ("Missing .callinfo");
+       as_bad (_("Missing .callinfo"));
       else
        {
          if (!within_entry_exit)
       else
        {
          if (!within_entry_exit)
-           as_bad ("No .ENTRY for this .EXIT");
+           as_bad (_("No .ENTRY for this .EXIT"));
          else
            {
              within_entry_exit = FALSE;
          else
            {
              within_entry_exit = FALSE;
@@ -4418,7 +5531,7 @@ pa_export (unused)
   /* Make sure the given symbol exists.  */
   if ((symbol = symbol_find_or_make (name)) == NULL)
     {
   /* Make sure the given symbol exists.  */
   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 = c;
       input_line_pointer++;
       p = input_line_pointer;
       *p = c;
       input_line_pointer++;
@@ -4449,13 +5562,13 @@ pa_type_args (symbolP, is_export)
   char *name, c, *p;
   unsigned int temp, arg_reloc;
   pa_symbol_type type = SYMBOL_TYPE_UNKNOWN;
   char *name, c, *p;
   unsigned int temp, arg_reloc;
   pa_symbol_type type = SYMBOL_TYPE_UNKNOWN;
-  obj_symbol_type *symbol = (obj_symbol_type *) symbolP->bsym;
+  obj_symbol_type *symbol = (obj_symbol_type *) symbol_get_bfdsym (symbolP);
 
   if (strncasecmp (input_line_pointer, "absolute", 8) == 0)
 
     {
       input_line_pointer += 8;
 
   if (strncasecmp (input_line_pointer, "absolute", 8) == 0)
 
     {
       input_line_pointer += 8;
-      symbolP->bsym->flags &= ~BSF_FUNCTION;
+      symbol_get_bfdsym (symbolP)->flags &= ~BSF_FUNCTION;
       S_SET_SEGMENT (symbolP, bfd_abs_section_ptr);
       type = SYMBOL_TYPE_ABSOLUTE;
     }
       S_SET_SEGMENT (symbolP, bfd_abs_section_ptr);
       type = SYMBOL_TYPE_ABSOLUTE;
     }
@@ -4468,54 +5581,55 @@ pa_type_args (symbolP, is_export)
          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
          silently fix them to be ENTRY types.  */
          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
          silently fix them to be ENTRY types.  */
-      if (symbolP->bsym->flags & BSF_FUNCTION)
+      if (S_IS_FUNCTION (symbolP))
        {
          if (is_export)
        {
          if (is_export)
-           as_tsktsk ("Using ENTRY rather than CODE in export directive for %s", symbolP->bsym->name);
+           as_tsktsk (_("Using ENTRY rather than CODE in export directive for %s"),
+                      S_GET_NAME (symbolP));
 
 
-         symbolP->bsym->flags |= BSF_FUNCTION;
+         symbol_get_bfdsym (symbolP)->flags |= BSF_FUNCTION;
          type = SYMBOL_TYPE_ENTRY;
        }
       else
        {
          type = SYMBOL_TYPE_ENTRY;
        }
       else
        {
-         symbolP->bsym->flags &= ~BSF_FUNCTION;
+         symbol_get_bfdsym (symbolP)->flags &= ~BSF_FUNCTION;
          type = SYMBOL_TYPE_CODE;
        }
     }
   else if (strncasecmp (input_line_pointer, "data", 4) == 0)
     {
       input_line_pointer += 4;
          type = SYMBOL_TYPE_CODE;
        }
     }
   else if (strncasecmp (input_line_pointer, "data", 4) == 0)
     {
       input_line_pointer += 4;
-      symbolP->bsym->flags &= ~BSF_FUNCTION;
+      symbol_get_bfdsym (symbolP)->flags &= ~BSF_FUNCTION;
       type = SYMBOL_TYPE_DATA;
     }
   else if ((strncasecmp (input_line_pointer, "entry", 5) == 0))
     {
       input_line_pointer += 5;
       type = SYMBOL_TYPE_DATA;
     }
   else if ((strncasecmp (input_line_pointer, "entry", 5) == 0))
     {
       input_line_pointer += 5;
-      symbolP->bsym->flags |= BSF_FUNCTION;
+      symbol_get_bfdsym (symbolP)->flags |= BSF_FUNCTION;
       type = SYMBOL_TYPE_ENTRY;
     }
   else if (strncasecmp (input_line_pointer, "millicode", 9) == 0)
     {
       input_line_pointer += 9;
       type = SYMBOL_TYPE_ENTRY;
     }
   else if (strncasecmp (input_line_pointer, "millicode", 9) == 0)
     {
       input_line_pointer += 9;
-      symbolP->bsym->flags |= BSF_FUNCTION;
+      symbol_get_bfdsym (symbolP)->flags |= BSF_FUNCTION;
       type = SYMBOL_TYPE_MILLICODE;
     }
   else if (strncasecmp (input_line_pointer, "plabel", 6) == 0)
     {
       input_line_pointer += 6;
       type = SYMBOL_TYPE_MILLICODE;
     }
   else if (strncasecmp (input_line_pointer, "plabel", 6) == 0)
     {
       input_line_pointer += 6;
-      symbolP->bsym->flags &= ~BSF_FUNCTION;
+      symbol_get_bfdsym (symbolP)->flags &= ~BSF_FUNCTION;
       type = SYMBOL_TYPE_PLABEL;
     }
   else if (strncasecmp (input_line_pointer, "pri_prog", 8) == 0)
     {
       input_line_pointer += 8;
       type = SYMBOL_TYPE_PLABEL;
     }
   else if (strncasecmp (input_line_pointer, "pri_prog", 8) == 0)
     {
       input_line_pointer += 8;
-      symbolP->bsym->flags |= BSF_FUNCTION;
+      symbol_get_bfdsym (symbolP)->flags |= BSF_FUNCTION;
       type = SYMBOL_TYPE_PRI_PROG;
     }
   else if (strncasecmp (input_line_pointer, "sec_prog", 8) == 0)
     {
       input_line_pointer += 8;
       type = SYMBOL_TYPE_PRI_PROG;
     }
   else if (strncasecmp (input_line_pointer, "sec_prog", 8) == 0)
     {
       input_line_pointer += 8;
-      symbolP->bsym->flags |= BSF_FUNCTION;
+      symbol_get_bfdsym (symbolP)->flags |= BSF_FUNCTION;
       type = SYMBOL_TYPE_SEC_PROG;
     }
 
       type = SYMBOL_TYPE_SEC_PROG;
     }
 
@@ -4523,7 +5637,7 @@ pa_type_args (symbolP, is_export)
      than BFD understands.  This is how we get this information
      to the SOM BFD backend.  */
 #ifdef obj_set_symbol_type
      than BFD understands.  This is how we get this information
      to the SOM BFD backend.  */
 #ifdef obj_set_symbol_type
-  obj_set_symbol_type (symbolP->bsym, (int) type);
+  obj_set_symbol_type (symbol_get_bfdsym (symbolP), (int) type);
 #endif
 
   /* Now that the type of the exported symbol has been handled,
 #endif
 
   /* Now that the type of the exported symbol has been handled,
@@ -4544,7 +5658,9 @@ pa_type_args (symbolP, is_export)
          name = input_line_pointer;
          c = get_symbol_end ();
          arg_reloc = pa_align_arg_reloc (temp, pa_build_arg_reloc (name));
          name = input_line_pointer;
          c = get_symbol_end ();
          arg_reloc = pa_align_arg_reloc (temp, pa_build_arg_reloc (name));
-         symbol->tc_data.hppa_arg_reloc |= arg_reloc;
+#ifdef OBJ_SOM
+         symbol->tc_data.ap.hppa_arg_reloc |= arg_reloc;
+#endif
          *input_line_pointer = c;
        }
       /* The return value.  */
          *input_line_pointer = c;
        }
       /* The return value.  */
@@ -4556,7 +5672,9 @@ pa_type_args (symbolP, is_export)
          name = input_line_pointer;
          c = get_symbol_end ();
          arg_reloc = pa_build_arg_reloc (name);
          name = input_line_pointer;
          c = get_symbol_end ();
          arg_reloc = pa_build_arg_reloc (name);
-         symbol->tc_data.hppa_arg_reloc |= arg_reloc;
+#ifdef OBJ_SOM
+         symbol->tc_data.ap.hppa_arg_reloc |= arg_reloc;
+#endif
          *input_line_pointer = c;
        }
       /* Privelege level.  */
          *input_line_pointer = c;
        }
       /* Privelege level.  */
@@ -4566,12 +5684,15 @@ pa_type_args (symbolP, is_export)
          *p = c;
          input_line_pointer++;
          temp = atoi (input_line_pointer);
          *p = c;
          input_line_pointer++;
          temp = atoi (input_line_pointer);
+#ifdef OBJ_SOM
+         symbol->tc_data.ap.hppa_priv_level = temp;
+#endif
          c = get_symbol_end ();
          *input_line_pointer = c;
        }
       else
        {
          c = get_symbol_end ();
          *input_line_pointer = c;
        }
       else
        {
-         as_bad ("Undefined .EXPORT/.IMPORT argument (ignored): %s", name);
+         as_bad (_("Undefined .EXPORT/.IMPORT argument (ignored): %s"), name);
          p = input_line_pointer;
          *p = c;
        }
          p = input_line_pointer;
          *p = c;
        }
@@ -4616,7 +5737,7 @@ pa_import (unused)
             the the current segment.  Note only BSF_FUNCTION really
             matters, we do not need to set the full SYMBOL_TYPE_* info.  */
          if (now_seg == text_section)
             the the current segment.  Note only BSF_FUNCTION really
             matters, we do not need to set the full SYMBOL_TYPE_* info.  */
          if (now_seg == text_section)
-           symbol->bsym->flags |= BSF_FUNCTION;
+           symbol_get_bfdsym (symbol)->flags |= BSF_FUNCTION;
 
          /* If the section is undefined, then the symbol is undefined
             Since this is an import, leave the section undefined.  */
 
          /* If the section is undefined, then the symbol is undefined
             Since this is an import, leave the section undefined.  */
@@ -4653,12 +5774,12 @@ pa_label (unused)
     }
   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 ();
     }
   demand_empty_rest_of_line ();
       ignore_rest_of_line ();
     }
   demand_empty_rest_of_line ();
@@ -4670,7 +5791,54 @@ static void
 pa_leave (unused)
      int unused;
 {
 pa_leave (unused)
      int unused;
 {
-  abort ();
+#ifdef OBJ_SOM
+  /* We must have a valid space and subspace.  */
+  pa_check_current_space_and_subspace ();
+#endif
+
+  as_bad (_("The .LEAVE pseudo-op is not supported"));
+  demand_empty_rest_of_line ();
+}
+
+/* Handle a .LEVEL pseudo-op.  */
+
+static void
+pa_level (unused)
+     int unused;
+{
+  char *level;
+
+  level = input_line_pointer;
+  if (strncmp (level, "1.0", 3) == 0)
+    {
+      input_line_pointer += 3;
+      if (!bfd_set_arch_mach (stdoutput, bfd_arch_hppa, 10))
+       as_warn (_("could not set architecture and machine"));
+    }
+  else if (strncmp (level, "1.1", 3) == 0)
+    {
+      input_line_pointer += 3;
+      if (!bfd_set_arch_mach (stdoutput, bfd_arch_hppa, 11))
+       as_warn (_("could not set architecture and machine"));
+    }
+  else if (strncmp (level, "2.0w", 4) == 0)
+    {
+      input_line_pointer += 4;
+      if (!bfd_set_arch_mach (stdoutput, bfd_arch_hppa, 25))
+       as_warn (_("could not set architecture and machine"));
+    }
+  else if (strncmp (level, "2.0", 3) == 0)
+    {
+      input_line_pointer += 3;
+      if (!bfd_set_arch_mach (stdoutput, bfd_arch_hppa, 20))
+       as_warn (_("could not set architecture and machine"));
+    }
+  else
+    {
+      as_bad (_("Unrecognized .LEVEL argument\n"));
+      ignore_rest_of_line ();
+    }
+  demand_empty_rest_of_line ();
 }
 
 /* Handle a .ORIGIN pseudo-op.  */
 }
 
 /* Handle a .ORIGIN pseudo-op.  */
@@ -4679,6 +5847,11 @@ static void
 pa_origin (unused)
      int unused;
 {
 pa_origin (unused)
      int unused;
 {
+#ifdef OBJ_SOM
+  /* We must have a valid space and subspace.  */
+  pa_check_current_space_and_subspace ();
+#endif
+
   s_org (0);
   pa_undefine_label ();
 }
   s_org (0);
   pa_undefine_label ();
 }
@@ -4698,7 +5871,7 @@ pa_param (unused)
 
   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 = c;
       input_line_pointer++;
       p = input_line_pointer;
       *p = c;
       input_line_pointer++;
@@ -4726,8 +5899,14 @@ pa_proc (unused)
      int unused;
 {
   struct call_info *call_info;
      int unused;
 {
   struct call_info *call_info;
+
+#ifdef OBJ_SOM
+  /* We must have a valid space and subspace.  */
+  pa_check_current_space_and_subspace ();
+#endif
+
   if (within_procedure)
   if (within_procedure)
-    as_fatal ("Nested procedures");
+    as_fatal (_("Nested procedures"));
 
   /* Reset global variables for new procedure.  */
   callinfo_found = FALSE;
 
   /* Reset global variables for new procedure.  */
   callinfo_found = FALSE;
@@ -4737,9 +5916,9 @@ pa_proc (unused)
   call_info = (struct call_info *) xmalloc (sizeof (struct call_info));
 
   if (!call_info)
   call_info = (struct call_info *) xmalloc (sizeof (struct call_info));
 
   if (!call_info)
-    as_fatal ("Cannot allocate unwind descriptor\n");
+    as_fatal (_("Cannot allocate unwind descriptor\n"));
 
 
-  bzero (call_info, sizeof (struct call_info));
+  memset (call_info, 0, sizeof (struct call_info));
 
   call_info->ci_next = NULL;
 
 
   call_info->ci_next = NULL;
 
@@ -4770,10 +5949,10 @@ pa_proc (unused)
        if (label_symbol->lss_label)
          {
            last_call_info->start_symbol = label_symbol->lss_label;
        if (label_symbol->lss_label)
          {
            last_call_info->start_symbol = label_symbol->lss_label;
-           label_symbol->lss_label->bsym->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
       last_call_info->start_symbol = NULL;
       }
     else
       last_call_info->start_symbol = NULL;
@@ -4790,6 +5969,11 @@ pa_procend (unused)
      int unused;
 {
 
      int unused;
 {
 
+#ifdef OBJ_SOM
+  /* We must have a valid space and subspace.  */
+  pa_check_current_space_and_subspace ();
+#endif
+
   /* If we are within a procedure definition, make sure we've
      defined a label for the procedure; handle case where the
      label was defined after the .PROC directive.
   /* If we are within a procedure definition, make sure we've
      defined a label for the procedure; handle case where the
      label was defined after the .PROC directive.
@@ -4806,7 +5990,8 @@ pa_procend (unused)
          if (label_symbol->lss_label)
            {
              last_call_info->start_symbol = label_symbol->lss_label;
          if (label_symbol->lss_label)
            {
              last_call_info->start_symbol = label_symbol->lss_label;
-             label_symbol->lss_label->bsym->flags |= BSF_FUNCTION;
+             symbol_get_bfdsym (label_symbol->lss_label)->flags
+               |= BSF_FUNCTION;
 #ifdef OBJ_SOM
              /* Also handle allocation of a fixup to hold the unwind
                 information when the label appears after the proc/procend.  */
 #ifdef OBJ_SOM
              /* Also handle allocation of a fixup to hold the unwind
                 information when the label appears after the proc/procend.  */
@@ -4822,20 +6007,20 @@ pa_procend (unused)
 #endif
            }
          else
 #endif
            }
          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
   /* ELF needs to mark the end of each function so that it can compute
 
 #ifdef OBJ_ELF
   /* ELF needs to mark the end of each function so that it can compute
@@ -4848,6 +6033,38 @@ pa_procend (unused)
   pa_undefine_label ();
 }
 
   pa_undefine_label ();
 }
 
+/* If VALUE is an exact power of two between zero and 2^31, then
+   return log2 (VALUE).  Else return -1.  */
+
+static int
+log2 (value)
+     int value;
+{
+  int shift = 0;
+
+  while ((1 << shift) != value && shift < 32)
+    shift++;
+
+  if (shift >= 32)
+    return -1;
+  else
+    return shift;
+}
+
+
+#ifdef OBJ_SOM
+/* Check to make sure we have a valid space and subspace.  */
+
+static void
+pa_check_current_space_and_subspace ()
+{
+  if (current_space == NULL)
+    as_fatal (_("Not in a space.\n"));
+
+  if (current_subspace == NULL)
+    as_fatal (_("Not in a subspace.\n"));
+}
+
 /* Parse the parameters to a .SPACE directive; if CREATE_FLAG is nonzero,
    then create a new space entry to hold the information specified
    by the parameters to the .SPACE directive.  */
 /* Parse the parameters to a .SPACE directive; if CREATE_FLAG is nonzero,
    then create a new space entry to hold the information specified
    by the parameters to the .SPACE directive.  */
@@ -4935,7 +6152,7 @@ pa_parse_space_stmt (space_name, create_flag)
                }
              else
                {
                }
              else
                {
-                 as_bad ("Invalid .SPACE argument");
+                 as_bad (_("Invalid .SPACE argument"));
                  *input_line_pointer = c;
                  if (!is_end_of_statement ())
                    input_line_pointer++;
                  *input_line_pointer = c;
                  if (!is_end_of_statement ())
                    input_line_pointer++;
@@ -4983,7 +6200,7 @@ pa_space (unused)
 
   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 ();
     }
   else
       ignore_rest_of_line ();
     }
   else
@@ -5110,30 +6327,12 @@ pa_spnum (unused)
       md_number_to_chars (p, SPACE_SPNUM (space), 4);
     }
   else
       md_number_to_chars (p, SPACE_SPNUM (space), 4);
     }
   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;
   demand_empty_rest_of_line ();
 }
 
 
   *input_line_pointer = c;
   demand_empty_rest_of_line ();
 }
 
-/* If VALUE is an exact power of two between zero and 2^31, then
-   return log2 (VALUE).  Else return -1.  */
-
-static int
-log2 (value)
-     int value;
-{
-  int shift = 0;
-
-  while ((1 << shift) != value && shift < 32)
-    shift++;
-
-  if (shift >= 32)
-    return -1;
-  else
-    return shift;
-}
-
 /* Handle a .SUBSPACE pseudo-op; this switches the current subspace to the
    given subspace, creating the new subspace if necessary.
 
 /* Handle a .SUBSPACE pseudo-op; this switches the current subspace to the
    given subspace, creating the new subspace if necessary.
 
@@ -5141,19 +6340,22 @@ log2 (value)
    they're broken up into subroutines.  */
 
 static void
    they're broken up into subroutines.  */
 
 static void
-pa_subspace (unused)
-     int unused;
+pa_subspace (create_new)
+     int create_new;
 {
 {
-  char *name, *ss_name, *alias, c;
+  char *name, *ss_name, c;
   char loadable, code_only, common, dup_common, zero, sort;
   int i, access, space_index, alignment, quadrant, applicable, flags;
   sd_chain_struct *space;
   ssd_chain_struct *ssd;
   asection *section;
 
   char loadable, code_only, common, dup_common, zero, sort;
   int i, access, space_index, alignment, quadrant, applicable, flags;
   sd_chain_struct *space;
   ssd_chain_struct *ssd;
   asection *section;
 
+  if (current_space == NULL)
+    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 ();
     }
   else
       ignore_rest_of_line ();
     }
   else
@@ -5175,10 +6377,12 @@ pa_subspace (unused)
       space_index = ~0;
       alignment = 1;
       quadrant = 0;
       space_index = ~0;
       alignment = 1;
       quadrant = 0;
-      alias = NULL;
 
       space = current_space;
 
       space = current_space;
-      ssd = is_defined_subspace (ss_name);
+      if (create_new)
+       ssd = NULL;
+      else
+       ssd = is_defined_subspace (ss_name);
       /* Allow user to override the builtin attributes of subspaces.  But
          only allow the attributes to be changed once!  */
       if (ssd && SUBSPACE_DEFINED (ssd))
       /* Allow user to override the builtin attributes of subspaces.  But
          only allow the attributes to be changed once!  */
       if (ssd && SUBSPACE_DEFINED (ssd))
@@ -5186,7 +6390,7 @@ pa_subspace (unused)
          subseg_set (ssd->ssd_seg, ssd->ssd_subseg);
          current_subspace = ssd;
          if (!is_end_of_statement ())
          subseg_set (ssd->ssd_seg, ssd->ssd_subseg);
          current_subspace = ssd;
          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 ();
          return;
        }
          demand_empty_rest_of_line ();
          return;
        }
@@ -5209,8 +6413,6 @@ pa_subspace (unused)
                  quadrant = pa_def_subspaces[i].quadrant;
                  access = pa_def_subspaces[i].access;
                  sort = pa_def_subspaces[i].sort;
                  quadrant = pa_def_subspaces[i].quadrant;
                  access = pa_def_subspaces[i].access;
                  sort = pa_def_subspaces[i].sort;
-                 if (USE_ALIASES && pa_def_subspaces[i].alias)
-                   alias = pa_def_subspaces[i].alias;
                  break;
                }
              i++;
                  break;
                }
              i++;
@@ -5239,7 +6441,7 @@ pa_subspace (unused)
                  alignment = get_absolute_expression ();
                  if (log2 (alignment) == -1)
                    {
                  alignment = get_absolute_expression ();
                  if (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;
                    }
                }
@@ -5281,9 +6483,9 @@ pa_subspace (unused)
                  zero = 1;
                }
              else if ((strncasecmp (name, "first", 5) == 0))
                  zero = 1;
                }
              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 ())
                input_line_pointer++;
            }
              if (!is_end_of_statement ())
                input_line_pointer++;
            }
@@ -5300,11 +6502,12 @@ pa_subspace (unused)
       if (common || dup_common)
        flags |= SEC_IS_COMMON;
 
       if (common || dup_common)
        flags |= SEC_IS_COMMON;
 
+      flags |= SEC_RELOC | SEC_HAS_CONTENTS;
+
       /* This is a zero-filled subspace (eg BSS).  */
       if (zero)
       /* This is a zero-filled subspace (eg BSS).  */
       if (zero)
-       flags &= ~SEC_LOAD;
+       flags &= ~(SEC_LOAD | SEC_HAS_CONTENTS);
 
 
-      flags |= SEC_RELOC | SEC_HAS_CONTENTS;
       applicable &= flags;
 
       /* If this is an existing subspace, then we want to use the
       applicable &= flags;
 
       /* If this is an existing subspace, then we want to use the
@@ -5314,19 +6517,16 @@ pa_subspace (unused)
          lots of sections.  It might be a problem in the PA ELF
          code, I do not know yet.  For now avoid creating anything
          but the "standard" sections for ELF.  */
          lots of sections.  It might be a problem in the PA ELF
          code, I do not know yet.  For now avoid creating anything
          but the "standard" sections for ELF.  */
-      if (ssd)
+      if (create_new)
+       section = subseg_force_new (ss_name, 0);
+      else if (ssd)
        section = ssd->ssd_seg;
        section = ssd->ssd_seg;
-      else if (alias)
-       section = subseg_new (alias, 0);
-      else if (!alias && USE_ALIASES)
-       {
-         as_warn ("Ignoring subspace decl due to ELF BFD bugs.");
-         demand_empty_rest_of_line ();
-         return;
-       }
       else
        section = subseg_new (ss_name, 0);
 
       else
        section = subseg_new (ss_name, 0);
 
+      if (zero)
+       seg_info (section)->bss = 1;
+
       /* Now set the flags.  */
       bfd_set_section_flags (stdoutput, section, applicable);
 
       /* Now set the flags.  */
       bfd_set_section_flags (stdoutput, section, applicable);
 
@@ -5377,10 +6577,7 @@ pa_spaces_begin ()
       char *name;
 
       /* Pick the right name to use for the new section.  */
       char *name;
 
       /* Pick the right name to use for the new section.  */
-      if (pa_def_spaces[i].alias && USE_ALIASES)
-       name = pa_def_spaces[i].alias;
-      else
-       name = pa_def_spaces[i].name;
+      name = pa_def_spaces[i].name;
 
       pa_def_spaces[i].segment = subseg_new (name, 0);
       create_new_space (pa_def_spaces[i].name, pa_def_spaces[i].spnum,
 
       pa_def_spaces[i].segment = subseg_new (name, 0);
       create_new_space (pa_def_spaces[i].name, pa_def_spaces[i].spnum,
@@ -5400,16 +6597,8 @@ pa_spaces_begin ()
 
       /* Pick the right name for the new section and pick the right
          subsegment number.  */
 
       /* Pick the right name for the new section and pick the right
          subsegment number.  */
-      if (pa_def_subspaces[i].alias && USE_ALIASES)
-       {
-         name = pa_def_subspaces[i].alias;
-         subsegment = pa_def_subspaces[i].subsegment;
-       }
-      else
-       {
-         name = pa_def_subspaces[i].name;
-         subsegment = 0;
-       }
+      name = pa_def_subspaces[i].name;
+      subsegment = 0;
 
       /* Create the new section.  */
       segment = subseg_new (name, subsegment);
 
       /* Create the new section.  */
       segment = subseg_new (name, subsegment);
@@ -5418,7 +6607,7 @@ pa_spaces_begin ()
       /* For SOM we want to replace the standard .text, .data, and .bss
          sections with our own.   We also want to set BFD flags for
         all the built-in subspaces.  */
       /* For SOM we want to replace the standard .text, .data, and .bss
          sections with our own.   We also want to set BFD flags for
         all the built-in subspaces.  */
-      if (!strcmp (pa_def_subspaces[i].name, "$CODE$") && !USE_ALIASES)
+      if (!strcmp (pa_def_subspaces[i].name, "$CODE$"))
        {
          text_section = segment;
          applicable = bfd_applicable_section_flags (stdoutput);
        {
          text_section = segment;
          applicable = bfd_applicable_section_flags (stdoutput);
@@ -5428,7 +6617,7 @@ pa_spaces_begin ()
                                               | SEC_READONLY
                                               | SEC_HAS_CONTENTS));
        }
                                               | SEC_READONLY
                                               | SEC_HAS_CONTENTS));
        }
-      else if (!strcmp (pa_def_subspaces[i].name, "$DATA$") && !USE_ALIASES)
+      else if (!strcmp (pa_def_subspaces[i].name, "$DATA$"))
        {
          data_section = segment;
          applicable = bfd_applicable_section_flags (stdoutput);
        {
          data_section = segment;
          applicable = bfd_applicable_section_flags (stdoutput);
@@ -5439,14 +6628,23 @@ pa_spaces_begin ()
 
 
        }
 
 
        }
-      else if (!strcmp (pa_def_subspaces[i].name, "$BSS$") && !USE_ALIASES)
+      else if (!strcmp (pa_def_subspaces[i].name, "$BSS$"))
        {
          bss_section = segment;
          applicable = bfd_applicable_section_flags (stdoutput);
          bfd_set_section_flags (stdoutput, segment,
                                 applicable & SEC_ALLOC);
        }
        {
          bss_section = segment;
          applicable = bfd_applicable_section_flags (stdoutput);
          bfd_set_section_flags (stdoutput, segment,
                                 applicable & SEC_ALLOC);
        }
-      else if (!strcmp (pa_def_subspaces[i].name, "$LIT$") && !USE_ALIASES)
+      else if (!strcmp (pa_def_subspaces[i].name, "$LIT$"))
+       {
+         applicable = bfd_applicable_section_flags (stdoutput);
+         bfd_set_section_flags (stdoutput, segment,
+                                applicable & (SEC_ALLOC | SEC_LOAD
+                                              | SEC_RELOC
+                                              | SEC_READONLY
+                                              | SEC_HAS_CONTENTS));
+       }
+      else if (!strcmp (pa_def_subspaces[i].name, "$MILLICODE$"))
        {
          applicable = bfd_applicable_section_flags (stdoutput);
          bfd_set_section_flags (stdoutput, segment,
        {
          applicable = bfd_applicable_section_flags (stdoutput);
          bfd_set_section_flags (stdoutput, segment,
@@ -5455,7 +6653,7 @@ pa_spaces_begin ()
                                               | SEC_READONLY
                                               | SEC_HAS_CONTENTS));
        }
                                               | SEC_READONLY
                                               | SEC_HAS_CONTENTS));
        }
-      else if (!strcmp (pa_def_subspaces[i].name, "$UNWIND$") && !USE_ALIASES)
+      else if (!strcmp (pa_def_subspaces[i].name, "$UNWIND$"))
        {
          applicable = bfd_applicable_section_flags (stdoutput);
          bfd_set_section_flags (stdoutput, segment,
        {
          applicable = bfd_applicable_section_flags (stdoutput);
          bfd_set_section_flags (stdoutput, segment,
@@ -5470,7 +6668,7 @@ pa_spaces_begin ()
                                                 def_space_index].segment);
       if (space == NULL)
        {
                                                 def_space_index].segment);
       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);
        }
 
@@ -5511,7 +6709,7 @@ create_new_space (name, spnum, loadable, defined, private,
 
   chain_entry = (sd_chain_struct *) xmalloc (sizeof (sd_chain_struct));
   if (!chain_entry)
 
   chain_entry = (sd_chain_struct *) xmalloc (sizeof (sd_chain_struct));
   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);
 
   SPACE_NAME (chain_entry) = (char *) xmalloc (strlen (name) + 1);
              name);
 
   SPACE_NAME (chain_entry) = (char *) xmalloc (strlen (name) + 1);
@@ -5597,7 +6795,7 @@ create_new_subspace (space, name, loadable, code_only, common,
 
   chain_entry = (ssd_chain_struct *) xmalloc (sizeof (ssd_chain_struct));
   if (!chain_entry)
 
   chain_entry = (ssd_chain_struct *) xmalloc (sizeof (ssd_chain_struct));
   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) = (char *) xmalloc (strlen (name) + 1);
   strcpy (SUBSPACE_NAME (chain_entry), name);
 
   SUBSPACE_NAME (chain_entry) = (char *) xmalloc (strlen (name) + 1);
   strcpy (SUBSPACE_NAME (chain_entry), name);
@@ -5606,7 +6804,7 @@ create_new_subspace (space, name, loadable, code_only, common,
      we'll set it to 1 which "locks-in" the subspace attributes.  */
   SUBSPACE_DEFINED (chain_entry) = 0;
 
      we'll set it to 1 which "locks-in" the subspace attributes.  */
   SUBSPACE_DEFINED (chain_entry) = 0;
 
-  chain_entry->ssd_subseg = USE_ALIASES ? pa_next_subseg (space) : 0;
+  chain_entry->ssd_subseg = 0;
   chain_entry->ssd_seg = seg;
   chain_entry->ssd_next = NULL;
 
   chain_entry->ssd_seg = seg;
   chain_entry->ssd_next = NULL;
 
@@ -5809,7 +7007,7 @@ pa_find_space_by_number (number)
        space_chain;
        space_chain = space_chain->sd_next)
     {
        space_chain;
        space_chain = space_chain->sd_next)
     {
-      if (SPACE_SPNUM (space_chain) == number)
+      if (SPACE_SPNUM (space_chain) == (unsigned int) number)
        return space_chain;
     }
 
        return space_chain;
     }
 
@@ -5833,6 +7031,7 @@ pa_subspace_start (space, quadrant)
     return 0x40000000;
   else
     return 0;
     return 0x40000000;
   else
     return 0;
+  return 0;
 }
 
 /* FIXME.  Needs documentation.  */
 }
 
 /* FIXME.  Needs documentation.  */
@@ -5844,6 +7043,7 @@ pa_next_subseg (space)
   space->sd_last_subseg++;
   return space->sd_last_subseg;
 }
   space->sd_last_subseg++;
   return space->sd_last_subseg;
 }
+#endif
 
 /* Helper function for pa_stringer.  Used to find the end of
    a string.  */
 
 /* Helper function for pa_stringer.  Used to find the end of
    a string.  */
@@ -5853,6 +7053,12 @@ pa_stringer_aux (s)
      char *s;
 {
   unsigned int c = *s & CHAR_MASK;
      char *s;
 {
   unsigned int c = *s & CHAR_MASK;
+
+#ifdef OBJ_SOM
+  /* We must have a valid space and subspace.  */
+  pa_check_current_space_and_subspace ();
+#endif
+
   switch (c)
     {
     case '\"':
   switch (c)
     {
     case '\"':
@@ -5951,6 +7157,20 @@ pa_version (unused)
   pa_undefine_label ();
 }
 
   pa_undefine_label ();
 }
 
+#ifdef OBJ_SOM
+
+/* Handle a .COMPILER pseudo-op.  */
+
+static void
+pa_compiler (unused)
+     int unused;
+{
+  obj_som_compiler (0);
+  pa_undefine_label ();
+}
+
+#endif
+
 /* Handle a .COPYRIGHT pseudo-op.  */
 
 static void
 /* Handle a .COPYRIGHT pseudo-op.  */
 
 static void
@@ -5978,9 +7198,11 @@ static void
 pa_data (unused)
      int unused;
 {
 pa_data (unused)
      int unused;
 {
+#ifdef OBJ_SOM
   current_space = is_defined_space ("$PRIVATE$");
   current_subspace
     = pa_subsegment_to_subspace (current_space->sd_seg, 0);
   current_space = is_defined_space ("$PRIVATE$");
   current_subspace
     = pa_subsegment_to_subspace (current_space->sd_seg, 0);
+#endif
   s_data (0);
   pa_undefine_label ();
 }
   s_data (0);
   pa_undefine_label ();
 }
@@ -6001,6 +7223,11 @@ static void
 pa_fill (unused)
      int unused;
 {
 pa_fill (unused)
      int unused;
 {
+#ifdef OBJ_SOM
+  /* We must have a valid space and subspace.  */
+  pa_check_current_space_and_subspace ();
+#endif
+
   s_fill (0);
   pa_undefine_label ();
 }
   s_fill (0);
   pa_undefine_label ();
 }
@@ -6011,6 +7238,11 @@ static void
 pa_lcomm (needs_align)
      int needs_align;
 {
 pa_lcomm (needs_align)
      int needs_align;
 {
+#ifdef OBJ_SOM
+  /* We must have a valid space and subspace.  */
+  pa_check_current_space_and_subspace ();
+#endif
+
   s_lcomm (needs_align);
   pa_undefine_label ();
 }
   s_lcomm (needs_align);
   pa_undefine_label ();
 }
@@ -6021,6 +7253,11 @@ static void
 pa_lsym (unused)
      int unused;
 {
 pa_lsym (unused)
      int unused;
 {
+#ifdef OBJ_SOM
+  /* We must have a valid space and subspace.  */
+  pa_check_current_space_and_subspace ();
+#endif
+
   s_lsym (0);
   pa_undefine_label ();
 }
   s_lsym (0);
   pa_undefine_label ();
 }
@@ -6031,9 +7268,11 @@ static void
 pa_text (unused)
      int unused;
 {
 pa_text (unused)
      int unused;
 {
+#ifdef OBJ_SOM
   current_space = is_defined_space ("$TEXT$");
   current_subspace
     = pa_subsegment_to_subspace (current_space->sd_seg, 0);
   current_space = is_defined_space ("$TEXT$");
   current_subspace
     = pa_subsegment_to_subspace (current_space->sd_seg, 0);
+#endif
 
   s_text (0);
   pa_undefine_label ();
 
   s_text (0);
   pa_undefine_label ();
@@ -6058,13 +7297,11 @@ pa_text (unused)
    selectors).
 
    Reject reductions involving symbols with external scope; such
    selectors).
 
    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. 
 
 
-   FIXME.  Also reject R_HPPA relocations which are 32 bits
-   wide.  Helps with code lables in arrays for SOM.  (SOM BFD code
-   needs to generate relocations to push the addend and symbol value
-   onto the stack, add them, then pop the value off the stack and
-   use it in a relocation -- yuk.  */
+   FIXME.  Also reject R_HPPA relocations which are 32bits wide in
+   the code space.  The SOM BFD backend doesn't know how to pull the
+   right bits out of an instruction.  */
 
 int
 hppa_fix_adjustable (fixp)
 
 int
 hppa_fix_adjustable (fixp)
@@ -6074,22 +7311,53 @@ hppa_fix_adjustable (fixp)
 
   hppa_fix = (struct hppa_fix_struct *) fixp->tc_fix_data;
 
 
   hppa_fix = (struct hppa_fix_struct *) fixp->tc_fix_data;
 
-  /* Reject reductions of symbols in 32bit plabel relocs.  */
+#ifdef OBJ_SOM
+  /* Reject reductions of symbols in 32bit relocs.  */
   if (fixp->fx_r_type == R_HPPA && hppa_fix->fx_r_format == 32)
     return 0;
 
   if (fixp->fx_r_type == R_HPPA && hppa_fix->fx_r_format == 32)
     return 0;
 
-  /* Reject reductions of symbols in DLT relative relocs.  */
+  /* Reject reductions of symbols in sym1-sym2 expressions when
+     the fixup will occur in a CODE subspace. 
+
+     XXX FIXME: Long term we probably want to reject all of these;
+     for example reducing in the debug section would lose if we ever
+     supported using the optimizing hp linker.  */
+  if (fixp->fx_addsy
+      && fixp->fx_subsy
+      && (hppa_fix->segment->flags & SEC_CODE))
+    {
+      /* Apparently sy_used_in_reloc never gets set for sub symbols.  */
+      symbol_mark_used_in_reloc (fixp->fx_subsy);
+      return 0;
+    }
+
+  /* We can't adjust any relocs that use LR% and RR% field selectors.
+     That confuses the HP linker.  */
+  if (hppa_fix->fx_r_field == e_lrsel
+      || hppa_fix->fx_r_field == e_rrsel
+      || hppa_fix->fx_r_field == e_nlrsel)
+    return 0;
+#endif
+
+  /* Reject reductions of symbols in DLT relative relocs,
+     relocations with plabels.  */
   if (hppa_fix->fx_r_field == e_tsel
       || hppa_fix->fx_r_field == e_ltsel
   if (hppa_fix->fx_r_field == e_tsel
       || 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_rpsel
+      || hppa_fix->fx_r_field == e_lpsel)
+    return 0;
+
+  if (fixp->fx_addsy && S_IS_EXTERNAL (fixp->fx_addsy))
     return 0;
 
     return 0;
 
-  if (fixp->fx_addsy && fixp->fx_addsy->bsym->flags & BSF_GLOBAL)
+  /* Reject absolute calls (jumps).  */
+  if (hppa_fix->fx_r_type == R_HPPA_ABS_CALL)
     return 0;
 
   /* Reject reductions of function symbols.  */
     return 0;
 
   /* Reject reductions of function symbols.  */
-  if (fixp->fx_addsy == 0
-      || (fixp->fx_addsy->bsym->flags & BSF_FUNCTION) == 0)
+  if (fixp->fx_addsy == 0 || ! S_IS_FUNCTION (fixp->fx_addsy))
     return 1;
 
   return 0;
     return 1;
 
   return 0;
@@ -6104,26 +7372,43 @@ hppa_force_relocation (fixp)
      fixS *fixp;
 {
   struct hppa_fix_struct *hppa_fixp;
      fixS *fixp;
 {
   struct hppa_fix_struct *hppa_fixp;
+  int distance;
 
   hppa_fixp = (struct hppa_fix_struct *) fixp->tc_fix_data;
 #ifdef OBJ_SOM
 
   hppa_fixp = (struct hppa_fix_struct *) fixp->tc_fix_data;
 #ifdef OBJ_SOM
-  if (fixp->fx_r_type == R_HPPA_ENTRY || fixp->fx_r_type == R_HPPA_EXIT)
+  if (fixp->fx_r_type == R_HPPA_ENTRY || fixp->fx_r_type == R_HPPA_EXIT
+      || fixp->fx_r_type == R_HPPA_BEGIN_BRTAB
+      || fixp->fx_r_type == R_HPPA_END_BRTAB
+      || fixp->fx_r_type == R_HPPA_BEGIN_TRY
+      || fixp->fx_r_type == R_HPPA_END_TRY
+      || (fixp->fx_addsy != NULL && fixp->fx_subsy != NULL
+         && (hppa_fixp->segment->flags & SEC_CODE) != 0))
     return 1;
 #endif
 
     return 1;
 #endif
 
-#define stub_needed(CALLER, CALLEE) \
+#define arg_reloc_stub_needed(CALLER, CALLEE) \
   ((CALLEE) && (CALLER) && ((CALLEE) != (CALLER)))
 
   ((CALLEE) && (CALLER) && ((CALLEE) != (CALLER)))
 
+#ifdef OBJ_SOM
   /* It is necessary to force PC-relative calls/jumps to have a relocation
      entry if they're going to need either a argument relocation or long
      call stub.  FIXME.  Can't we need the same for absolute calls?  */
   if (fixp->fx_pcrel && fixp->fx_addsy
   /* It is necessary to force PC-relative calls/jumps to have a relocation
      entry if they're going to need either a argument relocation or long
      call stub.  FIXME.  Can't we need the same for absolute calls?  */
   if (fixp->fx_pcrel && fixp->fx_addsy
-      && (stub_needed (((obj_symbol_type *)
-                       fixp->fx_addsy->bsym)->tc_data.hppa_arg_reloc,
-                      hppa_fixp->fx_arg_reloc)))
-       return 1;
+      && (arg_reloc_stub_needed ((long) ((obj_symbol_type *)
+       symbol_get_bfdsym (fixp->fx_addsy))->tc_data.ap.hppa_arg_reloc,
+       hppa_fixp->fx_arg_reloc)))
+    return 1;
+#endif
+  distance = (fixp->fx_offset + S_GET_VALUE (fixp->fx_addsy)
+             - md_pcrel_from (fixp));
+  /* Now check and see if we're going to need a long-branch stub.  */
+  if (fixp->fx_r_type == R_HPPA_PCREL_CALL
+      && (distance > 262143 || distance < -262144))
+    return 1;
 
 
-#undef stub_needed
+  if (fixp->fx_r_type == R_HPPA_ABS_CALL)
+    return 1;
+#undef arg_reloc_stub_needed
 
   /* No need (yet) to force another relocations to be emitted.  */
   return 0;
 
   /* No need (yet) to force another relocations to be emitted.  */
   return 0;
@@ -6166,24 +7451,22 @@ hppa_elf_mark_end_of_function ()
        {
          /* symbol value should be the offset of the
             last instruction of the function */
        {
          /* symbol value should be the offset of the
             last instruction of the function */
-         symbolP = symbol_new (name, now_seg,
-                               (valueT) (obstack_next_free (&frags)
-                                         - frag_now->fr_literal - 4),
+         symbolP = symbol_new (name, now_seg, (valueT) (frag_now_fix () - 4),
                                frag_now);
 
          assert (symbolP);
                                frag_now);
 
          assert (symbolP);
-         symbolP->bsym->flags = BSF_LOCAL;
+         S_CLEAR_EXTERNAL (symbolP);
          symbol_table_insert (symbolP);
        }
 
       if (symbolP)
        last_call_info->end_symbol = symbolP;
       else
          symbol_table_insert (symbolP);
        }
 
       if (symbolP)
        last_call_info->end_symbol = symbolP;
       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."));
 
 }
 
 
 }
 
@@ -6202,7 +7485,8 @@ elf_hppa_final_processing ()
        call_info_pointer = call_info_pointer->ci_next)
     {
       elf_symbol_type *esym
        call_info_pointer = call_info_pointer->ci_next)
     {
       elf_symbol_type *esym
-      = (elf_symbol_type *) call_info_pointer->start_symbol->bsym;
+       = ((elf_symbol_type *)
+          symbol_get_bfdsym (call_info_pointer->start_symbol));
       esym->internal_elf_sym.st_size =
        S_GET_VALUE (call_info_pointer->end_symbol)
        - S_GET_VALUE (call_info_pointer->start_symbol) + 4;
       esym->internal_elf_sym.st_size =
        S_GET_VALUE (call_info_pointer->end_symbol)
        - S_GET_VALUE (call_info_pointer->start_symbol) + 4;
This page took 0.086414 seconds and 4 git commands to generate.