* config/tc-m68k.c: Add some ATTRIBUTE_UNUSED.
[deliverable/binutils-gdb.git] / gas / config / tc-hppa.c
index e588ca89abced5facc978cd96262348a6d2d9e60..f7f1fa9f88b2c7208d3e2558a5c32136d472924b 100644 (file)
@@ -1,11 +1,12 @@
 /* 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
-   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,
@@ -14,8 +15,9 @@
    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
 #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"
 
+#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
-/* 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 ".hppa_unwind"
-/* Nonzero if CODE is a fixup code needing further processing.  */
-
 /* 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;
 
+#ifdef BFD64
 /* 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
 
-/* Who knows.  */
+/* ELF objects can have versions, but apparently do not have anywhere
+   to store a copyright string.  */
 #define obj_version obj_elf_version
-
-/* Use space aliases.  */
-#define USE_ALIASES 1
-
-/* Some local functions only used by ELF.  */
-static void pa_build_symextn_section PARAMS ((void));
-static void hppa_tc_make_symextn_section PARAMS ((void));
+#define obj_copyright obj_elf_version
 #endif
 
 #ifdef OBJ_SOM
@@ -73,17 +71,28 @@ static void hppa_tc_make_symextn_section PARAMS ((void));
 /* Object file formats specify relocation types.  */
 typedef int reloc_type;
 
-/* Who knows.  */
+/* SOM objects can have both a version string and a copyright string.  */
 #define obj_version obj_som_version
-
-/* Do not use space aliases.  */
-#define USE_ALIASES 0
+#define obj_copyright obj_som_copyright
 
 /* How to generate a relocation.  */
 #define hppa_gen_reloc_type hppa_som_gen_reloc_type
 
 /* Object file formats specify BFD symbol types.  */
 typedef som_symbol_type obj_symbol_type;
+
+/* This apparently isn't in older versions of hpux reloc.h.  */
+#ifndef R_DLT_REL
+#define R_DLT_REL 0x78
+#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.  */
@@ -135,12 +144,6 @@ struct unwind_table
 
 struct call_info
   {
-    /* Should sr3 be saved in the prologue?  */
-    int entry_sr;
-
-    /* Does this function make calls?  */
-    int makes_calls;
-
     /* The unwind descriptor being built.  */
     struct unwind_table ci_unwind;
 
@@ -150,23 +153,6 @@ struct call_info
     /* (temporary) symbol used to mark the end of this function.  */
     symbolS *end_symbol;
 
-    /* frags associated with start and end of this function.  */
-    fragS *start_frag;
-    fragS *end_frag;
-
-    /* frags for starting/ending offset of this descriptor.  */
-    fragS *start_offset_frag;
-    fragS *end_offset_frag;
-
-    /* The location within {start,end}_offset_frag to find the 
-       {start,end}_offset.  */
-    int start_frag_where;
-    int end_frag_where;
-
-    /* Fixups (relocations) for start_offset and end_offset.  */
-    fixS *start_fix;
-    fixS *end_fix;
-
     /* Next entry in the chain.  */
     struct call_info *ci_next;
   };
@@ -176,7 +162,7 @@ struct call_info
    SGL and DBL).  */
 typedef enum
   {
-    SGL, DBL, ILLEGAL_FMT, QUAD
+    SGL, DBL, ILLEGAL_FMT, QUAD, W, UW, DW, UDW, QW, UQW
   }
 fp_operand_format;
 
@@ -197,7 +183,7 @@ typedef enum
   }
 pa_symbol_type;
 
-/* This structure contains information needed to assemble 
+/* This structure contains information needed to assemble
    individual instructions.  */
 struct pa_it
   {
@@ -214,6 +200,7 @@ struct pa_it
     fp_operand_format fpof1;
     fp_operand_format fpof2;
 
+
     /* Holds the field selector for this instruction
        (for example L%, LR%, etc).  */
     long field_selector;
@@ -255,9 +242,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
-   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;
@@ -276,55 +263,15 @@ struct call_desc
     unsigned int arg_count;
   };
 
+#ifdef OBJ_SOM
 /* This structure defines an entry in the subspace dictionary
    chain.  */
 
 struct subspace_dictionary_chain
   {
-    /* Index of containing space.  */
-    unsigned long ssd_space_index;
-
     /* Nonzero if this space has been defined by the user code.  */
     unsigned int ssd_defined;
 
-    /* Which quadrant within the space this subspace should be loaded into.  */
-    unsigned char ssd_quadrant;
-
-    /* Alignment (in bytes) for this subspace.  */
-    unsigned long ssd_alignment;
-
-    /* Access control bits to determine read/write/execute permissions
-       as well as gateway privilege promotions.  */
-    unsigned char ssd_access_control_bits;
-
-    /* A sorting key so that it is possible to specify ordering of
-       subspaces within a space.  */
-    unsigned char ssd_sort_key;
-
-    /* Nonzero of this space should be zero filled.  */
-    unsigned long ssd_zero;
-
-    /* Nonzero if this is a common subspace.  */
-    unsigned char ssd_common;
-
-    /* Nonzero if this is a common subspace which allows symbols to be 
-       multiply defined.  */
-    unsigned char ssd_dup_common;
-
-    /* Nonzero if this subspace is loadable.  Note loadable subspaces
-       must be contained within loadable spaces; unloadable subspaces
-       must be contained in unloadable spaces.  */
-    unsigned char ssd_loadable;
-
-    /* Nonzero if this subspace contains only code.  */
-    unsigned char ssd_code_only;
-
-    /* Starting offset of this subspace.  */
-    unsigned long ssd_subspace_start;
-
-    /* Length of this subspace.  */
-    unsigned long ssd_subspace_length;
-
     /* Name of this subspace.  */
     char *ssd_name;
 
@@ -332,13 +279,6 @@ struct subspace_dictionary_chain
     asection *ssd_seg;
     int ssd_subseg;
 
-    /* Index of this subspace within the subspace dictionary of the object
-       file.  Not used until object file is written.  */
-    int object_file_index;
-
-    /* The size of the last alignment request for this subspace.  */
-    int ssd_last_align;
-
     /* Next space in the subspace dictionary chain.  */
     struct subspace_dictionary_chain *ssd_next;
   };
@@ -350,31 +290,16 @@ typedef struct subspace_dictionary_chain ssd_chain_struct;
 
 struct space_dictionary_chain
   {
-
-    /* Holds the index into the string table of the name of this 
-       space.  */
-    unsigned int sd_name_index;
-
-    /* Nonzero if the space is loadable.  */
-    unsigned int sd_loadable;
-
-    /* Nonzero if this space has been defined by the user code or 
+    /* Nonzero if this space has been defined by the user code or
        as a default space.  */
     unsigned int sd_defined;
 
     /* Nonzero if this spaces has been defined by the user code.  */
     unsigned int sd_user_defined;
 
-    /* Nonzero if this space is not sharable.  */
-    unsigned int sd_private;
-
     /* The space number (or index).  */
     unsigned int sd_spnum;
 
-    /* The sort key for this space.  May be used to determine how to lay
-       out the spaces within the object file.  */
-    unsigned char sd_sort_key;
-
     /* The name of this subspace.  */
     char *sd_name;
 
@@ -393,17 +318,6 @@ struct space_dictionary_chain
 
 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.  */
 
@@ -450,9 +364,6 @@ struct default_subspace_dict
     /* 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;
   };
@@ -483,16 +394,30 @@ struct default_space_dict
 
     /* 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.  */
-    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;
@@ -503,8 +428,8 @@ struct hppa_fix_struct
     /* Argument relocation bits.  */
     long fx_arg_reloc;
 
-    /* The unwind descriptor associated with this fixup.  */
-    char fx_unwind[8];
+    /* The segment this fixup appears in.  */
+    segT segment;
   };
 
 /* Structure to hold information about predefined registers.  */
@@ -533,10 +458,13 @@ struct selector_entry
 
 /* 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 void pa_desc PARAMS ((int));
 static void pa_float_cons PARAMS ((int));
 static void pa_fill PARAMS ((int));
 static void pa_lcomm PARAMS ((int));
@@ -556,6 +484,8 @@ 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_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));
@@ -572,29 +502,33 @@ 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_level 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 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 sd_chain_struct *create_new_space PARAMS ((char *, int, char,
-                                                 char, char, char,
+#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 ssd_chain_struct *create_new_subspace PARAMS ((sd_chain_struct *,
-                                                     char *, char, char,
-                                                     char, char, char,
-                                                     char, int, int, int,
+                                                     char *, int, int,
+                                                     int, int, int,
+                                                     int, int, int, int,
                                                      int, asection *));
 static ssd_chain_struct *update_subspace PARAMS ((sd_chain_struct *,
-                                                 char *, char, char, char,
-                                                 char, char, char, int,
+                                                 char *, int, int, int,
+                                                 int, int, int, int,
                                                  int, int, int,
                                                  asection *));
 static sd_chain_struct *is_defined_space PARAMS ((char *));
@@ -604,28 +538,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));
+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, short int, symbolS *,
+static void fix_new_hppa PARAMS ((fragS *, int, int, symbolS *,
                                  long, expressionS *, int,
                                  bfd_reloc_code_real_type,
-                                 enum hppa_reloc_field_selector_type,
-                                 int, long, char *));
-static void md_apply_fix_1 PARAMS ((fixS *, long));
+                                 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 *));
-static void pa_build_unwind_subspace PARAMS ((struct call_info *));
 static void process_exit PARAMS ((void));
-static sd_chain_struct *pa_parse_space_stmt PARAMS ((char *, int));
 static int log2 PARAMS ((int));
-static int pa_next_subseg PARAMS ((sd_chain_struct *));
 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 pa_build_unwind_subspace PARAMS ((struct call_info *));
+#endif
 
 /* 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;
@@ -633,6 +571,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;
+#endif
 
 /* Root of the call_info chain.  */
 static struct call_info *call_info_root;
@@ -645,14 +584,6 @@ static struct call_info *last_call_info;
 /* 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;
 
@@ -667,98 +598,71 @@ const pseudo_typeS md_pseudo_table[] =
 {
   /* 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},
+#endif
+#ifdef OBJ_ELF
   {"align", s_align_bytes, 8},
-  {"ALIGN", s_align_bytes, 8},
+#endif
+  {"begin_brtab", pa_brtab, 1},
+  {"begin_try", pa_try, 1},
   {"block", pa_block, 1},
-  {"BLOCK", pa_block, 1},
   {"blockz", pa_block, 0},
-  {"BLOCKZ", pa_block, 0},
   {"byte", pa_cons, 1},
-  {"BYTE", pa_cons, 1},
   {"call", pa_call, 0},
-  {"CALL", pa_call, 0},
   {"callinfo", pa_callinfo, 0},
-  {"CALLINFO", pa_callinfo, 0},
   {"code", pa_code, 0},
-  {"CODE", pa_code, 0},
   {"comm", pa_comm, 0},
-  {"COMM", pa_comm, 0},
+#ifdef OBJ_SOM
+  {"compiler", pa_compiler, 0},
+#endif
   {"copyright", pa_copyright, 0},
-  {"COPYRIGHT", pa_copyright, 0},
   {"data", pa_data, 0},
-  {"DATA", pa_data, 0},
-  {"desc", pa_desc, 0},
-  {"DESC", pa_desc, 0},
   {"double", pa_float_cons, 'd'},
-  {"DOUBLE", pa_float_cons, 'd'},
   {"end", pa_end, 0},
-  {"END", pa_end, 0},
+  {"end_brtab", pa_brtab, 0},
+  {"end_try", pa_try, 0},
   {"enter", pa_enter, 0},
-  {"ENTER", pa_enter, 0},
   {"entry", pa_entry, 0},
-  {"ENTRY", pa_entry, 0},
   {"equ", pa_equ, 0},
-  {"EQU", pa_equ, 0},
   {"exit", pa_exit, 0},
-  {"EXIT", pa_exit, 0},
   {"export", pa_export, 0},
-  {"EXPORT", pa_export, 0},
   {"fill", pa_fill, 0},
-  {"FILL", pa_fill, 0},
   {"float", pa_float_cons, 'f'},
-  {"FLOAT", pa_float_cons, 'f'},
   {"half", pa_cons, 2},
-  {"HALF", pa_cons, 2},
   {"import", pa_import, 0},
-  {"IMPORT", pa_import, 0},
   {"int", pa_cons, 4},
-  {"INT", pa_cons, 4},
   {"label", pa_label, 0},
-  {"LABEL", pa_label, 0},
   {"lcomm", pa_lcomm, 0},
-  {"LCOMM", pa_lcomm, 0},
   {"leave", pa_leave, 0},
-  {"LEAVE", pa_leave, 0},
+  {"level", pa_level, 0},
   {"long", pa_cons, 4},
-  {"LONG", pa_cons, 4},
   {"lsym", pa_lsym, 0},
-  {"LSYM", pa_lsym, 0},
+#ifdef OBJ_SOM
+  {"nsubspa", pa_subspace, 1},
+#endif
   {"octa", pa_cons, 16},
-  {"OCTA", pa_cons, 16},
   {"org", pa_origin, 0},
-  {"ORG", pa_origin, 0},
   {"origin", pa_origin, 0},
-  {"ORIGIN", pa_origin, 0},
   {"param", pa_param, 0},
-  {"PARAM", pa_param, 0},
   {"proc", pa_proc, 0},
-  {"PROC", pa_proc, 0},
   {"procend", pa_procend, 0},
-  {"PROCEND", pa_procend, 0},
   {"quad", pa_cons, 8},
-  {"QUAD", pa_cons, 8},
   {"reg", pa_equ, 1},
-  {"REG", pa_equ, 1},
   {"short", pa_cons, 2},
-  {"SHORT", pa_cons, 2},
   {"single", pa_float_cons, 'f'},
-  {"SINGLE", pa_float_cons, 'f'},
+#ifdef OBJ_SOM
   {"space", pa_space, 0},
-  {"SPACE", pa_space, 0},
   {"spnum", pa_spnum, 0},
-  {"SPNUM", pa_spnum, 0},
+#endif
   {"string", pa_stringer, 0},
-  {"STRING", pa_stringer, 0},
   {"stringz", pa_stringer, 1},
-  {"STRINGZ", pa_stringer, 1},
+#ifdef OBJ_SOM
   {"subspa", pa_subspace, 0},
-  {"SUBSPA", pa_subspace, 0},
+#endif
   {"text", pa_text, 0},
-  {"TEXT", pa_text, 0},
   {"version", pa_version, 0},
-  {"VERSION", pa_version, 0},
   {"word", pa_cons, 4},
-  {"WORD", pa_cons, 4},
   {NULL, 0, 0}
 };
 
@@ -770,7 +674,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.
 
-   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.  */
@@ -780,9 +684,9 @@ const char line_separator_chars[] = "!";
 const char EXP_CHARS[] = "eE";
 
 /* Chars that mean this number is a floating point constant.
-   As in 0f12.456 or 0d1.2345e12. 
+   As in 0f12.456 or 0d1.2345e12.
 
-   Be aware that MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT may have to be 
+   Be aware that MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT may have to be
    changed in read.c.  Ideally it shouldn't hae to know abou it at
    all, but nothing is ideal around here.  */
 const char FLT_CHARS[] = "rRsSfFdDxXpP";
@@ -810,16 +714,21 @@ static label_symbol_struct *label_symbols_rootp = NULL;
 /* Holds the last field selector.  */
 static int hppa_field_selector;
 
+#ifdef OBJ_SOM
+/* 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;
 
 /* List of registers that are pre-defined:
 
    Each general register has one predefined name of the form
-   %r<REGNUM> which has the value <REGNUM>.  
+   %r<REGNUM> which has the value <REGNUM>.
 
    Space and control registers are handled in a similar manner,
-   but use %sr<REGNUM> and %cr<REGNUM> as their predefined names. 
+   but use %sr<REGNUM> and %cr<REGNUM> as their predefined names.
 
    Likewise for the floating point registers, but of the form
    %fr<REGNUM>.  Floating point registers have additional predefined
@@ -835,7 +744,7 @@ static int print_errors = 1;
    %r2  has %rp as a synonym
 
    Almost every control register has a synonym; they are not listed
-   here for brevity.  
+   here for brevity.
 
    The table is sorted. Suitable for searching by a binary search. */
 
@@ -874,101 +783,101 @@ static const struct pd_reg pre_defined_registers[] =
   {"%eiem", 15},
   {"%eirr", 23},
   {"%fr0", 0},
-  {"%fr0L", 0},
-  {"%fr0R", 0},
+  {"%fr0l", 0},
+  {"%fr0r", 0},
   {"%fr1", 1},
   {"%fr10", 10},
-  {"%fr10L", 10},
-  {"%fr10R", 10},
+  {"%fr10l", 10},
+  {"%fr10r", 10},
   {"%fr11", 11},
-  {"%fr11L", 11},
-  {"%fr11R", 11},
+  {"%fr11l", 11},
+  {"%fr11r", 11},
   {"%fr12", 12},
-  {"%fr12L", 12},
-  {"%fr12R", 12},
+  {"%fr12l", 12},
+  {"%fr12r", 12},
   {"%fr13", 13},
-  {"%fr13L", 13},
-  {"%fr13R", 13},
+  {"%fr13l", 13},
+  {"%fr13r", 13},
   {"%fr14", 14},
-  {"%fr14L", 14},
-  {"%fr14R", 14},
+  {"%fr14l", 14},
+  {"%fr14r", 14},
   {"%fr15", 15},
-  {"%fr15L", 15},
-  {"%fr15R", 15},
+  {"%fr15l", 15},
+  {"%fr15r", 15},
   {"%fr16", 16},
