Add support for 9_PCREL and 12_PCREL relocs.
[deliverable/binutils-gdb.git] / bfd / som.c
index 8531a5b91ab33c358b4d5e35ea91d8ee3762fe7f..ffdbf69886dad7c0951dc7a139cbf6b6d1cfac29 100644 (file)
--- a/bfd/som.c
+++ b/bfd/som.c
@@ -1,5 +1,6 @@
 /* bfd back-end for HP PA-RISC SOM objects.
-   Copyright (C) 1990, 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
+   Copyright (C) 1990, 91, 92, 93, 94, 95, 96, 97, 1998
+   Free Software Foundation, Inc.
 
    Contributed by the Center for Software Science at the
    University of Utah (pa-gdb-bugs@cs.utah.edu).
@@ -18,7 +19,8 @@
 
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+   02111-1307, USA.  */
 
 #include "bfd.h"
 #include "sysdep.h"
 #include "libbfd.h"
 #include "som.h"
 
-#include <stdio.h>
-#include <sys/types.h>
 #include <sys/param.h>
 #include <signal.h>
 #include <machine/reg.h>
 #include <sys/file.h>
-#include <errno.h>
+#include <ctype.h>
 
 /* Magic not defined in standard HP-UX header files until 8.0 */
 
 #define CPU_PA_RISC1_1 0x210
 #endif /* CPU_PA_RISC1_1 */
 
+#ifndef CPU_PA_RISC2_0
+#define CPU_PA_RISC2_0 0x214
+#endif /* CPU_PA_RISC2_0 */
+
 #ifndef _PA_RISC1_0_ID
 #define _PA_RISC1_0_ID CPU_PA_RISC1_0
 #endif /* _PA_RISC1_0_ID */
 #define _PA_RISC1_1_ID CPU_PA_RISC1_1
 #endif /* _PA_RISC1_1_ID */
 
+#ifndef _PA_RISC2_0_ID
+#define _PA_RISC2_0_ID CPU_PA_RISC2_0
+#endif /* _PA_RISC2_0_ID */
+
 #ifndef _PA_RISC_MAXID
 #define _PA_RISC_MAXID 0x2FF
 #endif /* _PA_RISC_MAXID */
@@ -166,10 +174,14 @@ static asymbol * som_make_empty_symbol PARAMS ((bfd *));
 static void som_print_symbol PARAMS ((bfd *, PTR,
                                      asymbol *, bfd_print_symbol_type));
 static boolean som_new_section_hook PARAMS ((bfd *, asection *));
+static boolean som_bfd_copy_private_symbol_data PARAMS ((bfd *, asymbol *,
+                                                         bfd *, asymbol *));
 static boolean som_bfd_copy_private_section_data PARAMS ((bfd *, asection *,
                                                          bfd *, asection *));
 static boolean som_bfd_copy_private_bfd_data PARAMS ((bfd *, bfd *));