-  {"%fr16L", 16},
-  {"%fr16R", 16},
+  {"%fr16l", 16},
+  {"%fr16r", 16},
   {"%fr17", 17},
-  {"%fr17L", 17},
-  {"%fr17R", 17},
+  {"%fr17l", 17},
+  {"%fr17r", 17},
   {"%fr18", 18},
-  {"%fr18L", 18},
-  {"%fr18R", 18},
+  {"%fr18l", 18},
+  {"%fr18r", 18},
   {"%fr19", 19},
-  {"%fr19L", 19},
-  {"%fr19R", 19},
-  {"%fr1L", 1},
-  {"%fr1R", 1},
+  {"%fr19l", 19},
+  {"%fr19r", 19},
+  {"%fr1l", 1},
+  {"%fr1r", 1},
   {"%fr2", 2},
   {"%fr20", 20},
-  {"%fr20L", 20},
-  {"%fr20R", 20},
+  {"%fr20l", 20},
+  {"%fr20r", 20},
   {"%fr21", 21},
-  {"%fr21L", 21},
-  {"%fr21R", 21},
+  {"%fr21l", 21},
+  {"%fr21r", 21},
   {"%fr22", 22},
-  {"%fr22L", 22},
-  {"%fr22R", 22},
+  {"%fr22l", 22},
+  {"%fr22r", 22},
   {"%fr23", 23},
-  {"%fr23L", 23},
-  {"%fr23R", 23},
+  {"%fr23l", 23},
+  {"%fr23r", 23},
   {"%fr24", 24},
-  {"%fr24L", 24},
-  {"%fr24R", 24},
+  {"%fr24l", 24},
+  {"%fr24r", 24},
   {"%fr25", 25},
-  {"%fr25L", 25},
-  {"%fr25R", 25},
+  {"%fr25l", 25},
+  {"%fr25r", 25},
   {"%fr26", 26},
-  {"%fr26L", 26},
-  {"%fr26R", 26},
+  {"%fr26l", 26},
+  {"%fr26r", 26},
   {"%fr27", 27},
-  {"%fr27L", 27},
-  {"%fr27R", 27},
+  {"%fr27l", 27},
+  {"%fr27r", 27},
   {"%fr28", 28},
-  {"%fr28L", 28},
-  {"%fr28R", 28},
+  {"%fr28l", 28},
+  {"%fr28r", 28},
   {"%fr29", 29},
-  {"%fr29L", 29},
-  {"%fr29R", 29},
-  {"%fr2L", 2},
-  {"%fr2R", 2},
+  {"%fr29l", 29},
+  {"%fr29r", 29},
+  {"%fr2l", 2},
+  {"%fr2r", 2},
   {"%fr3", 3},
   {"%fr30", 30},
-  {"%fr30L", 30},
-  {"%fr30R", 30},
+  {"%fr30l", 30},
+  {"%fr30r", 30},
   {"%fr31", 31},
-  {"%fr31L", 31},
-  {"%fr31R", 31},
-  {"%fr3L", 3},
-  {"%fr3R", 3},
+  {"%fr31l", 31},
+  {"%fr31r", 31},
+  {"%fr3l", 3},
+  {"%fr3r", 3},
   {"%fr4", 4},
-  {"%fr4L", 4},
-  {"%fr4R", 4},
+  {"%fr4l", 4},
+  {"%fr4r", 4},
   {"%fr5", 5},
-  {"%fr5L", 5},
-  {"%fr5R", 5},
+  {"%fr5l", 5},
+  {"%fr5r", 5},
   {"%fr6", 6},
-  {"%fr6L", 6},
-  {"%fr6R", 6},
+  {"%fr6l", 6},
+  {"%fr6r", 6},
   {"%fr7", 7},
-  {"%fr7L", 7},
-  {"%fr7R", 7},
+  {"%fr7l", 7},
+  {"%fr7r", 7},
   {"%fr8", 8},
-  {"%fr8L", 8},
-  {"%fr8R", 8},
+  {"%fr8l", 8},
+  {"%fr8r", 8},
   {"%fr9", 9},
-  {"%fr9L", 9},
-  {"%fr9R", 9},
+  {"%fr9l", 9},
+  {"%fr9r", 9},
   {"%hta", 25},
   {"%iir", 19},
   {"%ior", 21},
@@ -1010,23 +919,11 @@ static const struct pd_reg pre_defined_registers[] =
   {"%r30", 30},
   {"%r31", 31},
   {"%r4", 4},
-  {"%r4L", 4},
-  {"%r4R", 4},
   {"%r5", 5},
-  {"%r5L", 5},
-  {"%r5R", 5},
   {"%r6", 6},
-  {"%r6L", 6},
-  {"%r6R", 6},
   {"%r7", 7},
-  {"%r7L", 7},
-  {"%r7R", 7},
   {"%r8", 8},
-  {"%r8L", 8},
-  {"%r8R", 8},
   {"%r9", 9},
-  {"%r9L", 9},
-  {"%r9R", 9},
   {"%rctr", 0},
   {"%ret0", 28},
   {"%ret1", 29},
@@ -1052,7 +949,7 @@ static const struct pd_reg pre_defined_registers[] =
 };
 
 /* This table is sorted by order of the length of the string. This is
-   so we check for <> before we check for <. If we had a <> and checked 
+   so we check for <> before we check for <. If we had a <> and checked
    for < first, we would get a false match.  */
 static const struct fp_cond_map fp_cond_map[] =
 {
@@ -1092,39 +989,27 @@ static const struct fp_cond_map fp_cond_map[] =
 
 static const struct selector_entry selector_table[] =
 {
-  {"F'", e_fsel},
-  {"F%", e_fsel},
-  {"LS'", e_lssel},
-  {"LS%", e_lssel},
-  {"RS'", e_rssel},
-  {"RS%", e_rssel},
-  {"L'", e_lsel},
-  {"L%", e_lsel},
-  {"R'", e_rsel},
-  {"R%", e_rsel},
-  {"LD'", e_ldsel},
-  {"LD%", e_ldsel},
-  {"RD'", e_rdsel},
-  {"RD%", e_rdsel},
-  {"LR'", e_lrsel},
-  {"LR%", e_lrsel},
-  {"RR'", e_rrsel},
-  {"RR%", e_rrsel},
-  {"P'", e_psel},
-  {"P%", e_psel},
-  {"RP'", e_rpsel},
-  {"RP%", e_rpsel},
-  {"LP'", e_lpsel},
-  {"LP%", e_lpsel},
-  {"T'", e_tsel},
-  {"T%", e_tsel},
-  {"RT'", e_rtsel},
-  {"RT%", e_rtsel},
-  {"LT'", e_ltsel},
-  {"LT%", e_ltsel},
-  {NULL, e_fsel}
+  {"f", e_fsel},
+  {"l", e_lsel},
+  {"ld", e_ldsel},
+  {"lp", e_lpsel},
+  {"lr", e_lrsel},
+  {"ls", e_lssel},
+  {"lt", e_ltsel},
+  {"n", e_nsel},
+  {"nl", e_nlsel},
+  {"nlr", e_nlrsel},
+  {"p", e_psel},
+  {"r", e_rsel},
+  {"rd", e_rdsel},
+  {"rp", e_rpsel},
+  {"rr", e_rrsel},
+  {"rs", e_rssel},
+  {"rt", e_rtsel},
+  {"t", e_tsel},
 };
 
+#ifdef OBJ_SOM
 /* default space and subspace dictionaries */
 
 #define GDB_SYMBOLS          GDB_SYMBOLS_SUBSPACE_NAME
@@ -1132,8 +1017,9 @@ static const struct selector_entry selector_table[] =
 
 /* pre-defined subsegments (subspaces) for the HPPA.  */
 #define SUBSEG_CODE   0
-#define SUBSEG_DATA   0
 #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
@@ -1141,54 +1027,37 @@ static const struct selector_entry selector_table[] =
 
 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, ".hppa_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[] =
 {
-  {"$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.  */
 
-/* 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
-#define SPACE_PRIVATE(space_chain)     (space_chain)->sd_private
-#define SPACE_LOADABLE(space_chain)    (space_chain)->sd_loadable
 #define SPACE_SPNUM(space_chain)       (space_chain)->sd_spnum
-#define SPACE_SORT(space_chain)                (space_chain)->sd_sort_key
 #define SPACE_NAME(space_chain)                (space_chain)->sd_name
-#define SPACE_NAME_INDEX(space_chain)   (space_chain)->sd_name_index
 
-#define SUBSPACE_SPACE_INDEX(ss_chain)  (ss_chain)->ssd_space_index
 #define SUBSPACE_DEFINED(ss_chain)     (ss_chain)->ssd_defined
-#define SUBSPACE_QUADRANT(ss_chain)    (ss_chain)->ssd_quadrant
-#define SUBSPACE_ALIGN(ss_chain)       (ss_chain)->ssd_alignment
-#define SUBSPACE_ACCESS(ss_chain)      (ss_chain)->ssd_access_control_bits
-#define SUBSPACE_SORT(ss_chain)                (ss_chain)->ssd_sort_key
-#define SUBSPACE_COMMON(ss_chain)      (ss_chain)->ssd_common
-#define SUBSPACE_ZERO(ss_chain)                (ss_chain)->ssd_zero
-#define SUBSPACE_DUP_COMM(ss_chain)    (ss_chain)->ssd_dup_common
-#define SUBSPACE_CODE_ONLY(ss_chain)    (ss_chain)->ssd_code_only
-#define SUBSPACE_LOADABLE(ss_chain)    (ss_chain)->ssd_loadable
-#define SUBSPACE_SUBSPACE_START(ss_chain) (ss_chain)->ssd_subspace_start
-#define SUBSPACE_SUBSPACE_LENGTH(ss_chain) (ss_chain)->ssd_subspace_length
 #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.  */
@@ -1199,7 +1068,7 @@ static struct default_space_dict pa_def_spaces[] =
     continue; \
   }
 
-/* Simple range checking for FIELD againt HIGH and LOW bounds.  
+/* Simple range checking for FIELD againt HIGH and LOW bounds.
    IGNORE is used to suppress the error message.  */
 
 #define CHECK_FIELD(FIELD, HIGH, LOW, IGNORE) \
@@ -1207,7 +1076,7 @@ static struct default_space_dict pa_def_spaces[] =
     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; \
       } \
@@ -1215,17 +1084,33 @@ static struct default_space_dict pa_def_spaces[] =
 
 #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                    \
-   && 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
+   need real complex handling yet.  */
 #define is_complex(exp)                                \
   ((exp).X_op != O_constant && (exp).X_op != O_symbol)
 
 /* 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.  */
 
@@ -1233,13 +1118,20 @@ static label_symbol_struct *
 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)
-    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;
+#endif
+    }
 
   return NULL;
 }
@@ -1252,7 +1144,6 @@ pa_define_label (symbol)
      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;
@@ -1262,7 +1153,12 @@ pa_define_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)
@@ -1280,13 +1176,19 @@ pa_undefine_label ()
 {
   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)
     {
-      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)
@@ -1306,24 +1208,24 @@ pa_undefine_label ()
    code needs to keep track of some extra stuff.  Each call to fix_new_hppa
    results in the creation of an instance of an hppa_fix_struct.  An
    hppa_fix_struct stores the extra information along with a pointer to the
-   original fixS.  This is attached to the original fixup via the 
+   original fixS.  This is attached to the original fixup via the
    tc_fix_data field.  */
 
 static void
 fix_new_hppa (frag, where, size, add_symbol, offset, exp, pcrel,
-             r_type, r_field, r_format, arg_reloc, unwind_desc)
+             r_type, r_field, r_format, arg_reloc, unwind_bits)
      fragS *frag;
      int where;
-     short int size;
+     int size;
      symbolS *add_symbol;
      long offset;
      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;
-     char *unwind_desc;
+     int* unwind_bits;
 {
   fixS *new_fix;
 
@@ -1334,22 +1236,16 @@ fix_new_hppa (frag, where, size, add_symbol, offset, exp, pcrel,
     new_fix = fix_new_exp (frag, where, size, exp, pcrel, r_type);
   else
     new_fix = fix_new (frag, where, size, add_symbol, offset, pcrel, r_type);
-  new_fix->tc_fix_data = hppa_fix;
+  new_fix->tc_fix_data = (void *) hppa_fix;
   hppa_fix->fx_r_type = r_type;
   hppa_fix->fx_r_field = r_field;
   hppa_fix->fx_r_format = r_format;
   hppa_fix->fx_arg_reloc = arg_reloc;
-  if (unwind_desc)
-    {
-      bcopy (unwind_desc, hppa_fix->fx_unwind, 8);
-
-      /* If necessary call BFD backend function to attach the
-         unwind bits to the target dependent parts of a BFD symbol.
-         Yuk.  */
-#ifdef obj_attach_unwind_info
-      obj_attach_unwind_info (add_symbol->bsym, unwind_desc);
+  hppa_fix->segment = now_seg;
+#ifdef OBJ_SOM
+  if (r_type == R_ENTRY || r_type == R_EXIT)
+    new_fix->fx_offset = *unwind_bits;
 #endif
-    }
 
   /* foo-$global$ is used to access non-automatic storage.  $global$
      is really just a marker and has served its purpose, so eliminate
@@ -1380,21 +1276,22 @@ cons_fix_new_hppa (frag, where, size, exp)
      int size;
      expressionS *exp;
 {
-  unsigned int reloc_type;
+  unsigned int rel_type;
 
+  /* Get a base relocation type.  */
   if (is_DP_relative (*exp))
-    reloc_type = R_HPPA_GOTOFF;
+    rel_type = R_HPPA_GOTOFF;
   else if (is_complex (*exp))
-    reloc_type = R_HPPA_COMPLEX;
+    rel_type = R_HPPA_COMPLEX;
   else
-    reloc_type = R_HPPA;
+    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, reloc_type,
-               hppa_field_selector, 32, 0, (char *) 0);
+               (symbolS *) NULL, (offsetT) 0, exp, 0, rel_type,
+               hppa_field_selector, 32, 0, NULL);
 
   /* Reset field selector to its default state.  */
   hppa_field_selector = 0;
@@ -1413,20 +1310,23 @@ md_begin ()
   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 (flagseen['R'])
+  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;
-      flagseen['R'] = 0;
     }
 
+#ifdef OBJ_SOM
   pa_spaces_begin ();
+#endif
 
   op_hash = hash_new ();
-  if (op_hash == NULL)
-    as_fatal ("Virtual memory exhausted");
 
   while (i < NUMOPCODES)
     {
@@ -1434,7 +1334,7 @@ md_begin ()
       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
@@ -1442,7 +1342,7 @@ md_begin ()
          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;
            }
@@ -1452,20 +1352,20 @@ md_begin ()
     }
 
   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);
-}
-
-/* Called at the end of assembling a source file.  Nothing to do
-   at this point on the PA.  */
+#endif
 
-void
-md_end ()
-{
-  return;
+#ifdef OBJ_SOM
+  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.  */
@@ -1478,6 +1378,45 @@ md_assemble (str)
   /* The had better be something to assemble.  */
   assert (str);
 
+  /* 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.
+
+     Note there's not need to diddle with the segment or fragment
+     for the label symbol in this case.  We have already switched
+     into the new $CODE$ subspace at this point.  */
+  if (within_procedure && last_call_info->start_symbol == NULL)
+    {
+      label_symbol_struct *label_symbol = pa_get_label ();
+
+      if (label_symbol)
+       {
+         if (label_symbol->lss_label)
+           {
+             last_call_info->start_symbol = label_symbol->lss_label;
+             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.  */
+             if (within_entry_exit)
+               {
+                 char *where = frag_more (0);
+
+                 fix_new_hppa (frag_now, where - frag_now->fr_literal, 0,
+                               NULL, (offsetT) 0, NULL,
+                               0, R_HPPA_ENTRY, e_fsel, 0, 0,
+                               (int *)&last_call_info->ci_unwind.descriptor);
+               }
+#endif
+           }
+         else
+           as_bad (_("Missing function name for .PROC (corrupted label chain)"));
+       }
+      else
+       as_bad (_("Missing function name for .PROC"));
+    }
+
   /* Assemble the instruction.  Results are saved into "the_insn".  */
   pa_ip (str);
 
@@ -1493,14 +1432,10 @@ md_assemble (str)
                  (offsetT) 0, &the_insn.exp, the_insn.pcrel,
                  the_insn.reloc, the_insn.field_selector,
                  the_insn.format, the_insn.arg_reloc, NULL);
-
 }
 
 /* Do the real work for assembling a single instruction.  Store results
-   into the global "the_insn" variable.
-
-   FIXME:  Should define and use some functions/macros to handle
-   various common insertions of information into the opcode.  */
+   into the global "the_insn" variable.  */
 
 static void
 pa_ip (str)
@@ -1515,6 +1450,17 @@ pa_ip (str)
   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)
     ;
@@ -1535,20 +1481,11 @@ pa_ip (str)
       break;
 
     default:
-      as_bad ("Unknown opcode: `%s'", str);
-      exit (1);
+      as_fatal (_("Unknown opcode: `%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)
     {
@@ -1568,10 +1505,26 @@ pa_ip (str)
     {
       /* Do some initialization.  */
       opcode = insn->match;
-      bzero (&the_insn, sizeof (the_insn));
+      memset (&the_insn, 0, sizeof (the_insn));
 
       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)
@@ -1644,7 +1597,7 @@ pa_ip (str)
              num = pa_get_absolute_expression (&the_insn, &s);
              s = expr_end;
              CHECK_FIELD (num, 15, -16, 0)
-               low_sign_unext (num, 5, &num);
+             low_sign_unext (num, 5, &num);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
 
            /* Handle an unsigned 5 bit immediate at 31.  */
@@ -1695,12 +1648,12 @@ pa_ip (str)
                    else if (strncasecmp (s, "s", 1) == 0)
                      uu = 1;
                    else
-                     as_bad ("Invalid Indexed Load Completer.");
+                     as_bad (_("Invalid Indexed Load Completer."));
                    s++;
                    i++;
                  }
                if (i > 2)
-                 as_bad ("Invalid Indexed Load Completer Syntax.");
+                 as_bad (_("Invalid Indexed Load Completer Syntax."));
                opcode |= m << 5;
                INSERT_FIELD_AND_CONTINUE (opcode, uu, 13);
              }
@@ -1724,11 +1677,15 @@ pa_ip (str)
                        m = 1;
                      }
                    else
-                     as_bad ("Invalid Short Load/Store Completer.");
+                     as_bad (_("Invalid Short Load/Store Completer."));
                    s += 2;
                  }
-               opcode |= m << 5;
-               INSERT_FIELD_AND_CONTINUE (opcode, a, 13);
+
+               if (*args == 'C')
+                 {
+                   opcode |= m << 5;
+                   INSERT_FIELD_AND_CONTINUE (opcode, a, 13);
+                 }
              }
 
            /* Handle a stbys completer.  */
@@ -1747,12 +1704,12 @@ pa_ip (str)
                    else if (strncasecmp (s, "e", 1) == 0)
                      a = 1;
                    else
-                     as_bad ("Invalid Store Bytes Short Completer");
+                     as_bad (_("Invalid Store Bytes Short Completer"));
                    s++;
                    i++;
                  }
                if (i > 2)
-                 as_bad ("Invalid Store Bytes Short Completer");
+                 as_bad (_("Invalid Store Bytes Short Completer"));
                opcode |= m << 5;
                INSERT_FIELD_AND_CONTINUE (opcode, a, 13);
              }
@@ -1762,7 +1719,7 @@ pa_ip (str)
              cmpltr = pa_parse_nonneg_cmpsub_cmpltr (&s, 1);
              if (cmpltr < 0)
                {
-                 as_bad ("Invalid Compare/Subtract Condition: %c", *s);
+                 as_bad (_("Invalid Compare/Subtract Condition: %c"), *s);
                  cmpltr = 0;
                }
              INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 13);
@@ -1777,7 +1734,7 @@ pa_ip (str)
                  cmpltr = pa_parse_neg_cmpsub_cmpltr (&s, 1);
                  if (cmpltr < 0)
                    {
-                     as_bad ("Invalid Compare/Subtract Condition.");
+                     as_bad (_("Invalid Compare/Subtract Condition."));
                      cmpltr = 0;
                    }
                  else
@@ -1786,10 +1743,21 @@ pa_ip (str)
                      opcode |= 1 << 27;
                    }
                }
+       
              INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 13);
 
-           /* Handle a negated or non-negated add condition.  */
+           /* 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);
+
+           /* Handle a negated or non-negated add condition.  */
+           case '@':
              save_s = s;
              cmpltr = pa_parse_nonneg_add_cmpltr (&s, 1);
              if (cmpltr < 0)
@@ -1798,7 +1766,7 @@ pa_ip (str)
                  cmpltr = pa_parse_neg_add_cmpltr (&s, 1);
                  if (cmpltr < 0)
                    {
-                     as_bad ("Invalid Compare/Subtract Condition");
+                     as_bad (_("Invalid Compare/Subtract Condition"));
                      cmpltr = 0;
                    }
                  else
@@ -1813,29 +1781,6 @@ pa_ip (str)
            case 'a':
              cmpltr = 0;
              flag = 0;
-             save_s = s;
-             if (*s == ',')
-               {
-                 cmpltr = pa_parse_nonneg_cmpsub_cmpltr (&s, 0);
-                 if (cmpltr < 0)
-                   {
-                     flag = 1;
-                     s = save_s;
-                     cmpltr = pa_parse_neg_cmpsub_cmpltr (&s, 0);
-                     if (cmpltr < 0)
-                       {
-                         as_bad ("Invalid Compare/Subtract Condition");
-                       }
-                   }
-               }
-             opcode |= cmpltr << 13;
-             INSERT_FIELD_AND_CONTINUE (opcode, flag, 12);
-
-           /* Handle a non-negated add condition.  */
-           case 'd':
-             cmpltr = 0;
-             nullif = 0;
-             flag = 0;
              if (*s == ',')
                {
                  s++;
@@ -1850,42 +1795,40 @@ pa_ip (str)
                    cmpltr = 2;
                  else if (strcmp (name, "<=") == 0)
                    cmpltr = 3;
-                 else if (strcasecmp (name, "nuv") == 0)
+                 else if (strcasecmp (name, "<<") == 0)
                    cmpltr = 4;
-                 else if (strcasecmp (name, "znv") == 0)
+                 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, "n") == 0)
-                   nullif = 1;
                  else if (strcasecmp (name, "tr") == 0)
                    {
                      cmpltr = 0;
                      flag = 1;
                    }
-                 else if (strcasecmp (name, "<>") == 0)
+                 else if (strcmp (name, "<>") == 0)
                    {
                      cmpltr = 1;
                      flag = 1;
                    }
-                 else if (strcasecmp (name, ">=") == 0)
+                 else if (strcmp (name, ">=") == 0)
                    {
                      cmpltr = 2;
                      flag = 1;
                    }
-                 else if (strcasecmp (name, ">") == 0)
+                 else if (strcmp (name, ">") == 0)
                    {
                      cmpltr = 3;
                      flag = 1;
                    }
-                 else if (strcasecmp (name, "uv") == 0)
+                 else if (strcasecmp (name, ">>=") == 0)
                    {
                      cmpltr = 4;
                      flag = 1;
                    }
-                 else if (strcasecmp (name, "vnz") == 0)
+                 else if (strcasecmp (name, ">>") == 0)
                    {
                      cmpltr = 5;
                      flag = 1;
@@ -1901,16 +1844,14 @@ pa_ip (str)
                      flag = 1;
                    }
                  else
-                   as_bad ("Invalid Add Condition: %s", name);
+                   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);
 
-           /* HANDLE a logical instruction condition.  */
-           case '&':
+           /* Handle a non-negated add condition.  */
+           case 'd':
              cmpltr = 0;
              flag = 0;
              if (*s == ',')
@@ -1927,6 +1868,12 @@ pa_ip (str)
                    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)
@@ -1949,14 +1896,83 @@ pa_ip (str)
                      cmpltr = 3;
                      flag = 1;
                    }
-                 else if (strcasecmp (name, "ev") == 0)
+                 else if (strcasecmp (name, "uv") == 0)
                    {
-                     cmpltr = 7;
+                     cmpltr = 4;
                      flag = 1;
                    }
-                 else
-                   as_bad ("Invalid Logical Instruction Condition.");
-                 *s = c;
+                 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;
+                   }
+                 else
+                   as_bad (_("Invalid Add Condition: %s"), name);
+                 *s = c;
+               }
+             opcode |= cmpltr << 13;
+             INSERT_FIELD_AND_CONTINUE (opcode, flag, 12);
+
+           /* 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)
+                   {
+                     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;
+                   }
+                 else
+                   as_bad (_("Invalid Logical Instruction Condition."));
+                 *s = c;
                }
              opcode |= cmpltr << 13;
              INSERT_FIELD_AND_CONTINUE (opcode, flag, 12);
@@ -1968,6 +1984,8 @@ pa_ip (str)
              if (*s == ',')
                {
                  s++;
+
+
                  if (strncasecmp (s, "sbz", 3) == 0)
                    {
                      cmpltr = 2;
@@ -2030,7 +2048,7 @@ pa_ip (str)
                      s += 3;
                    }
                  else
-                   as_bad ("Invalid Logical Instruction Condition.");
+                   as_bad (_("Invalid Logical Instruction Condition."));
                }
              opcode |= cmpltr << 13;
              INSERT_FIELD_AND_CONTINUE (opcode, flag, 12);
@@ -2042,6 +2060,8 @@ pa_ip (str)
              if (*s == ',')
                {
                  save_s = s++;
+
+
                  name = s;
                  while (*s != ',' && *s != ' ' && *s != '\t')
                    s += 1;
@@ -2061,7 +2081,7 @@ pa_ip (str)
                    cmpltr = 6;
                  else if (strcasecmp (name, "ev") == 0)
                    cmpltr = 7;
-                 /* Handle movb,n.  Put things back the way they were.  
+                 /* Handle movb,n.  Put things back the way they were.
                     This includes moving s back to where it started.  */
                  else if (strcasecmp (name, "n") == 0 && *args == '|')
                    {
@@ -2070,7 +2090,7 @@ pa_ip (str)
                      continue;
                    }
                  else
-                   as_bad ("Invalid Shift/Extract/Deposit Condition.");
+                   as_bad (_("Invalid Shift/Extract/Deposit Condition."));
                  *s = c;
                }
              INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 13);
@@ -2083,18 +2103,18 @@ pa_ip (str)
                  s++;
                  if (strncmp (s, "<", 1) == 0)
                    {
-                     cmpltr = 2;
+                     cmpltr = 0;
                      s++;
                    }
                  else if (strncmp (s, ">=", 2) == 0)
                    {
-                     cmpltr = 6;
+                     cmpltr = 1;
                      s += 2;
                    }
                  else
-                   as_bad ("Invalid Bit Branch Condition: %c", *s);
+                   as_bad (_("Invalid Bit Branch Condition: %c"), *s);
                }
-             INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 13);
+             INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 15);
 
            /* Handle a system control completer.  */
            case 'Z':
@@ -2113,6 +2133,12 @@ pa_ip (str)
              nullif = pa_parse_nullif (&s);
              INSERT_FIELD_AND_CONTINUE (opcode, nullif, 1);
 
+           /* Handle a nullification completer for copr and spop insns.  */
+           case 'N':
+             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);
@@ -2131,14 +2157,13 @@ pa_ip (str)
                    the_insn.reloc = R_HPPA_GOTOFF;
                  else if (is_PC_relative (the_insn.exp))
                    the_insn.reloc = R_HPPA_PCREL_CALL;
-                 else if (is_complex (the_insn.exp))
-                   the_insn.reloc = R_HPPA_COMPLEX;
                  else
                    the_insn.reloc = R_HPPA;
                  the_insn.format = 11;
                  continue;
                }
 
+
            /* Handle a 14 bit immediate at 31.  */
            case 'j':
              the_insn.field_selector = pa_chk_field_selector (&s);
@@ -2157,8 +2182,6 @@ pa_ip (str)
                    the_insn.reloc = R_HPPA_GOTOFF;
                  else if (is_PC_relative (the_insn.exp))
                    the_insn.reloc = R_HPPA_PCREL_CALL;
-                 else if (is_complex (the_insn.exp))
-                   the_insn.reloc = R_HPPA_COMPLEX;
                  else
                    the_insn.reloc = R_HPPA;
                  the_insn.format = 14;
@@ -2183,8 +2206,6 @@ pa_ip (str)
                    the_insn.reloc = R_HPPA_GOTOFF;
                  else if (is_PC_relative (the_insn.exp))
                    the_insn.reloc = R_HPPA_PCREL_CALL;
-                 else if (is_complex (the_insn.exp))
-                   the_insn.reloc = R_HPPA_COMPLEX;
                  else
                    the_insn.reloc = R_HPPA;
                  the_insn.format = 21;
@@ -2204,23 +2225,20 @@ pa_ip (str)
                  num = evaluate_absolute (&the_insn);
                  if (num % 4)
                    {
-                     as_bad ("Branch to unaligned address");
+                     as_bad (_("Branch to unaligned address"));
                      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);
                }
              else
                {
-                 if (is_complex (the_insn.exp))
-                   the_insn.reloc = R_HPPA_COMPLEX_PCREL_CALL;
-                 else
-                   the_insn.reloc = R_HPPA_PCREL_CALL;
+                 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;
                }
@@ -2240,7 +2258,7 @@ pa_ip (str)
                  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);
@@ -2255,13 +2273,10 @@ pa_ip (str)
                }
              else
                {
-                 if (is_complex (the_insn.exp))
-                   the_insn.reloc = R_HPPA_COMPLEX_PCREL_CALL;
-                 else
-                   the_insn.reloc = R_HPPA_PCREL_CALL;
+                 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;
                }
 
@@ -2280,7 +2295,7 @@ pa_ip (str)
                  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);
@@ -2295,11 +2310,10 @@ pa_ip (str)
                }
              else
                {
-                 if (is_complex (the_insn.exp))
-                   the_insn.reloc = R_HPPA_COMPLEX_ABS_CALL;
-                 else
-                   the_insn.reloc = R_HPPA_ABS_CALL;
+                 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;
                }
 
@@ -2319,7 +2333,10 @@ pa_ip (str)
 
            /* Handle a 5 bit immediate at 10.  */
            case 'Q':
+
              num = pa_get_absolute_expression (&the_insn, &s);
+             if (the_insn.exp.X_op != O_constant)
+               break;
              s = expr_end;
              CHECK_FIELD (num, 31, 0, 0);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 21);
@@ -2328,7 +2345,7 @@ pa_ip (str)
            case 'A':
              num = pa_get_absolute_expression (&the_insn, &s);
              s = expr_end;
-             CHECK_FIELD (num, 4095, -4096, 0);
+             CHECK_FIELD (num, 8191, 0, 0);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 13);
 
            /* Handle a 26 bit immediate at 31.  */
@@ -2336,21 +2353,65 @@ pa_ip (str)
              num = pa_get_absolute_expression (&the_insn, &s);
              s = expr_end;
              CHECK_FIELD (num, 671108864, 0, 0);
-             INSERT_FIELD_AND_CONTINUE (opcode, num, 1);
+             INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
 
            /* Handle a 3 bit SFU identifier at 25.  */
            case 'f':
+             if (*s++ != ',')
+               as_bad (_("Invalid SFU identifier"));
              num = pa_get_absolute_expression (&the_insn, &s);
              s = expr_end;
              CHECK_FIELD (num, 7, 0, 0);
              INSERT_FIELD_AND_CONTINUE (opcode, num, 6);
 
-           /* We don't support any of these.  FIXME.  */
+           /* Handle a 20 bit SOP field for spop0.  */
            case 'O':
-             get_expression (s);
+             num = pa_get_absolute_expression (&the_insn, &s);
              s = expr_end;
-             abort ();
-             continue;
+             CHECK_FIELD (num, 1048575, 0, 0);
+             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);
+             s = expr_end;
+             CHECK_FIELD (num, 32767, 0, 0);
+             INSERT_FIELD_AND_CONTINUE (opcode, num, 11);
+
+           /* Handle a 10bit SOP field for spop3.  */
+           case '0':
+             num = pa_get_absolute_expression (&the_insn, &s);
+             s = expr_end;
+             CHECK_FIELD (num, 1023, 0, 0);
+             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);
+             s = expr_end;
+             CHECK_FIELD (num, 32767, 0, 0);
+             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"));
+             num = pa_get_absolute_expression (&the_insn, &s);
+             s = expr_end;
+             CHECK_FIELD (num, 7, 0, 0);
+             INSERT_FIELD_AND_CONTINUE (opcode, num, 6);
+
+           /* Handle a 22bit SOP field for copr.  */
+           case '2':
+             num = pa_get_absolute_expression (&the_insn, &s);
+             s = expr_end;
+             CHECK_FIELD (num, 4194303, 0, 0);
+             num = (num & 0x1f) | ((num & 0x003fffe0) << 4);
+             INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
+
 
            /* Handle a source FP operand format completer.  */
            case 'F':
@@ -2374,7 +2435,7 @@ pa_ip (str)
            /* Handle L/R register halves like 't'.  */
            case 'v':
              {
-               struct pa_89_fp_reg_struct result;
+               struct pa_11_fp_reg_struct result;
 
                pa_parse_number (&s, &result);
                CHECK_FIELD (result.number_part, 31, 0, 0);
@@ -2383,7 +2444,7 @@ pa_ip (str)
                /* 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)
+               if (need_pa11_opcode (&the_insn, &result)
                    && ((opcode & 0xfc000000) == 0x30000000))
                  opcode |= 1 << 27;
 
@@ -2393,12 +2454,12 @@ pa_ip (str)
            /* Handle L/R register halves like 'b'.  */
            case 'E':
              {
-               struct pa_89_fp_reg_struct result;
+               struct pa_11_fp_reg_struct result;
 
                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))
+               if (need_pa11_opcode (&the_insn, &result))
                  {
                    opcode |= (result.l_r_select & 1) << 7;
                    opcode |= 1 << 27;
@@ -2406,15 +2467,44 @@ pa_ip (str)
                continue;
              }
 