-static boolean som_bfd_is_local_label PARAMS ((bfd *, asymbol *));
+#define som_bfd_merge_private_bfd_data _bfd_generic_bfd_merge_private_bfd_data
+#define som_bfd_set_private_flags _bfd_generic_bfd_set_private_flags
+static boolean som_bfd_is_local_label_name PARAMS ((bfd *, const char *));
 static boolean som_set_section_contents PARAMS ((bfd *, sec_ptr, PTR,
                                                 file_ptr, bfd_size_type));
 static boolean som_get_section_contents PARAMS ((bfd *, sec_ptr, PTR,
@@ -212,10 +224,11 @@ static unsigned char * som_reloc_call PARAMS ((bfd *, unsigned char *,
 static unsigned long som_count_spaces PARAMS ((bfd *));
 static unsigned long som_count_subspaces PARAMS ((bfd *));
 static int compare_syms PARAMS ((const void *, const void *));
+static int compare_subspaces PARAMS ((const void *, const void *));
 static unsigned long som_compute_checksum PARAMS ((bfd *));
 static boolean som_prep_headers PARAMS ((bfd *));
 static int som_sizeof_headers PARAMS ((bfd *, boolean));
-static boolean som_write_headers PARAMS ((bfd *));
+static boolean som_finish_writing PARAMS ((bfd *));
 static boolean som_build_and_write_symbol_table PARAMS ((bfd *));
 static void som_prep_for_fixups PARAMS ((bfd *, asymbol **, unsigned long));
 static boolean som_write_fixups PARAMS ((bfd *, unsigned long, unsigned int *));
@@ -225,7 +238,7 @@ static boolean som_write_symbol_strings PARAMS ((bfd *, unsigned long,
                                                 asymbol **, unsigned int,
                                                 unsigned *));
 static boolean som_begin_writing PARAMS ((bfd *));
-static const reloc_howto_type * som_bfd_reloc_type_lookup
+static reloc_howto_type * som_bfd_reloc_type_lookup
        PARAMS ((bfd *, bfd_reloc_code_real_type));
 static char som_section_type PARAMS ((const char *));
 static int som_decode_symclass PARAMS ((asymbol *));
@@ -244,12 +257,13 @@ static boolean som_bfd_prep_for_ar_write PARAMS ((bfd *, unsigned int *,
 static unsigned int som_bfd_ar_symbol_hash PARAMS ((asymbol *));
 static boolean som_bfd_ar_write_symbol_stuff PARAMS ((bfd *, unsigned int,
                                                      unsigned int,
-                                                     struct lst_header));
-static CONST char *normalize PARAMS ((CONST char *file));
+                                                     struct lst_header,
+                                                     unsigned int));
 static boolean som_is_space PARAMS ((asection *));
 static boolean som_is_subspace PARAMS ((asection *));
 static boolean som_is_container PARAMS ((asection *, asection *));
 static boolean som_bfd_free_cached_info PARAMS ((bfd *));
+static boolean som_bfd_link_split_section PARAMS ((bfd *, asection *));
        
 /* Map SOM section names to POSIX/BSD single-character symbol types.
 
@@ -423,8 +437,9 @@ static const struct fixup_format som_fixup_formats[256] =
   1,    "Lb4*=Mb1+L*=",        /* 0x2b */
   2,    "Lb4*=Md1+4*=",        /* 0x2c */
   3,    "Ld1+=Me1+=",  /* 0x2d */
-  /* R_RESERVED */
+  /* R_SHORT_PCREL_MODE */
   0,           "",             /* 0x2e */
+  /* R_LONG_PCREL_MODE */
   0,           "",             /* 0x2f */
   /* R_PCREL_CALL */
   0,    "L4=RD=Sb=",   /* 0x30 */
@@ -630,14 +645,21 @@ static const struct fixup_format som_fixup_formats[256] =
   1,    "P",           /* 0xd4 */
   2,    "P",           /* 0xd5 */
   3,    "P",           /* 0xd6 */
-  /* R_RESERVED */
+  /* R_SEC_STMT */
   0,   "",             /* 0xd7 */
+  /* R_N0SEL */
   0,   "",             /* 0xd8 */
+  /* R_N1SEL */
   0,   "",             /* 0xd9 */
+  /* R_LINETAB */
   0,   "",             /* 0xda */
+  /* R_LINETAB_ESC */
   0,   "",             /* 0xdb */
+  /* R_LTP_OVERRIDE */
   0,   "",             /* 0xdc */
+  /* R_COMMENT */
   0,   "",             /* 0xdd */
+  /* R_RESERVED */
   0,   "",             /* 0xde */
   0,   "",             /* 0xdf */
   0,   "",             /* 0xe0 */
@@ -712,7 +734,7 @@ static const int comp3_opcodes[] =
   -1
 };
 
-/* These apparently are not in older versions of hpux reloc.h.  */
+/* These apparently are not in older versions of hpux reloc.h (hpux7).  */
 #ifndef R_DLT_REL
 #define R_DLT_REL 0x78
 #endif
@@ -725,6 +747,39 @@ static const int comp3_opcodes[] =
 #define R_SEC_STMT 0xd7
 #endif
 
+/* And these first appeared in hpux10.  */
+#ifndef R_SHORT_PCREL_MODE
+#define R_SHORT_PCREL_MODE 0x3e
+#endif
+
+#ifndef R_LONG_PCREL_MODE
+#define R_LONG_PCREL_MODE 0x3f
+#endif
+
+#ifndef R_N0SEL
+#define R_N0SEL 0xd8
+#endif
+
+#ifndef R_N1SEL
+#define R_N1SEL 0xd9
+#endif
+
+#ifndef R_LINETAB
+#define R_LINETAB 0xda
+#endif
+
+#ifndef R_LINETAB_ESC
+#define R_LINETAB_ESC 0xdb
+#endif
+
+#ifndef R_LTP_OVERRIDE
+#define R_LTP_OVERRIDE 0xdc
+#endif
+
+#ifndef R_COMMENT
+#define R_COMMENT 0xdd
+#endif
+
 static reloc_howto_type som_hppa_howto_table[] =
 {
   {R_NO_RELOCATION, 0, 0, 32, false, 0, 0, hppa_som_reloc, "R_NO_RELOCATION"},
@@ -789,8 +844,8 @@ static reloc_howto_type som_hppa_howto_table[] =
   {R_PCREL_CALL, 0, 0, 32, false, 0, 0, hppa_som_reloc, "R_PCREL_CALL"},
   {R_PCREL_CALL, 0, 0, 32, false, 0, 0, hppa_som_reloc, "R_PCREL_CALL"},
   {R_PCREL_CALL, 0, 0, 32, false, 0, 0, hppa_som_reloc, "R_PCREL_CALL"},
-  {R_RESERVED, 0, 0, 32, false, 0, 0, hppa_som_reloc, "R_RESERVED"},
-  {R_RESERVED, 0, 0, 32, false, 0, 0, hppa_som_reloc, "R_RESERVED"},
+  {R_SHORT_PCREL_MODE, 0, 0, 32, false, 0, 0, hppa_som_reloc, "R_SHORT_PCREL_MODE"},
+  {R_LONG_PCREL_MODE, 0, 0, 32, false, 0, 0, hppa_som_reloc, "R_LONG_PCREL_MODE"},
   {R_ABS_CALL, 0, 0, 32, false, 0, 0, hppa_som_reloc, "R_ABS_CALL"},
   {R_ABS_CALL, 0, 0, 32, false, 0, 0, hppa_som_reloc, "R_ABS_CALL"},
   {R_ABS_CALL, 0, 0, 32, false, 0, 0, hppa_som_reloc, "R_ABS_CALL"},
@@ -943,12 +998,12 @@ static reloc_howto_type som_hppa_howto_table[] =
   {R_PREV_FIXUP, 0, 0, 32, false, 0, 0, hppa_som_reloc, "R_PREV_FIXUP"},
   {R_PREV_FIXUP, 0, 0, 32, false, 0, 0, hppa_som_reloc, "R_PREV_FIXUP"},
   {R_SEC_STMT, 0, 0, 32, false, 0, 0, hppa_som_reloc, "R_SEC_STMT"},
-  {R_RESERVED, 0, 0, 32, false, 0, 0, hppa_som_reloc, "R_RESERVED"},
-  {R_RESERVED, 0, 0, 32, false, 0, 0, hppa_som_reloc, "R_RESERVED"},
-  {R_RESERVED, 0, 0, 32, false, 0, 0, hppa_som_reloc, "R_RESERVED"},
-  {R_RESERVED, 0, 0, 32, false, 0, 0, hppa_som_reloc, "R_RESERVED"},
-  {R_RESERVED, 0, 0, 32, false, 0, 0, hppa_som_reloc, "R_RESERVED"},
-  {R_RESERVED, 0, 0, 32, false, 0, 0, hppa_som_reloc, "R_RESERVED"},
+  {R_N0SEL, 0, 0, 32, false, 0, 0, hppa_som_reloc, "R_N0SEL"},
+  {R_N1SEL, 0, 0, 32, false, 0, 0, hppa_som_reloc, "R_N1SEL"},
+  {R_LINETAB, 0, 0, 32, false, 0, 0, hppa_som_reloc, "R_LINETAB"},
+  {R_LINETAB_ESC, 0, 0, 32, false, 0, 0, hppa_som_reloc, "R_LINETAB_ESC"},
+  {R_LTP_OVERRIDE, 0, 0, 32, false, 0, 0, hppa_som_reloc, "R_LTP_OVERRIDE"},
+  {R_COMMENT, 0, 0, 32, false, 0, 0, hppa_som_reloc, "R_COMMENT"},
   {R_RESERVED, 0, 0, 32, false, 0, 0, hppa_som_reloc, "R_RESERVED"},
   {R_RESERVED, 0, 0, 32, false, 0, 0, hppa_som_reloc, "R_RESERVED"},
   {R_RESERVED, 0, 0, 32, false, 0, 0, hppa_som_reloc, "R_RESERVED"},
@@ -1390,21 +1445,20 @@ hppa_som_reloc (abfd, reloc_entry, symbol_in, data,
    and a field selector, return one or more appropriate SOM relocations.  */
 
 int **
-hppa_som_gen_reloc_type (abfd, base_type, format, field)
+hppa_som_gen_reloc_type (abfd, base_type, format, field, sym_diff, sym)
      bfd *abfd;
      int base_type;
      int format;
      enum hppa_reloc_field_selector_type_alt field;
+     int sym_diff;
+     asymbol *sym;
 {
   int *final_type, **final_types;
 
-  final_types = (int **) bfd_alloc_by_size_t (abfd, sizeof (int *) * 3);
-  final_type = (int *) bfd_alloc_by_size_t (abfd, sizeof (int));
+  final_types = (int **) bfd_alloc (abfd, sizeof (int *) * 6);
+  final_type = (int *) bfd_alloc (abfd, sizeof (int));
   if (!final_types || !final_type)
-    {
-      bfd_set_error (bfd_error_no_memory);
-      return NULL;
-    }
+    return NULL;
 
   /* The field selector may require additional relocations to be 
      generated.  It's impossible to know at this moment if additional
@@ -1426,12 +1480,9 @@ hppa_som_gen_reloc_type (abfd, base_type, format, field)
       case e_tsel:
       case e_ltsel:
       case e_rtsel:
-       final_types[0] = (int *) bfd_alloc_by_size_t (abfd, sizeof (int));
+       final_types[0] = (int *) bfd_alloc (abfd, sizeof (int));
        if (!final_types[0])
-         {
-           bfd_set_error (bfd_error_no_memory);
-           return NULL;
-         }
+         return NULL;
        if (field == e_tsel)
          *final_types[0] = R_FSEL;
        else if (field == e_ltsel)
@@ -1445,12 +1496,9 @@ hppa_som_gen_reloc_type (abfd, base_type, format, field)
 
       case e_lssel:
       case e_rssel:
-       final_types[0] = (int *) bfd_alloc_by_size_t (abfd, sizeof (int));
+       final_types[0] = (int *) bfd_alloc (abfd, sizeof (int));
        if (!final_types[0])
-         {
-           bfd_set_error (bfd_error_no_memory);
-           return NULL;
-         }
+         return NULL;
        *final_types[0] = R_S_MODE;
        final_types[1] = final_type;
        final_types[2] = NULL;
@@ -1459,12 +1507,9 @@ hppa_som_gen_reloc_type (abfd, base_type, format, field)
 
       case e_lsel:
       case e_rsel:
-       final_types[0] = (int *) bfd_alloc_by_size_t (abfd, sizeof (int));
+       final_types[0] = (int *) bfd_alloc (abfd, sizeof (int));
        if (!final_types[0])
-         {
-           bfd_set_error (bfd_error_no_memory);
-           return NULL;
-         }
+         return NULL;
        *final_types[0] = R_N_MODE;
        final_types[1] = final_type;
        final_types[2] = NULL;
@@ -1473,12 +1518,9 @@ hppa_som_gen_reloc_type (abfd, base_type, format, field)
 
       case e_ldsel:
       case e_rdsel:
-       final_types[0] = (int *) bfd_alloc_by_size_t (abfd, sizeof (int));
+       final_types[0] = (int *) bfd_alloc (abfd, sizeof (int));
        if (!final_types[0])
-         {
-           bfd_set_error (bfd_error_no_memory);
-           return NULL;
-         }
+         return NULL;
        *final_types[0] = R_D_MODE;
        final_types[1] = final_type;
        final_types[2] = NULL;
@@ -1487,24 +1529,75 @@ hppa_som_gen_reloc_type (abfd, base_type, format, field)
 
       case e_lrsel:
       case e_rrsel:
-       final_types[0] = (int *) bfd_alloc_by_size_t (abfd, sizeof (int));
+       final_types[0] = (int *) bfd_alloc (abfd, sizeof (int));
        if (!final_types[0])
-         {
-           bfd_set_error (bfd_error_no_memory);
-           return NULL;
-         }
+         return NULL;
        *final_types[0] = R_R_MODE;
        final_types[1] = final_type;
        final_types[2] = NULL;
        *final_type = base_type;
        break;
+
+      case e_nsel:
+       final_types[0] = (int *) bfd_alloc (abfd, sizeof (int));
+       if (!final_types[0])
+         return NULL;
+       *final_types[0] = R_N1SEL;
+       final_types[1] = final_type;
+       final_types[2] = NULL;
+       *final_type = base_type;
+       break;
+
+      case e_nlsel:
+      case e_nlrsel:
+       final_types[0] = (int *) bfd_alloc (abfd, sizeof (int));
+       if (!final_types[0])
+         return NULL;
+       *final_types[0] = R_N0SEL;
+       final_types[1] = (int *) bfd_alloc (abfd, sizeof (int));
+       if (!final_types[1])
+         return NULL;
+       if (field == e_nlsel)
+         *final_types[1] = R_N_MODE;
+       else
+         *final_types[1] = R_R_MODE;
+       final_types[2] = final_type;
+       final_types[3] = NULL;
+       *final_type = base_type;
+       break;
     }
   
   switch (base_type)
     {
     case R_HPPA:
+      /* The difference of two symbols needs *very* special handling.  */
+      if (sym_diff)
+       {
+         final_types[0] = (int *)bfd_alloc (abfd, sizeof (int));
+         final_types[1] = (int *)bfd_alloc (abfd, sizeof (int));
+         final_types[2] = (int *)bfd_alloc (abfd, sizeof (int));
+         final_types[3] = (int *)bfd_alloc (abfd, sizeof (int));
+         if (!final_types[0] || !final_types[1] || !final_types[2])
+            return NULL;
+         if (field == e_fsel)
+           *final_types[0] = R_FSEL;
+         else if (field == e_rsel)
+           *final_types[0] = R_RSEL;
+         else if (field == e_lsel)
+           *final_types[0] = R_LSEL;
+         *final_types[1] = R_COMP2;
+         *final_types[2] = R_COMP2;
+         *final_types[3] = R_COMP1;
+         final_types[4] = final_type;
+         if (format == 32)
+           *final_types[4] = R_DATA_EXPR;
+         else
+           *final_types[4] = R_CODE_EXPR;
+         final_types[5] = NULL;
+         break;
+       }
       /* PLABELs get their own relocation type.  */
-      if (field == e_psel
+      else if (field == e_psel
          || field == e_lpsel
          || field == e_rpsel)
        {
@@ -1522,10 +1615,33 @@ hppa_som_gen_reloc_type (abfd, base_type, format, field)
        *final_type = R_DLT_REL;
       /* A relocation in the data space is always a full 32bits.  */
       else if (format == 32)
-       *final_type = R_DATA_ONE_SYMBOL;
+       {
+         *final_type = R_DATA_ONE_SYMBOL;
+
+         /* If there's no SOM symbol type associated with this BFD
+            symbol, then set the symbol type to ST_DATA.
+
+            Only do this if the type is going to default later when
+            we write the object file.
 
+            This is done so that the linker never encounters an
+            R_DATA_ONE_SYMBOL reloc involving an ST_CODE symbol.
+
+            This allows the compiler to generate exception handling
+            tables.
+
+            Note that one day we may need to also emit BEGIN_BRTAB and
+            END_BRTAB to prevent the linker from optimizing away insns
+            in exception handling regions.  */
+         if (som_symbol_data (sym)->som_type == SYMBOL_TYPE_UNKNOWN
+             && (sym->flags & BSF_SECTION_SYM) == 0
+             && (sym->flags & BSF_FUNCTION) == 0
+             && ! bfd_is_com_section (sym->section))
+           som_symbol_data (sym)->som_type = SYMBOL_TYPE_DATA;
+       }
       break;
 
+
     case R_HPPA_GOTOFF:
       /* More PLABEL special cases.  */
       if (field == e_psel
@@ -1534,6 +1650,36 @@ hppa_som_gen_reloc_type (abfd, base_type, format, field)
        *final_type = R_DATA_PLABEL;
       break;
 
+    case R_HPPA_COMPLEX:
+      /* The difference of two symbols needs *very* special handling.  */
+      if (sym_diff)
+       {
+         final_types[0] = (int *)bfd_alloc (abfd, sizeof (int));
+         final_types[1] = (int *)bfd_alloc (abfd, sizeof (int));
+         final_types[2] = (int *)bfd_alloc (abfd, sizeof (int));
+         final_types[3] = (int *)bfd_alloc (abfd, sizeof (int));
+         if (!final_types[0] || !final_types[1] || !final_types[2])
+            return NULL;
+         if (field == e_fsel)
+           *final_types[0] = R_FSEL;
+         else if (field == e_rsel)
+           *final_types[0] = R_RSEL;
+         else if (field == e_lsel)
+           *final_types[0] = R_LSEL;
+         *final_types[1] = R_COMP2;
+         *final_types[2] = R_COMP2;
+         *final_types[3] = R_COMP1;
+         final_types[4] = final_type;
+         if (format == 32)
+           *final_types[4] = R_DATA_EXPR;
+         else
+           *final_types[4] = R_CODE_EXPR;
+         final_types[5] = NULL;
+         break;
+       }
+      else
+       break;
+
     case R_HPPA_NONE:
     case R_HPPA_ABS_CALL:
     case R_HPPA_PCREL_CALL:
@@ -1547,7 +1693,7 @@ hppa_som_gen_reloc_type (abfd, base_type, format, field)
    howto table.  */
 
 /*ARGSUSED*/
-static const reloc_howto_type *
+static reloc_howto_type *
 som_bfd_reloc_type_lookup (abfd, code)
      bfd *abfd;
      bfd_reloc_code_real_type code;
@@ -1570,12 +1716,15 @@ som_object_setup (abfd, file_hdrp, aux_hdrp)
      struct header *file_hdrp;
      struct som_exec_auxhdr *aux_hdrp;
 {
+  asection *section;
+  int found;
+
   /* som_mkobject will set bfd_error if som_mkobject fails.  */
   if (som_mkobject (abfd) != true)
     return 0;
 
   /* Set BFD flags based on what information is available in the SOM.  */
-  abfd->flags = NO_FLAGS;
+  abfd->flags = BFD_NO_FLAGS;
   if (file_hdrp->symbol_total)
     abfd->flags |= HAS_LINENO | HAS_DEBUG | HAS_SYMS | HAS_LOCALS;
 
@@ -1610,17 +1759,31 @@ som_object_setup (abfd, file_hdrp, aux_hdrp)
   obj_som_exec_data (abfd) = (struct som_exec_data *)
     bfd_zalloc (abfd, sizeof (struct som_exec_data ));
   if (obj_som_exec_data (abfd) == NULL)
-    {
-      bfd_set_error (bfd_error_no_memory);
-      return NULL;
-    }
+    return NULL;
 
   /* The braindamaged OSF1 linker switched exec_flags and exec_entry!
 
-     It seems rather backward that the OSF1 linker which is much
-     older than any HPUX linker I've got uses a newer SOM version
-     id...  But that's what I've found by experimentation.  */
-  if (file_hdrp->version_id == NEW_VERSION_ID)
+     We used to identify OSF1 binaries based on NEW_VERSION_ID, but
+     apparently the latest HPUX linker is using NEW_VERSION_ID now.
+
+     It's about time, OSF has used the new id since at least 1992;
+     HPUX didn't start till nearly 1995!.
+    
+     The new approach examines the entry field.  If it's zero or not 4
+     byte aligned then it's not a proper code address and we guess it's
+     really the executable flags.  */
+  found = 0;
+  for (section = abfd->sections; section; section = section->next)
+    {
+      if ((section->flags & SEC_CODE) == 0)
+       continue;
+      if (aux_hdrp->exec_entry >= section->vma
+         && aux_hdrp->exec_entry < section->vma + section->_cooked_size)
+       found = 1;
+    }
+  if (aux_hdrp->exec_entry == 0
+      || (aux_hdrp->exec_entry & 0x3) != 0
+      || ! found)
     {
       bfd_get_start_address (abfd) = aux_hdrp->exec_flags;
       obj_som_exec_data (abfd)->exec_flags = aux_hdrp->exec_entry;
@@ -1631,7 +1794,7 @@ som_object_setup (abfd, file_hdrp, aux_hdrp)
       obj_som_exec_data (abfd)->exec_flags = aux_hdrp->exec_flags;
     }
 
-  bfd_default_set_arch_mach (abfd, bfd_arch_hppa, 0);
+  bfd_default_set_arch_mach (abfd, bfd_arch_hppa, pa10);
   bfd_get_symcount (abfd) = file_hdrp->symbol_total;
 
   /* Initialize the saved symbol table and string table to NULL.  
@@ -1639,6 +1802,7 @@ som_object_setup (abfd, file_hdrp, aux_hdrp)
      the BFD.  */
   obj_som_stringtab (abfd) = (char  *) NULL;
   obj_som_symtab (abfd) = (som_symbol_type *) NULL;
+  obj_som_sorted_syms (abfd) = NULL;
   obj_som_stringtab_size (abfd) = file_hdrp->symbol_strings_size;
   obj_som_sym_filepos (abfd) = file_hdrp->symbol_location;
   obj_som_str_filepos (abfd) = file_hdrp->symbol_strings_location;
@@ -1660,17 +1824,15 @@ setup_sections (abfd, file_hdr)
      struct header *file_hdr;
 {
   char *space_strings;
-  int space_index;
+  unsigned int space_index, i;
   unsigned int total_subspaces = 0;
+  asection **subspace_sections, *section;
 
   /* First, read in space names */
 
-  space_strings = malloc (file_hdr->space_strings_size);
+  space_strings = bfd_malloc (file_hdr->space_strings_size);
   if (!space_strings && file_hdr->space_strings_size != 0)
-    {
-      bfd_set_error (bfd_error_no_memory);
-      goto error_return;
-    }
+    goto error_return;
 
   if (bfd_seek (abfd, file_hdr->space_strings_location, SEEK_SET) < 0)
     goto error_return;
@@ -1716,6 +1878,10 @@ setup_sections (abfd, file_hdr)
                                          space.space_number) == false)
        goto error_return;
 
+      /* If the space has no subspaces, then we're done.  */
+      if (space.subspace_quantity == 0)
+       continue;
+
       /* Now, read in the first subspace for this space */
       if (bfd_seek (abfd, file_hdr->subspace_location
                    + space.subspace_index * sizeof subspace,
@@ -1771,8 +1937,17 @@ setup_sections (abfd, file_hdr)
                                                 subspace.quadrant) == false)
            goto error_return;
 
-         /* Keep an easy mapping between subspaces and sections.  */
-         subspace_asect->target_index = total_subspaces++;
+         /* Keep an easy mapping between subspaces and sections. 
+            Note we do not necessarily read the subspaces in the
+            same order in which they appear in the object file.
+
+            So to make the target index come out correctly, we
+            store the location of the subspace header in target
+            index, then sort using the location of the subspace
+            header as the key.  Then we can assign correct
+            subspace indices.  */
+         total_subspaces++;
+         subspace_asect->target_index = bfd_tell (abfd) - sizeof (subspace);
 
          /* Set SEC_READONLY and SEC_CODE/SEC_DATA as specified
             by the access_control_bits in the subspace header.  */
@@ -1822,7 +1997,7 @@ setup_sections (abfd, file_hdr)
             be zero for a BSS like subspace.  */
          if (subspace.file_loc_init_value == 0
              && subspace.initialization_length == 0)
-           subspace_asect->flags &= ~(SEC_DATA | SEC_LOAD);
+           subspace_asect->flags &= ~(SEC_DATA | SEC_LOAD | SEC_HAS_CONTENTS);
 
          /* This subspace has relocations.
             The fixup_request_quantity is a byte count for the number of
@@ -1852,26 +2027,62 @@ setup_sections (abfd, file_hdr)
            goto error_return;
        }
 
-      /* Yow! there is no subspace within the space which actually 
-         has initialized information in it; this should never happen
-         as far as I know.  */
+      /* This can happen for a .o which defines symbols in otherwise
+         empty subspaces.  */
       if (!save_subspace.file_loc_init_value)
-       goto error_return;
+       {
+         space_asect->_cooked_size = 0;
+         space_asect->_raw_size = 0;
+       }
+      else
+       {
+         /* Setup the sizes for the space section based upon the info in the
+            last subspace of the space.  */
+         space_asect->_cooked_size = (save_subspace.subspace_start
+                                      - space_asect->vma
+                                      + save_subspace.subspace_length);
+         space_asect->_raw_size = (save_subspace.file_loc_init_value
+                                   - space_asect->filepos
+                                   + save_subspace.initialization_length);
+       }
+    }
+  /* Now that we've read in all the subspace records, we need to assign
+     a target index to each subspace.  */
+  subspace_sections = (asection **) bfd_malloc (total_subspaces
+                                               * sizeof (asection *));
+  if (subspace_sections == NULL)
+    goto error_return;
 
-      /* Setup the sizes for the space section based upon the info in the
-         last subspace of the space.  */
-      space_asect->_cooked_size = save_subspace.subspace_start
-       - space_asect->vma + save_subspace.subspace_length;
-      space_asect->_raw_size = save_subspace.file_loc_init_value
-       - space_asect->filepos + save_subspace.initialization_length;
+  for (i = 0, section = abfd->sections; section; section = section->next)
+    {
+      if (!som_is_subspace (section))
+       continue;
+
+      subspace_sections[i] = section;
+      i++;
     }
+  qsort (subspace_sections, total_subspaces,
+        sizeof (asection *), compare_subspaces);
+  
+  /* subspace_sections is now sorted in the order in which the subspaces
+     appear in the object file.  Assign an index to each one now.  */
+  for (i = 0; i < total_subspaces; i++)
+    subspace_sections[i]->target_index = i;
+
   if (space_strings != NULL)
     free (space_strings);
+
+  if (subspace_sections != NULL)
+    free (subspace_sections);
+
   return true;
 
  error_return:
   if (space_strings != NULL)
     free (space_strings);
+
+  if (subspace_sections != NULL)
+    free (subspace_sections);
   return false;
 }
 
@@ -1963,10 +2174,7 @@ som_mkobject (abfd)
   abfd->tdata.som_data = (struct som_data_struct *)
     bfd_zalloc (abfd, sizeof (struct som_data_struct));
   if (abfd->tdata.som_data == NULL)
-    {
-      bfd_set_error (bfd_error_no_memory);
-      return false;
-    }
+    return false;
   return true;
 }
 
@@ -1984,11 +2192,7 @@ som_prep_headers (abfd)
   /* Make and attach a file header to the BFD.  */
   file_hdr = (struct header *) bfd_zalloc (abfd, sizeof (struct header));
   if (file_hdr == NULL)
-
-    {
-      bfd_set_error (bfd_error_no_memory);
-      return false;
-    }
+    return false;
   obj_som_file_hdr (abfd) = file_hdr;
 
   if (abfd->flags & (EXEC_P | DYNAMIC))
@@ -1998,10 +2202,7 @@ som_prep_headers (abfd)
       obj_som_exec_hdr (abfd) = (struct som_exec_auxhdr *)
        bfd_zalloc (abfd, sizeof (struct som_exec_auxhdr));
       if (obj_som_exec_hdr (abfd) == NULL)
-       {
-         bfd_set_error (bfd_error_no_memory);
-         return false;
-       }
+       return false;
 
       if (abfd->flags & D_PAGED)
        file_hdr->a_magic = DEMAND_MAGIC;
@@ -2048,10 +2249,7 @@ som_prep_headers (abfd)
            = (struct space_dictionary_record *)
              bfd_zalloc (abfd, sizeof (struct space_dictionary_record));
          if (som_section_data (section)->space_dict == NULL)
-           {
-             bfd_set_error (bfd_error_no_memory);
-             return false;
-           }
+           return false;
          /* Set space attributes.  Note most attributes of SOM spaces
             are set based on the subspaces it contains.  */
          som_section_data (section)->space_dict->loader_fix_index = -1;
@@ -2074,10 +2272,7 @@ som_prep_headers (abfd)
            = (struct subspace_dictionary_record *)
              bfd_zalloc (abfd, sizeof (struct subspace_dictionary_record));
          if (som_section_data (section)->subspace_dict == NULL)
-           {
-             bfd_set_error (bfd_error_no_memory);
-             return false;
-           }
+           return false;
 
          /* Set subspace attributes.  Basic stuff is done here, additional
             attributes are filled in later as more information becomes
@@ -2128,7 +2323,9 @@ som_is_space (section)
 
   /* If the containing space isn't the same as the given section,
      then this isn't a space.  */
-  if (som_section_data (section)->copy_data->container != section)
+  if (som_section_data (section)->copy_data->container != section
+      && (som_section_data (section)->copy_data->container->output_section
+         != section))
     return false;
 
   /* OK.  Must be a space.  */
@@ -2148,7 +2345,9 @@ som_is_subspace (section)
 
   /* If the containing space is the same as the given section,
      then this isn't a subspace.  */
-  if (som_section_data (section)->copy_data->container == section)
+  if (som_section_data (section)->copy_data->container == section
+      || (som_section_data (section)->copy_data->container->output_section
+         == section))
     return false;
 
   /* OK.  Must be a subspace.  */
@@ -2163,7 +2362,9 @@ static boolean
 som_is_container (space, subspace)
      asection *space, *subspace;
 {
-  return som_section_data (subspace)->copy_data->container == space;
+  return (som_section_data (subspace)->copy_data->container == space
+         || (som_section_data (subspace)->copy_data->container->output_section
+             == space));
 }
 
 /* Count and return the number of spaces attached to the given BFD.  */
@@ -2215,12 +2416,12 @@ compare_syms (arg1, arg2)
   /* Get relocation count for each symbol.  Note that the count
      is stored in the udata pointer for section symbols!  */
   if ((*sym1)->flags & BSF_SECTION_SYM)
-    count1 = (int)(*sym1)->udata;
+    count1 = (*sym1)->udata.i;
   else
     count1 = som_symbol_data (*sym1)->reloc_count;
 
   if ((*sym2)->flags & BSF_SECTION_SYM)
-    count2 = (int)(*sym2)->udata;
+    count2 = (*sym2)->udata.i;
   else
     count2 = som_symbol_data (*sym2)->reloc_count;
 
@@ -2232,6 +2433,27 @@ compare_syms (arg1, arg2)
   return 0;
 }
 
+/* Return -1, 0, 1 indicating the relative ordering of subspace1
+   and subspace.  */
+
+static int
+compare_subspaces (arg1, arg2)
+     const PTR arg1;
+     const PTR arg2;
+
+{
+  asection **subspace1 = (asection **) arg1;
+  asection **subspace2 = (asection **) arg2;
+  unsigned int count1, count2;
+  
+  if ((*subspace1)->target_index < (*subspace2)->target_index)
+    return -1;
+  else if ((*subspace2)->target_index < (*subspace1)->target_index)
+    return 1;
+  else
+    return 0;
+}
+
 /* Perform various work in preparation for emitting the fixup stream.  */
 
 static void
@@ -2242,6 +2464,7 @@ som_prep_for_fixups (abfd, syms, num_syms)
 {
   int i;
   asection *section;
+  asymbol **sorted_syms;
 
   /* Most SOM relocations involving a symbol have a length which is
      dependent on the index of the symbol.  So symbols which are
@@ -2250,14 +2473,14 @@ som_prep_for_fixups (abfd, syms, num_syms)
   /* First initialize the counters for each symbol.  */
   for (i = 0; i < num_syms; i++)
     {
-      /* Handle a section symbol; these have no pointers back to the 
-        SOM symbol info.  So we just use the pointer field (udata)
-        to hold the relocation count.  */
+      /* Handle a section symbol; these have no pointers back to the
+        SOM symbol info.  So we just use the udata field to hold the
+        relocation count.  */
       if (som_symbol_data (syms[i]) == NULL
          || syms[i]->flags & BSF_SECTION_SYM)
        {
          syms[i]->flags |= BSF_SECTION_SYM;
-         syms[i]->udata = (PTR) 0;
+         syms[i]->udata.i = 0;
        }
       else
        som_symbol_data (syms[i])->reloc_count = 0;
@@ -2296,13 +2519,13 @@ som_prep_for_fixups (abfd, syms, num_syms)
          else
            scale = 1;
 
-         /* Handle section symbols by ramming the count in the udata
+         /* Handle section symbols by storing the count in the udata
             field.  It will not be used and the count is very important
             for these symbols.  */
          if ((*reloc->sym_ptr_ptr)->flags & BSF_SECTION_SYM)
            {
-             (*reloc->sym_ptr_ptr)->udata =
-               (PTR) ((int) (*reloc->sym_ptr_ptr)->udata + scale);
+             (*reloc->sym_ptr_ptr)->udata.i =
+               (*reloc->sym_ptr_ptr)->udata.i + scale;
              continue;
            }
 
@@ -2311,18 +2534,23 @@ som_prep_for_fixups (abfd, syms, num_syms)
        }
     }
 
-  qsort (syms, num_syms, sizeof (asymbol *), compare_syms);
+  /* Sort a copy of the symbol table, rather than the canonical
+     output symbol table.  */
+  sorted_syms = (asymbol **) bfd_zalloc (abfd, num_syms * sizeof (asymbol *));
+  memcpy (sorted_syms, syms, num_syms * sizeof (asymbol *));
+  qsort (sorted_syms, num_syms, sizeof (asymbol *), compare_syms);
+  obj_som_sorted_syms (abfd) = sorted_syms;
 
   /* Compute the symbol indexes, they will be needed by the relocation
      code.  */
   for (i = 0; i < num_syms; i++)
     {
       /* A section symbol.  Again, there is no pointer to backend symbol
-        information, so we reuse (abuse) the udata field again.  */
-      if (syms[i]->flags & BSF_SECTION_SYM)
-       syms[i]->udata = (PTR) i;
+        information, so we reuse the udata field again.  */
+      if (sorted_syms[i]->flags & BSF_SECTION_SYM)
+       sorted_syms[i]->udata.i = i;
       else
-        som_symbol_data (syms[i])->index = i;
+        som_symbol_data (sorted_syms[i])->index = i;
     }
 }
 
@@ -2374,7 +2602,7 @@ som_write_fixups (abfd, current_offset, total_reloc_sizep)
 
          /* If this subspace does not have real data, then we are
             finised with it.  */
-         if ((subsection->flags & (SEC_LOAD | SEC_DEBUGGING)) == 0)
+         if ((subsection->flags & SEC_HAS_CONTENTS) == 0)
            {
              som_section_data (subsection)->subspace_dict->fixup_request_index
                = -1;
@@ -2412,7 +2640,7 @@ som_write_fixups (abfd, current_offset, total_reloc_sizep)
              /* Get the symbol number.  Remember it's stored in a 
                 special place for section symbols.  */
              if ((*bfd_reloc->sym_ptr_ptr)->flags & BSF_SECTION_SYM)
-               sym_num = (int) (*bfd_reloc->sym_ptr_ptr)->udata;
+               sym_num = (*bfd_reloc->sym_ptr_ptr)->udata.i;
              else
                sym_num = som_symbol_data (*bfd_reloc->sym_ptr_ptr)->index;
              
@@ -2446,8 +2674,6 @@ som_write_fixups (abfd, current_offset, total_reloc_sizep)
                 later relocation.  */
              switch (bfd_reloc->howto->type)
                {
-               /* This only needs to handle relocations that may be
-                  made by hppa_som_gen_reloc.  */
                case R_ENTRY:
                case R_ALT_ENTRY:
                case R_EXIT:
@@ -2458,6 +2684,14 @@ som_write_fixups (abfd, current_offset, total_reloc_sizep)
                case R_FSEL:
                case R_LSEL:
                case R_RSEL:
+               case R_COMP1:
+               case R_COMP2:
+               case R_BEGIN_BRTAB:
+               case R_END_BRTAB:
+               case R_BEGIN_TRY:
+               case R_END_TRY:
+               case R_N0SEL:
+               case R_N1SEL:
                  reloc_offset = bfd_reloc->address;
                  break;
 
@@ -2511,8 +2745,9 @@ som_write_fixups (abfd, current_offset, total_reloc_sizep)
                case R_DATA_PLABEL:
                case R_CODE_PLABEL:
                case R_DLT_REL:
-                 /* Account for any addend.  */
-                 if (bfd_reloc->addend)
+                 /* Account for any addend using R_DATA_OVERRIDE.  */
+                 if (bfd_reloc->howto->type != R_DATA_ONE_SYMBOL
+                     && bfd_reloc->addend)
                    p = som_reloc_addend (abfd, bfd_reloc->addend, p, 
                                          &subspace_reloc_size, reloc_queue);
 
@@ -2538,7 +2773,7 @@ som_write_fixups (abfd, current_offset, total_reloc_sizep)
                case R_ENTRY:
                  {
                    int tmp;
-                   arelent *tmp_reloc;
+                   arelent *tmp_reloc = NULL;
                    bfd_put_8 (abfd, R_ENTRY, p);
 
                    /* R_ENTRY relocations have 64 bits of associated
@@ -2586,6 +2821,66 @@ som_write_fixups (abfd, current_offset, total_reloc_sizep)
                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:
+                 bfd_put_8 (abfd, bfd_reloc->howto->type, p);
+                 subspace_reloc_size += 1;
+                 p += 1;
+                 break;
+
+               case R_END_TRY:
+                 /* The end of a exception handling region.  The reloc's
+                    addend contains the offset of the exception handling
+                    code.  */
+                 if (bfd_reloc->addend == 0)
+                   bfd_put_8 (abfd, bfd_reloc->howto->type, p);
+                 else if (bfd_reloc->addend < 1024)
+                   {
+                     bfd_put_8 (abfd, bfd_reloc->howto->type + 1, p);
+                     bfd_put_8 (abfd, bfd_reloc->addend / 4, p + 1);
+                     p = try_prev_fixup (abfd, &subspace_reloc_size,
+                                         p, 2, reloc_queue);
+                   }
+                 else
+                   {
+                     bfd_put_8 (abfd, bfd_reloc->howto->type + 2, p);
+                     bfd_put_8 (abfd, (bfd_reloc->addend / 4) >> 16, p + 1);
+                     bfd_put_16 (abfd, bfd_reloc->addend / 4, p + 2);
+                     p = try_prev_fixup (abfd, &subspace_reloc_size,
+                                         p, 4, reloc_queue);
+                   }
+                 break;
+                     
+               case R_COMP1:
+                 /* The only time we generate R_COMP1, R_COMP2 and 
+                    R_CODE_EXPR relocs is for the difference of two
+                    symbols.  Hence we can cheat here.  */
+                 bfd_put_8 (abfd, bfd_reloc->howto->type, p);
+                 bfd_put_8 (abfd, 0x44, p + 1);
+                 p = try_prev_fixup (abfd, &subspace_reloc_size,
+                                     p, 2, reloc_queue);
+                 break;
+
+               case R_COMP2:
+                 /* The only time we generate R_COMP1, R_COMP2 and 
+                    R_CODE_EXPR relocs is for the difference of two
+                    symbols.  Hence we can cheat here.  */
+                 bfd_put_8 (abfd, bfd_reloc->howto->type, p);
+                 bfd_put_8 (abfd, 0x80, p + 1);
+                 bfd_put_8 (abfd, sym_num >> 16, p + 2);
+                 bfd_put_16 (abfd, sym_num, p + 3);
+                 p = try_prev_fixup (abfd, &subspace_reloc_size,
+                                     p, 5, reloc_queue);
+                 break;
+
+               case R_CODE_EXPR:
+               case R_DATA_EXPR:
+                 /* The only time we generate R_COMP1, R_COMP2 and 
+                    R_CODE_EXPR relocs is for the difference of two
+                    symbols.  Hence we can cheat here.  */
                  bfd_put_8 (abfd, bfd_reloc->howto->type, p);
                  subspace_reloc_size += 1;
                  p += 1;
@@ -2791,11 +3086,10 @@ som_begin_writing (abfd)
   unsigned long current_offset = 0;
   int strings_size = 0;
   unsigned int total_reloc_size = 0;
-  unsigned long num_spaces, num_subspaces, num_syms, i;
+  unsigned long num_spaces, num_subspaces, i;
   asection *section;
-  asymbol **syms = bfd_get_outsymbols (abfd);
   unsigned int total_subspaces = 0;
-  struct som_exec_auxhdr *exec_header;
+  struct som_exec_auxhdr *exec_header = NULL;
 
   /* The file header will always be first in an object file, 
      everything else can be in random locations.  To keep things
@@ -2925,54 +3219,6 @@ som_begin_writing (abfd)
   obj_som_file_hdr (abfd)->space_strings_size = strings_size;
   current_offset += strings_size;
 
-  /* Next is the symbol table.  These are fixed length records.
-
-     Count the number of symbols to determine how much room is needed
-     in the object file for the symbol table.
-
-     The names of the symbols are stored in a separate string table,
-     and the index for each symbol name into the string table is computed
-     below.  Therefore, it is not possible to write the symobl table
-     at this time.  */
-  num_syms = bfd_get_symcount (abfd);
-  obj_som_file_hdr (abfd)->symbol_location = current_offset;
-  obj_som_file_hdr (abfd)->symbol_total = num_syms;
-  current_offset += num_syms * sizeof (struct symbol_dictionary_record);
-
-  /* Do prep work before handling fixups.  */
-  som_prep_for_fixups (abfd, syms, num_syms);
-
-  /* Next comes the fixup stream which starts on a word boundary.  */
-  if (current_offset % 4)
-    current_offset += (4 - (current_offset % 4)); 
-  obj_som_file_hdr (abfd)->fixup_request_location = current_offset;
-
-  /* Write the fixups and update fields in subspace headers which
-     relate to the fixup stream.  */
-  if (som_write_fixups (abfd, current_offset, &total_reloc_size) == false)
-    return false;
-
-  /* Record the total size of the fixup stream in the file header.  */
-  obj_som_file_hdr (abfd)->fixup_request_total = total_reloc_size;
-  current_offset += total_reloc_size;
-
-  /* Next are the symbol strings.
-     Align them to a word boundary.  */
-  if (current_offset % 4)
-    current_offset += (4 - (current_offset % 4));
-  obj_som_file_hdr (abfd)->symbol_strings_location = current_offset;
-
-  /* Scribble out the symbol strings.  */
-  if (som_write_symbol_strings (abfd, current_offset, syms, 
-                               num_syms, &strings_size)
-      == false)
-    return false;
-
-  /* Record total string table size in header and update the
-     current offset.  */
-  obj_som_file_hdr (abfd)->symbol_strings_size = strings_size;
-  current_offset += strings_size;
-
   /* Next is the compiler records.  We do not use these.  */
   obj_som_file_hdr (abfd)->compiler_location = current_offset;
   obj_som_file_hdr (abfd)->compiler_total = 0;
@@ -3131,7 +3377,7 @@ som_begin_writing (abfd)
              || (subsection->flags & SEC_ALLOC) != 0)
            continue;
 
-         subsection->target_index = total_subspaces;
+         subsection->target_index = total_subspaces++;
          /* This is real data to be loaded from the file.  */
          if ((subsection->flags & SEC_LOAD) == 0)
            {
@@ -3170,7 +3416,7 @@ som_begin_writing (abfd)
   obj_som_file_hdr (abfd)->loader_fixup_location = 0;
   obj_som_file_hdr (abfd)->loader_fixup_total = 0;
 
-  /* Done.  Store the total size of the SOM.  */
+  /* Done.  Store the total size of the SOM so far.  */
   obj_som_file_hdr (abfd)->som_length = current_offset;
 
   return true;
@@ -3179,14 +3425,85 @@ som_begin_writing (abfd)
 /* Finally, scribble out the various headers to the disk.  */
 
 static boolean
-som_write_headers (abfd)
+som_finish_writing (abfd)
      bfd *abfd;
 {
   int num_spaces = som_count_spaces (abfd);
-  int i;
+  asymbol **syms = bfd_get_outsymbols (abfd);
+  int i, num_syms, strings_size;
   int subspace_index = 0;
   file_ptr location;
   asection *section;
+  unsigned long current_offset;
+  unsigned int total_reloc_size;
+
+  /* Next is the symbol table.  These are fixed length records.
+
+     Count the number of symbols to determine how much room is needed
+     in the object file for the symbol table.
+
+     The names of the symbols are stored in a separate string table,
+     and the index for each symbol name into the string table is computed
+     below.  Therefore, it is not possible to write the symbol table
+     at this time. 
+
+     These used to be output before the subspace contents, but they
+     were moved here to work around a stupid bug in the hpux linker
+     (fixed in hpux10).  */
+  current_offset = obj_som_file_hdr (abfd)->som_length;
+
+  /* Make sure we're on a word boundary.  */
+  if (current_offset % 4)
+    current_offset += (4 - (current_offset % 4)); 
+
+  num_syms = bfd_get_symcount (abfd);
+  obj_som_file_hdr (abfd)->symbol_location = current_offset;
+  obj_som_file_hdr (abfd)->symbol_total = num_syms;
+  current_offset += num_syms * sizeof (struct symbol_dictionary_record);
+
+  /* Next are the symbol strings.
+     Align them to a word boundary.  */
+  if (current_offset % 4)
+    current_offset += (4 - (current_offset % 4));
+  obj_som_file_hdr (abfd)->symbol_strings_location = current_offset;
+
+  /* Scribble out the symbol strings.  */
+  if (som_write_symbol_strings (abfd, current_offset, syms,
+                               num_syms, &strings_size)
+      == false)
+    return false;
+
+  /* Record total string table size in header and update the
+     current offset.  */
+  obj_som_file_hdr (abfd)->symbol_strings_size = strings_size;
+  current_offset += strings_size;
+
+  /* Do prep work before handling fixups.  */
+  som_prep_for_fixups (abfd,
+                      bfd_get_outsymbols (abfd),
+                      bfd_get_symcount (abfd));
+
+  /* At the end of the file is the fixup stream which starts on a
+     word boundary.  */
+  if (current_offset % 4)
+    current_offset += (4 - (current_offset % 4)); 
+  obj_som_file_hdr (abfd)->fixup_request_location = current_offset;
+
+  /* Write the fixups and update fields in subspace headers which
+     relate to the fixup stream.  */
+  if (som_write_fixups (abfd, current_offset, &total_reloc_size) == false)
+    return false;
+
+  /* Record the total size of the fixup stream in the file header.  */
+  obj_som_file_hdr (abfd)->fixup_request_total = total_reloc_size;
+
+  /* Done.  Store the total size of the SOM.  */
+  obj_som_file_hdr (abfd)->som_length = current_offset + total_reloc_size;
+  /* Now that the symbol table information is complete, build and
+     write the symbol table.  */
+  if (som_build_and_write_symbol_table (abfd) == false)
+    return false;
 
   /* Subspaces are written first so that we can set up information
      about them in their containing spaces as the subspace is written.  */
@@ -3333,13 +3650,14 @@ som_write_headers (abfd)
       section = section->next;
     }
 
-  /* FIXME.  This should really be conditional based on whether or not
-     PA1.1 instructions/registers have been used. 
-
-     Setting of the system_id has to happen very late now that copying of
+  /* Setting of the system_id has to happen very late now that copying of
      BFD private data happens *after* section contents are set.  */
   if (abfd->flags & (EXEC_P | DYNAMIC))
     obj_som_file_hdr(abfd)->system_id = obj_som_exec_data (abfd)->system_id;
+  else if (bfd_get_mach (abfd) == pa20)
+    obj_som_file_hdr(abfd)->system_id = CPU_PA_RISC2_0;
+  else if (bfd_get_mach (abfd) == pa11)
+    obj_som_file_hdr(abfd)->system_id = CPU_PA_RISC1_1;
   else
     obj_som_file_hdr(abfd)->system_id = CPU_PA_RISC1_0;
 
@@ -3457,9 +3775,8 @@ som_bfd_derive_misc_symbol_info (abfd, sym, info)
          info->arg_reloc = som_symbol_data (sym)->tc_data.hppa_arg_reloc;
        }
 
-      /* If the type is unknown at this point, it should be ST_DATA or
-        ST_CODE (function/ST_ENTRY symbols were handled  as special
-        cases above). */
+      /* For unknown symbols set the symbol's type based on the symbol's
+        section (ST_DATA for DATA sections, ST_CODE for CODE sections).  */
       else if (som_symbol_data (sym)->som_type == SYMBOL_TYPE_UNKNOWN)
        {
          if (sym->section->flags & SEC_CODE)
@@ -3467,6 +3784,9 @@ som_bfd_derive_misc_symbol_info (abfd, sym, info)
          else
            info->symbol_type = ST_DATA;
        }
+  
+      else if (som_symbol_data (sym)->som_type == SYMBOL_TYPE_UNKNOWN)
+       info->symbol_type = ST_DATA;
 
       /* From now on it's a very simple mapping.  */
       else if (som_symbol_data (sym)->som_type == SYMBOL_TYPE_ABSOLUTE)
@@ -3488,11 +3808,10 @@ som_bfd_derive_misc_symbol_info (abfd, sym, info)
   /* Now handle the symbol's scope.  Exported data which is not
      in the common section has scope SS_UNIVERSAL.  Note scope
      of common symbols was handled earlier!  */
-  if (sym->flags & BSF_EXPORT && ! bfd_is_com_section (sym->section))
-    info->symbol_scope = SS_UNIVERSAL;
-  /* Any undefined symbol at this point has a scope SS_UNSAT.  */
-  else if (bfd_is_und_section (sym->section))
+  if (bfd_is_und_section (sym->section))
     info->symbol_scope = SS_UNSAT;
+  else if (sym->flags & BSF_EXPORT && ! bfd_is_com_section (sym->section))
+    info->symbol_scope = SS_UNIVERSAL;
   /* Anything else which is not in the common section has scope
      SS_LOCAL.  */
   else if (! bfd_is_com_section (sym->section))
@@ -3524,19 +3843,16 @@ som_build_and_write_symbol_table (abfd)
 {
   unsigned int num_syms = bfd_get_symcount (abfd);
   file_ptr symtab_location = obj_som_file_hdr (abfd)->symbol_location;
-  asymbol **bfd_syms = bfd_get_outsymbols (abfd);
+  asymbol **bfd_syms = obj_som_sorted_syms (abfd);
   struct symbol_dictionary_record *som_symtab = NULL;
   int i, symtab_size;
 
   /* Compute total symbol table size and allocate a chunk of memory
      to hold the symbol table as we build it.  */
   symtab_size = num_syms * sizeof (struct symbol_dictionary_record);
-  som_symtab = (struct symbol_dictionary_record *) malloc (symtab_size);
+  som_symtab = (struct symbol_dictionary_record *) bfd_malloc (symtab_size);
   if (som_symtab == NULL && symtab_size != 0)
-    {
-      bfd_set_error (bfd_error_no_memory);
-      goto error_return;
-    }
+    goto error_return;
   memset (som_symtab, 0, symtab_size);
 
   /* Walk over each symbol.  */
@@ -3594,12 +3910,7 @@ som_write_object_contents (abfd)
       som_begin_writing (abfd);
     }
 
-  /* Now that the symbol table information is complete, build and
-     write the symbol table.  */
-  if (som_build_and_write_symbol_table (abfd) == false)
-    return false;
-
-  return (som_write_headers (abfd));
+  return (som_finish_writing (abfd));
 }
 
 \f
@@ -3625,12 +3936,10 @@ som_slurp_string_table (abfd)
     }
 
   /* Allocate and read in the string table.  */
-  stringtab = malloc (obj_som_stringtab_size (abfd));
+  stringtab = bfd_malloc (obj_som_stringtab_size (abfd));
   if (stringtab == NULL)
-    {
-      bfd_set_error (bfd_error_no_memory);
-      return false;
-    }
+    return false;
+  memset (stringtab, 0, obj_som_stringtab_size (abfd));
 
   if (bfd_seek (abfd, obj_som_str_filepos (abfd), SEEK_SET) < 0)
     return false;
@@ -3677,7 +3986,7 @@ bfd_section_from_som_symbol (abfd, symbol)
     {
       unsigned int index = symbol->symbol_info;
       for (section = abfd->sections; section != NULL; section = section->next)
-       if (section->target_index == index)
+       if (section->target_index == index && som_is_subspace (section))
          return section;
 
       /* Could be a symbol from an external library (such as an OMOS
@@ -3694,7 +4003,8 @@ bfd_section_from_som_symbol (abfd, symbol)
       for (section = abfd->sections; section; section = section->next)
        {
          if (value >= section->vma
-             && value <= section->vma + section->_cooked_size)
+             && value <= section->vma + section->_cooked_size
+             && som_is_subspace (section))
            return section;
        }
 
@@ -3730,21 +4040,16 @@ som_slurp_symbol_table (abfd)
 
   stringtab = obj_som_stringtab (abfd);
 
-  symbase = (som_symbol_type *)
-    malloc (symbol_count * sizeof (som_symbol_type));
+  symbase = ((som_symbol_type *)
+            bfd_malloc (symbol_count * sizeof (som_symbol_type)));
   if (symbase == NULL)
-    {
-      bfd_set_error (bfd_error_no_memory);
-      goto error_return;
-    }
+    goto error_return;
+  memset (symbase, 0, symbol_count * sizeof (som_symbol_type));
 
   /* Read in the external SOM representation.  */
-  buf = malloc (symbol_count * symsize);
+  buf = bfd_malloc (symbol_count * symsize);
   if (buf == NULL && symbol_count * symsize != 0)
-    {
-      bfd_set_error (bfd_error_no_memory);
-      goto error_return;
-    }
+    goto error_return;
   if (bfd_seek (abfd, obj_som_sym_filepos (abfd), SEEK_SET) < 0)
     goto error_return;
   if (bfd_read (buf, symbol_count * symsize, 1, abfd) 
@@ -3856,7 +4161,7 @@ som_slurp_symbol_table (abfd)
         Note $START$ is a magic code symbol, NOT a section symbol.  */
       if (sym->symbol.name[0] == '$'
          && sym->symbol.name[strlen (sym->symbol.name) - 1] == '$'
-         && strcmp (sym->symbol.name, "$START$"))
+         && !strcmp (sym->symbol.name, sym->symbol.section->name))
        sym->symbol.flags |= BSF_SECTION_SYM;
       else if (!strncmp (sym->symbol.name, "L$0\002", 4))
        {
@@ -3871,6 +4176,10 @@ som_slurp_symbol_table (abfd)
       sym++;
     }
 
+  /* We modify the symbol count to record the number of BFD symbols we
+     created.  */
+  bfd_get_symcount (abfd) = sym - symbase;
+
   /* Save our results and return success.  */
   obj_som_symtab (abfd) = symbase;
  successful_return:
@@ -3918,10 +4227,7 @@ som_make_empty_symbol (abfd)
   som_symbol_type *new =
   (som_symbol_type *) bfd_zalloc (abfd, sizeof (som_symbol_type));
   if (new == NULL)
-    {
-      bfd_set_error (bfd_error_no_memory);
-      return 0;
-    }
+    return 0;
   new->symbol.the_bfd = abfd;
 
   return &new->symbol;
@@ -3959,11 +4265,11 @@ som_print_symbol (ignore_abfd, afile, symbol, how)
 }
 
 static boolean
-som_bfd_is_local_label (abfd, sym)
+som_bfd_is_local_label_name (abfd, name)
      bfd *abfd;
-     asymbol *sym;
+     const char *name;
 {
-  return (sym->name[0] == 'L' && sym->name[1] == '$');
+  return (name[0] == 'L' && name[1] == '$');
 }
 
 /* Count or process variable-length SOM fixup records.
@@ -3988,7 +4294,7 @@ som_set_reloc_info (fixup, end, internal_relocs, section, symbols, just_count)
      asymbol **symbols;
      boolean just_count;
 {
-  unsigned int op, varname;
+  unsigned int op, varname, deallocate_contents = 0;
   unsigned char *end_fixups = &fixup[end];
   const struct fixup_format *fp;
   char *cp;
@@ -4079,8 +4385,11 @@ som_set_reloc_info (fixup, end, internal_relocs, section, symbols, just_count)
                 the stack.  */
              else if (islower (c))
                {
+                 int bits = (c - 'a') * 8;
                  for (v = 0; c > 'a'; --c)
                    v = (v << 8) | *fixup++;
+                 if (varname == 'V')
+                   v = sign_extend (v, bits);
                  push (v);
                }
 
@@ -4142,6 +4451,73 @@ som_set_reloc_info (fixup, end, internal_relocs, section, symbols, just_count)
              if (! just_count)
                rptr->sym_ptr_ptr = &symbols[c];
              break;
+           /* Argument relocation bits for a function call.  */
+           case 'R':
+             if (! just_count)
+               {
+                 unsigned int tmp = var ('R');
+                 rptr->addend = 0;
+
+                 if ((som_hppa_howto_table[op].type == R_PCREL_CALL
+                      && R_PCREL_CALL + 10 > op)
+                     || (som_hppa_howto_table[op].type == R_ABS_CALL
+                         && R_ABS_CALL + 10 > op))
+                   {
+                     /* Simple encoding.  */
+                     if (tmp > 4)
+                       {
+                         tmp -= 5;
+                         rptr->addend |= 1;
+                       }
+                     if (tmp == 4)
+                       rptr->addend |= 1 << 8 | 1 << 6 | 1 << 4 | 1 << 2;
+                     else if (tmp == 3)
+                       rptr->addend |= 1 << 8 | 1 << 6 | 1 << 4;
+                     else if (tmp == 2)
+                       rptr->addend |= 1 << 8 | 1 << 6;
+                     else if (tmp == 1)
+                       rptr->addend |= 1 << 8;
+                   }
+                 else
+                   {
+                     unsigned int tmp1, tmp2;
+
+                     /* First part is easy -- low order two bits are
+                        directly copied, then shifted away.  */
+                     rptr->addend = tmp & 0x3;
+                     tmp >>= 2;
+
+                     /* Diving the result by 10 gives us the second
+                        part.  If it is 9, then the first two words
+                        are a double precision paramater, else it is
+                        3 * the first arg bits + the 2nd arg bits.  */
+                     tmp1 = tmp / 10;
+                     tmp -= tmp1 * 10;
+                     if (tmp1 == 9)
+                       rptr->addend += (0xe << 6);
+                     else
+                       {
+                         /* Get the two pieces.  */
+                         tmp2 = tmp1 / 3;
+                         tmp1 -= tmp2 * 3;
+                         /* Put them in the addend.  */
+                         rptr->addend += (tmp2 << 8) + (tmp1 << 6);
+                       }
+
+                     /* What's left is the third part.  It's unpacked
+                        just like the second.  */
+                     if (tmp == 9)
+                       rptr->addend += (0xe << 2);
+                     else
+                       {
+                         tmp2 = tmp / 3;
+                         tmp -= tmp2 * 3;
+                         rptr->addend += (tmp2 << 4) + (tmp << 2);
+                       }
+                   }
+                 rptr->addend = HPPA_R_ADDEND (rptr->addend, 0);
+               }
+             break;
            /* Handle the linker expression stack.  */
            case 'O':
              switch (op)
@@ -4194,6 +4570,40 @@ som_set_reloc_info (fixup, end, internal_relocs, section, symbols, just_count)
                rptr->addend = var ('T');
              else if (som_hppa_howto_table[op].type == R_EXIT)
                rptr->addend = var ('U');
+             else if (som_hppa_howto_table[op].type == R_PCREL_CALL
+                      || som_hppa_howto_table[op].type == R_ABS_CALL)
+               ;
+             else if (som_hppa_howto_table[op].type == R_DATA_ONE_SYMBOL)
+               {
+                 unsigned addend = var ('V');
+
+                 /* Try what was specified in R_DATA_OVERRIDE first
+                    (if anything).  Then the hard way using the
+                    section contents.  */
+                 rptr->addend = var ('V');
+
+                 if (rptr->addend == 0 && !section->contents)
+                   {
+                     /* Got to read the damn contents first.  We don't
+                        bother saving the contents (yet).  Add it one
+                        day if the need arises.  */
+                     section->contents = bfd_malloc (section->_raw_size);
+                     if (section->contents == NULL)
+                       return -1;
+
+                     deallocate_contents = 1;
+                     bfd_get_section_contents (section->owner,
+                                               section,
+                                               section->contents,
+                                               0,
+                                               section->_raw_size);
+                   }
+                 else if (rptr->addend == 0)
+                   rptr->addend = bfd_get_32 (section->owner,
+                                              (section->contents
+                                               + offset - var ('L')));
+                       
+               }
              else
                rptr->addend = var ('V');
              rptr++;
@@ -4205,6 +4615,9 @@ som_set_reloc_info (fixup, end, internal_relocs, section, symbols, just_count)
          memset (stack, 0, sizeof (stack));
        }
     }
+  if (deallocate_contents)
+    free (section->contents);
+
   return count;
 
 #undef var
@@ -4240,12 +4653,9 @@ som_slurp_reloc_table (abfd, section, symbols, just_count)
      parsed.  We must do so now to know how many relocations exist.  */
   if (section->reloc_count == -1)
     {
-      external_relocs = (char *) malloc (fixup_stream_size);
+      external_relocs = (char *) bfd_malloc (fixup_stream_size);
       if (external_relocs == (char *) NULL)
-       {
-         bfd_set_error (bfd_error_no_memory);
-         return false;
-       }
+       return false;
       /* Read in the external forms. */
       if (bfd_seek (abfd,
                    obj_som_reloc_filepos (abfd) + section->rel_filepos,
@@ -4276,17 +4686,19 @@ som_slurp_reloc_table (abfd, section, symbols, just_count)
   if (section->relocation != (arelent *) NULL)
     return true;
 
-  internal_relocs = (arelent *) malloc (num_relocs * sizeof (arelent));
+  internal_relocs = (arelent *) 
+    bfd_zalloc (abfd, (num_relocs * sizeof (arelent)));
   if (internal_relocs == (arelent *) NULL)
-    {
-      bfd_set_error (bfd_error_no_memory);
-      return false;
-    }
+    return false;
 
   /* Process and internalize the relocations.  */
   som_set_reloc_info (external_relocs, fixup_stream_size,
                      internal_relocs, section, symbols, false);
 
+  /* We're done with the external relocations.  Free them.  */
+  free (external_relocs);
+  som_section_data (section)->reloc_stream = NULL;
+
   /* Save our results and return success.  */
   section->relocation = internal_relocs;
   return (true);
@@ -4305,8 +4717,8 @@ som_get_reloc_upper_bound (abfd, asect)
   if (asect->flags & SEC_RELOC)
     {
       if (! som_slurp_reloc_table (abfd, asect, NULL, true))
-       return false;
-      return (asect->reloc_count + 1) * sizeof (arelent);
+       return -1;
+      return (asect->reloc_count + 1) * sizeof (arelent *);
     }
   /* There are no relocations.  */
   return 0;
@@ -4350,16 +4762,38 @@ som_new_section_hook (abfd, newsect)
   newsect->used_by_bfd =
     (PTR) bfd_zalloc (abfd, sizeof (struct som_section_data_struct));
   if (!newsect->used_by_bfd)
-    {
-      bfd_set_error (bfd_error_no_memory);
-      return false;
-    }
+    return false;
   newsect->alignment_power = 3;
 
   /* We allow more than three sections internally */
   return true;
 }
 
+/* Copy any private info we understand from the input symbol
+   to the output symbol.  */
+
+static boolean
+som_bfd_copy_private_symbol_data (ibfd, isymbol, obfd, osymbol)
+     bfd *ibfd;
+     asymbol *isymbol;
+     bfd *obfd;
+     asymbol *osymbol;
+{
+  struct som_symbol *input_symbol = (struct som_symbol *) isymbol;
+  struct som_symbol *output_symbol = (struct som_symbol *) osymbol;
+
+  /* One day we may try to grok other private data.  */
+  if (ibfd->xvec->flavour != bfd_target_som_flavour
+      || obfd->xvec->flavour != bfd_target_som_flavour)
+    return false;
+
+  /* The only private information we need to copy is the argument relocation
+     bits.  */
+  output_symbol->tc_data.hppa_arg_reloc = input_symbol->tc_data.hppa_arg_reloc;
+
+  return true;
+}
+
 /* Copy any private info we understand from the input section
    to the output section.  */
 static boolean
@@ -4373,16 +4807,13 @@ som_bfd_copy_private_section_data (ibfd, isection, obfd, osection)
   if (ibfd->xvec->flavour != bfd_target_som_flavour
       || obfd->xvec->flavour != bfd_target_som_flavour
       || (!som_is_space (isection) && !som_is_subspace (isection)))
-    return false;
+    return true;
 
   som_section_data (osection)->copy_data
     = (struct som_copyable_section_data_struct *)
       bfd_zalloc (obfd, sizeof (struct som_copyable_section_data_struct));
   if (som_section_data (osection)->copy_data == NULL)
-    {
-      bfd_set_error (bfd_error_no_memory);
-      return false;
-    }
+    return false;
 
   memcpy (som_section_data (osection)->copy_data,
          som_section_data (isection)->copy_data,
@@ -4406,16 +4837,13 @@ som_bfd_copy_private_bfd_data (ibfd, obfd)
   /* One day we may try to grok other private data.  */
   if (ibfd->xvec->flavour != bfd_target_som_flavour
       || obfd->xvec->flavour != bfd_target_som_flavour)
-    return false;
+    return true;
 
   /* Allocate some memory to hold the data we need.  */
   obj_som_exec_data (obfd) = (struct som_exec_data *)
     bfd_zalloc (obfd, sizeof (struct som_exec_data));
   if (obj_som_exec_data (obfd) == NULL)
-    {
-      bfd_set_error (bfd_error_no_memory);
-      return false;
-    }
+    return false;
 
   /* Now copy the data.  */
   memcpy (obj_som_exec_data (obfd), obj_som_exec_data (ibfd),
@@ -4443,10 +4871,7 @@ bfd_som_set_section_attributes (section, defined, private, sort_key, spnum)
          bfd_zalloc (section->owner,
                      sizeof (struct som_copyable_section_data_struct));
       if (som_section_data (section)->copy_data == NULL)
-       {
-         bfd_set_error (bfd_error_no_memory);
-         return false;
-       }
+       return false;
     }
   som_section_data (section)->copy_data->sort_key = sort_key;
   som_section_data (section)->copy_data->is_defined = defined;
@@ -4476,10 +4901,7 @@ bfd_som_set_subsection_attributes (section, container, access,
          bfd_zalloc (section->owner,
                      sizeof (struct som_copyable_section_data_struct));
       if (som_section_data (section)->copy_data == NULL)
-       {
-         bfd_set_error (bfd_error_no_memory);
-         return false;
-       }
+       return false;
     }
   som_section_data (section)->copy_data->sort_key = sort_key;
   som_section_data (section)->copy_data->access_control_bits = access;
@@ -4521,10 +4943,7 @@ bfd_som_attach_aux_hdr (abfd, type, string)
        bfd_zalloc (abfd, sizeof (struct aux_id)
                              + sizeof (unsigned int) + len + pad);
       if (!obj_som_version_hdr (abfd))
-       {
-         bfd_set_error (bfd_error_no_memory);
-         return false;
-       }
+       return false;
       obj_som_version_hdr (abfd)->header_id.type = VERSION_AUX_ID;
       obj_som_version_hdr (abfd)->header_id.length = len + pad;
       obj_som_version_hdr (abfd)->header_id.length += sizeof (int);
@@ -4542,10 +4961,7 @@ bfd_som_attach_aux_hdr (abfd, type, string)
        bfd_zalloc (abfd, sizeof (struct aux_id)
                            + sizeof (unsigned int) + len + pad);
       if (!obj_som_copyright_hdr (abfd))
-       {
-         bfd_set_error (bfd_error_no_memory);
-         return false;
-       }
+       return false;
       obj_som_copyright_hdr (abfd)->header_id.type = COPYRIGHT_AUX_ID;
       obj_som_copyright_hdr (abfd)->header_id.length = len + pad;
       obj_som_copyright_hdr (abfd)->header_id.length += sizeof (int);
@@ -4563,7 +4979,7 @@ som_get_section_contents (abfd, section, location, offset, count)
      file_ptr offset;
      bfd_size_type count;
 {
-  if (count == 0 || ((section->flags & (SEC_LOAD | SEC_DEBUGGING)) == 0))
+  if (count == 0 || ((section->flags & SEC_HAS_CONTENTS) == 0))
     return true;
   if ((bfd_size_type)(offset+count) > section->_raw_size
       || bfd_seek (abfd, (file_ptr)(section->filepos + offset), SEEK_SET) == -1
@@ -4594,7 +5010,7 @@ som_set_section_contents (abfd, section, location, offset, count)
   /* Only write subspaces which have "real" contents (eg. the contents
      are not generated at run time by the OS).  */
   if (!som_is_subspace (section)
-      || ((section->flags & (SEC_LOAD | SEC_DEBUGGING)) == 0))
+      || ((section->flags & SEC_HAS_CONTENTS) == 0))
     return true;
 
   /* Seek to the proper offset within the object file and write the
@@ -4629,9 +5045,6 @@ som_find_nearest_line (abfd, section, symbols, offset, filename_ptr,
      CONST char **functionname_ptr;
      unsigned int *line_ptr;
 {
-  fprintf (stderr, "som_find_nearest_line unimplemented\n");
-  fflush (stderr);
-  abort ();
   return (false);
 }
 
@@ -4640,7 +5053,7 @@ som_sizeof_headers (abfd, reloc)
      bfd *abfd;
      boolean reloc;
 {
-  fprintf (stderr, "som_sizeof_headers unimplemented\n");
+  (*_bfd_error_handler) (_("som_sizeof_headers unimplemented"));
   fflush (stderr);
   abort ();
   return (0);
@@ -4676,7 +5089,9 @@ som_decode_symclass (symbol)
   if (!(symbol->flags & (BSF_GLOBAL|BSF_LOCAL)))
     return '?';
 
-  if (bfd_is_abs_section (symbol->section))
+  if (bfd_is_abs_section (symbol->section)
+      || (som_symbol_data (symbol) != NULL
+         && som_symbol_data (symbol)->som_type == SYMBOL_TYPE_ABSOLUTE))
     c = 'a';
   else if (symbol->section)
     c = som_section_type (symbol->section->name);
@@ -4717,12 +5132,10 @@ som_bfd_count_ar_symbols (abfd, lst_header, count)
   file_ptr lst_filepos = bfd_tell (abfd) - sizeof (struct lst_header);
 
   hash_table = 
-    (unsigned int *) malloc (lst_header->hash_size * sizeof (unsigned int));
+    (unsigned int *) bfd_malloc (lst_header->hash_size
+                                * sizeof (unsigned int));
   if (hash_table == NULL && lst_header->hash_size != 0)
-    {
-      bfd_set_error (bfd_error_no_memory);
-      goto error_return;
-    }
+    goto error_return;
 
   /* Don't forget to initialize the counter!  */
   *count = 0;
@@ -4797,21 +5210,16 @@ som_bfd_fill_in_ar_symbols (abfd, lst_header, syms)
   file_ptr lst_filepos = bfd_tell (abfd) - sizeof (struct lst_header);
 
   hash_table = 
-    (unsigned int *) malloc (lst_header->hash_size * sizeof (unsigned int));
+    (unsigned int *) bfd_malloc (lst_header->hash_size
+                                * sizeof (unsigned int));
   if (hash_table == NULL && lst_header->hash_size != 0)
-    {
-      bfd_set_error (bfd_error_no_memory);
-      goto error_return;
-    }
+    goto error_return;
 
   som_dict =
-    (struct som_entry *) malloc (lst_header->module_count
-                                * sizeof (struct som_entry));
+    (struct som_entry *) bfd_malloc (lst_header->module_count
+                                    * sizeof (struct som_entry));
   if (som_dict == NULL && lst_header->module_count != 0)
-    {
-      bfd_set_error (bfd_error_no_memory);
-      goto error_return;
-    }
+    goto error_return;
 
   /* Read in the hash table.  The has table is an array of 32bit file offsets
      which point to the hash chains.  */
@@ -4863,10 +5271,7 @@ som_bfd_fill_in_ar_symbols (abfd, lst_header, syms)
       /* Allocate space for the name and null terminate it too.  */
       set->name = bfd_zalloc (abfd, len + 1);
       if (!set->name)
-       {
-         bfd_set_error (bfd_error_no_memory);
-         goto error_return;
-       }
+       goto error_return;
       if (bfd_read (set->name, 1, len, abfd) != len)
        goto error_return;
 
@@ -4902,10 +5307,7 @@ som_bfd_fill_in_ar_symbols (abfd, lst_header, syms)
          /* Allocate space for the name and null terminate it too.  */
          set->name = bfd_zalloc (abfd, len + 1);
          if (!set->name)
-           {
-             bfd_set_error (bfd_error_no_memory);
-             goto error_return;
-           }
+           goto error_return;
 
          if (bfd_read (set->name, 1, len, abfd) != len)
            goto error_return;
@@ -5016,10 +5418,7 @@ som_slurp_armap (abfd)
                                          (ardata->symdef_count
                                           * sizeof (carsym)));
   if (!ardata->symdefs)
-    {
-      bfd_set_error (bfd_error_no_memory);
-      return false;
-    }
+    return false;
 
   /* Now fill in the canonical archive symbols.  */
   if (som_bfd_fill_in_ar_symbols (abfd, &lst_header, &ardata->symdefs)
@@ -5128,27 +5527,15 @@ som_bfd_ar_symbol_hash (symbol)
          | (symbol->name[len-2] << 8) | symbol->name[len-1];
 }
 
-static CONST char *
-normalize (file)
-     CONST char *file;
-{
-  CONST char *filename = strrchr (file, '/');
-
-  if (filename != NULL)
-    filename++;
-  else
-    filename = file;
-  return filename;
-}
-
 /* Do the bulk of the work required to write the SOM library
    symbol table.  */
    
 static boolean
-som_bfd_ar_write_symbol_stuff (abfd, nsyms, string_size, lst)
+som_bfd_ar_write_symbol_stuff (abfd, nsyms, string_size, lst, elength)
      bfd *abfd;
      unsigned int nsyms, string_size;
      struct lst_header lst;
+     unsigned elength;
 {
   file_ptr lst_filepos;
   char *strings = NULL, *p;
@@ -5157,33 +5544,23 @@ som_bfd_ar_write_symbol_stuff (abfd, nsyms, string_size, lst)
   unsigned int *hash_table = NULL;
   struct som_entry *som_dict = NULL;
   struct lst_symbol_record **last_hash_entry = NULL;
-  unsigned int curr_som_offset, som_index, extended_name_length = 0;
-  unsigned int maxname = abfd->xvec->ar_max_namelen;
+  unsigned int curr_som_offset, som_index = 0;
 
   hash_table =
-    (unsigned int *) malloc (lst.hash_size * sizeof (unsigned int));
+    (unsigned int *) bfd_malloc (lst.hash_size * sizeof (unsigned int));
   if (hash_table == NULL && lst.hash_size != 0)
-    {
-      bfd_set_error (bfd_error_no_memory);
-      goto error_return;
-    }
+    goto error_return;
   som_dict =
-    (struct som_entry *) malloc (lst.module_count
-                                * sizeof (struct som_entry));
+    (struct som_entry *) bfd_malloc (lst.module_count
+                                    * sizeof (struct som_entry));
   if (som_dict == NULL && lst.module_count != 0)
-    {
-      bfd_set_error (bfd_error_no_memory);
-      goto error_return;
-    }
+    goto error_return;
 
   last_hash_entry =
     ((struct lst_symbol_record **)
-     malloc (lst.hash_size * sizeof (struct lst_symbol_record *)));
+     bfd_malloc (lst.hash_size * sizeof (struct lst_symbol_record *)));
   if (last_hash_entry == NULL && lst.hash_size != 0)
-    {
-      bfd_set_error (bfd_error_no_memory);
-      goto error_return;
-    }
+    goto error_return;
 
   /* Lots of fields are file positions relative to the start
      of the lst record.  So save its location.  */
@@ -5203,48 +5580,28 @@ som_bfd_ar_write_symbol_stuff (abfd, nsyms, string_size, lst)
      describes.  We have to compute that information as we iterate
      through the SOMs/symbols.  */
   som_index = 0;
-  curr_som_offset = 8 + 2 * sizeof (struct ar_hdr) + lst.file_end;
 
-  /* Yow!  We have to know the size of the extended name table
-     too.  */
-  for (curr_bfd = abfd->archive_head;
-       curr_bfd != NULL;
-       curr_bfd = curr_bfd->next)
-    {
-      CONST char *normal = normalize (curr_bfd->filename);
-      unsigned int thislen;
-
-      if (!normal)
-       {
-         bfd_set_error (bfd_error_no_memory);
-         return false;
-       }
-      thislen = strlen (normal);
-      if (thislen > maxname)
-       extended_name_length += thislen + 1;
-    }
+  /* We add in the size of the archive header twice as the location
+     in the SOM dictionary is the actual offset of the SOM, not the
+     archive header before the SOM.  */
+  curr_som_offset = 8 + 2 * sizeof (struct ar_hdr) + lst.file_end;
 
   /* Make room for the archive header and the contents of the
-     extended string table.  */
-  if (extended_name_length)
-    curr_som_offset += extended_name_length + sizeof (struct ar_hdr);
+     extended string table.  Note that elength includes the size
+     of the archive header for the extended name table!  */
+  if (elength)
+    curr_som_offset += elength;
 
   /* Make sure we're properly aligned.  */
   curr_som_offset = (curr_som_offset + 0x1) & ~0x1;
 
   /* FIXME should be done with buffers just like everything else... */
-  lst_syms = malloc (nsyms * sizeof (struct lst_symbol_record));
+  lst_syms = bfd_malloc (nsyms * sizeof (struct lst_symbol_record));
   if (lst_syms == NULL && nsyms != 0)
-    {
-      bfd_set_error (bfd_error_no_memory);
-      goto error_return;
-    }
-  strings = malloc (string_size);
+    goto error_return;
+  strings = bfd_malloc (string_size);
   if (strings == NULL && string_size != 0)
-    {
-      bfd_set_error (bfd_error_no_memory);
-      goto error_return;
-    }
+    goto error_return;
 
   p = strings;
   curr_lst_sym = lst_syms;
@@ -5373,6 +5730,11 @@ som_bfd_ar_write_symbol_stuff (abfd, nsyms, string_size, lst)
       /* Keep track of where each SOM will finally reside; then look
         at the next BFD.  */
       curr_som_offset += arelt_size (curr_bfd) + sizeof (struct ar_hdr);
+      /* A particular object in the archive may have an odd length; the
+        linker requires objects begin on an even boundary.  So round
+        up the current offset as necessary.  */
+      curr_som_offset = (curr_som_offset + 0x1) & ~0x1;
       curr_bfd = curr_bfd->next;
       som_index++;
     }
@@ -5457,6 +5819,8 @@ som_write_armap (abfd, elength, map, orl_count, stridx)
   lst_size = sizeof (struct lst_header);
 
   /* Start building the LST header.  */
+  /* FIXME:  Do we need to examine each element to determine the
+     largest id number?  */
   lst.system_id = CPU_PA_RISC1_0;
   lst.a_magic = LIBMAGIC;
   lst.version_id = VERSION_ID;
@@ -5543,7 +5907,8 @@ som_write_armap (abfd, elength, map, orl_count, stridx)
     return false;
 
   /* Build and write the armap.  */
-  if (som_bfd_ar_write_symbol_stuff (abfd, nsyms, stringsize, lst) == false)
+  if (som_bfd_ar_write_symbol_stuff (abfd, nsyms, stringsize, lst, elength)
+      == false)
     return false;
   
   /* Done.  */
@@ -5581,16 +5946,34 @@ som_bfd_free_cached_info (abfd)
 
 /* End of miscellaneous support functions. */
 
+/* Linker support functions.  */
+static boolean
+som_bfd_link_split_section (abfd, sec)
+     bfd *abfd;
+     asection *sec;
+{
+  return (som_is_subspace (sec) && sec->_raw_size > 240000);
+}
+
 #define        som_close_and_cleanup           som_bfd_free_cached_info
 
+#define som_read_ar_hdr                        _bfd_generic_read_ar_hdr
 #define som_openr_next_archived_file   bfd_generic_openr_next_archived_file
+#define som_get_elt_at_index           _bfd_generic_get_elt_at_index
 #define som_generic_stat_arch_elt      bfd_generic_stat_arch_elt
 #define som_truncate_arname            bfd_bsd_truncate_arname
 #define som_slurp_extended_name_table  _bfd_slurp_extended_name_table
+#define som_construct_extended_name_table \
+  _bfd_archive_coff_construct_extended_name_table
 #define som_update_armap_timestamp     bfd_true
+#define som_bfd_print_private_bfd_data  _bfd_generic_bfd_print_private_bfd_data
 
 #define som_get_lineno                  _bfd_nosymbols_get_lineno
 #define som_bfd_make_debug_symbol      _bfd_nosymbols_bfd_make_debug_symbol
+#define som_read_minisymbols           _bfd_generic_read_minisymbols
+#define som_minisymbol_to_symbol       _bfd_generic_minisymbol_to_symbol
+#define som_get_section_contents_in_window \
+  _bfd_generic_get_section_contents_in_window
 
 #define som_bfd_get_relocated_section_contents \
  bfd_generic_get_relocated_section_contents
@@ -5599,12 +5982,15 @@ som_bfd_free_cached_info (abfd)
 #define som_bfd_link_add_symbols _bfd_generic_link_add_symbols
 #define som_bfd_final_link _bfd_generic_final_link
 
+#define som_bfd_gc_sections            bfd_generic_gc_sections
+
+
 const bfd_target som_vec =
 {
   "som",                       /* name */
   bfd_target_som_flavour,
-  true,                                /* target byte order */
-  true,                                /* target headers byte order */
+  BFD_ENDIAN_BIG,              /* target byte order */
+  BFD_ENDIAN_BIG,              /* target headers byte order */
   (HAS_RELOC | EXEC_P |                /* object flags */
    HAS_LINENO | HAS_DEBUG |
    HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED | DYNAMIC),
@@ -5616,7 +6002,6 @@ const bfd_target som_vec =
   0,
   '/',                         /* ar_pad_char */
   14,                          /* ar_max_namelen */
-  3,                           /* minimum alignment */
   bfd_getb64, bfd_getb_signed_64, bfd_putb64,
   bfd_getb32, bfd_getb_signed_32, bfd_putb32,
   bfd_getb16, bfd_getb_signed_16, bfd_putb16,  /* data */
This page took 0.049031 seconds and 4 git commands to generate.