+           /* Handle L/R register halves like 'b'.  */
+           case '3':
+             {
+               struct pa_11_fp_reg_struct result;
+               int regnum;
+
+               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;
+             }
+
+           /* Handle L/R register halves like 'x'.  */
+           case 'e':
+             {
+               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_pa11_opcode (&the_insn, &result))
+                 {
+                   opcode |= (result.l_r_select & 1) << 1;
+                 }
+               continue;
+             }
+
            /* Handle L/R register halves like 'x'.  */
            case 'X':
              {
-               struct pa_89_fp_reg_struct result;
+               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))
+               if (need_pa11_opcode (&the_insn, &result))
                  {
                    opcode |= (result.l_r_select & 1) << 12;
                    opcode |= 1 << 27;
@@ -2425,12 +2515,18 @@ pa_ip (str)
            /* Handle a 5 bit register field at 10.  */
            case '4':
              {
-               struct pa_89_fp_reg_struct result;
-               
+               struct pa_11_fp_reg_struct result;
+
                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;
                  }
@@ -2440,12 +2536,17 @@ pa_ip (str)
            /* Handle a 5 bit register field at 15.  */
            case '6':
              {
-               struct pa_89_fp_reg_struct result;
+               struct pa_11_fp_reg_struct result;
 
                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;
                  }
@@ -2455,12 +2556,17 @@ pa_ip (str)
            /* Handle a 5 bit register field at 31.  */
            case '7':
              {
-               struct pa_89_fp_reg_struct result;
+               struct pa_11_fp_reg_struct result;
 
                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;
                  }
@@ -2470,12 +2576,17 @@ pa_ip (str)
            /* Handle a 5 bit register field at 20.  */
            case '8':
              {
-               struct pa_89_fp_reg_struct result;
+               struct pa_11_fp_reg_struct result;
 
                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;
                  }
@@ -2485,12 +2596,17 @@ pa_ip (str)
            /* Handle a 5 bit register field at 25.  */
            case '9':
              {
-               struct pa_89_fp_reg_struct result;
+               struct pa_11_fp_reg_struct result;
 
                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;
                  }
@@ -2512,7 +2628,7 @@ pa_ip (str)
                case QUAD:
                case ILLEGAL_FMT:
                default:
-                 as_bad ("Invalid Floating Point Operand Format.");
+                 as_bad (_("Invalid Floating Point Operand Format."));
                }
              break;
 
@@ -2522,10 +2638,11 @@ pa_ip (str)
          break;
        }
 
+ failed:
       /* 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;
@@ -2534,7 +2651,7 @@ pa_ip (str)
            }
          else
            {
-             as_bad ("Invalid operands %s", error_message);
+             as_bad (_("Invalid operands %s"), error_message);
              return;
            }
        }
@@ -2542,7 +2659,6 @@ pa_ip (str)
     }
 
   the_insn.opcode = opcode;
-  return;
 }
 
 /* Turn a string in input_line_pointer into a floating point constant of type
@@ -2591,7 +2707,7 @@ md_atof (type, litP, sizeP)
 
     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)
@@ -2613,21 +2729,7 @@ md_number_to_chars (buf, val, n)
      valueT val;
      int n;
 {
-
-  switch (n)
-    {
-    case 4:
-      *buf++ = val >> 24;
-      *buf++ = val >> 16;
-    case 2:
-      *buf++ = val >> 8;
-    case 1:
-      *buf = val;
-      break;
-    default:
-      abort ();
-    }
-  return;
+  number_to_chars_bigendian (buf, val, n);
 }
 
 /* Translate internal representation of relocation info to BFD target
@@ -2639,94 +2741,39 @@ tc_gen_reloc (section, fixp)
      fixS *fixp;
 {
   arelent *reloc;
-  struct hppa_fix_struct *hppa_fixp = fixp->tc_fix_data;
+  struct hppa_fix_struct *hppa_fixp;
   bfd_reloc_code_real_type code;
-  static int unwind_reloc_fixp_cnt = 0;
-  static arelent *unwind_reloc_entryP = NULL;
   static arelent *no_relocs = NULL;
   arelent **relocs;
   bfd_reloc_code_real_type **codes;
   int n_relocs;
   int i;
 
+  hppa_fixp = (struct hppa_fix_struct *) fixp->tc_fix_data;
   if (fixp->fx_addsy == 0)
     return &no_relocs;
   assert (hppa_fixp != 0);
   assert (section != 0);
 
-#ifdef OBJ_ELF
-  /* Yuk.  I would really like to push all this ELF specific unwind
-     crud into BFD and the linker.  That's how SOM does it -- and
-     if we could make ELF emulate that then we could share more code
-     in GAS (and potentially a gnu-linker later).
-
-     Unwind section relocations are handled in a special way.
-     The relocations for the .unwind section are originally
-     built in the usual way.  That is, for each unwind table
-     entry there are two relocations:  one for the beginning of
-     the function and one for the end.
-
-     The first time we enter this function we create a
-     relocation of the type R_HPPA_UNWIND_ENTRIES.  The addend
-     of the relocation is initialized to 0.  Each additional
-     pair of times this function is called for the unwind
-     section represents an additional unwind table entry.  Thus,
-     the addend of the relocation should end up to be the number
-     of unwind table entries.  */
-  if (strcmp (UNWIND_SECTION_NAME, section->name) == 0)
-    {
-      if (unwind_reloc_entryP == NULL)
-       {
-         reloc = (arelent *) bfd_alloc_by_size_t (stdoutput,
-                                                  sizeof (arelent));
-         assert (reloc != 0);
-         unwind_reloc_entryP = reloc;
-         unwind_reloc_fixp_cnt++;
-         unwind_reloc_entryP->address
-           = fixp->fx_frag->fr_address + fixp->fx_where;
-         /* A pointer to any function will do.  We only
-            need one to tell us what section the unwind
-            relocations are for. */
-         unwind_reloc_entryP->sym_ptr_ptr = &fixp->fx_addsy->bsym;
-         hppa_fixp->fx_r_type = code = R_HPPA_UNWIND_ENTRIES;
-         fixp->fx_r_type = R_HPPA_UNWIND;
-         unwind_reloc_entryP->howto = bfd_reloc_type_lookup (stdoutput, code);
-         unwind_reloc_entryP->addend = unwind_reloc_fixp_cnt / 2;
-         relocs = (arelent **) bfd_alloc_by_size_t (stdoutput,
-                                                    sizeof (arelent *) * 2);
-         assert (relocs != 0);
-         relocs[0] = unwind_reloc_entryP;
-         relocs[1] = NULL;
-         return relocs;
-       }
-      unwind_reloc_fixp_cnt++;
-      unwind_reloc_entryP->addend = unwind_reloc_fixp_cnt / 2;
+  reloc = (arelent *) xmalloc (sizeof (arelent));
 
-      return &no_relocs;
-    }
-#endif
-
-  reloc = (arelent *) bfd_alloc_by_size_t (stdoutput, sizeof (arelent));
-  assert (reloc != 0);
-
-  reloc->sym_ptr_ptr = &fixp->fx_addsy->bsym;
-  codes = hppa_gen_reloc_type (stdoutput,
+  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,
-                              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++)
     ;
 
-  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];
 
@@ -2735,38 +2782,13 @@ tc_gen_reloc (section, fixp)
 #ifdef OBJ_ELF
   switch (fixp->fx_r_type)
     {
-    case R_HPPA_COMPLEX:
-    case R_HPPA_COMPLEX_PCREL_CALL:
-    case R_HPPA_COMPLEX_ABS_CALL:
-      assert (n_relocs == 5);
-
-      for (i = 0; i < n_relocs; i++)
-       {
-         reloc[i].sym_ptr_ptr = NULL;
-         reloc[i].address = 0;
-         reloc[i].addend = 0;
-         reloc[i].howto = bfd_reloc_type_lookup (stdoutput, *codes[i]);
-         assert (reloc[i].howto && *codes[i] == reloc[i].howto->type);
-       }
-
-      reloc[0].sym_ptr_ptr = &fixp->fx_addsy->bsym;
-      reloc[1].sym_ptr_ptr = &fixp->fx_subsy->bsym;
-      reloc[4].address = fixp->fx_frag->fr_address + fixp->fx_where;
-
-      if (fixp->fx_r_type == R_HPPA_COMPLEX)
-       reloc[3].addend = fixp->fx_addnumber;
-      else if (fixp->fx_r_type == R_HPPA_COMPLEX_PCREL_CALL ||
-              fixp->fx_r_type == R_HPPA_COMPLEX_ABS_CALL)
-       reloc[1].addend = fixp->fx_addnumber;
-
-      break;
-
     default:
       assert (n_relocs == 1);
 
       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 */
@@ -2776,112 +2798,134 @@ tc_gen_reloc (section, fixp)
       /* Now, do any processing that is dependent on the relocation type.  */
       switch (code)
        {
-       case R_HPPA_PLABEL_32:
-       case R_HPPA_PLABEL_11:
-       case R_HPPA_PLABEL_14:
-       case R_HPPA_PLABEL_L21:
-       case R_HPPA_PLABEL_R11:
-       case R_HPPA_PLABEL_R14:
+       case R_PARISC_DLTREL21L:
+       case R_PARISC_DLTREL14R:
+       case R_PARISC_DLTREL14F:
+       case R_PARISC_PLABEL32:
+       case R_PARISC_PLABEL21L:
+       case R_PARISC_PLABEL14R:
          /* For plabel relocations, the addend of the
             relocation should be either 0 (no static link) or 2
             (static link required).
 
-            FIXME: assume that fx_addnumber contains this
-            information */
-         reloc->addend = fixp->fx_addnumber;
+            FIXME: We always assume no static link!
+
+            We also slam a zero addend into the DLT relative relocs;
+            it doesn't make a lot of sense to use any addend since
+            it gets you a different (eg unknown) DLT entry.  */
+         reloc->addend = 0;
          break;
 
-       case R_HPPA_ABS_CALL_11:
-       case R_HPPA_ABS_CALL_14:
-       case R_HPPA_ABS_CALL_17:
-       case R_HPPA_ABS_CALL_L21:
-       case R_HPPA_ABS_CALL_R11:
-       case R_HPPA_ABS_CALL_R14:
-       case R_HPPA_ABS_CALL_R17:
-       case R_HPPA_ABS_CALL_LS21:
-       case R_HPPA_ABS_CALL_RS11:
-       case R_HPPA_ABS_CALL_RS14:
-       case R_HPPA_ABS_CALL_RS17:
-       case R_HPPA_ABS_CALL_LD21:
-       case R_HPPA_ABS_CALL_RD11:
-       case R_HPPA_ABS_CALL_RD14:
-       case R_HPPA_ABS_CALL_RD17:
-       case R_HPPA_ABS_CALL_LR21:
-       case R_HPPA_ABS_CALL_RR14:
-       case R_HPPA_ABS_CALL_RR17:
-
-       case R_HPPA_PCREL_CALL_11:
-       case R_HPPA_PCREL_CALL_14:
-       case R_HPPA_PCREL_CALL_17:
-       case R_HPPA_PCREL_CALL_L21:
-       case R_HPPA_PCREL_CALL_R11:
-       case R_HPPA_PCREL_CALL_R14:
-       case R_HPPA_PCREL_CALL_R17:
-       case R_HPPA_PCREL_CALL_LS21:
-       case R_HPPA_PCREL_CALL_RS11:
-       case R_HPPA_PCREL_CALL_RS14:
-       case R_HPPA_PCREL_CALL_RS17:
-       case R_HPPA_PCREL_CALL_LD21:
-       case R_HPPA_PCREL_CALL_RD11:
-       case R_HPPA_PCREL_CALL_RD14:
-       case R_HPPA_PCREL_CALL_RD17:
-       case R_HPPA_PCREL_CALL_LR21:
-       case R_HPPA_PCREL_CALL_RR14:
-       case R_HPPA_PCREL_CALL_RR17:
+       case R_PARISC_PCREL21L:
+       case R_PARISC_PCREL17R:
+       case R_PARISC_PCREL17F:
+       case R_PARISC_PCREL17C:
+       case R_PARISC_PCREL14R:
+       case R_PARISC_PCREL14F:
          /* The constant is stored in the instruction.  */
          reloc->addend = HPPA_R_ADDEND (hppa_fixp->fx_arg_reloc, 0);
          break;
        default:
-         reloc->addend = fixp->fx_addnumber;
+         reloc->addend = fixp->fx_offset;
          break;
        }
       break;
     }
 #else /* OBJ_SOM */
 
-  /* Preliminary relocation handling for SOM.  Needs to handle
-     COMPLEX relocations (yes, I've seen them occur) and it will
-     need to handle R_ENTRY/R_EXIT relocations in the very near future
-     (for generating unwinds).  */
-  switch (fixp->fx_r_type)
+  /* Walk over reach relocation returned by the BFD backend.  */
+  for (i = 0; i < n_relocs; i++)
     {
-    case R_HPPA_COMPLEX:
-    case R_HPPA_COMPLEX_PCREL_CALL:
-    case R_HPPA_COMPLEX_ABS_CALL:
-      abort ();
-      break;
-    default:
-      assert (n_relocs == 1);
-
-      code = *codes[0];
+      code = *codes[i];
 
-      reloc->sym_ptr_ptr = &fixp->fx_addsy->bsym;
-      reloc->howto = bfd_reloc_type_lookup (stdoutput, code);
-      reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
+      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)
        {
+       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:
-         reloc->addend = HPPA_R_ADDEND (hppa_fixp->fx_arg_reloc, 0);
+         relocs[i]->addend = HPPA_R_ADDEND (hppa_fixp->fx_arg_reloc, 0);
          break;
 
+       case R_DLT_REL:
        case R_DATA_PLABEL:
        case R_CODE_PLABEL:
          /* For plabel relocations, the addend of the
             relocation should be either 0 (no static link) or 2
             (static link required).
 
-            FIXME: We always assume no static link!  */
-         reloc->addend = 0;
+            FIXME: We always assume no static link!
+
+            We also slam a zero addend into the DLT relative relocs;
+            it doesn't make a lot of sense to use any addend since
+            it gets you a different (eg unknown) DLT entry.  */
+         relocs[i]->addend = 0;
          break;
 
-       default:
-         reloc->addend = fixp->fx_addnumber;
+       case R_N_MODE:
+       case R_S_MODE:
+       case R_D_MODE:
+       case R_R_MODE:
+       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.  */
+          relocs[i]->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
+          *relocs[i]->sym_ptr_ptr = symbol_get_bfdsym (dummy_symbol);
+         relocs[i]->addend = 0;
+         break;
+
+       case R_END_TRY:
+       case R_ENTRY:
+       case R_EXIT:
+         /* There is no symbol associated with these fixups.  */
+          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;
+
+       default:
+         relocs[i]->addend = fixp->fx_offset;
        }
-      break;
     }
+
+ done:
 #endif
 
   return relocs;
@@ -2931,31 +2975,6 @@ md_section_align (segment, size)
   int align2 = (1 << align) - 1;
 
   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.  */
@@ -2973,17 +2992,27 @@ md_estimate_size_before_relax (fragP, segment)
 
   return size;
 }
+\f
+CONST char *md_shortopts = "";
+struct option md_longopts[] = {
+  {NULL, no_argument, NULL, 0}
+};
+size_t md_longopts_size = sizeof(md_longopts);
 
-/* Parse machine dependent options.  There are none on the PA.  */
 int
-md_parse_option (argP, cntP, vecP)
-     char **argP;
-     int *cntP;
-     char ***vecP;
+md_parse_option (c, arg)
+     int c;
+     char *arg;
 {
-  return 1;
+  return 0;
 }
 
+void
+md_show_usage (stream)
+     FILE *stream;
+{
+}
+\f
 /* We have no need to default values of symbols.  */
 
 symbolS *
@@ -2993,38 +3022,38 @@ md_undefined_symbol (name)
   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.  */
+/* Apply a fixup to an instruction.  */
 
-void
-md_operand (expressionP)
-     expressionS *expressionP;
-{
-}
-
-/* Helper function for md_apply_fix.  Actually determine if the fix
-   can be applied, and if so, apply it.
-
-   If a fix is applied, then set fx_addsy to NULL which indicates
-   the fix was applied and need not be emitted into the object file.  */
-
-static void
-md_apply_fix_1 (fixP, val)
+int
+md_apply_fix (fixP, valp)
      fixS *fixP;
-     long val;
+     valueT *valp;
 {
   char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
-  struct hppa_fix_struct *hppa_fixP = fixP->tc_fix_data;
-  long new_val, result;
-  unsigned int w1, w2, w;
-
-  /* SOM uses R_HPPA_ENTRY and R_HPPA_EXIT relocations which can 
-     never be "applied".  They must always be emitted.  */
+  struct hppa_fix_struct *hppa_fixP;
+  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
+     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
-      || 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
@@ -3034,27 +3063,56 @@ md_apply_fix_1 (fixP, val)
       unsigned long buf_wd = bfd_get_32 (stdoutput, buf);
       unsigned char fmt = bfd_hppa_insn2fmt (buf_wd);
 
-      if (fixP->fx_r_type == R_HPPA_NONE)
-       fmt = 0;
-
-      /* Remember this value for emit_reloc.  FIXME, is this braindamage
-         documented anywhere!?!  */
-      fixP->fx_addnumber = val;
-
-      /* Check if this is an undefined symbol.  No relocation can
-         possibly be performed in this case.  */
-      if ((fixP->fx_addsy && fixP->fx_addsy->bsym->section == &bfd_und_section)
-         || (fixP->fx_subsy
-             && fixP->fx_subsy->bsym->section == &bfd_und_section))
-       return;
-
-      if (fmt != 0 && hppa_fixP->fx_r_field != R_HPPA_PSEL
-         && hppa_fixP->fx_r_field != R_HPPA_LPSEL
-         && hppa_fixP->fx_r_field != R_HPPA_RPSEL)
-       new_val = hppa_field_adjust (val, 0, hppa_fixP->fx_r_field);
+      /* If there is a symbol associated with this fixup, then it's something
+        which will need a SOM relocation (except for some PC-relative relocs).
+        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)
+#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 = 0;
+       new_val = hppa_field_adjust (*valp, 0, hppa_fixP->fx_r_field);
 
+      /* Handle pc-relative exceptions from above.  */
+#define arg_reloc_stub_needed(CALLER, CALLEE) \
+  ((CALLEE) && (CALLER) && ((CALLEE) != (CALLER)))
+      if ((fmt == 12 || fmt == 17 || fmt == 22)
+         && fixP->fx_addsy
+         && fixP->fx_pcrel
+#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);
+#undef arg_reloc_stub_needed
+       
       switch (fmt)
        {
        /* Handle all opcodes with the 'j' operand type.  */
@@ -3065,7 +3123,8 @@ md_apply_fix_1 (fixP, val)
          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.  */
@@ -3076,7 +3135,8 @@ md_apply_fix_1 (fixP, val)
          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.  */
@@ -3087,96 +3147,68 @@ md_apply_fix_1 (fixP, val)
          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:
-         CHECK_FIELD (new_val, 8191, -8192, 0)
+         CHECK_FIELD (new_val, 8199, -8184, 0);
 
          /* 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);
 
-         dis_assemble_12 (result, &w1, &w);
+         dis_assemble_12 (resulti, &w1, &w);
          result = ((w1 << 2) | w);
-         fixP->fx_addsy = NULL;
          break;
 
-#define stub_needed(CALLER, CALLEE) \
-  ((CALLEE) && (CALLER) && ((CALLEE) != (CALLER)))
-
        /* Handle some of the opcodes with the 'W' operand type.  */
        case 17:
-         /* If a long-call stub or argument relocation stub is
-            needed, then we can not apply this relocation, instead
-            the linker must handle it.  */
-         if (new_val > 262143 || new_val < -262144
-             || stub_needed (((obj_symbol_type *)
-                              fixP->fx_addsy->bsym)->tc_data.hppa_arg_reloc,
-                             hppa_fixP->fx_arg_reloc))
-           return;
-
-         /* No stubs were needed, we can perform this relocation.  */
-         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);
-         fixP->fx_addsy = NULL;
-         break;
-
-#undef too_far
-#undef stub_needed
+         {
+           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:
-#ifdef OBJ_ELF
-         /* These are ELF specific relocations.  ELF unfortunately
-            handles unwinds in a completely different manner.  */
-         if (hppa_fixP->fx_r_type == R_HPPA_UNWIND_ENTRY
-             || hppa_fixP->fx_r_type == R_HPPA_UNWIND_ENTRIES)
-           result = fixP->fx_addnumber;
-         else
-#endif
-           {
-             result = 0;
-             fixP->fx_addnumber = fixP->fx_offset;
-             bfd_put_32 (stdoutput, 0, buf);
-             return;
-           }
+         result = 0;
+         bfd_put_32 (stdoutput, new_val, buf);
          break;
 
-       case 0:
-         return;
-
        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);
+      return 1;
+    }
+  else
+    {
+      printf (_("no hppa_fixup entry for this fixup (fixP = 0x%x, type = 0x%x)\n"),
+             (unsigned int) fixP, fixP->fx_r_type);
+      return 0;
     }
-  else
-    printf ("no hppa_fixup entry for this fixup (fixP = 0x%x, type = 0x%x)\n",
-           (unsigned int) fixP, fixP->fx_r_type);
-}
-
-/* Apply a fix into a frag's data (if possible).  */
-
-int
-md_apply_fix (fixP, valp)
-     fixS *fixP;
-     valueT *valp;
-{
-  md_apply_fix_1 (fixP, (long) *valp);
-  return 1;
 }
 
 /* Exactly what point is a PC-relative offset relative TO?
@@ -3189,7 +3221,7 @@ md_pcrel_from (fixP)
   return fixP->fx_where + fixP->fx_frag->fr_address;
 }
 
-/* Return nonzero if the input line pointer is at the end of 
+/* Return nonzero if the input line pointer is at the end of
    a statement.  */
 
 static int
@@ -3216,7 +3248,7 @@ is_end_of_statement ()
 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;
@@ -3295,7 +3327,7 @@ pa_parse_number (s, result)
       p++;
       c = *p;
       /* Tege hack: Special case for general registers as the general
-         code makes a binary search with case translation, and is VERY 
+         code makes a binary search with case translation, and is VERY
          slow. */
       if (c == 'r')
        {
@@ -3315,7 +3347,7 @@ pa_parse_number (s, result)
          else if (!isdigit (*p))
            {
              if (print_errors)
-               as_bad ("Undefined register: '%s'.", name);
+               as_bad (_("Undefined register: '%s'."), name);
              num = -1;
            }
          else
@@ -3340,7 +3372,7 @@ pa_parse_number (s, result)
          else
            {
              if (print_errors)
-               as_bad ("Undefined register: '%s'.", name);
+               as_bad (_("Undefined register: '%s'."), name);
              num = -1;
            }
          *p = c;
@@ -3378,7 +3410,7 @@ pa_parse_number (s, result)
          else
            {
              if (print_errors)
-               as_bad ("Non-absolute symbol: '%s'.", name);
+               as_bad (_("Non-absolute symbol: '%s'."), name);
              num = -1;
            }
        }
@@ -3393,7 +3425,7 @@ pa_parse_number (s, result)
          else
            {
              if (print_errors)
-               as_bad ("Undefined absolute constant: '%s'.", name);
+               as_bad (_("Undefined absolute constant: '%s'."), name);
              num = -1;
            }
        }
@@ -3426,6 +3458,7 @@ reg_name_search (name)
      char *name;
 {
   int middle, low, high;
+  int cmp;
 
   low = 0;
   high = REG_NAME_CNT - 1;
@@ -3433,31 +3466,39 @@ reg_name_search (name)
   do
     {
       middle = (low + high) / 2;
-      if (strcasecmp (name, pre_defined_registers[middle].name) < 0)
+      cmp = strcasecmp (name, pre_defined_registers[middle].name);
+      if (cmp < 0)
        high = middle - 1;
-      else
+      else if (cmp > 0)
        low = middle + 1;
+      else
+       return pre_defined_registers[middle].value;
     }
-  while (!((strcasecmp (name, pre_defined_registers[middle].name) == 0) ||
-          (low > high)));
+  while (low <= high);
 
-  if (strcasecmp (name, pre_defined_registers[middle].name) == 0)
-    return (pre_defined_registers[middle].value);
-  else
-    return (-1);
+  return -1;
 }
 
 
 /* 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
-need_89_opcode (insn, result)
+need_pa11_opcode (insn, result)
      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))
-    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;
 }
@@ -3480,16 +3521,29 @@ pa_parse_fp_cmp_cond (s)
        {
          cond = fp_cond_map[i].cond;
          *s += strlen (fp_cond_map[i].string);
+         /* If not a complete match, back up the input string and
+            report an error.  */
+         if (**s != ' ' && **s != '\t')
+           {
+             *s -= strlen (fp_cond_map[i].string);
+             break;
+           }
          while (**s == ' ' || **s == '\t')
            *s = *s + 1;
          return cond;
        }
     }
 
-  as_bad ("Invalid FP Compare Condition: %c", **s);
+  as_bad (_("Invalid FP Compare Condition: %s"), *s);
+
+  /* Advance over the bogus completer.  */
+  while (**s != ',' && **s != ' ' && **s != '\t')
+    *s += 1;
+
   return 0;
 }
 
+
 /* Parse an FP operand format completer returning the completer
    type.  */
 
@@ -3521,7 +3575,7 @@ pa_parse_fp_format (s)
       else
        {
          format = ILLEGAL_FMT;
-         as_bad ("Invalid FP Operand Format: %3s", *s);
+         as_bad (_("Invalid FP Operand Format: %3s"), *s);
        }
     }
 
@@ -3534,28 +3588,56 @@ static int
 pa_chk_field_selector (str)
      char **str;
 {
-  int selector;
-  const struct selector_entry *tablep;
-
-  selector = e_fsel;
+  int middle, low, high;
+  int cmp;
+  char name[4];
 
   /* Read past any whitespace.  */
+  /* FIXME: should we read past newlines and formfeeds??? */
   while (**str == ' ' || **str == '\t' || **str == '\n' || **str == '\f')
     *str = *str + 1;
 
-  /* Yuk.  Looks like a linear search through the table.  With the
-     frequence of some selectors it might make sense to sort the
-     table by usage.  */
-  for (tablep = selector_table; tablep->prefix; tablep++)
+  if ((*str)[1] == '\'' || (*str)[1] == '%')
+    name[0] = tolower ((*str)[0]),
+    name[1] = 0;
+  else if ((*str)[2] == '\'' || (*str)[2] == '%')
+    name[0] = tolower ((*str)[0]),
+    name[1] = tolower ((*str)[1]),
+    name[2] = 0;
+#ifdef OBJ_SOM
+  else if ((*str)[3] == '\'' || (*str)[3] == '%')
+    name[0] = tolower ((*str)[0]),
+    name[1] = tolower ((*str)[1]),
+    name[2] = tolower ((*str)[2]),
+    name[3] = 0;
+#endif
+  else
+    return e_fsel;
+
+  low = 0;
+  high = sizeof (selector_table) / sizeof (struct selector_entry) - 1;
+
+  do
     {
-      if (strncasecmp (tablep->prefix, *str, strlen (tablep->prefix)) == 0)
+      middle = (low + high) / 2;
+      cmp = strcmp (name, selector_table[middle].prefix);
+      if (cmp < 0)
+       high = middle - 1;
+      else if (cmp > 0)
+       low = middle + 1;
+      else
        {
-         *str += strlen (tablep->prefix);
-         selector = tablep->field_selector;
-         break;
+         *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;
+  while (low <= high);
+
+  return e_fsel;
 }
 
 /* Mark (via expr_end) the end of an expression (I think).  FIXME.  */
@@ -3574,7 +3656,7 @@ get_expression (str)
        || 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;
@@ -3596,9 +3678,36 @@ pa_get_absolute_expression (insn, strp)
   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);
+    }
   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;
@@ -3608,7 +3717,7 @@ pa_get_absolute_expression (insn, strp)
   return evaluate_absolute (insn);
 }
 
-/* Evaluate an absolute expression EXP which may be modified by 
+/* Evaluate an absolute expression EXP which may be modified by
    the selector FIELD_SELECTOR.  Return the value of the expression.  */
 static int
 evaluate_absolute (insn)
@@ -3655,8 +3764,6 @@ evaluate_absolute (insn)
     /* Add 0x800 and arithmetic shift right 11 bits.  */
     case e_ldsel:
       value += 0x800;
-
-
       value = (value & 0xfffff800) >> 11;
       break;
 
@@ -3665,11 +3772,15 @@ evaluate_absolute (insn)
       value |= 0xfffff800;
       break;
 
-    /* This had better get fixed.  It looks like we're quickly moving
-       to LR/RR.  FIXME.  */
+#define RSEL_ROUND(c)  (((c) + 0x1000) & ~0x1fff)
     case e_rrsel:
+      value = (RSEL_ROUND (value) & 0x7ff) + (value - RSEL_ROUND (value));
+      break;
+
     case e_lrsel:
-      abort ();
+      value = (RSEL_ROUND (value) >> 11) & 0x1fffff;
+      break;
+#undef RSEL_ROUND
 
     default:
       BAD_CASE (field_selector);
@@ -3695,7 +3806,7 @@ pa_build_arg_reloc (type_name)
   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;
 }
@@ -3726,7 +3837,7 @@ pa_align_arg_reloc (reg, arg_reloc)
       new_reloc <<= 2;
       break;
     default:
-      as_bad ("Invalid argument description: %d", reg);
+      as_bad (_("Invalid argument description: %d"), reg);
     }
 
   return new_reloc;
@@ -3749,7 +3860,7 @@ pa_parse_nullif (s)
        nullif = 1;
       else
        {
-         as_bad ("Invalid Nullification: (%c)", **s);
+         as_bad (_("Invalid Nullification: (%c)"), **s);
          nullif = 0;
        }
       *s = *s + 1;
@@ -3774,6 +3885,7 @@ pa_parse_nonneg_cmpsub_cmpltr (s, isbranch)
   char *name = *s + 1;
   char c;
   char *save_s = *s;
+  int nullify = 0;
 
   cmpltr = 0;
   if (**s == ',')
@@ -3783,6 +3895,8 @@ pa_parse_nonneg_cmpsub_cmpltr (s, isbranch)
        *s += 1;
       c = **s;
       **s = 0x00;
+
+
       if (strcmp (name, "=") == 0)
        {
          cmpltr = 1;
@@ -3816,6 +3930,7 @@ pa_parse_nonneg_cmpsub_cmpltr (s, isbranch)
       else if (strcasecmp (name, "n") == 0 && isbranch)
        {
          cmpltr = 0;
+         nullify = 1;
        }
       else
        {
@@ -3825,9 +3940,10 @@ pa_parse_nonneg_cmpsub_cmpltr (s, isbranch)
     }
 
   /* Reset pointers if this was really a ,n for a branch instruction.  */
-  if (cmpltr == 0 && *name == 'n' && isbranch)
+  if (nullify)
     *s = save_s;
 
+
   return cmpltr;
 }
 
@@ -3847,6 +3963,7 @@ pa_parse_neg_cmpsub_cmpltr (s, isbranch)
   char *name = *s + 1;
   char c;
   char *save_s = *s;
+  int nullify = 0;
 
   cmpltr = 0;
   if (**s == ',')
@@ -3856,6 +3973,8 @@ pa_parse_neg_cmpsub_cmpltr (s, isbranch)
        *s += 1;
       c = **s;
       **s = 0x00;
+
+
       if (strcasecmp (name, "tr") == 0)
        {
          cmpltr = 0;
@@ -3893,6 +4012,7 @@ pa_parse_neg_cmpsub_cmpltr (s, isbranch)
       else if (strcasecmp (name, "n") == 0 && isbranch)
        {
          cmpltr = 0;
+         nullify = 1;
        }
       else
        {
@@ -3902,12 +4022,14 @@ pa_parse_neg_cmpsub_cmpltr (s, isbranch)
     }
 
   /* Reset pointers if this was really a ,n for a branch instruction.  */
-  if (cmpltr == 0 && *name == 'n' && isbranch)
+  if (nullify)
     *s = save_s;
 
+
   return cmpltr;
 }
 
+
 /* Parse a non-negated addition completer returning the number
    (for encoding in instrutions) of the given completer.
 
@@ -3986,7 +4108,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
-   computational instruction.  */
+   computational instruction).  */
 
 static int
 pa_parse_neg_add_cmpltr (s, isbranch)
@@ -4022,11 +4144,11 @@ pa_parse_neg_add_cmpltr (s, isbranch)
        {
          cmpltr = 3;
        }
-      else if (strcmp (name, "uv") == 0)
+      else if (strcasecmp (name, "uv") == 0)
        {
          cmpltr = 4;
        }
-      else if (strcmp (name, "vnz") == 0)
+      else if (strcasecmp (name, "vnz") == 0)
        {
          cmpltr = 5;
        }
@@ -4058,6 +4180,25 @@ pa_parse_neg_add_cmpltr (s, isbranch)
   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)
+{
+  /* 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);
+
+  /* If bytes is a power of 2, then update the current subspace's
+     alignment if necessary.  */
+  if (log2 (bytes) != -1)
+    record_alignment (current_subspace->ssd_seg, log2 (bytes));
+}
+#endif
+
 /* Handle a .BLOCK type pseudo-op.  */
 
 static void
@@ -4067,7 +4208,12 @@ pa_block (z)
   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 ();
 
@@ -4075,8 +4221,8 @@ pa_block (z)
   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.  */
 
@@ -4089,7 +4235,52 @@ pa_block (z)
 
   pa_undefine_label ();
   demand_empty_rest_of_line ();
-  return;
+}
+
+/* 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
@@ -4100,9 +4291,13 @@ static void
 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 ();
-  return;
 }
 
 /* Do the dirty work of building a call descriptor which describes
@@ -4144,7 +4339,7 @@ pa_call_args (call_desc)
        }
       else
        {
-         as_bad ("Invalid .CALL argument: %s", name);
+         as_bad (_("Invalid .CALL argument: %s"), name);
        }
       p = input_line_pointer;
       *p = c;
@@ -4174,7 +4369,7 @@ is_same_frag (frag1, frag2)
 }
 
 #ifdef OBJ_ELF
-/* Build an entry in the UNWIND subspace from the given function 
+/* Build an entry in the UNWIND subspace from the given function
    attributes in CALL_INFO.  This is not needed for SOM as using
    R_ENTRY and R_EXIT relocations allow the linker to handle building
    of the unwind spaces.  */
@@ -4183,6 +4378,7 @@ static void
 pa_build_unwind_subspace (call_info)
      struct call_info *call_info;
 {
+#if 0
   char *unwind;
   asection *seg, *save_seg;
   subsegT subseg, save_subseg;
@@ -4210,58 +4406,27 @@ pa_build_unwind_subspace (call_info)
   /* Get some space to hold relocation information for the unwind
      descriptor.  */
   p = frag_more (4);
-  call_info->start_offset_frag = frag_now;
-  call_info->start_frag_where = p - frag_now->fr_literal;
+  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,
-               (expressionS *) NULL, 0, R_HPPA_UNWIND, e_fsel, 32, 0,
-               (char *) 0);
+               (expressionS *) NULL, 0, R_PARISC_DIR32, e_fsel, 32, 0, NULL);
 
-  /* We need to search for the first relocation involving the start_symbol of
-     this call_info descriptor.  */
-  {
-    fixS *fixP;
+  p = frag_more (4);
+  md_number_to_chars (p, 0, 4);
 
-    call_info->start_fix = seg_info (now_seg)->fix_root;
-    for (fixP = call_info->start_fix; fixP; fixP = fixP->fx_next)
-      {
-       if (fixP->fx_addsy == call_info->start_symbol
-           || fixP->fx_subsy == call_info->start_symbol)
-         {
-           call_info->start_fix = fixP;
-           break;
-         }
-      }
-  }
+  /* Relocation info. for end offset of the function.
 
-  p = frag_more (4);
-  call_info->end_offset_frag = frag_now;
-  call_info->end_frag_where = p - frag_now->fr_literal;
+     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,
-               (expressionS *) NULL, 0, R_HPPA_UNWIND, e_fsel, 32, 0,
-               (char *) 0);
-
-  /* We need to search for the first relocation involving the end_symbol of
-     this call_info descriptor.  */
-  {
-    fixS *fixP;
-
-    call_info->end_fix = seg_info (now_seg)->fix_root; /* the default */
-    for (fixP = call_info->end_fix; fixP; fixP = fixP->fx_next)
-      {
-       if (fixP->fx_addsy == call_info->end_symbol
-           || fixP->fx_subsy == call_info->end_symbol)
-         {
-           call_info->end_fix = fixP;
-           break;
-         }
-      }
-  }
+               (expressionS *) NULL, 0, R_PARISC_DIR32, e_fsel, 32, 0, NULL);
 
   /* Dump it. */
   unwind = (char *) &call_info->ci_unwind;
@@ -4275,6 +4440,7 @@ pa_build_unwind_subspace (call_info)
 
   /* Return back to the original segment/subsegment.  */
   subseg_set (save_seg, save_subseg);
+#endif
 }
 #endif
 
@@ -4289,9 +4455,14 @@ pa_callinfo (unused)
   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)
-    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.  */
@@ -4311,7 +4482,7 @@ pa_callinfo (unused)
          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;
            }
 
@@ -4327,10 +4498,10 @@ pa_callinfo (unused)
          input_line_pointer++;
          temp = get_absolute_expression ();
          /* The HP assembler accepts 19 as the high bound for ENTRY_GR
-            even though %r19 is caller saved.  I think this is a bug in 
+            even though %r19 is caller saved.  I think this is a bug in
             the HP assembler, and we are not going to emulate it.  */
          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))
@@ -4339,10 +4510,10 @@ pa_callinfo (unused)
          *p = c;
          input_line_pointer++;
          temp = get_absolute_expression ();
-         /* Similarly the HP assembler takes 31 as the high bound even 
+         /* Similarly the HP assembler takes 31 as the high bound even
             though %fr21 is the last callee saved floating point register.  */
          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))
@@ -4352,8 +4523,7 @@ pa_callinfo (unused)
          input_line_pointer++;
          temp = get_absolute_expression ();
          if (temp != 3)
-           as_bad ("Value for ENTRY_SR must be 3\n");
-         last_call_info->entry_sr = temp - 2;
+           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) ||
@@ -4361,13 +4531,11 @@ pa_callinfo (unused)
        {
          p = input_line_pointer;
          *p = c;
-         last_call_info->makes_calls = 1;
        }
       else if ((strncasecmp (name, "no_calls", 8) == 0))
        {
          p = input_line_pointer;
          *p = c;
-         last_call_info->makes_calls = 0;
        }
       /* Should RP be saved into the stack.  */
       else if ((strncasecmp (name, "save_rp", 7) == 0))
@@ -4399,16 +4567,26 @@ pa_callinfo (unused)
          *p = c;
          last_call_info->ci_unwind.descriptor.hpux_interrupt_marker = 1;
        }
+      /* Is this a millicode routine.  "millicode" isn't in my
+        assembler manual, but my copy is old.  The HP assembler
+        accepts it, and there's a place in the unwind descriptor
+        to drop the information, so we'll accept it too.  */
+      else if ((strncasecmp (name, "millicode", 9) == 0))
+       {
+         p = input_line_pointer;
+         *p = c;
+         last_call_info->ci_unwind.descriptor.millicode = 1;
+       }
       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++;
     }
 
   demand_empty_rest_of_line ();
-  return;
 }
 
 /* Switch into the code subspace.  */
@@ -4417,25 +4595,13 @@ static void
 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 ();
-  return;
+#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,
@@ -4446,7 +4612,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
-   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)
@@ -4466,59 +4642,15 @@ pa_comm (unused)
 
   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 %d. Not changed.",
-                      S_GET_NAME (symbol), S_GET_VALUE (symbol));
-             return;
-           }
-       }
-      else
-       {
-         S_SET_VALUE (symbol, size);
-         S_SET_SEGMENT (symbol, &bfd_und_section);
-         S_SET_EXTERNAL (symbol);
-       }
-    }
-  demand_empty_rest_of_line ();
-}
-
-/* Process a .COPYRIGHT pseudo-op.  */
-
-static void
-pa_copyright (unused)
-     int unused;
-{
-  char *name;
-  char c;
+      S_SET_VALUE (symbol, size);
+      S_SET_SEGMENT (symbol, bfd_und_section_ptr);
+      S_SET_EXTERNAL (symbol);
 
-  SKIP_WHITESPACE ();
-  if (*input_line_pointer == '\"')
-    {
-      ++input_line_pointer;
-      name = input_line_pointer;
-      while ((c = next_char_of_string ()) >= 0)
-       ;
-      c = *input_line_pointer;
-      *input_line_pointer = '\0';
-      *(input_line_pointer - 1) = '\0';
-      {
-       /* FIXME.  Not supported */
-       abort ();
-      }
-      *input_line_pointer = c;
-    }
-  else
-    {
-      as_bad ("Expected \"-ed string");
+      /* 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);
     }
-  pa_undefine_label ();
   demand_empty_rest_of_line ();
 }
 
@@ -4529,7 +4661,6 @@ pa_end (unused)
      int unused;
 {
   demand_empty_rest_of_line ();
-  return;
 }
 
 /* Process a .ENTER pseudo-op.  This is not supported.  */
@@ -4537,8 +4668,13 @@ static void
 pa_enter (unused)
      int unused;
 {
-  abort ();
-  return;
+#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
@@ -4547,22 +4683,21 @@ static void
 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)
-    as_bad ("Misplaced .entry. Ignored.");
+    as_bad (_("Misplaced .entry. Ignored."));
   else
     {
       if (!callinfo_found)
-       as_bad ("Missing .callinfo.");
-
-      last_call_info->start_frag = frag_now;
+       as_bad (_("Missing .callinfo."));
     }
   demand_empty_rest_of_line ();
   within_entry_exit = TRUE;
 
-  /* Go back to the last symbol and turn on the BSF_FUNCTION flag.
-     It will not be on if no .EXPORT pseudo-op exists (static function).  */
-  last_call_info->start_symbol->bsym->flags |= BSF_FUNCTION;
-
 #ifdef OBJ_SOM
   /* SOM defers building of unwind descriptors until the link phase.
      The assembler is responsible for creating an R_ENTRY relocation
@@ -4573,17 +4708,16 @@ pa_entry (unused)
      is an unwind requires too much relocation space.  Hmmm.  Maybe
      if we split the unwind bits up between the relocations which
      denote the entry and exit points.  */
-  {
-    char *where = frag_more (0);
+  if (last_call_info->start_symbol != NULL)
+    {
+      char *where = frag_more (0);
 
-    fix_new_hppa (frag_now, where - frag_now->fr_literal, 0,
-                 last_call_info->start_symbol, (offsetT) 0, NULL,
-                 0, R_HPPA_ENTRY, e_fsel, 0, 0,
-                 (char *) &last_call_info->ci_unwind.descriptor);
-  }
+      fix_new_hppa (frag_now, where - frag_now->fr_literal, 0,
+                   NULL, (offsetT) 0, NULL,
+                   0, R_HPPA_ENTRY, e_fsel, 0, 0,
+                   (int *) &last_call_info->ci_unwind.descriptor);
+    }
 #endif
-
-  return;
 }
 
 /* Handle a .EQU pseudo-op.  */
@@ -4598,20 +4732,22 @@ pa_equ (reg)
   if (label_symbol)
     {
       symbol = label_symbol->lss_label;
-      S_SET_VALUE (symbol, (unsigned int) get_absolute_expression ());
-      S_SET_SEGMENT (symbol, &bfd_abs_section);
+      if (reg)
+       S_SET_VALUE (symbol, pa_parse_number (&input_line_pointer, 0));
+      else
+       S_SET_VALUE (symbol, (unsigned int) get_absolute_expression ());
+      S_SET_SEGMENT (symbol, bfd_abs_section_ptr);
     }
   else
     {
       if (reg)
-       as_bad (".REG must use a label");
+       as_bad (_(".REG must use a label"));
       else
-       as_bad (".EQU must use a label");
+       as_bad (_(".EQU must use a label"));
     }
 
   pa_undefine_label ();
   demand_empty_rest_of_line ();
-  return;
 }
 
 /* Helper function.  Does processing for the end of a function.  This
@@ -4626,49 +4762,10 @@ process_exit ()
   where = frag_more (0);
 
 #ifdef OBJ_ELF
-  /* ELF does not have EXIT relocations.  All we do is create a
-     temporary symbol marking the end of the function.  */
-  {
-    char *name = (char *) xmalloc (strlen ("L$\001end_") +
-                   strlen (S_GET_NAME (last_call_info->start_symbol)) + 1);
-
-    if (name)
-      {
-       symbolS *symbolP;
-
-       strcpy (name, "L$\001end_");
-       strcat (name, S_GET_NAME (last_call_info->start_symbol));
-
-       symbolP = symbol_find (name);
-       if (symbolP)
-         as_warn ("Symbol '%s' already defined.", name);
-       else
-         {
-           /* 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),
-                                 frag_now);
-
-           assert (symbolP);
-           symbolP->bsym->flags = BSF_LOCAL;
-           symbol_table_insert (symbolP);
-         }
-       if (symbolP)
-         last_call_info->end_symbol = symbolP;
-       else
-         as_bad ("Symbol '%s' could not be created.", name);
-
-      }
-    else
-      as_bad ("No memory for symbol name.");
-  }
-
-  /* Stuff away the location of the frag for the end of the function,
-     and call pa_build_unwind_subspace to add an entry in the unwind
-     table.  */
-  last_call_info->end_frag = frag_now;
+  /* Mark the end of the function, stuff away the location of the frag
+     for the end of the function, and finally call pa_build_unwind_subspace
+     to add an entry in the unwind table.  */
+  hppa_elf_mark_end_of_function ();
   pa_build_unwind_subspace (last_call_info);
 #else
   /* SOM defers building of unwind descriptors until the link phase.
@@ -4681,10 +4778,10 @@ process_exit ()
      if we split the unwind bits up between the relocations which
      denote the entry and exit points.  */
   fix_new_hppa (frag_now, where - frag_now->fr_literal, 0,
-               last_call_info->start_symbol, (offsetT) 0,
-               NULL, 0, R_HPPA_EXIT, e_fsel, 0, 0, NULL);
+               NULL, (offsetT) 0,
+               NULL, 0, R_HPPA_EXIT, e_fsel, 0, 0,
+               (int *) &last_call_info->ci_unwind.descriptor + 1);
 #endif
-
 }
 
 /* Process a .EXIT pseudo-op.  */
@@ -4693,16 +4790,21 @@ static void
 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)
-    as_bad (".EXIT must appear within a procedure");
+    as_bad (_(".EXIT must appear within a procedure"));
   else
     {
       if (!callinfo_found)
-       as_bad ("Missing .callinfo");
+       as_bad (_("Missing .callinfo"));
       else
        {
          if (!within_entry_exit)
-           as_bad ("No .ENTRY for this .EXIT");
+           as_bad (_("No .ENTRY for this .EXIT"));
          else
            {
              within_entry_exit = FALSE;
@@ -4711,11 +4813,10 @@ pa_exit (unused)
        }
     }
   demand_empty_rest_of_line ();
-  return;
 }
 
 /* Process a .EXPORT directive.  This makes functions external
-   and provides information such as argument relocation entries 
+   and provides information such as argument relocation entries
    to callers.  */
 
 static void
@@ -4730,7 +4831,7 @@ pa_export (unused)
   /* 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++;
@@ -4745,14 +4846,10 @@ pa_export (unused)
        {
          input_line_pointer++;
          pa_type_args (symbol, 1);
-#ifdef OBJ_ELF
-         pa_build_symextn_section ();
-#endif
        }
     }
 
   demand_empty_rest_of_line ();
-  return;
 }
 
 /* Helper function to process arguments to a .EXPORT pseudo-op.  */
@@ -4765,14 +4862,14 @@ pa_type_args (symbolP, is_export)
   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;
-      symbolP->bsym->flags &= ~BSF_FUNCTION;
-      S_SET_SEGMENT (symbolP, &bfd_abs_section);
+      symbol_get_bfdsym (symbolP)->flags &= ~BSF_FUNCTION;
+      S_SET_SEGMENT (symbolP, bfd_abs_section_ptr);
       type = SYMBOL_TYPE_ABSOLUTE;
     }
   else if (strncasecmp (input_line_pointer, "code", 4) == 0)
@@ -4784,54 +4881,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.  */
-      if (symbolP->bsym->flags & BSF_FUNCTION)
+      if (S_IS_FUNCTION (symbolP))
        {
          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
        {
-         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;
-      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;
-      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;
-      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;
-      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;
-      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;
-      symbolP->bsym->flags |= BSF_FUNCTION;
+      symbol_get_bfdsym (symbolP)->flags |= BSF_FUNCTION;
       type = SYMBOL_TYPE_SEC_PROG;
     }
 
@@ -4839,7 +4937,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
-  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,
@@ -4860,7 +4958,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));
-         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.  */
@@ -4872,7 +4972,9 @@ pa_type_args (symbolP, is_export)
          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.  */
@@ -4882,12 +4984,15 @@ pa_type_args (symbolP, is_export)
          *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
        {
-         as_bad ("Undefined .EXPORT/.IMPORT argument (ignored): %s", name);
+         as_bad (_("Undefined .EXPORT/.IMPORT argument (ignored): %s"), name);
          p = input_line_pointer;
          *p = c;
        }
@@ -4910,31 +5015,44 @@ pa_import (unused)
   name = input_line_pointer;
   c = get_symbol_end ();
 
-  symbol = symbol_find_or_make (name);
-  p = input_line_pointer;
-  *p = c;
-
-  if (!is_end_of_statement ())
+  symbol = symbol_find (name);
+  /* Ugh.  We might be importing a symbol defined earlier in the file,
+     in which case all the code below will really screw things up
+     (set the wrong segment, symbol flags & type, etc).  */
+  if (symbol == NULL || !S_IS_DEFINED (symbol))
     {
-      input_line_pointer++;
-      pa_type_args (symbol, 0);
+      symbol = symbol_find_or_make (name);
+      p = input_line_pointer;
+      *p = c;
+
+      if (!is_end_of_statement ())
+       {
+         input_line_pointer++;
+         pa_type_args (symbol, 0);
+       }
+      else
+       {
+         /* Sigh.  To be compatable with the HP assembler and to help
+            poorly written assembly code, we assign a type based on
+            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_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.  */
+         S_SET_SEGMENT (symbol, bfd_und_section_ptr);
+       }
     }
   else
     {
-      /* Sigh.  To be compatable with the HP assembler and to help
-         poorly written assembly code, we assign a type based on 
-         the the current segment.  Note only BSF_FUNCTION really
-         matters, we do not need to set the full SYMBOL_TYPE_* info here.  */
-      if (now_seg == text_section)
-       symbol->bsym->flags |= BSF_FUNCTION;
-
-      /* If the section is undefined, then the symbol is undefined
-         Since this is an import, leave the section undefined.  */
-      S_SET_SEGMENT (symbol, &bfd_und_section);
+      /* The symbol was already defined.  Just eat everything up to
+        the end of the current statement.  */
+      while (!is_end_of_statement ())
+       input_line_pointer++;
     }
 
   demand_empty_rest_of_line ();
-  return;
 }
 
 /* Handle a .LABEL pseudo-op.  */
@@ -4956,16 +5074,15 @@ pa_label (unused)
     }
   else
     {
-      as_warn ("Missing label name on .LABEL");
+      as_warn (_("Missing label name on .LABEL"));
     }
 
   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 ();
-  return;
 }
 
 /* Handle a .LEAVE pseudo-op.  This is not supported yet.  */
@@ -4974,7 +5091,48 @@ static void
 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.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.  */
@@ -4983,9 +5141,13 @@ static void
 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 ();
-  return;
 }
 
 /* Handle a .PARAM pseudo-op.  This is much like a .EXPORT, except it
@@ -5003,7 +5165,7 @@ pa_param (unused)
 
   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++;
@@ -5021,7 +5183,6 @@ pa_param (unused)
     }
 
   demand_empty_rest_of_line ();
-  return;
 }
 
 /* Handle a .PROC pseudo-op.  It is used to mark the beginning
@@ -5033,8 +5194,13 @@ pa_proc (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)
-    as_fatal ("Nested procedures");
+    as_fatal (_("Nested procedures"));
 
   /* Reset global variables for new procedure.  */
   callinfo_found = FALSE;
@@ -5044,9 +5210,9 @@ pa_proc (unused)
   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;
 
@@ -5066,8 +5232,6 @@ pa_proc (unused)
   call_info->ci_unwind.descriptor.cannot_unwind = 0;
   call_info->ci_unwind.descriptor.region_desc = 1;
   call_info->ci_unwind.descriptor.hpux_interrupt_marker = 0;
-  call_info->entry_sr = ~0;
-  call_info->makes_calls = 1;
 
   /* If we got a .PROC pseudo-op, we know that the function is defined
      locally.  Make sure it gets into the symbol table.  */
@@ -5079,20 +5243,19 @@ pa_proc (unused)
        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
-         as_bad ("Missing function name for .PROC (corrupted label)");
+         as_bad (_("Missing function name for .PROC (corrupted label chain)"));
       }
     else
-      as_bad ("Missing function name for .PROC");
+      last_call_info->start_symbol = NULL;
   }
 
   demand_empty_rest_of_line ();
-  return;
 }
 
-/* Process the syntatical end of a procedure.  Make sure all the 
+/* Process the syntatical end of a procedure.  Make sure all the
    appropriate pseudo-ops were found within the procedure.  */
 
 static void
@@ -5100,18 +5263,100 @@ pa_procend (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.
+
+     Note there's not need to diddle with the segment or fragment
+     for the label symbol in this case.  We have already switched
+     into the new $CODE$ subspace at this point.  */
+  if (within_procedure && last_call_info->start_symbol == NULL)
+    {
+      label_symbol_struct *label_symbol = pa_get_label ();
+
+      if (label_symbol)
+       {
+         if (label_symbol->lss_label)
+           {
+             last_call_info->start_symbol = label_symbol->lss_label;
+             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.  */
+             if (within_entry_exit)
+               {
+                 char *where = frag_more (0);
+
+                 fix_new_hppa (frag_now, where - frag_now->fr_literal, 0,
+                               NULL, (offsetT) 0, NULL,
+                               0, R_HPPA_ENTRY, e_fsel, 0, 0,
+                               (int *) &last_call_info->ci_unwind.descriptor);
+               }
+#endif
+           }
+         else
+           as_bad (_("Missing function name for .PROC (corrupted label chain)"));
+       }
+      else
+       as_bad (_("Missing function name for .PROC"));
+    }
+
   if (!within_procedure)
-    as_bad ("misplaced .procend");
+    as_bad (_("misplaced .procend"));
 
   if (!callinfo_found)
-    as_bad ("Missing .callinfo for this procedure");
+    as_bad (_("Missing .callinfo for this procedure"));
 
   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
+     the size of the function (apparently its needed in the symbol table).  */
+  hppa_elf_mark_end_of_function ();
+#endif
 
   within_procedure = FALSE;
   demand_empty_rest_of_line ();
-  return;
+  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,
@@ -5125,7 +5370,7 @@ pa_parse_space_stmt (space_name, create_flag)
 {
   char *name, *ptemp, c;
   char loadable, defined, private, sort;
-  int spnum;
+  int spnum, temp;
   asection *seg = NULL;
   sd_chain_struct *space;
 
@@ -5135,15 +5380,21 @@ pa_parse_space_stmt (space_name, create_flag)
   loadable = TRUE;
   defined = TRUE;
   private = FALSE;
-  if (strcasecmp (space_name, "$TEXT$") == 0)
+  if (strcmp (space_name, "$TEXT$") == 0)
     {
       seg = pa_def_spaces[0].segment;
+      defined = pa_def_spaces[0].defined;
+      private = pa_def_spaces[0].private;
       sort = pa_def_spaces[0].sort;
+      spnum = pa_def_spaces[0].spnum;
     }
-  else if (strcasecmp (space_name, "$PRIVATE$") == 0)
+  else if (strcmp (space_name, "$PRIVATE$") == 0)
     {
       seg = pa_def_spaces[1].segment;
+      defined = pa_def_spaces[1].defined;
+      private = pa_def_spaces[1].private;
       sort = pa_def_spaces[1].sort;
+      spnum = pa_def_spaces[1].spnum;
     }
 
   if (!is_end_of_statement ())
@@ -5151,10 +5402,14 @@ pa_parse_space_stmt (space_name, create_flag)
       print_errors = FALSE;
       ptemp = input_line_pointer + 1;
       /* First see if the space was specified as a number rather than
-         as a name.  According to the PA assembly manual the rest of 
+         as a name.  According to the PA assembly manual the rest of
          the line should be ignored.  */
-      if ((spnum = pa_parse_number (&ptemp, 0)) >= 0)
-       input_line_pointer = ptemp;
+      temp = pa_parse_number (&ptemp, 0);
+      if (temp >= 0)
+       {
+         spnum = temp;
+         input_line_pointer = ptemp;
+       }
       else
        {
          while (!is_end_of_statement ())
@@ -5162,36 +5417,36 @@ pa_parse_space_stmt (space_name, create_flag)
              input_line_pointer++;
              name = input_line_pointer;
              c = get_symbol_end ();
-             if ((strncasecmp (name, "SPNUM", 5) == 0))
+             if ((strncasecmp (name, "spnum", 5) == 0))
                {
                  *input_line_pointer = c;
                  input_line_pointer++;
                  spnum = get_absolute_expression ();
                }
-             else if ((strncasecmp (name, "SORT", 4) == 0))
+             else if ((strncasecmp (name, "sort", 4) == 0))
                {
                  *input_line_pointer = c;
                  input_line_pointer++;
                  sort = get_absolute_expression ();
                }
-             else if ((strncasecmp (name, "UNLOADABLE", 10) == 0))
+             else if ((strncasecmp (name, "unloadable", 10) == 0))
                {
                  *input_line_pointer = c;
                  loadable = FALSE;
                }
-             else if ((strncasecmp (name, "NOTDEFINED", 10) == 0))
+             else if ((strncasecmp (name, "notdefined", 10) == 0))
                {
                  *input_line_pointer = c;
                  defined = FALSE;
                }
-             else if ((strncasecmp (name, "PRIVATE", 7) == 0))
+             else if ((strncasecmp (name, "private", 7) == 0))
                {
                  *input_line_pointer = c;
                  private = TRUE;
                }
              else
                {
-                 as_bad ("Invalid .SPACE argument");
+                 as_bad (_("Invalid .SPACE argument"));
                  *input_line_pointer = c;
                  if (!is_end_of_statement ())
                    input_line_pointer++;
@@ -5205,7 +5460,7 @@ pa_parse_space_stmt (space_name, create_flag)
     seg = subseg_new (space_name, 0);
 
   /* If create_flag is nonzero, then create the new space with
-     the attributes computed above.  Else set the values in 
+     the attributes computed above.  Else set the values in
      an already existing space -- this can only happen for
      the first occurence of a built-in space.  */
   if (create_flag)
@@ -5215,12 +5470,8 @@ pa_parse_space_stmt (space_name, create_flag)
     {
       space = is_defined_space (space_name);
       SPACE_SPNUM (space) = spnum;
-      SPACE_LOADABLE (space) = loadable & 1;
       SPACE_DEFINED (space) = defined & 1;
       SPACE_USER_DEFINED (space) = 1;
-      SPACE_PRIVATE (space) = private & 1;
-      SPACE_SORT (space) = sort & 0xff;
-      space->sd_seg = seg;
     }
 
 #ifdef obj_set_section_attributes
@@ -5243,7 +5494,7 @@ pa_space (unused)
 
   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
@@ -5251,7 +5502,9 @@ pa_space (unused)
       /* Check for some of the predefined spaces.   FIXME: most of the code
          below is repeated several times, can we extract the common parts
          and place them into a subroutine or something similar?  */
-      if (strncasecmp (input_line_pointer, "$text$", 6) == 0)
+      /* FIXME Is this (and the next IF stmt) really right?
+        What if INPUT_LINE_POINTER points to "$TEXT$FOO"?  */
+      if (strncmp (input_line_pointer, "$TEXT$", 6) == 0)
        {
          input_line_pointer += 6;
          sd_chain = is_defined_space ("$TEXT$");
@@ -5268,7 +5521,7 @@ pa_space (unused)
          demand_empty_rest_of_line ();
          return;
        }
-      if (strncasecmp (input_line_pointer, "$private$", 9) == 0)
+      if (strncmp (input_line_pointer, "$PRIVATE$", 9) == 0)
        {
          input_line_pointer += 9;
          sd_chain = is_defined_space ("$PRIVATE$");
@@ -5316,7 +5569,7 @@ pa_space (unused)
       save_s = input_line_pointer;
       if ((temp = pa_parse_number (&input_line_pointer, 0)) >= 0)
        {
-         if (sd_chain = pa_find_space_by_number (temp))
+         if ((sd_chain = pa_find_space_by_number (temp)))
            {
              current_space = sd_chain;
 
@@ -5346,7 +5599,6 @@ pa_space (unused)
                                                  sd_chain->sd_last_subseg);
       demand_empty_rest_of_line ();
     }
-  return;
 }
 
 /* Switch to a new space.  (I think).  FIXME.  */
@@ -5369,51 +5621,35 @@ pa_spnum (unused)
       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 ();
-  return;
-}
-
-/* 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. 
+   given subspace, creating the new subspace if necessary.
 
-   FIXME.  Should mirror pa_space more closely, in particular how 
+   FIXME.  Should mirror pa_space more closely, in particular how
    they're broken up into subroutines.  */
 
 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;
 
+  if (current_space == NULL)
+    as_fatal (_("Must be in a space before changing or declaring subspaces.\n"));
+
   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
@@ -5433,19 +5669,22 @@ pa_subspace (unused)
       code_only = 0;
       zero = 0;
       space_index = ~0;
-      alignment = 0;
+      alignment = 1;
       quadrant = 0;
-      alias = NULL;
 
       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))
        {
          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;
        }
@@ -5468,8 +5707,6 @@ pa_subspace (unused)
                  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++;
@@ -5485,64 +5722,64 @@ pa_subspace (unused)
            {
              name = input_line_pointer;
              c = get_symbol_end ();
-             if ((strncasecmp (name, "QUAD", 4) == 0))
+             if ((strncasecmp (name, "quad", 4) == 0))
                {
                  *input_line_pointer = c;
                  input_line_pointer++;
                  quadrant = get_absolute_expression ();
                }
-             else if ((strncasecmp (name, "ALIGN", 5) == 0))
+             else if ((strncasecmp (name, "align", 5) == 0))
                {
                  *input_line_pointer = c;
                  input_line_pointer++;
                  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;
                    }
                }
-             else if ((strncasecmp (name, "ACCESS", 6) == 0))
+             else if ((strncasecmp (name, "access", 6) == 0))
                {
                  *input_line_pointer = c;
                  input_line_pointer++;
                  access = get_absolute_expression ();
                }
-             else if ((strncasecmp (name, "SORT", 4) == 0))
+             else if ((strncasecmp (name, "sort", 4) == 0))
                {
                  *input_line_pointer = c;
                  input_line_pointer++;
                  sort = get_absolute_expression ();
                }
-             else if ((strncasecmp (name, "CODE_ONLY", 9) == 0))
+             else if ((strncasecmp (name, "code_only", 9) == 0))
                {
                  *input_line_pointer = c;
                  code_only = 1;
                }
-             else if ((strncasecmp (name, "UNLOADABLE", 10) == 0))
+             else if ((strncasecmp (name, "unloadable", 10) == 0))
                {
                  *input_line_pointer = c;
                  loadable = 0;
                }
-             else if ((strncasecmp (name, "COMMON", 6) == 0))
+             else if ((strncasecmp (name, "common", 6) == 0))
                {
                  *input_line_pointer = c;
                  common = 1;
                }
-             else if ((strncasecmp (name, "DUP_COMM", 8) == 0))
+             else if ((strncasecmp (name, "dup_comm", 8) == 0))
                {
                  *input_line_pointer = c;
                  dup_common = 1;
                }
-             else if ((strncasecmp (name, "ZERO", 4) == 0))
+             else if ((strncasecmp (name, "zero", 4) == 0))
                {
                  *input_line_pointer = c;
                  zero = 1;
                }
-             else if ((strncasecmp (name, "FIRST", 5) == 0))
-               as_bad ("FIRST not supported as a .SUBSPACE argument");
+             else if ((strncasecmp (name, "first", 5) == 0))
+               as_bad (_("FIRST not supported as a .SUBSPACE argument"));
              else
-               as_bad ("Invalid .SUBSPACE argument");
+               as_bad (_("Invalid .SUBSPACE argument"));
              if (!is_end_of_statement ())
                input_line_pointer++;
            }
@@ -5559,33 +5796,31 @@ pa_subspace (unused)
       if (common || dup_common)
        flags |= SEC_IS_COMMON;
 
+      flags |= SEC_RELOC | SEC_HAS_CONTENTS;
+
       /* 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 
+      /* If this is an existing subspace, then we want to use the
          segment already associated with the subspace.
 
          FIXME NOW!  ELF BFD doesn't appear to be ready to deal with
          lots of sections.  It might be a problem in the PA ELF
          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;
-      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);
 
+      if (zero)
+       seg_info (section)->bss = 1;
+
       /* Now set the flags.  */
       bfd_set_section_flags (stdoutput, section, applicable);
 
@@ -5617,7 +5852,6 @@ pa_subspace (unused)
       subseg_set (current_subspace->ssd_seg, current_subspace->ssd_subseg);
     }
   SUBSPACE_DEFINED (current_subspace) = 1;
-  return;
 }
 
 
@@ -5637,10 +5871,7 @@ pa_spaces_begin ()
       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,
@@ -5660,58 +5891,78 @@ pa_spaces_begin ()
 
       /* 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);
 
 
       /* For SOM we want to replace the standard .text, .data, and .bss
-         sections with our own.  */
-      if (!strcmp (pa_def_subspaces[i].name, "$CODE$") && !USE_ALIASES)
+         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$"))
        {
          text_section = segment;
          applicable = bfd_applicable_section_flags (stdoutput);
-         bfd_set_section_flags (stdoutput, text_section,
+         bfd_set_section_flags (stdoutput, segment,
                                 applicable & (SEC_ALLOC | SEC_LOAD
                                               | SEC_RELOC | SEC_CODE
                                               | 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);
-         bfd_set_section_flags (stdoutput, data_section,
+         bfd_set_section_flags (stdoutput, segment,
                                 applicable & (SEC_ALLOC | SEC_LOAD
                                               | SEC_RELOC
                                               | SEC_HAS_CONTENTS));
 
 
        }
-      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, bss_section,
+         bfd_set_section_flags (stdoutput, segment,
                                 applicable & SEC_ALLOC);
        }
+      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 & (SEC_ALLOC | SEC_LOAD
+                                              | SEC_RELOC
+                                              | SEC_READONLY
+                                              | SEC_HAS_CONTENTS));
+       }
+      else if (!strcmp (pa_def_subspaces[i].name, "$UNWIND$"))
+       {
+         applicable = bfd_applicable_section_flags (stdoutput);
+         bfd_set_section_flags (stdoutput, segment,
+                                applicable & (SEC_ALLOC | SEC_LOAD
+                                              | SEC_RELOC
+                                              | SEC_READONLY
+                                              | SEC_HAS_CONTENTS));
+       }
 
       /* Find the space associated with this subspace.  */
       space = pa_segment_to_space (pa_def_spaces[pa_def_subspaces[i].
                                                 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);
        }
 
@@ -5734,20 +5985,17 @@ pa_spaces_begin ()
 
 
 /* Create a new space NAME, with the appropriate flags as defined
-   by the given parameters.
-
-   Add the new space to the space dictionary chain in numerical
-   order as defined by the SORT entries.  */
+   by the given parameters.  */
 
 static sd_chain_struct *
 create_new_space (name, spnum, loadable, defined, private,
                  sort, seg, user_defined)
      char *name;
      int spnum;
-     char loadable;
-     char defined;
-     char private;
-     char sort;
+     int loadable;
+     int defined;
+     int private;
+     int sort;
      asection *seg;
      int user_defined;
 {
@@ -5755,21 +6003,18 @@ create_new_space (name, spnum, loadable, defined, private,
 
   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);
   strcpy (SPACE_NAME (chain_entry), name);
-  SPACE_NAME_INDEX (chain_entry) = 0;
-  SPACE_LOADABLE (chain_entry) = loadable;
   SPACE_DEFINED (chain_entry) = defined;
   SPACE_USER_DEFINED (chain_entry) = user_defined;
-  SPACE_PRIVATE (chain_entry) = private;
   SPACE_SPNUM (chain_entry) = spnum;
-  SPACE_SORT (chain_entry) = sort;
 
   chain_entry->sd_seg = seg;
   chain_entry->sd_last_subseg = -1;
+  chain_entry->sd_subspaces = NULL;
   chain_entry->sd_next = NULL;
 
   /* Find spot for the new space based on its sort key.  */
@@ -5788,13 +6033,8 @@ create_new_space (name, spnum, loadable, defined, private,
 
       while (chain_pointer)
        {
-         if (SPACE_SORT (chain_pointer) <= SPACE_SORT (chain_entry))
-           {
-             prev_chain_pointer = chain_pointer;
-             chain_pointer = chain_pointer->sd_next;
-           }
-         else
-           break;
+         prev_chain_pointer = chain_pointer;
+         chain_pointer = chain_pointer->sd_next;
        }
 
       /* At this point we've found the correct place to add the new
@@ -5837,8 +6077,8 @@ create_new_subspace (space, name, loadable, code_only, common,
                     alignment, quadrant, seg)
      sd_chain_struct *space;
      char *name;
-     char loadable, code_only, common, dup_common, is_zero;
-     char sort;
+     int loadable, code_only, common, dup_common, is_zero;
+     int sort;
      int access;
      int space_index;
      int alignment;
@@ -5849,30 +6089,17 @@ create_new_subspace (space, name, loadable, code_only, common,
 
   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_ACCESS (chain_entry) = access;
-  SUBSPACE_LOADABLE (chain_entry) = loadable;
-  SUBSPACE_COMMON (chain_entry) = common;
-  SUBSPACE_DUP_COMM (chain_entry) = dup_common;
-  SUBSPACE_SORT (chain_entry) = sort;
-  SUBSPACE_CODE_ONLY (chain_entry) = code_only;
-  SUBSPACE_ALIGN (chain_entry) = alignment;
-  SUBSPACE_QUADRANT (chain_entry) = quadrant;
-  SUBSPACE_SUBSPACE_START (chain_entry) = pa_subspace_start (space, quadrant);
-  SUBSPACE_SPACE_INDEX (chain_entry) = space_index;
-  SUBSPACE_ZERO (chain_entry) = is_zero;
-
   /* Initialize subspace_defined.  When we hit a .subspace directive
      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_last_align = 1;
   chain_entry->ssd_next = NULL;
 
   /* Find spot for the new subspace based on its sort key.  */
@@ -5888,14 +6115,8 @@ create_new_subspace (space, name, loadable, code_only, common,
 
       while (chain_pointer)
        {
-         if (SUBSPACE_SORT (chain_pointer) <= SUBSPACE_SORT (chain_entry))
-           {
-             prev_chain_pointer = chain_pointer;
-             chain_pointer = chain_pointer->ssd_next;
-           }
-         else
-           break;
-
+         prev_chain_pointer = chain_pointer;
+         chain_pointer = chain_pointer->ssd_next;
        }
 
       /* Now we have somewhere to put the new entry.  Insert it and update
@@ -5918,7 +6139,6 @@ create_new_subspace (space, name, loadable, code_only, common,
 #endif
 
   return chain_entry;
-
 }
 
 /* Update the information for the given subspace based upon the
@@ -5929,12 +6149,12 @@ update_subspace (space, name, loadable, code_only, common, dup_common, sort,
                 zero, access, space_index, alignment, quadrant, section)
      sd_chain_struct *space;
      char *name;
-     char loadable;
-     char code_only;
-     char common;
-     char dup_common;
-     char zero;
-     char sort;
+     int loadable;
+     int code_only;
+     int common;
+     int dup_common;
+     int zero;
+     int sort;
      int access;
      int space_index;
      int alignment;
@@ -5943,21 +6163,7 @@ update_subspace (space, name, loadable, code_only, common, dup_common, sort,
 {
   ssd_chain_struct *chain_entry;
 
-  if ((chain_entry = is_defined_subspace (name)))
-    {
-      SUBSPACE_ACCESS (chain_entry) = access;
-      SUBSPACE_LOADABLE (chain_entry) = loadable;
-      SUBSPACE_COMMON (chain_entry) = common;
-      SUBSPACE_DUP_COMM (chain_entry) = dup_common;
-      SUBSPACE_CODE_ONLY (chain_entry) = 1;
-      SUBSPACE_SORT (chain_entry) = sort;
-      SUBSPACE_ALIGN (chain_entry) = alignment;
-      SUBSPACE_QUADRANT (chain_entry) = quadrant;
-      SUBSPACE_SPACE_INDEX (chain_entry) = space_index;
-      SUBSPACE_ZERO (chain_entry) = zero;
-    }
-  else
-    chain_entry = NULL;
+  chain_entry = is_defined_subspace (name);
 
 #ifdef obj_set_subsection_attributes
   obj_set_subsection_attributes (section, space->sd_seg, access,
@@ -5965,7 +6171,6 @@ update_subspace (space, name, loadable, code_only, common, dup_common, sort,
 #endif
 
   return chain_entry;
-
 }
 
 /* Return the space chain entry for the space with the name NAME or
@@ -5989,7 +6194,7 @@ is_defined_space (name)
   return NULL;
 }
 
-/* Find and return the space associated with the given seg.  If no mapping 
+/* Find and return the space associated with the given seg.  If no mapping
    from the given seg to a space is found, then return NULL.
 
    Unlike subspaces, the number of spaces is not expected to grow much,
@@ -6048,7 +6253,7 @@ is_defined_subspace (name)
 /* Find and return the subspace associated with the given seg.  If no
    mapping from the given seg to a subspace is found, then return NULL.
 
-   If we ever put each procedure/function within its own subspace 
+   If we ever put each procedure/function within its own subspace
    (to make life easier on the compiler and linker), then this will have
    to become more efficient.  */
 
@@ -6081,7 +6286,7 @@ pa_subsegment_to_subspace (seg, subseg)
   return NULL;
 }
 
-/* Given a number, try and find a space with the name number.  
+/* Given a number, try and find a space with the name number.
 
    Return a pointer to a space dictionary chain entry for the space
    that was found or NULL on failure.  */
@@ -6096,7 +6301,7 @@ pa_find_space_by_number (number)
        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;
     }
 
@@ -6114,12 +6319,13 @@ pa_subspace_start (space, quadrant)
 {
   /* FIXME.  Assumes everyone puts read/write data at 0x4000000, this
      is not correct for the PA OSF1 port.  */
-  if ((strcasecmp (SPACE_NAME (space), "$PRIVATE$") == 0) && quadrant == 1)
+  if ((strcmp (SPACE_NAME (space), "$PRIVATE$") == 0) && quadrant == 1)
     return 0x40000000;
   else if (space->sd_seg == data_section && quadrant == 1)
     return 0x40000000;
   else
     return 0;
+  return 0;
 }
 
 /* FIXME.  Needs documentation.  */
@@ -6131,8 +6337,9 @@ pa_next_subseg (space)
   space->sd_last_subseg++;
   return space->sd_last_subseg;
 }
+#endif
 
-/* Helper function for pa_stringer.  Used to find the end of 
+/* Helper function for pa_stringer.  Used to find the end of
    a string.  */
 
 static unsigned int
@@ -6140,6 +6347,12 @@ pa_stringer_aux (s)
      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 '\"':
@@ -6162,7 +6375,7 @@ pa_stringer (append_zero)
   int i;
 
   /* Preprocess the string to handle PA-specific escape sequences.
-     For example, \xDD where DD is a hexidecimal number should be 
+     For example, \xDD where DD is a hexidecimal number should be
      changed to \OOO where OOO is an octal number.  */
 
   /* Skip the opening quote.  */
@@ -6238,6 +6451,30 @@ pa_version (unused)
   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
+pa_copyright (unused)
+     int unused;
+{
+  obj_copyright (0);
+  pa_undefine_label ();
+}
+
 /* Just like a normal cons, but when finished we have to undefine
    the latest space label.  */
 
@@ -6255,19 +6492,15 @@ static void
 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);
+#endif
   s_data (0);
   pa_undefine_label ();
 }
 
-/* FIXME.  What's the purpose of this pseudo-op?  */
-
-static void
-pa_desc (unused)
-     int unused;
-{
-  pa_undefine_label ();
-}
-
 /* Like float_cons, but we need to undefine our label.  */
 
 static void
@@ -6284,6 +6517,11 @@ static void
 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 ();
 }
@@ -6294,6 +6532,11 @@ static void
 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 ();
 }
@@ -6304,29 +6547,55 @@ static void
 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 ();
 }
 
-/* Switch to the text space.  Like s_text, but delete our 
+/* Switch to the text space.  Like s_text, but delete our
    label when finished.  */
 static void
 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);
+#endif
+
   s_text (0);
   pa_undefine_label ();
 }
 
-/* On the PA relocations which involve function symbols must not be 
+/* On the PA relocations which involve function symbols must not be
    adjusted.  This so that the linker can know when/how to create argument
    relocation stubs for indirect calls and calls to static functions.
 
-   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.  */
+   "T" field selectors create DLT relative fixups for accessing
+   globals and statics in PIC code; each DLT relative fixup creates
+   an entry in the DLT table.  The entries contain the address of
+   the final target (eg accessing "foo" would create a DLT entry
+   with the address of "foo").
+
+   Unfortunately, the HP linker doesn't take into account any addend
+   when generating the DLT; so accessing $LIT$+8 puts the address of
+   $LIT$ into the DLT rather than the address of $LIT$+8.
+
+   The end result is we can't perform relocation symbol reductions for
+   any fixup which creates entries in the DLT (eg they use "T" field
+   selectors).
+
+   Reject reductions involving symbols with external scope; such
+   reductions make life a living hell for object file editors. 
+
+   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)
@@ -6334,194 +6603,171 @@ hppa_fix_adjustable (fixp)
 {
   struct hppa_fix_struct *hppa_fix;
 
-  hppa_fix = fixp->tc_fix_data;
+  hppa_fix = (struct hppa_fix_struct *) fixp->tc_fix_data;
 
+#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_addsy == 0
-      || (fixp->fx_addsy->bsym->flags & BSF_FUNCTION) == 0)
-    return 1;
-
-  return 0;
-}
-
-/* Now for some ELF specific code.  FIXME.  */
-#ifdef OBJ_ELF
-static symext_chainS *symext_rootP;
-static symext_chainS *symext_lastP;
-
-/* Do any symbol processing requested by the target-cpu or target-format.  */
-
-void
-hppa_tc_symbol (abfd, symbolP, sym_idx)
-     bfd *abfd;
-     elf_symbol_type *symbolP;
-     int sym_idx;
-{
-  symext_chainS *symextP;
-  unsigned int arg_reloc;
-
-  /* Only functions can have argument relocations.  */
-  if (!(symbolP->symbol.flags & BSF_FUNCTION))
-    return;
+  /* Reject reductions of symbols in sym1-sym2 expressions when
+     the fixup will occur in a CODE subspace. 
 
-  arg_reloc = symbolP->tc_data.hppa_arg_reloc;
-
-  /* If there are no argument relocation bits, then no relocation is
-     necessary.  Do not add this to the symextn section.  */
-  if (arg_reloc == 0)
-    return;
-
-  symextP = (symext_chainS *) bfd_alloc (abfd, sizeof (symext_chainS) * 2);
-
-  symextP[0].entry = ELF32_HPPA_SX_WORD (HPPA_SXT_SYMNDX, sym_idx);
-  symextP[0].next = &symextP[1];
-
-  symextP[1].entry = ELF32_HPPA_SX_WORD (HPPA_SXT_ARG_RELOC, arg_reloc);
-  symextP[1].next = NULL;
-
-  if (symext_rootP == NULL)
-    {
-      symext_rootP = &symextP[0];
-      symext_lastP = &symextP[1];
-    }
-  else
+     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))
     {
-      symext_lastP->next = &symextP[0];
-      symext_lastP = &symextP[1];
+      /* Apparently sy_used_in_reloc never gets set for sub symbols.  */
+      symbol_mark_used_in_reloc (fixp->fx_subsy);
+      return 0;
     }
-}
-
-/* Make sections needed by the target cpu and/or target format.  */
-void
-hppa_tc_make_sections (abfd)
-     bfd *abfd;
-{
-  symext_chainS *symextP;
-  int size, n;
-  asection *symextn_sec;
-  segT save_seg = now_seg;
-  subsegT save_subseg = now_subseg;
-
-  /* Build the symbol extension section.  */
-  hppa_tc_make_symextn_section ();
 
-  /* Force some calculation to occur.  */
-  bfd_set_section_contents (stdoutput, stdoutput->sections, "", 0, 0);
-
-  hppa_elf_stub_finish (abfd);
+  /* 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
 
-  /* If no symbols for the symbol extension section, then stop now.  */
-  if (symext_rootP == NULL)
-    return;
+  /* 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
+      || 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;
 
-  /* Count the number of symbols for the symbol extension section.  */
-  for (n = 0, symextP = symext_rootP; symextP; symextP = symextP->next, ++n)
-    ;
+  if (fixp->fx_addsy && S_IS_EXTERNAL (fixp->fx_addsy))
+    return 0;
 
-  size = sizeof (symext_entryS) * n;
+  /* Reject absolute calls (jumps).  */
+  if (hppa_fix->fx_r_type == R_HPPA_ABS_CALL)
+    return 0;
 
-  /* Switch to the symbol extension section.  */
-  symextn_sec = subseg_new (SYMEXTN_SECTION_NAME, 0);
+  /* Reject reductions of function symbols.  */
+  if (fixp->fx_addsy == 0 || ! S_IS_FUNCTION (fixp->fx_addsy))
+    return 1;
 
-  frag_wane (frag_now);
-  frag_new (0);
+  return 0;
+}
 
-  for (symextP = symext_rootP; symextP; symextP = symextP->next)
-    {
-      char *ptr;
-      int *symtab_map = elf_sym_extra (abfd);
-      int idx;
+/* Return nonzero if the fixup in FIXP will require a relocation,
+   even it if appears that the fixup could be completely handled
+   within GAS.  */
 
-      /* First, patch the symbol extension record to reflect the true
-         symbol table index.  */
+int
+hppa_force_relocation (fixp)
+     fixS *fixp;
+{
+  struct hppa_fix_struct *hppa_fixp;
+  int distance;
 
-      if (ELF32_HPPA_SX_TYPE (symextP->entry) == HPPA_SXT_SYMNDX)
-       {
-         idx = ELF32_HPPA_SX_VAL (symextP->entry) - 1;
-         symextP->entry = ELF32_HPPA_SX_WORD (HPPA_SXT_SYMNDX,
-                                              symtab_map[idx]);
-       }
+  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
+      || 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
 
-      ptr = frag_more (sizeof (symextP->entry));
-      md_number_to_chars (ptr, symextP->entry, sizeof (symextP->entry));
-    }
+#define arg_reloc_stub_needed(CALLER, CALLEE) \
+  ((CALLEE) && (CALLER) && ((CALLEE) != (CALLER)))
 
-  frag_now->fr_fix = obstack_next_free (&frags) - frag_now->fr_literal;
-  frag_wane (frag_now);
+#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
+      && (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;
 
-  /* Switch back to the original segment.  */
-  subseg_set (save_seg, save_subseg);
+  if (fixp->fx_r_type == R_HPPA_ABS_CALL)
+    return 1;
+#undef arg_reloc_stub_needed
 
-  return;
+  /* No need (yet) to force another relocations to be emitted.  */
+  return 0;
 }
 
-/* Make the symbol extension section.  */
+/* Now for some ELF specific code.  FIXME.  */
+#ifdef OBJ_ELF
+/* Mark the end of a function so that it's possible to compute
+   the size of the function in hppa_elf_final_processing.  */
 
 static void
-hppa_tc_make_symextn_section ()
+hppa_elf_mark_end_of_function ()
 {
-  if (symext_rootP)
+  /* ELF does not have EXIT relocations.  All we do is create a
+     temporary symbol marking the end of the function.  */
+  char *name = (char *)
+    xmalloc (strlen ("L$\001end_") +
+            strlen (S_GET_NAME (last_call_info->start_symbol)) + 1);
+
+  if (name)
     {
-      symext_chainS *symextP;
-      int n;
-      unsigned int size;
-      segT symextn_sec;
-      segT save_seg = now_seg;
-      subsegT save_subseg = now_subseg;
+      symbolS *symbolP;
 
-      for (n = 0, symextP = symext_rootP; symextP; symextP = symextP->next, ++n)
-       ;
+      strcpy (name, "L$\001end_");
+      strcat (name, S_GET_NAME (last_call_info->start_symbol));
 
-      size = sizeof (symext_entryS) * n;
+      /* If we have a .exit followed by a .procend, then the
+        symbol will have already been defined.  */
+      symbolP = symbol_find (name);
+      if (symbolP)
+       {
+         /* The symbol has already been defined!  This can
+            happen if we have a .exit followed by a .procend.
 
-      symextn_sec = subseg_new (SYMEXTN_SECTION_NAME, 0);
+            This is *not* an error.  All we want to do is free
+            the memory we just allocated for the name and continue.  */
+         xfree (name);
+       }
+      else
+       {
+         /* symbol value should be the offset of the
+            last instruction of the function */
+         symbolP = symbol_new (name, now_seg, (valueT) (frag_now_fix () - 4),
+                               frag_now);
+
+         assert (symbolP);
+         S_CLEAR_EXTERNAL (symbolP);
+         symbol_table_insert (symbolP);
+       }
 
-      bfd_set_section_flags (stdoutput, symextn_sec,
-                            SEC_LOAD | SEC_HAS_CONTENTS | SEC_DATA);
-      bfd_set_section_size (stdoutput, symextn_sec, size);
+      if (symbolP)
+       last_call_info->end_symbol = symbolP;
+      else
+       as_bad (_("Symbol '%s' could not be created."), name);
 
-      /* Now, switch back to the original segment.  */
-      subseg_set (save_seg, save_subseg);
     }
-}
-
-/* Build the symbol extension section.  */
-
-static void
-pa_build_symextn_section ()
-{
-  segT seg;
-  asection *save_seg = now_seg;
-  subsegT subseg = (subsegT) 0;
-  subsegT save_subseg = now_subseg;
-
-  seg = subseg_new (".hppa_symextn", subseg);
-  bfd_set_section_flags (stdoutput,
-                        seg,
-                        SEC_HAS_CONTENTS | SEC_READONLY
-                        | SEC_ALLOC | SEC_LOAD);
-
-  subseg_set (save_seg, save_subseg);
+  else
+    as_bad (_("No memory for symbol name."));
 
 }
 
 /* For ELF, this function serves one purpose:  to setup the st_size
    field of STT_FUNC symbols.  To do this, we need to scan the
-   call_info structure list, determining st_size in one of two possible
-   ways:
-
-   1. call_info->start_frag->fr_fix has the size of the fragment.
-   This approach assumes that the function was built into a
-   single fragment.  This works for most cases, but might fail.
-   For example, if there was a segment change in the middle of
-   the function.
-
-   2. The st_size field is the difference in the addresses of the
-   call_info->start_frag->fr_address field and the fr_address
-   field of the next fragment with fr_type == rs_fill and
-   fr_fix != 0.  */
+   call_info structure list, determining st_size in by taking the
+   difference in the address of the beginning/end marker symbols.  */
 
 void
 elf_hppa_final_processing ()
@@ -6533,7 +6779,8 @@ elf_hppa_final_processing ()
        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;
This page took 0.097111 seconds and 4 git commands to generate.