* remote-es.c (es1800_child_ops): Don't declare it static.
[deliverable/binutils-gdb.git] / bfd / elf32-hppa.c
index b677e4db391f0c497f830cd2723fbf51c9f9794c..6486565167725164b60e0e2339b6b0fa68210d7a 100644 (file)
@@ -1,5 +1,5 @@
 /* BFD back-end for HP PA-RISC ELF files.
-   Copyright (C) 1990-1991 Free Software Foundation, Inc.
+   Copyright (C) 1990, 91, 92, 93, 94 Free Software Foundation, Inc.
 
    Written by
 
@@ -27,29 +27,252 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "sysdep.h"
 #include "libbfd.h"
 #include "obstack.h"
+#include "bfdlink.h"
 #include "libelf.h"
 
+/* Note there isn't much error handling code in here yet.  Unexpected
+   conditions are handled by just calling abort.  FIXME damnit! */
 /* ELF32/HPPA relocation support
 
        This file contains ELF32/HPPA relocation support as specified
        in the Stratus FTX/Golf Object File Format (SED-1762) dated
-       November 19, 1992.
-*/
+       November 19, 1992.  */
 
 #include "elf32-hppa.h"
-#include "libhppa.h"
 #include "aout/aout64.h"
 #include "hppa_stubs.h"
 
-/* ELF/PA relocation howto entries */
+/* The basic stub types supported.  If/when shared libraries are
+   implemented some form of IMPORT and EXPORT stubs will be needed.  */
+typedef enum
+{
+  HPPA_STUB_ILLEGAL,
+  HPPA_STUB_ARG_RELOC,
+  HPPA_STUB_LONG_CALL,
+} hppa_stub_type;
+
+/* This is a list of all the stubs for a particular BFD.  */
+
+typedef struct elf32_hppa_stub_name_list_struct
+{
+  /* The symbol associated with this stub.  */
+  asymbol *sym;
+  /* Pointer to chain of all stub chains.  */
+  struct elf32_hppa_stub_description_struct *stub_desc;
+  /* Pointer to the stub contents (eg instructions).  */  
+  int *stub_secp;
+  /* Size of this stub?  (in what units?  FIXME).  */
+  unsigned size;
+  /* Pointer to the next stub entry in the chain.  */
+  struct elf32_hppa_stub_name_list_struct *next;
+} elf32_hppa_stub_name_list;
+
+/* This is a linked list in which each entry describes all the
+   linker stubs for a particular bfd.  */
+   
+typedef struct elf32_hppa_stub_description_struct
+{
+  /* The next group of stubs.  */
+  struct elf32_hppa_stub_description_struct *next;
+  /* Used to identify this group of stubs as belonging
+     to a particular bfd.  */
+  bfd *this_bfd;
+  /* FIXME: The stub section for this group of stubs?  Is
+     this redundant with stub_listP->sym->section?  */
+  asection *stub_sec;
+  /* FIXME: what the hell is this?  */
+  unsigned relocs_allocated_cnt;
+  /* The current real size of the stubs (in bytes?).  */
+  unsigned real_size;
+  /* How much space we have allocated for stubs (in bytes?).  */
+  unsigned allocated_size;
+  /* Pointer to the first available space for new stubs.  */
+  int *stub_secp;
+  /* Pointer to the beginning of the stubs.  FIXME: Why an int *
+     above and a char * here?  */
+  char *stub_contents;
+  /* The list of stubs for this bfd.  */
+  elf32_hppa_stub_name_list *stub_listP;
+  /* I guess we just carry this around for fun.  */
+  struct bfd_link_info *link_info;
+} elf32_hppa_stub_description;
+
+/* FIXME.  */
+#define ARGUMENTS      0
+#define RETURN_VALUE   1
+
+/* The various argument relocations that may be performed.
+   Note GRX,GRY really means ARGX,ARGY.  */
+typedef enum
+{
+  /* No relocation.  */
+  NO_ARG_RELOC,
+  /* Relocate 32 bits from general to FP register.  */
+  R_TO_FR,
+  /* Relocate 64 bits from arg0,arg1 to FParg1.  */
+  R01_TO_FR,
+  /* Relocate 64 bits from arg2,arg3 to FParg3.  */
+  R23_TO_FR,
+  /* Relocate 32 bits from FP to general register.  */
+  FR_TO_R,
+  /* Relocate 64 bits from FParg1 to arg0,arg1.  */
+  FR_TO_R01,
+  /* Relocate 64 bits from FParg3 to arg2,arg3.  */
+  FR_TO_R23,
+  /* Death.  */
+  ARG_RELOC_ERR,
+} arg_reloc_type;
+
+/* Where (what register type) is an argument comming from?  */
+typedef enum
+{
+  /* Not in a register.  */
+  AR_NO,
+  /* In a general argument register.  */
+  AR_GR,
+  /* In right half of a FP argument register.  */
+  AR_FR,
+  /* In upper (left) half of a FP argument register.  */
+  AR_FU,
+  /* In general argument register pair 0 (arg0, arg1).  */
+  AR_DBL01,
+  /* In general argument register pair 1 (arg2, arg3).  */
+  AR_DBL23,
+} arg_location;
+
+/* What is being relocated (eg which argument or the return value).  */
+typedef enum
+{
+  ARG0, ARG1, ARG2, ARG3, RETVAL,
+} arg_reloc_location;
+
+/* Horizontal represents callee's argument location information, vertical
+   represents caller's argument location information.  Value at a particular
+   X, Y location represents what (if any) argument relocation needs to
+   be performed to make caller and callee agree.  */
+static CONST arg_reloc_type mismatches[6][6] =
+{
+ {NO_ARG_RELOC, NO_ARG_RELOC, NO_ARG_RELOC, NO_ARG_RELOC,
+    NO_ARG_RELOC, NO_ARG_RELOC},
+ {NO_ARG_RELOC, NO_ARG_RELOC, R_TO_FR, ARG_RELOC_ERR,
+    R01_TO_FR, ARG_RELOC_ERR},
+ {NO_ARG_RELOC, FR_TO_R, NO_ARG_RELOC, ARG_RELOC_ERR,
+    ARG_RELOC_ERR, ARG_RELOC_ERR},
+ {ARG_RELOC_ERR, ARG_RELOC_ERR, ARG_RELOC_ERR, ARG_RELOC_ERR,
+    ARG_RELOC_ERR, ARG_RELOC_ERR},
+ {NO_ARG_RELOC, FR_TO_R01, NO_ARG_RELOC, ARG_RELOC_ERR,
+    NO_ARG_RELOC, ARG_RELOC_ERR},
+ {NO_ARG_RELOC, FR_TO_R23, NO_ARG_RELOC, ARG_RELOC_ERR,
+    ARG_RELOC_ERR, NO_ARG_RELOC},
+};
+
+/* Likewise for the return value.  */
+static CONST arg_reloc_type retval_mismatches[6][6] =
+{
+ {NO_ARG_RELOC, NO_ARG_RELOC, NO_ARG_RELOC, NO_ARG_RELOC,
+    NO_ARG_RELOC, NO_ARG_RELOC},
+ {NO_ARG_RELOC, NO_ARG_RELOC, FR_TO_R, ARG_RELOC_ERR,
+    FR_TO_R01, ARG_RELOC_ERR},
+ {NO_ARG_RELOC, R_TO_FR, NO_ARG_RELOC, ARG_RELOC_ERR,
+    ARG_RELOC_ERR, ARG_RELOC_ERR},
+ {ARG_RELOC_ERR, ARG_RELOC_ERR, ARG_RELOC_ERR, ARG_RELOC_ERR,
+    ARG_RELOC_ERR, ARG_RELOC_ERR},
+ {NO_ARG_RELOC, R01_TO_FR, NO_ARG_RELOC, ARG_RELOC_ERR,
+    NO_ARG_RELOC, ARG_RELOC_ERR},
+ {NO_ARG_RELOC, R23_TO_FR, NO_ARG_RELOC, ARG_RELOC_ERR,
+    ARG_RELOC_ERR, NO_ARG_RELOC},
+};
+
+/* Used for index mapping in symbol-extension sections.  */
+struct elf32_hppa_symextn_map_struct
+{
+  int old_index;
+  bfd *bfd;
+  asymbol *sym;
+  int new_index;
+};
+
+static bfd_reloc_status_type hppa_elf_reloc
+  PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
+
+static unsigned long hppa_elf_relocate_insn 
+  PARAMS ((bfd *, asection *, unsigned long, unsigned long, long,
+          long, unsigned long, unsigned long, unsigned long));
+
+static void hppa_elf_relocate_unwind_table
+  PARAMS ((bfd *, PTR, unsigned long, long, long,
+          unsigned long, unsigned long));
+
+static long get_symbol_value PARAMS ((asymbol *));
+
+static bfd_reloc_status_type hppa_elf_reloc
+  PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd*, char **));
+
+static CONST reloc_howto_type * elf_hppa_reloc_type_lookup
+  PARAMS ((bfd_arch_info_type *, bfd_reloc_code_real_type));
+
+static symext_entryS elf32_hppa_get_sym_extn PARAMS ((bfd *, asymbol *, int));
+
+static elf32_hppa_stub_description * find_stubs PARAMS ((bfd *, asection *));
+
+static elf32_hppa_stub_description * new_stub
+  PARAMS ((bfd *, asection *, struct bfd_link_info *));
+
+static arg_reloc_type type_of_mismatch PARAMS ((int, int, int));
+
+static elf32_hppa_stub_name_list * find_stub_by_name
+  PARAMS ((bfd *, asection *, char *));
+
+static elf32_hppa_stub_name_list * add_stub_by_name
+  PARAMS ((bfd *, asection *, asymbol *, struct bfd_link_info *));
+
+static void hppa_elf_stub_finish PARAMS ((bfd *));
+
+static void hppa_elf_stub_reloc
+  PARAMS ((elf32_hppa_stub_description *, bfd *, asymbol **, int,
+          elf32_hppa_reloc_type));
+
+static int hppa_elf_arg_reloc_needed_p
+  PARAMS ((bfd *, arelent *, arg_reloc_type [5], symext_entryS));
+
+static asymbol * hppa_elf_build_linker_stub
+  PARAMS ((bfd *, bfd *, struct bfd_link_info *, arelent *,
+          arg_reloc_type [5], int, unsigned *, hppa_stub_type));
+
+static void hppa_elf_create_stub_sec 
+  PARAMS ((bfd *, bfd *, asection **, struct bfd_link_info *));
+
+static int hppa_elf_long_branch_needed_p
+  PARAMS ((bfd *, asection *, arelent *, asymbol *, unsigned));
+
+static boolean hppa_elf_set_section_contents
+  PARAMS ((bfd *, sec_ptr, PTR, file_ptr, bfd_size_type));
+
+static void elf_info_to_howto
+  PARAMS ((bfd *, arelent *, Elf32_Internal_Rela *));
+
+static void elf32_hppa_backend_symbol_processing PARAMS ((bfd *, asymbol *));
+
+static boolean elf32_hppa_backend_section_processing
+  PARAMS ((bfd *, Elf32_Internal_Shdr *));
+
+static boolean elf32_hppa_backend_symbol_table_processing
+  PARAMS ((bfd *, elf_symbol_type *, int));
+
+static boolean elf32_hppa_backend_section_from_shdr
+  PARAMS ((bfd *, Elf32_Internal_Shdr *, char *));
+
+static boolean elf32_hppa_backend_fake_sections
+  PARAMS ((bfd *, Elf_Internal_Shdr *, asection *));
 
-static bfd_reloc_status_type hppa_elf_reloc ();
+static boolean elf32_hppa_backend_section_from_bfd_section
+  PARAMS ((bfd *, Elf32_Internal_Shdr *, asection *, int *));
+
+/* ELF/PA relocation howto entries.  */
 
 static reloc_howto_type elf_hppa_howto_table[ELF_HOWTO_TABLE_SIZE] =
 {
-/*  'bitpos' and 'abs' are obsolete */
-/* type                        rs sz bsz pcrel  bpos abs    ovrf  sf              name */
-/* 9.3.4. Address relocation types */
   {R_HPPA_NONE, 0, 3, 19, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_HPPA_NONE"},
   {R_HPPA_32, 0, 3, 32, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_HPPA_32"},
   {R_HPPA_11, 0, 3, 11, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_HPPA_11"},
@@ -70,7 +293,6 @@ static reloc_howto_type elf_hppa_howto_table[ELF_HOWTO_TABLE_SIZE] =
   {R_HPPA_LR21, 0, 3, 21, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_HPPA_LR21"},
   {R_HPPA_RR14, 0, 3, 14, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_HPPA_RR14"},
   {R_HPPA_RR17, 0, 3, 17, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_HPPA_RR17"},
-/* 9.3.5. GOTOFF address relocation types              */
   {R_HPPA_GOTOFF_11, 0, 3, 11, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_HPPA_GOTOFF_11"},
   {R_HPPA_GOTOFF_14, 0, 3, 14, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_HPPA_GOTOFF_14"},
   {R_HPPA_GOTOFF_L21, 0, 3, 21, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_HPPA_GOTOFF_L21"},
@@ -84,7 +306,6 @@ static reloc_howto_type elf_hppa_howto_table[ELF_HOWTO_TABLE_SIZE] =
   {R_HPPA_GOTOFF_RD14, 0, 3, 14, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_HPPA_GOTOFF_RD14"},
   {R_HPPA_GOTOFF_LR21, 0, 3, 21, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_HPPA_GOTOFF_LR21"},
   {R_HPPA_GOTOFF_RR14, 0, 3, 14, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_HPPA_GOTOFF_RR14"},
-/* 9.3.6. Absolute call relocation types       */
   {R_HPPA_ABS_CALL_11, 0, 3, 11, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_HPPA_ABS_CALL_11"},
   {R_HPPA_ABS_CALL_14, 0, 3, 14, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_HPPA_ABS_CALL_14"},
   {R_HPPA_ABS_CALL_17, 0, 3, 17, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_HPPA_ABS_CALL_17"},
@@ -103,7 +324,6 @@ static reloc_howto_type elf_hppa_howto_table[ELF_HOWTO_TABLE_SIZE] =
   {R_HPPA_ABS_CALL_LR21, 0, 3, 21, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_HPPA_ABS_CALL_LR21"},
   {R_HPPA_ABS_CALL_RR14, 0, 3, 14, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_HPPA_ABS_CALL_RR14"},
   {R_HPPA_ABS_CALL_RR17, 0, 3, 17, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_HPPA_ABS_CALL_RR17"},
-/* 9.3.7. PC-relative call relocation types    */
   {R_HPPA_PCREL_CALL_11, 0, 3, 11, true, 0, complain_overflow_signed, hppa_elf_reloc, "R_HPPA_PCREL_CALL_11"},
   {R_HPPA_PCREL_CALL_14, 0, 3, 14, true, 0, complain_overflow_signed, hppa_elf_reloc, "R_HPPA_PCREL_CALL_14"},
   {R_HPPA_PCREL_CALL_17, 0, 3, 17, true, 0, complain_overflow_signed, hppa_elf_reloc, "R_HPPA_PCREL_CALL_17"},
@@ -123,28 +343,20 @@ static reloc_howto_type elf_hppa_howto_table[ELF_HOWTO_TABLE_SIZE] =
   {R_HPPA_PCREL_CALL_LR21, 0, 3, 21, true, 0, complain_overflow_signed, hppa_elf_reloc, "R_HPPA_PCREL_CALL_LR21"},
   {R_HPPA_PCREL_CALL_RR14, 0, 3, 14, true, 0, complain_overflow_signed, hppa_elf_reloc, "R_HPPA_PCREL_CALL_RR14"},
   {R_HPPA_PCREL_CALL_RR17, 0, 3, 17, true, 0, complain_overflow_signed, hppa_elf_reloc, "R_HPPA_PCREL_CALL_RR17"},
-
-/* 9.3.8. Plabel relocation types */
   {R_HPPA_PLABEL_32, 0, 3, 32, false, 0, complain_overflow_signed, hppa_elf_reloc, "R_HPPA_PLABEL_32"},
   {R_HPPA_PLABEL_11, 0, 3, 11, false, 0, complain_overflow_signed, hppa_elf_reloc, "R_HPPA_PLABEL_11"},
   {R_HPPA_PLABEL_14, 0, 3, 14, false, 0, complain_overflow_signed, hppa_elf_reloc, "R_HPPA_PLABEL_14"},
   {R_HPPA_PLABEL_L21, 0, 3, 21, false, 0, complain_overflow_signed, hppa_elf_reloc, "R_HPPA_PLABEL_L21"},
   {R_HPPA_PLABEL_R11, 0, 3, 11, false, 0, complain_overflow_signed, hppa_elf_reloc, "R_HPPA_PLABEL_R11"},
   {R_HPPA_PLABEL_R14, 0, 3, 14, false, 0, complain_overflow_signed, hppa_elf_reloc, "R_HPPA_PLABEL_R14"},
-
-/* 9.3.9. Data linkage table (DLT) relocation types    */
   {R_HPPA_DLT_32, 0, 3, 32, false, 0, complain_overflow_signed, hppa_elf_reloc, "R_HPPA_DLT_32"},
   {R_HPPA_DLT_11, 0, 3, 11, false, 0, complain_overflow_signed, hppa_elf_reloc, "R_HPPA_DLT_11"},
   {R_HPPA_DLT_14, 0, 3, 14, false, 0, complain_overflow_signed, hppa_elf_reloc, "R_HPPA_DLT_14"},
   {R_HPPA_DLT_L21, 0, 3, 21, false, 0, complain_overflow_signed, hppa_elf_reloc, "R_HPPA_DLT_L21"},
   {R_HPPA_DLT_R11, 0, 3, 11, false, 0, complain_overflow_signed, hppa_elf_reloc, "R_HPPA_DLT_R11"},
   {R_HPPA_DLT_R14, 0, 3, 14, false, 0, complain_overflow_signed, hppa_elf_reloc, "R_HPPA_DLT_R14"},
-
-/* 9.3.10. Relocations for unwinder tables     */
   {R_HPPA_UNWIND_ENTRY, 0, 3, 32, true, 0, complain_overflow_signed, hppa_elf_reloc, "R_HPPA_UNWIND_ENTRY"},
   {R_HPPA_UNWIND_ENTRIES, 0, 3, 32, true, 0, complain_overflow_signed, hppa_elf_reloc, "R_HPPA_UNWIND_ENTRIES"},
-
-/*  9.3.11. Relocation types for complex expressions   */
   {R_HPPA_PUSH_CONST, 0, 3, 32, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_HPPA_PUSH_CONST"},
   {R_HPPA_PUSH_PC, 0, 3, 32, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_HPPA_PUSH_PC"},
   {R_HPPA_PUSH_SYM, 0, 3, 32, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_HPPA_PUSH_SYM"},
@@ -175,7 +387,6 @@ static reloc_howto_type elf_hppa_howto_table[ELF_HOWTO_TABLE_SIZE] =
   {R_HPPA_EXPR_RD, 0, 3, 32, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_HPPA_EXPR_RD"},
   {R_HPPA_EXPR_LR, 0, 3, 32, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_HPPA_EXPR_LR"},
   {R_HPPA_EXPR_RR, 0, 3, 32, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_HPPA_EXPR_RR"},
-
   {R_HPPA_EXPR_32, 0, 3, 32, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_HPPA_EXPR_32"},
   {R_HPPA_EXPR_21, 0, 3, 21, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_HPPA_EXPR_21"},
   {R_HPPA_EXPR_11, 0, 3, 11, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_HPPA_EXPR_11"},
@@ -189,90 +400,39 @@ static reloc_howto_type elf_hppa_howto_table[ELF_HOWTO_TABLE_SIZE] =
 static symext_chainS *symext_rootP;
 static symext_chainS *symext_lastP;
 static boolean symext_chain_built;
+static long global_value;
+static long GOT_value;
+static asymbol *global_symbol;
+static int global_sym_defined;
+static symext_entryS *symextn_contents;
+static unsigned int symextn_contents_real_size;
+static elf32_hppa_stub_description *elf_hppa_stub_rootP;
+static boolean stubs_finished = false;
+static struct elf32_hppa_symextn_map_struct *elf32_hppa_symextn_map;
+static int elf32_hppa_symextn_map_size;
 
-static unsigned long
-DEFUN (hppa_elf_rebuild_insn, (abfd, insn, value, r_type, r_field, r_format),
-       bfd * abfd AND
-       unsigned long insn AND
-       unsigned long value AND
-       unsigned short r_type AND
-       unsigned short r_field AND
-       unsigned short r_format)
-{
-  unsigned long const_part;    /* part of the instruction that does not change */
-  unsigned long rebuilt_part;
-
-  switch (r_format)
-    {
-    case 11:
-      {
-       unsigned w1, w;
-
-       const_part = insn & 0xffffe002;
-       dis_assemble_12 (value, &w1, &w);
-       rebuilt_part = (w1 << 2) | w;
-       return const_part | rebuilt_part;
-      }
-
-    case 12:
-      {
-       unsigned w1, w;
-
-       const_part = insn & 0xffffe002;
-       dis_assemble_12 (value, &w1, &w);
-       rebuilt_part = (w1 << 2) | w;
-       return const_part | rebuilt_part;
-      }
-
-    case 14:
-      const_part = insn & 0xffffc000;
-      low_sign_unext (value, 14, &rebuilt_part);
-      return const_part | rebuilt_part;
-
-    case 17:
-      {
-       unsigned w1, w2, w;
-
-       const_part = insn & 0xffe0e002;
-       dis_assemble_17 (value, &w1, &w2, &w);
-       rebuilt_part = (w2 << 2) | (w1 << 16) | w;
-       return const_part | rebuilt_part;
-      }
-
-    case 21:
-      const_part = insn & 0xffe00000;
-      dis_assemble_21 (value, &rebuilt_part);
-      return const_part | rebuilt_part;
+static char *linker_stubs = NULL;
+static int linker_stubs_size = 0;
+static int linker_stubs_max_size = 0;
+#define STUB_ALLOC_INCR        100
+#define STUB_SYM_BUFFER_INC    5
 
-    case 32:
-      const_part = 0;
-      return value;
+/* Relocate the given INSN given the various input parameters.
 
-    default:
-      fprintf (stderr, "Relocation problem : ");
-      fprintf (stderr,
-              "Unrecognized reloc type %d (fmt=%d,fld=%d), in module %s\n",
-              r_type, r_format, r_field, abfd->filename);
-    }
-  return insn;
-}
+   FIXME: endianness and sizeof (long) issues abound here.  */
 
 static unsigned long
-DEFUN (hppa_elf_relocate_insn,
-       (abfd, input_sect,
-       insn, address, symp, sym_value, r_addend,
-       r_type, r_format, r_field, pcrel),
-       bfd * abfd AND
-       asection * input_sect AND
-       unsigned long insn AND
-       unsigned long address AND
-       asymbol * symp AND
-       long sym_value AND
-       long r_addend AND
-       unsigned short r_type AND
-       unsigned short r_format AND
-       unsigned short r_field AND
-       unsigned char pcrel)
+hppa_elf_relocate_insn (abfd, input_sect, insn, address, sym_value,
+                       r_addend, r_format, r_field, pcrel)
+     bfd *abfd;
+     asection *input_sect;
+     unsigned long insn;
+     unsigned long address;
+     long sym_value;
+     long r_addend;
+     unsigned long r_format;
+     unsigned long r_field;
+     unsigned long pcrel;
 {
   unsigned char opcode = get_opcode (insn);
   long constant_value;
@@ -289,44 +449,30 @@ DEFUN (hppa_elf_relocate_insn,
     case STH:
     case STW:
     case STWM:
+    case COMICLR:
+    case SUBI:
+    case ADDIT:
+    case ADDI:
+    case LDIL:
+    case ADDIL:
       constant_value = HPPA_R_CONSTANT (r_addend);
-      BFD_ASSERT (r_format == 14);
 
       if (pcrel)
        sym_value -= address;
-      sym_value = hppa_field_adjust (sym_value, constant_value, r_field);
-      return hppa_elf_rebuild_insn (abfd, insn, sym_value, r_type, r_field, r_format);
-
-    case COMICLR:
-    case SUBI:                 /* case SUBIO: */
-    case ADDIT:                /* case ADDITO: */
-    case ADDI:                 /* case ADDIO: */
-      BFD_ASSERT (r_format == 11);
-
-      constant_value = HPPA_R_CONSTANT(r_addend);
-      sym_value = hppa_field_adjust (sym_value, constant_value, r_field);
-      return hppa_elf_rebuild_insn (abfd, insn, sym_value, r_type, r_field, r_format);
-
-    case LDIL:
-    case ADDIL:
-      BFD_ASSERT (r_format == 21);
 
-      constant_value = HPPA_R_CONSTANT (r_addend);
       sym_value = hppa_field_adjust (sym_value, constant_value, r_field);
-      return hppa_elf_rebuild_insn (abfd, insn, sym_value, r_type, r_field, r_format);
+      return hppa_rebuild_insn (abfd, insn, sym_value, r_format);
 
     case BL:
     case BE:
     case BLE:
       arg_reloc = HPPA_R_ARG_RELOC (r_addend);
 
-      BFD_ASSERT (r_format == 17);
-
       /* XXX computing constant_value is not needed??? */
       constant_value = assemble_17 ((insn & 0x001f0000) >> 16,
                                    (insn & 0x00001ffc) >> 2,
                                    insn & 1);
-      /* @@ Assumes only 32 bits.  */
+
       constant_value = (constant_value << 15) >> 15;
       if (pcrel)
        {
@@ -338,54 +484,47 @@ DEFUN (hppa_elf_relocate_insn,
       else
        sym_value = hppa_field_adjust (sym_value, constant_value, r_field);
 
-      return hppa_elf_rebuild_insn (abfd, insn, sym_value >> 2, r_type, r_field, r_format);
+      return hppa_rebuild_insn (abfd, insn, sym_value >> 2, r_format);
 
     default:
       if (opcode == 0)
        {
-         BFD_ASSERT (r_format == 32);
          constant_value = HPPA_R_CONSTANT (r_addend);
 
+         if (pcrel)
+           sym_value -= address;
+
          return hppa_field_adjust (sym_value, constant_value, r_field);
        }
       else
-       {
-         fprintf (stderr,
-                  "Unrecognized opcode 0x%02x (fmt=%x,field=%x)\n",
-                  opcode, r_format, r_field);
-         return insn;
-       }
+       abort ();
     }
 }
 
+/* Relocate a single unwind entry, or an entire table of them.  */
+
 static void
-DEFUN (hppa_elf_relocate_unwind_table,
-       (abfd, input_sect,
-       data, address, symp, sym_value, r_addend,
-       r_type, r_format, r_field, pcrel),
-       bfd * abfd AND
-       asection * input_sect AND
-       PTR data AND
-       unsigned long address AND
-       asymbol * symp AND
-       long sym_value AND
-       long r_addend AND
-       unsigned short r_type AND
-       unsigned short r_format AND
-       unsigned short r_field AND
-       unsigned char pcrel)
+hppa_elf_relocate_unwind_table (abfd, data, address, sym_value,
+                               r_addend, r_type, r_field)
+     bfd *abfd;
+     PTR data;
+     unsigned long address;
+     long sym_value;
+     long r_addend;
+     unsigned long r_type;
+     unsigned long r_field;
 {
-  bfd_byte *hit_data = address + (bfd_byte *) (data);
+  bfd_byte *hit_data = address + (bfd_byte *) data;
   long start_offset;
   long end_offset;
   long relocated_value;
   int i;
 
-  BFD_ASSERT (r_format == 32);
-  BFD_ASSERT (r_field == e_fsel);
   switch (r_type)
     {
     case R_HPPA_UNWIND_ENTRY:
+      /* Need to relocate the first two 32bit fields in the unwind.  They
+        correspond to a function's start and end address.  */
       start_offset = bfd_get_32 (abfd, hit_data);
       relocated_value = hppa_field_adjust (sym_value, start_offset, r_field);
       bfd_put_32 (abfd, relocated_value, hit_data);
@@ -397,79 +536,51 @@ DEFUN (hppa_elf_relocate_unwind_table,
       break;
 
     case R_HPPA_UNWIND_ENTRIES:
+      /* Relocate a mass of unwind entires.  The count is passed in r_addend
+        (who's braindamaged idea was this anyway?  */
       for (i = 0; i < r_addend; i++, hit_data += 3 * sizeof (unsigned long))
        {
          unsigned int adjustment;
+         /* Adjust the first 32bit field in the unwind entry.  It's
+            the starting offset of a function.  */
          start_offset = bfd_get_32 (abfd, hit_data);
-         /* Stuff the symbol value into the first word */
-         /* of the  unwind descriptor */
          bfd_put_32 (abfd, sym_value, hit_data);
          adjustment = sym_value - start_offset;
 
+         /* Now adjust the second 32bit field, it's the ending offset
+            of a function.  */
          hit_data += sizeof (unsigned long);
          end_offset = adjustment + bfd_get_32 (abfd, hit_data);
          bfd_put_32 (abfd, end_offset, hit_data);
 
-         /* If this is not the last unwind entry, */
-         /* adjust the symbol value. */
-         if (i + 1 < r_addend)
-           {
-             start_offset = bfd_get_32 (abfd, hit_data + 3 * sizeof (unsigned long));
-              sym_value = start_offset + adjustment;
-           }
+         /* Prepare for the next iteration.  */
+         start_offset = bfd_get_32 (abfd, 
+                                    hit_data + 3 * sizeof (unsigned long));
+         sym_value = start_offset + adjustment;
        }
       break;
 
     default:
-      fprintf (stderr,
-              "Unrecognized relocation type 0x%02x (fmt=%x,field=%x)\n",
-              r_type, r_format, r_field);
+      abort ();
     }
 }
 
-/* Provided the symbol, returns the value reffed */
+/* Return the relocated value of the given symbol.  */
+
 static long
 get_symbol_value (symbol)
      asymbol *symbol;
 {
-  long relocation = 0;
-
-  if (symbol == (asymbol *) NULL)
-    relocation = 0;
-  else if (symbol->section == &bfd_com_section)
-    {
-      relocation = 0;
-    }
+  if (symbol == NULL
+      || symbol->section == &bfd_com_section)
+    return 0;
   else
-    {
-      relocation = symbol->value +
-       symbol->section->output_section->vma +
-       symbol->section->output_offset;
-    }
-
-  return (relocation);
+    return symbol->value + symbol->section->output_section->vma
+      + symbol->section->output_offset;
 }
 
-/* This function provides a pretty straight-forward mapping between a */
-/* base relocation type, format and field into the relocation type */
-/* that will be emitted in an object file.  The only wrinkle in the */
-/* mapping is that when the T, TR, TL, P, PR, or PL expression */
-/* prefixes are involved, the type gets promoted to a *_GOTOFF_* */
-/* relocation (in the case of T, TR, and TL) or a PLABEL relocation */
-/* (in the case of P, PR, and PL).     */
-
-/* NOTE: XXX the T, TR, TL, P, PR, and PL expression prefixes are not */
-/* handled yet. */
-
-static void
-hppa_elf_gen_reloc_error (base_type, fmt, field)
-     elf32_hppa_reloc_type base_type;
-     int fmt;
-     int field;
-{
-  fprintf (stderr, "undefined relocation: base=0x%x,fmt=0x%x,field=0x%x\n",
-          base_type, fmt, field);
-}
+/* Return one (or more) BFD relocations which implement the base
+   relocation with modifications based on format and field.  */
 
 elf32_hppa_reloc_type **
 hppa_elf_gen_reloc_type (abfd, base_type, format, field)
@@ -478,18 +589,20 @@ hppa_elf_gen_reloc_type (abfd, base_type, format, field)
      int format;
      int field;
 {
-#define UNDEFINED      hppa_elf_gen_reloc_error(base_type,format,field)
-
   elf32_hppa_reloc_type *finaltype;
   elf32_hppa_reloc_type **final_types;
-  int i;
 
-  final_types = (elf32_hppa_reloc_type **) bfd_alloc_by_size_t (abfd, sizeof (elf32_hppa_reloc_type *) * 2);
-  BFD_ASSERT (final_types != 0);
+  /* Allocate slots for the BFD relocation.  */
+  final_types = (elf32_hppa_reloc_type **)
+    bfd_alloc_by_size_t (abfd, sizeof (elf32_hppa_reloc_type *) * 2);
+  BFD_ASSERT (final_types != 0); /* FIXME */
 
-  finaltype = (elf32_hppa_reloc_type *) bfd_alloc_by_size_t (abfd, sizeof (elf32_hppa_reloc_type));
-  BFD_ASSERT (finaltype != 0);
+  /* Allocate space for the relocation itself.  */
+  finaltype = (elf32_hppa_reloc_type *)
+    bfd_alloc_by_size_t (abfd, sizeof (elf32_hppa_reloc_type));
+  BFD_ASSERT (finaltype != 0); /* FIXME */
 
+  /* Some reasonable defaults.  */
   final_types[0] = finaltype;
   final_types[1] = NULL;
 
@@ -497,6 +610,9 @@ hppa_elf_gen_reloc_type (abfd, base_type, format, field)
 
   final_type = base_type;
 
+  /* Just a tangle of nested switch statements to deal with the braindamage
+     that a different field selector means a completely different relocation
+     for PA ELF.  */
   switch (base_type)
     {
     case R_HPPA:
@@ -517,31 +633,24 @@ hppa_elf_gen_reloc_type (abfd, base_type, format, field)
            case e_rdsel:
              final_type = R_HPPA_RD11;
              break;
-
            case e_psel:
              final_type = R_HPPA_PLABEL_11;
              break;
            case e_rpsel:
              final_type = R_HPPA_PLABEL_R11;
              break;
-           case e_lpsel:
            case e_tsel:
-           case e_ltsel:
+             final_type = R_HPPA_DLT_11;
+             break;
            case e_rtsel:
-
-           case e_lsel:
-           case e_lrsel:
-           case e_lssel:
-           case e_rrsel:
+             final_type = R_HPPA_DLT_R11;
+             break;
            default:
-             UNDEFINED;
-             final_type = base_type;
+             abort ();
              break;
            }
          break;
-       case 12:
-         UNDEFINED;
-         break;
+
        case 14:
          switch (field)
            {
@@ -557,29 +666,24 @@ hppa_elf_gen_reloc_type (abfd, base_type, format, field)
            case e_rrsel:
              final_type = R_HPPA_RR14;
              break;
-
            case e_psel:
              final_type = R_HPPA_PLABEL_14;
              break;
            case e_rpsel:
              final_type = R_HPPA_PLABEL_R14;
              break;
-           case e_lpsel:
            case e_tsel:
-           case e_ltsel:
+             final_type = R_HPPA_DLT_14;
+             break;
            case e_rtsel:
-
-           case e_fsel:
-           case e_lsel:
-           case e_lssel:
-           case e_ldsel:
-           case e_lrsel:
+             final_type = R_HPPA_DLT_R14;
+             break;
            default:
-             UNDEFINED;
-             final_type = base_type;
+             abort ();
              break;
            }
          break;
+
        case 17:
          switch (field)
            {
@@ -598,16 +702,12 @@ hppa_elf_gen_reloc_type (abfd, base_type, format, field)
            case e_rrsel:
              final_type = R_HPPA_RR17;
              break;
-           case e_lsel:
-           case e_lssel:
-           case e_ldsel:
-           case e_lrsel:
            default:
-             UNDEFINED;
-             final_type = base_type;
+             abort ();
              break;
            }
          break;
+
        case 21:
          switch (field)
            {
@@ -626,17 +726,15 @@ hppa_elf_gen_reloc_type (abfd, base_type, format, field)
            case e_lpsel:
              final_type = R_HPPA_PLABEL_L21;
              break;
-           case e_rsel:
-           case e_rssel:
-           case e_rdsel:
-           case e_rrsel:
-           case e_fsel:
+           case e_ltsel:
+             final_type = R_HPPA_PLABEL_L21;
+             break;
            default:
-             UNDEFINED;
-             final_type = base_type;
+             abort ();
              break;
            }
          break;
+
        case 32:
          switch (field)
            {
@@ -646,18 +744,22 @@ hppa_elf_gen_reloc_type (abfd, base_type, format, field)
            case e_psel:
              final_type = R_HPPA_PLABEL_32;
              break;
+           case e_tsel:
+             final_type = R_HPPA_DLT_32;
+             break;
            default:
-             UNDEFINED;
-             final_type = base_type;
+             abort ();
              break;
            }
          break;
+
        default:
-         UNDEFINED;
-         final_type = base_type;
+         abort ();
          break;
        }
       break;
+
+
     case R_HPPA_GOTOFF:
       switch (format)
        {
@@ -676,20 +778,12 @@ hppa_elf_gen_reloc_type (abfd, base_type, format, field)
            case e_fsel:
              final_type = R_HPPA_GOTOFF_11;
              break;
-           case e_lsel:
-           case e_lrsel:
-           case e_lssel:
-           case e_rrsel:
            default:
-             UNDEFINED;
-             final_type = base_type;
+             abort ();
              break;
            }
          break;
-       case 12:
-         UNDEFINED;
-         final_type = base_type;
-         break;
+
        case 14:
          switch (field)
            {
@@ -708,20 +802,12 @@ hppa_elf_gen_reloc_type (abfd, base_type, format, field)
            case e_fsel:
              final_type = R_HPPA_GOTOFF_14;
              break;
-           case e_lsel:
-           case e_lssel:
-           case e_ldsel:
-           case e_lrsel:
            default:
-             UNDEFINED;
-             final_type = base_type;
+             abort ();
              break;
            }
          break;
-       case 17:
-         UNDEFINED;
-         final_type = base_type;
-         break;
+
        case 21:
          switch (field)
            {
@@ -737,27 +823,19 @@ hppa_elf_gen_reloc_type (abfd, base_type, format, field)
            case e_lrsel:
              final_type = R_HPPA_GOTOFF_LR21;
              break;
-           case e_rsel:
-           case e_rssel:
-           case e_rdsel:
-           case e_rrsel:
-           case e_fsel:
            default:
-             UNDEFINED;
-             final_type = base_type;
+             abort ();
              break;
            }
          break;
-       case 32:
-         UNDEFINED;
-         final_type = base_type;
-         break;
+
        default:
-         UNDEFINED;
-         final_type = base_type;
+         abort ();
          break;
        }
       break;
+
+
     case R_HPPA_PCREL_CALL:
       switch (format)
        {
@@ -776,20 +854,12 @@ hppa_elf_gen_reloc_type (abfd, base_type, format, field)
            case e_fsel:
              final_type = R_HPPA_PCREL_CALL_11;
              break;
-           case e_lsel:
-           case e_lrsel:
-           case e_lssel:
-           case e_rrsel:
            default:
-             UNDEFINED;
-             final_type = base_type;
+             abort ();
              break;
            }
          break;
-       case 12:
-         UNDEFINED;
-         final_type = base_type;
-         break;
+
        case 14:
          switch (field)
            {
@@ -808,16 +878,12 @@ hppa_elf_gen_reloc_type (abfd, base_type, format, field)
            case e_fsel:
              final_type = R_HPPA_PCREL_CALL_14;
              break;
-           case e_lsel:
-           case e_lssel:
-           case e_ldsel:
-           case e_lrsel:
            default:
-             UNDEFINED;
-             final_type = base_type;
+             abort ();
              break;
            }
          break;
+
        case 17:
          switch (field)
            {
@@ -836,16 +902,12 @@ hppa_elf_gen_reloc_type (abfd, base_type, format, field)
            case e_fsel:
              final_type = R_HPPA_PCREL_CALL_17;
              break;
-           case e_lsel:
-           case e_lssel:
-           case e_ldsel:
-           case e_lrsel:
            default:
-             UNDEFINED;
-             final_type = base_type;
+             abort ();
              break;
            }
          break;
+
        case 21:
          switch (field)
            {
@@ -861,27 +923,19 @@ hppa_elf_gen_reloc_type (abfd, base_type, format, field)
            case e_lrsel:
              final_type = R_HPPA_PCREL_CALL_LR21;
              break;
-           case e_rsel:
-           case e_rssel:
-           case e_rdsel:
-           case e_rrsel:
-           case e_fsel:
            default:
-             UNDEFINED;
-             final_type = base_type;
+             abort ();
              break;
            }
          break;
-       case 32:
-         UNDEFINED;
-         final_type = base_type;
-         break;
+
        default:
-         UNDEFINED;
-         final_type = base_type;
+         abort ();
          break;
        }
       break;
+
+
     case R_HPPA_PLABEL:
       switch (format)
        {
@@ -895,11 +949,11 @@ hppa_elf_gen_reloc_type (abfd, base_type, format, field)
              final_type = R_HPPA_PLABEL_R11;
              break;
            default:
-             UNDEFINED;
-             final_type = base_type;
+             abort ();
              break;
            }
          break;
+
        case 14:
          switch (field)
            {
@@ -910,11 +964,11 @@ hppa_elf_gen_reloc_type (abfd, base_type, format, field)
              final_type = R_HPPA_PLABEL_R14;
              break;
            default:
-             UNDEFINED;
-             final_type = base_type;
+             abort ();
              break;
            }
          break;
+
        case 21:
          switch (field)
            {
@@ -922,11 +976,11 @@ hppa_elf_gen_reloc_type (abfd, base_type, format, field)
              final_type = R_HPPA_PLABEL_L21;
              break;
            default:
-             UNDEFINED;
-             final_type = base_type;
+             abort ();
              break;
            }
          break;
+
        case 32:
          switch (field)
            {
@@ -934,16 +988,17 @@ hppa_elf_gen_reloc_type (abfd, base_type, format, field)
              final_type = R_HPPA_PLABEL_32;
              break;
            default:
-             UNDEFINED;
-             final_type = base_type;
+             abort ();
              break;
            }
          break;
+
        default:
-         UNDEFINED;
-         final_type = base_type;
+         abort ();
          break;
        }
+
+
     case R_HPPA_ABS_CALL:
       switch (format)
        {
@@ -962,20 +1017,12 @@ hppa_elf_gen_reloc_type (abfd, base_type, format, field)
            case e_fsel:
              final_type = R_HPPA_ABS_CALL_11;
              break;
-           case e_lsel:
-           case e_lrsel:
-           case e_lssel:
-           case e_rrsel:
            default:
-             UNDEFINED;
-             final_type = base_type;
+             abort ();
              break;
            }
          break;
-       case 12:
-         UNDEFINED;
-         final_type = base_type;
-         break;
+
        case 14:
          switch (field)
            {
@@ -994,16 +1041,12 @@ hppa_elf_gen_reloc_type (abfd, base_type, format, field)
            case e_fsel:
              final_type = R_HPPA_ABS_CALL_14;
              break;
-           case e_lsel:
-           case e_lssel:
-           case e_ldsel:
-           case e_lrsel:
            default:
-             UNDEFINED;
-             final_type = base_type;
+             abort ();
              break;
            }
          break;
+
        case 17:
          switch (field)
            {
@@ -1022,16 +1065,12 @@ hppa_elf_gen_reloc_type (abfd, base_type, format, field)
            case e_fsel:
              final_type = R_HPPA_ABS_CALL_17;
              break;
-           case e_lsel:
-           case e_lssel:
-           case e_ldsel:
-           case e_lrsel:
            default:
-             UNDEFINED;
-             final_type = base_type;
+             abort ();
              break;
            }
          break;
+
        case 21:
          switch (field)
            {
@@ -1047,110 +1086,33 @@ hppa_elf_gen_reloc_type (abfd, base_type, format, field)
            case e_lrsel:
              final_type = R_HPPA_ABS_CALL_LR21;
              break;
-           case e_rsel:
-           case e_rssel:
-           case e_rdsel:
-           case e_rrsel:
-           case e_fsel:
            default:
-             UNDEFINED;
-             final_type = base_type;
+             abort ();
              break;
            }
          break;
-       case 32:
-         UNDEFINED;
-         final_type = base_type;
-         break;
+
        default:
-         UNDEFINED;
-         final_type = base_type;
+         abort ();
          break;
        }
       break;
+
+
     case R_HPPA_UNWIND:
       final_type = R_HPPA_UNWIND_ENTRY;
       break;
+
+
     case R_HPPA_COMPLEX:
     case R_HPPA_COMPLEX_PCREL_CALL:
     case R_HPPA_COMPLEX_ABS_CALL:
-      final_types = (elf32_hppa_reloc_type **) bfd_alloc_by_size_t (abfd, sizeof (elf32_hppa_reloc_type *) * 6);
-      BFD_ASSERT (final_types != 0);
-
-      finaltype = (elf32_hppa_reloc_type *) bfd_alloc_by_size_t (abfd, sizeof (elf32_hppa_reloc_type) * 5);
-      BFD_ASSERT (finaltype != 0);
-
-      for (i = 0; i < 5; i++)
-       final_types[i] = &finaltype[i];
-
-      final_types[5] = NULL;
-
-      finaltype[0] = R_HPPA_PUSH_SYM;
-
-      if (base_type == R_HPPA_COMPLEX)
-       finaltype[1] = R_HPPA_PUSH_SYM;
-      else if (base_type == R_HPPA_COMPLEX_PCREL_CALL)
-       finaltype[1] = R_HPPA_PUSH_PCREL_CALL;
-      else                     /* base_type == R_HPPA_COMPLEX_ABS_CALL */
-       finaltype[1] = R_HPPA_PUSH_ABS_CALL;
-
-      finaltype[2] = R_HPPA_SUB;
-
-      switch (field)
-       {
-       case e_fsel:
-         finaltype[3] = R_HPPA_EXPR_F;
-         break;
-       case e_lsel:
-         finaltype[3] = R_HPPA_EXPR_L;
-         break;
-       case e_rsel:
-         finaltype[3] = R_HPPA_EXPR_R;
-         break;
-       case e_lssel:
-         finaltype[3] = R_HPPA_EXPR_LS;
-         break;
-       case e_rssel:
-         finaltype[3] = R_HPPA_EXPR_RS;
-         break;
-       case e_ldsel:
-         finaltype[3] = R_HPPA_EXPR_LD;
-         break;
-       case e_rdsel:
-         finaltype[3] = R_HPPA_EXPR_RD;
-         break;
-       case e_lrsel:
-         finaltype[3] = R_HPPA_EXPR_LR;
-         break;
-       case e_rrsel:
-         finaltype[3] = R_HPPA_EXPR_RR;
-         break;
-       }
-
-      switch (format)
-       {
-       case 11:
-         finaltype[4] = R_HPPA_EXPR_11;
-         break;
-       case 12:
-         finaltype[4] = R_HPPA_EXPR_12;
-         break;
-       case 14:
-         finaltype[4] = R_HPPA_EXPR_14;
-         break;
-       case 17:
-         finaltype[4] = R_HPPA_EXPR_17;
-         break;
-       case 21:
-         finaltype[4] = R_HPPA_EXPR_21;
-         break;
-       case 32:
-         finaltype[4] = R_HPPA_EXPR_32;
-         break;
-       }
-
+      /* The code originally here was horribly broken, and apparently
+        never used.  Zap it.  When we need complex relocations rewrite
+        it correctly!  */
+      abort ();
       break;
-
+      
     default:
       final_type = base_type;
       break;
@@ -1162,34 +1124,32 @@ hppa_elf_gen_reloc_type (abfd, base_type, format, field)
 #undef final_type
 
 
-/* this function is in charge of performing all the HP PA relocations */
-static long global_value;
-static long GOT_value; /* XXX:  need to calculate this! For HPUX, GOT == DP */
-static asymbol *global_symbol;
-static int global_sym_defined;
+/* Actually perform a relocation.  */
 
 static bfd_reloc_status_type
-hppa_elf_reloc (abfd, reloc_entry, symbol_in, data, input_section, output_bfd)
+hppa_elf_reloc (abfd, reloc_entry, symbol_in, data, input_section, output_bfd,
+               error_message)
      bfd *abfd;
      arelent *reloc_entry;
      asymbol *symbol_in;
      PTR data;
      asection *input_section;
      bfd *output_bfd;
+     char **error_message;
 {
   unsigned long insn;
   long sym_value = 0;
   unsigned long addr = reloc_entry->address;
-  bfd_byte *hit_data = addr + (bfd_byte *) (data);
-  unsigned short r_type = reloc_entry->howto->type & 0xFF;
-  unsigned short r_field = e_fsel;
+  bfd_byte *hit_data = addr + (bfd_byte *) data;
+  unsigned long r_type = reloc_entry->howto->type;
+  unsigned long r_field = e_fsel;
   boolean r_pcrel = reloc_entry->howto->pc_relative;
   unsigned r_format = reloc_entry->howto->bitsize;
   long r_addend = reloc_entry->addend;
 
+  /* If only performing a partial link, get out early.  */
   if (output_bfd)
     {
-      /* Partial linking - do nothing */
       reloc_entry->address += input_section->output_offset;
       return bfd_reloc_ok;
     }
@@ -1199,9 +1159,16 @@ hppa_elf_reloc (abfd, reloc_entry, symbol_in, data, input_section, output_bfd)
   if (symbol_in && symbol_in->section == &bfd_und_section)
     return bfd_reloc_undefined;
 
+  /* Get the final relocated value.  */
   sym_value = get_symbol_value (symbol_in);
 
-  /* Compute the value of $global$.  */
+  /* Compute the value of $global$.
+     FIXME: None of this should be necessary.  $global$ is just a 
+     marker and shouldn't really figure into these computations.
+
+     Once that's fixed we'll need to teach this backend to change
+     DP-relative relocations involving symbols in the text section
+     to be simple absolute relocations.  */
   if (!global_sym_defined)
     {
       if (global_symbol)
@@ -1234,14 +1201,8 @@ hppa_elf_reloc (abfd, reloc_entry, symbol_in, data, input_section, output_bfd)
 
     /* Handle all the basic type 1 relocations.  */
     case R_HPPA_32:
-      r_field = e_fsel;
-      goto do_basic_type_1;
     case R_HPPA_11:
-      r_field = e_fsel;
-      goto do_basic_type_1;
     case R_HPPA_14:
-      r_field = e_fsel;
-      goto do_basic_type_1;
     case R_HPPA_17:
       r_field = e_fsel;
       goto do_basic_type_1;
@@ -1249,11 +1210,7 @@ hppa_elf_reloc (abfd, reloc_entry, symbol_in, data, input_section, output_bfd)
       r_field = e_lsel;
       goto do_basic_type_1;
     case R_HPPA_R11:
-      r_field = e_rsel;
-      goto do_basic_type_1;
     case R_HPPA_R14:
-      r_field = e_rsel;
-      goto do_basic_type_1;
     case R_HPPA_R17:
       r_field = e_rsel;
       goto do_basic_type_1;
@@ -1261,11 +1218,7 @@ hppa_elf_reloc (abfd, reloc_entry, symbol_in, data, input_section, output_bfd)
       r_field = e_lssel;
       goto do_basic_type_1;
     case R_HPPA_RS11:
-      r_field = e_rssel;
-      goto do_basic_type_1;
     case R_HPPA_RS14:
-      r_field = e_rssel;
-      goto do_basic_type_1;
     case R_HPPA_RS17:
       r_field = e_ldsel;
       goto do_basic_type_1;
@@ -1273,11 +1226,7 @@ hppa_elf_reloc (abfd, reloc_entry, symbol_in, data, input_section, output_bfd)
       r_field = e_ldsel;
       goto do_basic_type_1;
     case R_HPPA_RD11:
-      r_field = e_rdsel;
-      goto do_basic_type_1;
     case R_HPPA_RD14:
-      r_field = e_rdsel;
-      goto do_basic_type_1;
     case R_HPPA_RD17:
       r_field = e_rdsel;
       goto do_basic_type_1;
@@ -1285,21 +1234,17 @@ hppa_elf_reloc (abfd, reloc_entry, symbol_in, data, input_section, output_bfd)
       r_field = e_lrsel;
       goto do_basic_type_1;
     case R_HPPA_RR14:
-      r_field = e_rrsel;
-      goto do_basic_type_1;
     case R_HPPA_RR17:
       r_field = e_rrsel;
 
     do_basic_type_1:
       insn = hppa_elf_relocate_insn (abfd, input_section, insn, addr,
-                                    symbol_in, sym_value, r_addend,
-                                    r_type, r_format, r_field, r_pcrel);
+                                    sym_value, r_addend, r_format,
+                                    r_field, r_pcrel);
       break;
 
     /* Handle all the basic type 2 relocations.  */
     case R_HPPA_GOTOFF_11:
-      r_field = e_fsel;
-      goto do_basic_type_2;
     case R_HPPA_GOTOFF_14:
       r_field = e_fsel;
       goto do_basic_type_2;
@@ -1307,8 +1252,6 @@ hppa_elf_reloc (abfd, reloc_entry, symbol_in, data, input_section, output_bfd)
       r_field = e_lsel;
       goto do_basic_type_2;
     case R_HPPA_GOTOFF_R11:
-      r_field = e_rsel;
-      goto do_basic_type_2;
     case R_HPPA_GOTOFF_R14:
       r_field = e_rsel;
       goto do_basic_type_2;
@@ -1316,8 +1259,6 @@ hppa_elf_reloc (abfd, reloc_entry, symbol_in, data, input_section, output_bfd)
       r_field = e_lssel;
       goto do_basic_type_2;
     case R_HPPA_GOTOFF_RS11:
-      r_field = e_rssel;
-      goto do_basic_type_2;
     case R_HPPA_GOTOFF_RS14:
       r_field = e_rssel;
       goto do_basic_type_2;
@@ -1325,8 +1266,6 @@ hppa_elf_reloc (abfd, reloc_entry, symbol_in, data, input_section, output_bfd)
       r_field = e_ldsel;
       goto do_basic_type_2;
     case R_HPPA_GOTOFF_RD11:
-      r_field = e_rdsel;
-      goto do_basic_type_2;
     case R_HPPA_GOTOFF_RD14:
       r_field = e_rdsel;
       goto do_basic_type_2;
@@ -1339,17 +1278,13 @@ hppa_elf_reloc (abfd, reloc_entry, symbol_in, data, input_section, output_bfd)
     do_basic_type_2:
       sym_value -= GOT_value;
       insn = hppa_elf_relocate_insn (abfd, input_section, insn, addr,
-                                    symbol_in, sym_value, r_addend,
-                                    r_type, r_format, r_field, r_pcrel);
+                                    sym_value, r_addend, r_format,
+                                    r_field, r_pcrel);
       break;
 
     /* Handle all the basic type 3 relocations.  */
     case R_HPPA_ABS_CALL_11:
-      r_field = e_fsel;
-      goto do_basic_type_3;
     case R_HPPA_ABS_CALL_14:
-      r_field = e_fsel;
-      goto do_basic_type_3;
     case R_HPPA_ABS_CALL_17:
       r_field = e_fsel;
       goto do_basic_type_3;
@@ -1357,11 +1292,7 @@ hppa_elf_reloc (abfd, reloc_entry, symbol_in, data, input_section, output_bfd)
       r_field = e_lsel;
       goto do_basic_type_3;
     case R_HPPA_ABS_CALL_R11:
-      r_field = e_rsel;
-      goto do_basic_type_3;
     case R_HPPA_ABS_CALL_R14:
-      r_field = e_rsel;
-      goto do_basic_type_3;
     case R_HPPA_ABS_CALL_R17:
       r_field = e_rsel;
       goto do_basic_type_3;
@@ -1369,11 +1300,7 @@ hppa_elf_reloc (abfd, reloc_entry, symbol_in, data, input_section, output_bfd)
       r_field = e_lssel;
       goto do_basic_type_3;
     case R_HPPA_ABS_CALL_RS11:
-      r_field = e_lssel;
-      goto do_basic_type_3;
     case R_HPPA_ABS_CALL_RS14:
-      r_field = e_rssel;
-      goto do_basic_type_3;
     case R_HPPA_ABS_CALL_RS17:
       r_field = e_rssel;
       goto do_basic_type_3;
@@ -1381,11 +1308,7 @@ hppa_elf_reloc (abfd, reloc_entry, symbol_in, data, input_section, output_bfd)
       r_field = e_ldsel;
       goto do_basic_type_3;
     case R_HPPA_ABS_CALL_RD11:
-      r_field = e_rdsel;
-      goto do_basic_type_3;
     case R_HPPA_ABS_CALL_RD14:
-      r_field = e_rdsel;
-      goto do_basic_type_3;
     case R_HPPA_ABS_CALL_RD17:
       r_field = e_rdsel;
       goto do_basic_type_3;
@@ -1393,24 +1316,18 @@ hppa_elf_reloc (abfd, reloc_entry, symbol_in, data, input_section, output_bfd)
       r_field = e_lrsel;
       goto do_basic_type_3;
     case R_HPPA_ABS_CALL_RR14:
-      r_field = e_rrsel;
-      goto do_basic_type_3;
     case R_HPPA_ABS_CALL_RR17:
       r_field = e_rrsel;
 
     do_basic_type_3:
       insn = hppa_elf_relocate_insn (abfd, input_section, insn, addr,
-                                    symbol_in, sym_value, r_addend,
-                                    r_type, r_format, r_field, r_pcrel);
+                                    sym_value, r_addend, r_format,
+                                    r_field, r_pcrel);
       break;
 
     /* Handle all the basic type 4 relocations.  */  
     case R_HPPA_PCREL_CALL_11:
-      r_field = e_fsel;
-      goto do_basic_type_4;
     case R_HPPA_PCREL_CALL_14:
-      r_field = e_fsel;
-      goto do_basic_type_4;
     case R_HPPA_PCREL_CALL_17:
       r_field = e_fsel;
       goto do_basic_type_4;
@@ -1418,11 +1335,7 @@ hppa_elf_reloc (abfd, reloc_entry, symbol_in, data, input_section, output_bfd)
       r_field = e_lsel;
       goto do_basic_type_4;
     case R_HPPA_PCREL_CALL_R11:
-      r_field = e_rsel;
-      goto do_basic_type_4;
     case R_HPPA_PCREL_CALL_R14:
-      r_field = e_rsel;
-      goto do_basic_type_4;
     case R_HPPA_PCREL_CALL_R17:
       r_field = e_rsel;
       goto do_basic_type_4;
@@ -1430,11 +1343,7 @@ hppa_elf_reloc (abfd, reloc_entry, symbol_in, data, input_section, output_bfd)
       r_field = e_lssel;
       goto do_basic_type_4;
     case R_HPPA_PCREL_CALL_RS11:
-      r_field = e_rssel;
-      goto do_basic_type_4;
     case R_HPPA_PCREL_CALL_RS14:
-      r_field = e_rssel;
-      goto do_basic_type_4;
     case R_HPPA_PCREL_CALL_RS17:
       r_field = e_rssel;
       goto do_basic_type_4;
@@ -1442,11 +1351,7 @@ hppa_elf_reloc (abfd, reloc_entry, symbol_in, data, input_section, output_bfd)
       r_field = e_ldsel;
       goto do_basic_type_4;
     case R_HPPA_PCREL_CALL_RD11:
-      r_field = e_rdsel;
-      goto do_basic_type_4;
     case R_HPPA_PCREL_CALL_RD14:
-      r_field = e_rdsel;
-      goto do_basic_type_4;
     case R_HPPA_PCREL_CALL_RD17:
       r_field = e_rdsel;
       goto do_basic_type_4;
@@ -1454,15 +1359,13 @@ hppa_elf_reloc (abfd, reloc_entry, symbol_in, data, input_section, output_bfd)
       r_field = e_lrsel;
       goto do_basic_type_4;
     case R_HPPA_PCREL_CALL_RR14:
-      r_field = e_rrsel;
-      goto do_basic_type_4;
     case R_HPPA_PCREL_CALL_RR17:
       r_field = e_rrsel;
 
     do_basic_type_4:
       insn = hppa_elf_relocate_insn (abfd, input_section, insn, addr,
-                                    symbol_in, sym_value, r_addend,
-                                    r_type, r_format, r_field, r_pcrel);
+                                    sym_value, r_addend, r_format,
+                                    r_field, r_pcrel);
       break;
 
     /* Handle all the basic type 5 relocations.  */  
@@ -1479,65 +1382,23 @@ hppa_elf_reloc (abfd, reloc_entry, symbol_in, data, input_section, output_bfd)
       r_field = e_rsel;
     do_basic_type_5:
       insn = hppa_elf_relocate_insn (abfd, input_section, insn, addr,
-                                    symbol_in, sym_value, r_addend,
-                                    r_type, r_format, r_field, r_pcrel);
+                                    sym_value, r_addend, r_format,
+                                    r_field, r_pcrel);
       break;
 
     /* Handle all basic type 6 relocations.  */
     case R_HPPA_UNWIND_ENTRY:
     case R_HPPA_UNWIND_ENTRIES:
-      hppa_elf_relocate_unwind_table (abfd, input_section, data, addr,
-                                     symbol_in, sym_value, r_addend,
-                                     r_type, r_format, r_field, r_pcrel);
+      hppa_elf_relocate_unwind_table (abfd, data, addr,
+                                     sym_value, r_addend,
+                                     r_type, r_field);
       return bfd_reloc_ok;
 
-    /* Handle the stack operations and similar braindamage.  */
-    case R_HPPA_PUSH_CONST:
-    case R_HPPA_PUSH_PC:
-    case R_HPPA_PUSH_SYM:
-    case R_HPPA_PUSH_GOTOFF:
-    case R_HPPA_PUSH_ABS_CALL:
-    case R_HPPA_PUSH_PCREL_CALL:
-    case R_HPPA_PUSH_PLABEL:
-    case R_HPPA_MAX:
-    case R_HPPA_MIN:
-    case R_HPPA_ADD:
-    case R_HPPA_SUB:
-    case R_HPPA_MULT:
-    case R_HPPA_DIV:
-    case R_HPPA_MOD:
-    case R_HPPA_AND:
-    case R_HPPA_OR:
-    case R_HPPA_XOR:
-    case R_HPPA_NOT:
-    case R_HPPA_LSHIFT:
-    case R_HPPA_ARITH_RSHIFT:
-    case R_HPPA_LOGIC_RSHIFT:
-    case R_HPPA_EXPR_F:
-    case R_HPPA_EXPR_L:
-    case R_HPPA_EXPR_R:
-    case R_HPPA_EXPR_LS:
-    case R_HPPA_EXPR_RS:
-    case R_HPPA_EXPR_LD:
-    case R_HPPA_EXPR_RD:
-    case R_HPPA_EXPR_LR:
-    case R_HPPA_EXPR_RR:
-    case R_HPPA_EXPR_32:
-    case R_HPPA_EXPR_21:
-    case R_HPPA_EXPR_11:
-    case R_HPPA_EXPR_14:
-    case R_HPPA_EXPR_17:
-    case R_HPPA_EXPR_12:
-      fprintf (stderr, "Relocation problem: ");
-      fprintf (stderr, "Unimplemented reloc type %d, in module %s\n",
-              r_type, abfd->filename);
-      return bfd_reloc_notsupported;
-
     /* This is a linker internal relocation.  */
     case R_HPPA_STUB_CALL_17:
       /* This relocation is for a branch to a long branch stub.
         Change instruction to a BLE,N.  It may also be necessary
-        to change interchange the branch and its delay slot.
+        to interchange the branch and its delay slot.
         The original instruction stream is
 
            bl <foo>,r          ; call foo using register r as
@@ -1553,17 +1414,34 @@ hppa_elf_reloc (abfd, reloc_entry, symbol_in, data, input_section, output_bfd)
         This braindamage is necessary because the compiler may put
         an instruction which uses %r31 in the delay slot of the original
         call.  By changing the call instruction from a "bl" to a "ble"
-        %r31 gets clobbered before the delay slot executes.
+        %r31 gets clobbered before the delay slot executes.  This
+        also means the stub has to play funny games to make sure
+        we return to the instruction just after the BLE rather than
+        two instructions after the BLE.
 
         We do not interchange the branch and delay slot if the delay
         slot was already nullified, or if the instruction in the delay
         slot modifies the return pointer to avoid an unconditional
-        jump after the call returns (GCC optimization).  */
+        jump after the call returns (GCC optimization).
+
+        None of this horseshit would be necessary if we put the
+        stubs between functions and just redirected the "bl" to
+        the stub.  Live and learn.  */
         
+      /* Is this instruction nullified?  (does this ever happen?)  */
       if (insn & 2)
-       insn = BLE_N_XXX_0_0;
+        {
+         insn = BLE_N_XXX_0_0;
+         bfd_put_32 (abfd, insn, hit_data);
+         r_type = R_HPPA_ABS_CALL_17;
+         r_pcrel = 0;
+         insn = hppa_elf_relocate_insn (abfd, input_section, insn,
+                                        addr, sym_value, r_addend,
+                                        r_format, r_field, r_pcrel);
+        }
       else
        {
+         /* So much for the trivial case...  */
          unsigned long old_delay_slot_insn = bfd_get_32 (abfd, hit_data + 4);
          unsigned rtn_reg = (insn & 0x03e00000) >> 21;
 
@@ -1574,32 +1452,47 @@ hppa_elf_reloc (abfd, reloc_entry, symbol_in, data, input_section, output_bfd)
 
              /* If the target of the LDO is the same as the return
                 register then there is no reordering.  We can leave the
-                instuction as a non-nullified BLE in this case.  */
+                instuction as a non-nullified BLE in this case.
+
+                FIXME:  This test looks wrong.  If we had a ble using
+                ldo_target_reg as the *source* we'd fuck this up.  */
              if (ldo_target_reg == rtn_reg)
                {
                  unsigned long new_delay_slot_insn = old_delay_slot_insn;
 
-                 BFD_ASSERT(ldo_src_reg == ldo_target_reg);
+                 BFD_ASSERT (ldo_src_reg == ldo_target_reg);
                  new_delay_slot_insn &= 0xfc00ffff;
                  new_delay_slot_insn |= ((31 << 21) | (31 << 16));
                  bfd_put_32 (abfd, new_delay_slot_insn, hit_data + 4);
                  insn = BLE_XXX_0_0;
-                 bfd_put_32 (abfd, insn, hit_data);
                  r_type = R_HPPA_ABS_CALL_17;
                  r_pcrel = 0;
                  insn = hppa_elf_relocate_insn (abfd, input_section, insn,
-                                                addr, symbol_in, sym_value,
-                                                r_addend, r_type, r_format,
-                                                r_field, r_pcrel);
-                 bfd_put_32 (abfd, insn, hit_data + 4);
+                                                addr, sym_value, r_addend,
+                                                r_format, r_field, r_pcrel);
+                 bfd_put_32 (abfd, insn, hit_data);
                  return bfd_reloc_ok;
                }
+              else if (rtn_reg == 31)
+                {
+                  /* The return register is r31, so this is a millicode
+                    call.  Do not perform any instruction reordering.  */
+                 insn = BLE_XXX_0_0;
+                 r_type = R_HPPA_ABS_CALL_17;
+                 r_pcrel = 0;
+                 insn = hppa_elf_relocate_insn (abfd, input_section, insn,
+                                                addr, sym_value,
+                                                r_addend, r_format,
+                                                r_field, r_pcrel);
+                 bfd_put_32 (abfd, insn, hit_data);
+                 return bfd_reloc_ok;
+                }
              else
                {
                  /* Check to see if the delay slot instruction has a
                     relocation.  If so, we need to change the address
-                    field of it, because the instruction it relocates
-                    is going to be moved.  */
+                    field of it because the instruction it relocates
+                    is going to be moved.  Oh what a mess.  */
                  arelent * next_reloc_entry = reloc_entry+1;
 
                  if (next_reloc_entry->address == reloc_entry->address + 4)
@@ -1612,13 +1505,28 @@ hppa_elf_reloc (abfd, reloc_entry, symbol_in, data, input_section, output_bfd)
                  r_type = R_HPPA_ABS_CALL_17;
                  r_pcrel = 0;
                  insn = hppa_elf_relocate_insn (abfd, input_section, insn,
-                                                addr + 4, symbol_in, 
-                                                sym_value, r_addend, r_type,
+                                                addr + 4,
+                                                sym_value, r_addend,
                                                 r_format, r_field, r_pcrel);
                  bfd_put_32 (abfd, insn, hit_data + 4);
                  return bfd_reloc_ok;
                }
            }
+         /* Same comments as above regarding incorrect test.  */
+          else if (rtn_reg == 31)
+            {
+              /* The return register is r31, so this is a millicode call.
+                Perform no instruction reordering in this case.  */
+             insn = BLE_XXX_0_0;
+             r_type = R_HPPA_ABS_CALL_17;
+             r_pcrel = 0;
+             insn = hppa_elf_relocate_insn (abfd, input_section, insn,
+                                            addr, sym_value,
+                                            r_addend, r_format,
+                                            r_field, r_pcrel);
+             bfd_put_32 (abfd, insn, hit_data);
+             return bfd_reloc_ok;
+            }
          else
            {
              /* Check to see if the delay slot instruction has a
@@ -1637,8 +1545,8 @@ hppa_elf_reloc (abfd, reloc_entry, symbol_in, data, input_section, output_bfd)
              r_type = R_HPPA_ABS_CALL_17;
              r_pcrel = 0;
              insn = hppa_elf_relocate_insn (abfd, input_section, insn,
-                                            addr + 4, symbol_in, sym_value,
-                                            r_addend, r_type, r_format,
+                                            addr + 4, sym_value,
+                                            r_addend, r_format,
                                             r_field, r_pcrel);
              bfd_put_32 (abfd, insn, hit_data + 4);
              return bfd_reloc_ok;
@@ -1646,11 +1554,10 @@ hppa_elf_reloc (abfd, reloc_entry, symbol_in, data, input_section, output_bfd)
        }
       break;
       
+    /* Something we don't know how to handle.  */
     default:
-      fprintf (stderr, "Relocation problem : ");
-      fprintf (stderr, "Unrecognized reloc type %d, in module %s\n",
-              r_type, abfd->filename);
-      return bfd_reloc_dangerous;
+      *error_message = (char *) "Unrecognized reloc";
+      return bfd_reloc_notsupported;
     }
 
   /* Update the instruction word.  */
@@ -1658,7 +1565,10 @@ hppa_elf_reloc (abfd, reloc_entry, symbol_in, data, input_section, output_bfd)
   return (bfd_reloc_ok);
 }
 
-static const reloc_howto_type *
+/* Return the address of the howto table entry to perform the CODE
+   relocation for an ARCH machine.  */
+
+static CONST reloc_howto_type *
 elf_hppa_reloc_type_lookup (arch, code)
      bfd_arch_info_type *arch;
      bfd_reloc_code_real_type code;
@@ -1668,18 +1578,20 @@ elf_hppa_reloc_type_lookup (arch, code)
       BFD_ASSERT ((int) elf_hppa_howto_table[(int) code].type == (int) code);
       return &elf_hppa_howto_table[(int) code];
     }
-
-  return (reloc_howto_type *) 0;
+  return NULL;
 }
 
-#define bfd_elf32_bfd_reloc_type_lookup        elf_hppa_reloc_type_lookup
 
+/* Update the symbol extention chain to include the symbol pointed to
+   by SYMBOLP if SYMBOLP is a function symbol.  Used internally and by GAS.  */
 
 void
-DEFUN (elf_hppa_tc_symbol, (abfd, symbolP, sym_idx),
-       bfd * abfd AND
-       elf_symbol_type * symbolP AND
-       int sym_idx)
+elf_hppa_tc_symbol (abfd, symbolP, sym_idx, symext_root, symext_last)
+     bfd *abfd;
+     elf_symbol_type *symbolP;
+     int sym_idx;
+     symext_chainS **symext_root;
+     symext_chainS **symext_last;
 {
   symext_chainS *symextP;
   unsigned int arg_reloc;
@@ -1695,7 +1607,13 @@ DEFUN (elf_hppa_tc_symbol, (abfd, symbolP, sym_idx),
   if (arg_reloc == 0)
     return;
 
+  /* Allocate memory and initialize this entry.  */
   symextP = (symext_chainS *) bfd_alloc (abfd, sizeof (symext_chainS) * 2);
+  if (!symextP)
+    {
+      bfd_set_error (bfd_error_no_memory);
+      abort();                 /* FIXME */
+    }
 
   symextP[0].entry = ELF32_HPPA_SX_WORD (HPPA_SXT_SYMNDX, sym_idx);
   symextP[0].next = &symextP[1];
@@ -1703,47 +1621,45 @@ DEFUN (elf_hppa_tc_symbol, (abfd, symbolP, sym_idx),
   symextP[1].entry = ELF32_HPPA_SX_WORD (HPPA_SXT_ARG_RELOC, arg_reloc);
   symextP[1].next = NULL;
 
-  if (symext_rootP == NULL)
+  /* Now update the chain itself so it can be walked later to build
+     the symbol extension section.  */
+  if (*symext_root == NULL)
     {
-      symext_rootP = &symextP[0];
-      symext_lastP = &symextP[1];
+      *symext_root = &symextP[0];
+      *symext_last = &symextP[1];
     }
   else
     {
-      symext_lastP->next = &symextP[0];
-      symext_lastP = &symextP[1];
+      (*symext_last)->next = &symextP[0];
+      *symext_last = &symextP[1];
     }
 }
 
-/* Accessor function for the list of symbol extension records. */
-symext_chainS *elf32_hppa_get_symextn_chain()
-{
-  return symext_rootP;
-}
-
-static symext_entryS *symextn_contents;
-static unsigned int symextn_contents_real_size;
+/* Build the symbol extension section.  Used internally and by GAS.  */ 
 
 void
-DEFUN (elf_hppa_tc_make_sections, (abfd, ignored),
-       bfd * abfd AND
-       PTR ignored)
+elf_hppa_tc_make_sections (abfd, symext_root)
+     bfd *abfd;
+     symext_chainS *symext_root;
 {
   symext_chainS *symextP;
-  int size;
-  int n;
-  int i;
-  void hppa_elf_stub_finish ();        /* forward declaration */
+  int size, n, i;
   asection *symextn_sec;
 
+  /* FIXME: Huh?  I don't see what this is supposed to do for us.  */
   hppa_elf_stub_finish (abfd);
 
-  if (symext_rootP == NULL)
+  /* If there are no entries in the symbol extension chain, then
+     there is no symbol extension section.  */
+  if (symext_root == NULL)
     return;
 
-  for (n = 0, symextP = symext_rootP; symextP; symextP = symextP->next, ++n)
+  /* Count the number of entries on the chain.  */
+  for (n = 0, symextP = symext_root; symextP; symextP = symextP->next, ++n)
     ;
 
+  /* Create the symbol extension section and set some appropriate
+     attributes.  */
   size = sizeof (symext_entryS) * n;
   symextn_sec = bfd_get_section_by_name (abfd, SYMEXTN_SECTION_NAME);
   if (symextn_sec == (asection *) 0)
@@ -1751,123 +1667,61 @@ DEFUN (elf_hppa_tc_make_sections, (abfd, ignored),
       symextn_sec = bfd_make_section (abfd, SYMEXTN_SECTION_NAME);
       bfd_set_section_flags (abfd,
                             symextn_sec,
-        SEC_HAS_CONTENTS | SEC_LOAD | SEC_ALLOC | SEC_CODE | SEC_READONLY);
+                            SEC_LOAD | SEC_HAS_CONTENTS | SEC_DATA);
       symextn_sec->output_section = symextn_sec;
       symextn_sec->output_offset = 0;
       bfd_set_section_alignment (abfd, symextn_sec, 2);
     }
+  bfd_set_section_size (abfd, symextn_sec, symextn_contents_real_size);
+  symextn_contents_real_size = size;
+
+  /* Grab some memory for the contents of the symbol extension section
+     itself.  */
   symextn_contents = (symext_entryS *) bfd_alloc (abfd, size);
+  if (!symextn_contents)
+    {
+      bfd_set_error (bfd_error_no_memory);
+      abort();                 /* FIXME */
+    }
 
-  for (i = 0, symextP = symext_rootP; symextP; symextP = symextP->next, ++i)
+  /* Fill in the contents of the symbol extension section.  */
+  for (i = 0, symextP = symext_root; symextP; symextP = symextP->next, ++i)
     symextn_contents[i] = symextP->entry;
-  symextn_contents_real_size = size;
-  bfd_set_section_size (abfd, symextn_sec, symextn_contents_real_size);
 
   return;
 }
 
-/* Support for HP PA-RISC stub generation.
-
-   Written by
-
-       Center for Software Science
-       Department of Computer Science
-       University of Utah
-
-    */
-
-/*
-    HP-PA calling conventions state:
-
-    1. an argument relocation stub is required whenever the callee and
-    caller argument relocation bits do not match exactly.  The exception
-    to this rule is if either the caller or callee argument relocation
-    bit are 00 (do not relocate).
-
-    2. The linker can optionally add a symbol record for the stub so that
-    the stub can be reused.  The symbol record will be the same as the
-    original export symbol record, except that the relocation bits will
-    reflect the input of the stub, the type would be STUB and the symbol
-    value will be the location of the relocation stub.
+/* Return the symbol extension record of type TYPE for the symbol SYM.  */
 
-    Other notes:
-
-    Stubs can be inserted *before* the section of the caller.  The stubs
-    can be treated as calls to code that manipulates the arguments.
-
- */
-
-typedef enum
-  {
-    HPPA_STUB_ILLEGAL,
-    HPPA_STUB_ARG_RELOC,
-    HPPA_STUB_LONG_BRANCH
-  } hppa_stub_type;
-
-symext_entryS
+static symext_entryS
 elf32_hppa_get_sym_extn (abfd, sym, type)
      bfd *abfd;
      asymbol *sym;
      int type;
 {
-  /* This function finds the symbol extension record of the */
-  /* specified type for the specified symbol.  It returns the */
-  /* value of the symbol extension record.     */
-  symext_entryS retval;
-
   switch (type)
     {
-    case HPPA_SXT_NULL:
-      retval = (symext_entryS) 0;
-      break;
     case HPPA_SXT_SYMNDX:
-      retval = (symext_entryS) 0;      /* XXX: need to fix this */
-      break;
+    case HPPA_SXT_NULL:
+      return (symext_entryS) 0;
     case HPPA_SXT_ARG_RELOC:
       {
        elf_symbol_type *esymP = (elf_symbol_type *) sym;
 
-       retval = (symext_entryS) esymP->tc_data.hppa_arg_reloc;
-       break;
+       return (symext_entryS) esymP->tc_data.hppa_arg_reloc;
       }
     /* This should never happen.  */
     default:
       abort();
     }
-  return retval;
 }
 
-typedef struct elf32_hppa_stub_name_list_struct
-{
-  /* name of this stub  */
-  asymbol *sym;
-  /* stub description for this stub  */
-  struct elf32_hppa_stub_description_struct *stub_desc;
-  /* pointer into stub contents  */
-  int *stub_secp;
-  /* size of this stub  */
-  unsigned size;
-  /* next stub name entry  */
-  struct elf32_hppa_stub_name_list_struct *next;
-} elf32_hppa_stub_name_list;
-
-typedef struct elf32_hppa_stub_description_struct
-  {
-    struct elf32_hppa_stub_description_struct *next;
-    bfd *this_bfd;             /* bfd to which this stub applies */
-    asection *stub_sec;                /* stub section for this bfd */
-    unsigned relocs_allocated_cnt; /* count of relocations for this stub section */
-    unsigned real_size;
-    unsigned allocated_size;
-    int *stub_secp;            /* pointer to the next available location in the buffer */
-    char *stub_contents;       /* contents of the stubs for this bfd */
-    elf32_hppa_stub_name_list *stub_listP;
-  }
-elf32_hppa_stub_description;
+/* Search the chain of stub descriptions and locate the stub
+   description for this the given section within the given bfd.
 
-static elf32_hppa_stub_description *elf_hppa_stub_rootP;
+   FIXME:  I see yet another wonderful linear linked list search
+   here.  This is probably bad.  */
 
-/* Locate the stub section information for the given bfd. */
 static elf32_hppa_stub_description *
 find_stubs (abfd, stub_sec)
      bfd *abfd;
@@ -1877,25 +1731,28 @@ find_stubs (abfd, stub_sec)
 
   for (stubP = elf_hppa_stub_rootP; stubP; stubP = stubP->next)
     {
-      if (stubP->this_bfd == abfd
-         && stubP->stub_sec == stub_sec)
+      /* Is this the right one?  */ 
+      if (stubP->this_bfd == abfd && stubP->stub_sec == stub_sec)
        return stubP;
     }
-
-  return (elf32_hppa_stub_description *) NULL;
+  return NULL;
 }
 
 static elf32_hppa_stub_description *
-new_stub (abfd, stub_sec)
+new_stub (abfd, stub_sec, link_info)
      bfd *abfd;
      asection *stub_sec;
+     struct bfd_link_info *link_info;
 {
   elf32_hppa_stub_description *stub = find_stubs (abfd, stub_sec);
 
+  /* If we found a list for this bfd, then use it.  */
   if (stub)
     return stub;
 
-  stub = (elf32_hppa_stub_description *) bfd_zalloc (abfd, sizeof (elf32_hppa_stub_description));
+  /* Nope, allocate and initialize a new entry in the stub list chain.  */
+  stub = (elf32_hppa_stub_description *)
+    bfd_zalloc (abfd, sizeof (elf32_hppa_stub_description));
   if (stub)
     {
       stub->this_bfd = abfd;
@@ -1904,57 +1761,69 @@ new_stub (abfd, stub_sec)
       stub->allocated_size = 0;
       stub->stub_contents = NULL;
       stub->stub_secp = NULL;
+      stub->link_info = link_info;
 
       stub->next = elf_hppa_stub_rootP;
       elf_hppa_stub_rootP = stub;
     }
   else
     {
-      bfd_error = no_memory;
-      bfd_perror ("new_stub");
+      bfd_set_error (bfd_error_no_memory);
+      abort();                 /* FIXME */
     }
 
   return stub;
 }
 
-/* Locate the stub by the given name.  */
+/* Try and locate a stub with the name NAME within the stubs
+   associated with ABFD.  More linked list searches.  */
+
 static elf32_hppa_stub_name_list *
 find_stub_by_name (abfd, stub_sec, name)
      bfd *abfd;
      asection *stub_sec;
      char *name;
 {
+  /* Find the stubs associated with this bfd.  */
   elf32_hppa_stub_description *stub = find_stubs (abfd, stub_sec);
 
+  /* If found, then we have to walk down them looking for a match.  */
   if (stub)
     {
       elf32_hppa_stub_name_list *name_listP;
 
-      for (name_listP = stub->stub_listP; name_listP; name_listP = name_listP->next)
+      for (name_listP = stub->stub_listP;
+          name_listP;
+          name_listP = name_listP->next)
        {
          if (!strcmp (name_listP->sym->name, name))
            return name_listP;
        }
     }
 
+  /* Not found.  */
   return 0;
 }
 
-/* Locate the stub by the given name.  */
+/* Add a new stub (SYM) to the list of stubs associated with the given BFD.  */
 static elf32_hppa_stub_name_list *
-add_stub_by_name(abfd, stub_sec, sym)
+add_stub_by_name(abfd, stub_sec, sym, link_info)
      bfd *abfd;
      asection *stub_sec;
      asymbol *sym;
+     struct bfd_link_info *link_info;
 {
   elf32_hppa_stub_description *stub = find_stubs (abfd, stub_sec);
   elf32_hppa_stub_name_list *stub_entry;
 
+  /* If no stubs are associated with this bfd, then we have to make
+     a chain-of-stubs associated with this bfd.  */
   if (!stub)
-    stub = new_stub(abfd, stub_sec);
+    stub = new_stub (abfd, stub_sec, link_info);
 
   if (stub)
     {
+      /* Allocate and initialize an entry in the stub chain.  */
       stub_entry = (elf32_hppa_stub_name_list *)
        bfd_zalloc (abfd, sizeof (elf32_hppa_stub_name_list));
 
@@ -1966,6 +1835,7 @@ add_stub_by_name(abfd, stub_sec, sym)
          /* First byte of this stub is the pointer to
             the next available location in the stub buffer.  */
          stub_entry->stub_secp = stub->stub_secp;
+         /* Add it to the chain.  */
          if (stub->stub_listP)
            stub_entry->next = stub->stub_listP;
          else
@@ -1975,88 +1845,20 @@ add_stub_by_name(abfd, stub_sec, sym)
        }
       else
        {
-         bfd_error = no_memory;
-         bfd_perror("add_stub_by_name");
+         bfd_set_error (bfd_error_no_memory);
+         abort();              /* FIXME */
        }
     }
-
+  /* Death by mis-adventure.  */
+  abort ();
   return (elf32_hppa_stub_name_list *)NULL;
 }
 
-#define ARGUMENTS      0
-#define RETURN_VALUE   1
-
-#define        NO_ARG_RELOC    0
-#define R_TO_FR                1
-#define R01_TO_FR      2
-#define R23_TO_FR      3
-#define FR_TO_R                4
-#define FR_TO_R01      5
-#define FR_TO_R23      6
-#define        ARG_RELOC_ERR   7
-
-#define ARG0   0
-#define ARG1   1
-#define ARG2   2
-#define ARG3   3
-#define RETVAL 4
-
-#define AR_NO  0
-#define AR_GR  1
-#define AR_FR  2
-#define AR_FU  3
-/* FP register in arg0/arg1.  This value can only appear in the arg0 location. */
-#define AR_DBL01       4
-/* FP register in arg2/arg3.  This value can only appear in the arg2 location. */
-#define AR_DBL23       5
-
-#define AR_WARN(type,loc) \
-  fprintf(stderr,"WARNING:  Illegal argument relocation: %s for %s\n", \
-         reloc_type_strings[type],reloc_loc_strings[loc])
-
-static CONST char *CONST reloc_type_strings[] =
-{
-  "NONE", "GR->FR", "GR0,GR1->FR1", "GR2,GR3->FR3", "FR->GR", "FR->GR0,GR1", "FR->GR2,GR3", "ERROR"
-};
-
-static CONST char *CONST reloc_loc_strings[] =
-{
-  "ARG0", "ARG1", "ARG2", "ARG3", "RETVAL"
-};
-
-static CONST char mismatches[6][6] =
-{                              /*      CALLEE NONE     CALLEE GR       CALLEE FR       CALLEE FU       CALLEE DBL01    CALLEE DBL23    */
-  /* CALLER NONE       */
- {NO_ARG_RELOC, NO_ARG_RELOC, NO_ARG_RELOC, ARG_RELOC_ERR, NO_ARG_RELOC, NO_ARG_RELOC},
- /* CALLER GR  */
- {NO_ARG_RELOC, NO_ARG_RELOC, R_TO_FR, ARG_RELOC_ERR, R01_TO_FR, ARG_RELOC_ERR},
- /* CALLER FR  */
- {NO_ARG_RELOC, FR_TO_R, NO_ARG_RELOC, ARG_RELOC_ERR, ARG_RELOC_ERR},
- /* CALLER FU  */
- {ARG_RELOC_ERR, ARG_RELOC_ERR, ARG_RELOC_ERR, ARG_RELOC_ERR, ARG_RELOC_ERR, ARG_RELOC_ERR},
- /* CALLER DBL01       */
- {NO_ARG_RELOC, FR_TO_R01, NO_ARG_RELOC, ARG_RELOC_ERR, NO_ARG_RELOC, ARG_RELOC_ERR},
- /* CALLER DBL23       */
- {NO_ARG_RELOC, FR_TO_R23, NO_ARG_RELOC, ARG_RELOC_ERR, ARG_RELOC_ERR, NO_ARG_RELOC},
-};
-
-static CONST char retval_mismatches[6][6] =
-{      /*      CALLEE NONE     CALLEE GR       CALLEE FR       CALLEE FU       CALLEE DBL01    CALLEE DBL23    */
-  /* CALLER NONE       */
- {NO_ARG_RELOC, NO_ARG_RELOC, NO_ARG_RELOC, ARG_RELOC_ERR, NO_ARG_RELOC, NO_ARG_RELOC},
- /* CALLER GR  */
- {NO_ARG_RELOC, NO_ARG_RELOC, FR_TO_R, ARG_RELOC_ERR, FR_TO_R01, ARG_RELOC_ERR},
- /* CALLER FR  */
- {NO_ARG_RELOC, R_TO_FR, NO_ARG_RELOC, ARG_RELOC_ERR, ARG_RELOC_ERR, ARG_RELOC_ERR},
- /* CALLER FU  */
- {ARG_RELOC_ERR, ARG_RELOC_ERR, ARG_RELOC_ERR, ARG_RELOC_ERR, ARG_RELOC_ERR, ARG_RELOC_ERR},
- /* CALLER DBL01       */
- {NO_ARG_RELOC, R01_TO_FR, NO_ARG_RELOC, ARG_RELOC_ERR, NO_ARG_RELOC, ARG_RELOC_ERR},
- /* CALLER DBL23       */
- {NO_ARG_RELOC, R23_TO_FR, NO_ARG_RELOC, ARG_RELOC_ERR, ARG_RELOC_ERR, NO_ARG_RELOC},
-};
+/* For the given caller/callee argument location information and the
+   type of relocation (arguments or return value), return the type
+   of argument relocation needed to make caller and callee happy.  */
 
-static int
+static arg_reloc_type
 type_of_mismatch (caller_bits, callee_bits, type)
      int caller_bits;
      int callee_bits;
@@ -2069,90 +1871,116 @@ type_of_mismatch (caller_bits, callee_bits, type)
     case RETURN_VALUE:
       return retval_mismatches[caller_bits][callee_bits];
     }
-
-  return 0;
+  return ARG_RELOC_ERR;
 }
 
-#define EXTRACT_ARBITS(ar,which)       ((ar) >> (8-(which*2))) & 3
+/* Extract specific argument location bits for WHICH from the
+   the full argument location information in AR.  */
+#define EXTRACT_ARBITS(ar, which)      ((ar) >> (8 - ((which) * 2))) & 3
 
-#define NEW_INSTRUCTION(entry,insn)    \
+/* Add the new instruction INSN into the stub area denoted by ENTRY.
+   FIXME:  Looks like more cases where we assume sizeof (int) ==
+   sizeof (insn) which may not be true if building cross tools.  */
+#define NEW_INSTRUCTION(entry, insn)   \
 { \
   *((entry)->stub_desc->stub_secp)++ = (insn); \
-  (entry)->stub_desc->real_size += sizeof(int);        \
+  (entry)->stub_desc->real_size += sizeof (int);       \
   (entry)->size += sizeof(int);        \
   bfd_set_section_size((entry)->stub_desc->this_bfd,   \
                       (entry)->stub_desc->stub_sec,    \
                       (entry)->stub_desc->real_size);  \
 }
 
+/* Find the offset of the current stub?  Looks more like it
+   finds the offset of the last instruction to me.  */
 #define CURRENT_STUB_OFFSET(entry)     \
-  ((int)(entry)->stub_desc->stub_secp \
-   - (int)(entry)->stub_desc->stub_contents - 4)
+  ((char *)(entry)->stub_desc->stub_secp \
+   - (char *)(entry)->stub_desc->stub_contents - 4)
 
-static boolean stubs_finished = false;
+/* All the stubs have already been built, finish up stub stuff
+   by applying relocations to the stubs.  */
 
-void
+static void
 hppa_elf_stub_finish (output_bfd)
      bfd *output_bfd;
 {
-  extern bfd_error_vector_type bfd_error_vector;
   elf32_hppa_stub_description *stub_list = elf_hppa_stub_rootP;
-  /* All the stubs have been built.  Finish up building        */
-  /* stub section.  Apply relocations to the section.  */
 
-  if ( stubs_finished )
+  /* If the stubs have been finished, then we're already done.  */
+  if (stubs_finished)
     return;
 
+  /* Walk down the list of stub lists. */
   for (; stub_list; stub_list = stub_list->next)
     {
+      /* If this list has stubs, then do something.  */
       if (stub_list->real_size)
        {
          bfd *stub_bfd = stub_list->this_bfd;
-         asection *stub_sec = bfd_get_section_by_name (stub_bfd, ".hppa_linker_stubs");
+         asection *stub_sec = bfd_get_section_by_name (stub_bfd,
+                                                       ".hppa_linker_stubs");
          bfd_size_type reloc_size;
          arelent **reloc_vector;
 
+         /* Some sanity checking.  */
          BFD_ASSERT (stub_sec == stub_list->stub_sec);
-         reloc_size = bfd_get_reloc_upper_bound (stub_bfd, stub_sec);
-         reloc_vector = (arelent **) alloca (reloc_size);
-
          BFD_ASSERT (stub_sec);
 
-         /* We are not relaxing the section, so just copy the size info */
+         /* For stub sections raw_size == cooked_size.  Also update
+            reloc_done as we're handling the relocs now.  */
          stub_sec->_cooked_size = stub_sec->_raw_size;
          stub_sec->reloc_done = true;
 
+         /* Make space to hold the relocations for the stub section.  */
+         reloc_size = bfd_get_reloc_upper_bound (stub_bfd, stub_sec);
+         reloc_vector = (arelent **) alloca (reloc_size);
 
-         if (bfd_canonicalize_reloc (stub_bfd,
-                                     stub_sec,
-                                     reloc_vector,
+         /* If we have relocations, do them.  */
+         if (bfd_canonicalize_reloc (stub_bfd, stub_sec, reloc_vector,
                                      output_bfd->outsymbols))
            {
              arelent **parent;
-             for (parent = reloc_vector; *parent != (arelent *) NULL;
-                  parent++)
+             for (parent = reloc_vector; *parent != NULL; parent++)
                {
+                 char *err = NULL;
                  bfd_reloc_status_type r =
-                 bfd_perform_relocation (stub_bfd,
-                                         *parent,
-                                         stub_list->stub_contents,
-                                         stub_sec, 0);
-
+                   bfd_perform_relocation (stub_bfd, *parent,
+                                           stub_list->stub_contents,
+                                           stub_sec, (bfd *) NULL, &err);
 
+                 /* If there was an error, tell someone about it.  */
                  if (r != bfd_reloc_ok)
                    {
+                     struct bfd_link_info *link_info = stub_list->link_info;
+
                      switch (r)
                        {
                        case bfd_reloc_undefined:
-                         bfd_error_vector.undefined_symbol (*parent, NULL);
+                         if (! ((*link_info->callbacks->undefined_symbol)
+                                (link_info,
+                                 bfd_asymbol_name (*(*parent)->sym_ptr_ptr),
+                                 stub_bfd, stub_sec, (*parent)->address)))
+                           abort ();
                          break;
                        case bfd_reloc_dangerous:
-                         bfd_error_vector.reloc_dangerous (*parent, NULL);
+                         if (! ((*link_info->callbacks->reloc_dangerous)
+                                (link_info, err, stub_bfd, stub_sec,
+                                 (*parent)->address)))
+                           abort ();
                          break;
-                       case bfd_reloc_outofrange:
                        case bfd_reloc_overflow:
-                         bfd_error_vector.reloc_value_truncated (*parent, NULL);
+                         {
+                           if (! ((*link_info->callbacks->reloc_overflow)
+                                  (link_info,
+                                   bfd_asymbol_name (*(*parent)->sym_ptr_ptr),
+                                   (*parent)->howto->name,
+                                   (*parent)->addend,
+                                   stub_bfd, stub_sec,
+                                   (*parent)->address)))
+                             abort ();
+                         }
                          break;
+                       case bfd_reloc_outofrange:
                        default:
                          abort ();
                          break;
@@ -2161,96 +1989,54 @@ hppa_elf_stub_finish (output_bfd)
                }
            }
 
-         bfd_set_section_contents (output_bfd,
-                                   stub_sec,
+         /* All done with the relocations.  Set the final contents
+            of the stub section.  FIXME: no check of return value!  */
+         bfd_set_section_contents (output_bfd, stub_sec,
                                    stub_list->stub_contents,
-                                   0,
-                                   stub_list->real_size);
-
-         free (reloc_vector);
+                                   0, stub_list->real_size);
        }
     }
+  /* All done.  */
   stubs_finished = true;
 }
 
-void
-hppa_elf_stub_branch_reloc (stub_desc, /* the bfd */
-                           output_bfd, /* the output bfd */
-                           target_sym, /* the target symbol */
-                           offset)     /* the offset within the stub buffer (pre-calculated) */
+/* Allocate a new relocation entry to be used in a linker stub.  */
+
+static void
+hppa_elf_stub_reloc (stub_desc, output_bfd, target_sym, offset, type)
      elf32_hppa_stub_description *stub_desc;
      bfd *output_bfd;
-     asymbol *target_sym;
+     asymbol **target_sym;
      int offset;
+     elf32_hppa_reloc_type type;
 {
-  /* Allocate a new relocation entry. */
   arelent relent;
   int size;
+  Elf_Internal_Shdr *rela_hdr;
 
+  /* I really don't like the realloc nonsense in here.  FIXME.  */
   if (stub_desc->relocs_allocated_cnt == stub_desc->stub_sec->reloc_count)
     {
+      /* Allocate the first few relocation entries.  */
       if (stub_desc->stub_sec->relocation == NULL)
        {
          stub_desc->relocs_allocated_cnt = STUB_RELOC_INCR;
          size = sizeof (arelent) * stub_desc->relocs_allocated_cnt;
-         stub_desc->stub_sec->relocation = (arelent *) zalloc (size);
+         stub_desc->stub_sec->relocation = (arelent *) bfd_zmalloc (size);
        }
       else
        {
+         /* We've used all the entries we've already allocated.  So get
+            some more.  */
          stub_desc->relocs_allocated_cnt += STUB_RELOC_INCR;
          size = sizeof (arelent) * stub_desc->relocs_allocated_cnt;
-         stub_desc->stub_sec->relocation = (arelent *) realloc (stub_desc->stub_sec->relocation,
-                                                                size);
-       }
-    }
-
-  /* Fill in the details. */
-  relent.address = offset;
-  relent.addend = 0;
-  relent.sym_ptr_ptr = (asymbol **) bfd_zalloc (stub_desc->this_bfd, sizeof (asymbol *));
-  BFD_ASSERT (relent.sym_ptr_ptr);
-
-  relent.sym_ptr_ptr[0] = target_sym;
-  relent.howto = bfd_reloc_type_lookup (stub_desc->this_bfd, R_HPPA_PCREL_CALL_17);
-
-  /* Save it in the array of relocations for the stub section. */
-
-  memcpy (&stub_desc->stub_sec->relocation[stub_desc->stub_sec->reloc_count++],
-         &relent,
-         sizeof (arelent));
-}
-
-void
-hppa_elf_stub_reloc (stub_desc,        /* the bfd */
-                    output_bfd,        /* the output bfd */
-                    target_sym,        /* the target symbol */
-                    offset,    /* the offset within the stub buffer (pre-calculated) */
-                    type)
-elf32_hppa_stub_description *stub_desc;
-bfd *output_bfd;
-asymbol *target_sym;
-int offset;
-elf32_hppa_reloc_type type;
-{
-  /* Allocate a new relocation entry. */
-  arelent relent;
-  int size;
-  Elf_Internal_Shdr *rela_hdr;
-
-  if (stub_desc->relocs_allocated_cnt == stub_desc->stub_sec->reloc_count)
-    {
-      if (stub_desc->stub_sec->relocation == NULL)
-       {
-         stub_desc->relocs_allocated_cnt = STUB_RELOC_INCR;
-         size = sizeof (arelent) * stub_desc->relocs_allocated_cnt;
-         stub_desc->stub_sec->relocation = (arelent *) zalloc (size);
+         stub_desc->stub_sec->relocation = (arelent *)
+           realloc (stub_desc->stub_sec->relocation, size);
        }
-      else
+      if (!stub_desc->stub_sec->relocation)
        {
-         stub_desc->relocs_allocated_cnt += STUB_RELOC_INCR;
-         size = sizeof (arelent) * stub_desc->relocs_allocated_cnt;
-         stub_desc->stub_sec->relocation = (arelent *) realloc (stub_desc->stub_sec->relocation,
-                                                                size);
+         bfd_set_error (bfd_error_no_memory);
+         abort ();             /* FIXME */
        }
     }
 
@@ -2260,39 +2046,41 @@ elf32_hppa_reloc_type type;
   /* Fill in the details. */
   relent.address = offset;
   relent.addend = 0;
-  relent.sym_ptr_ptr = (asymbol **) bfd_zalloc (stub_desc->this_bfd, sizeof (asymbol *));
-  BFD_ASSERT (relent.sym_ptr_ptr);
-
-  relent.sym_ptr_ptr[0] = target_sym;
+  relent.sym_ptr_ptr = target_sym;
   relent.howto = bfd_reloc_type_lookup (stub_desc->this_bfd, type);
 
-  /* Save it in the array of relocations for the stub section. */
-
+  /* Save it in the array of relocations for the stub section.  */
   memcpy (&stub_desc->stub_sec->relocation[stub_desc->stub_sec->reloc_count++],
-         &relent,
-         sizeof (arelent));
+         &relent, sizeof (arelent));
 }
 
-asymbol *
-hppa_elf_build_arg_reloc_stub (abfd, output_bfd, reloc_entry,
-                              stub_types, rtn_adjust, data)
+/* Build an argument relocation stub.  RTN_ADJUST is a hint that an
+   adjust to the return pointer from within the stub itself may be
+   needed.  */
+
+static asymbol *
+hppa_elf_build_linker_stub (abfd, output_bfd, link_info, reloc_entry,
+                           stub_types, rtn_adjust, data, linker_stub_type)
      bfd *abfd;
      bfd *output_bfd;
+     struct bfd_link_info *link_info;
      arelent *reloc_entry;
-     int stub_types[5];
+     arg_reloc_type stub_types[5];
      int rtn_adjust;
      unsigned *data;
+     hppa_stub_type linker_stub_type;
 {
-  asection *stub_sec = bfd_get_section_by_name (abfd, ".hppa_linker_stubs");
-  elf32_hppa_stub_description *stub_desc = find_stubs (abfd, stub_sec);
-  asymbol *stub_sym = NULL;
-  asymbol *target_sym = reloc_entry->sym_ptr_ptr[0];
-  asection *output_text_section = bfd_get_section_by_name (output_bfd, ".text");
   int i;
+  boolean milli, dyncall;
   char stub_sym_name[128];
   elf32_hppa_stub_name_list *stub_entry;
+  /* Some initialization.  */
   unsigned insn = data[0];
-
+  asymbol *stub_sym = NULL;
+  asymbol **orig_sym = reloc_entry->sym_ptr_ptr;
+  asection *stub_sec = bfd_get_section_by_name (abfd, ".hppa_linker_stubs");
+  elf32_hppa_stub_description *stub_desc = find_stubs (abfd, stub_sec);
+
   /* Perform some additional checks on whether we should really do the
      return adjustment.  For example, if the instruction is nullified
      or if the delay slot contains an instruction that modifies the return
@@ -2309,31 +2097,58 @@ hppa_elf_build_arg_reloc_stub (abfd, output_bfd, reloc_entry,
        rtn_adjust = false;
     }
 
-  /* See if the proper stub entry has already been made.  */
+  /* Some special code for long-call stubs.  */
+  if (linker_stub_type == HPPA_STUB_LONG_CALL)
+    {
+      
+      /* Is this a millicode call?  If so, the return address
+        comes in on r31 rather than r2 (rp) so a slightly
+        different code sequence is needed.  */
+      unsigned rtn_reg = (insn & 0x03e00000) >> 21;
+      if (rtn_reg == 31)
+       milli = true;
+      
+      /* Dyncall is special because the user code has already
+        put the return pointer in %r2 (aka RP).  Other millicode
+        calls have the return pointer in %r31.  */
+      if (strcmp ((*orig_sym)->name, "$$dyncall") == 0)
+       dyncall = true;
+      
+      /* If we are creating a call from a stub to another stub, then
+        never do the instruction reordering.  We can tell if we are
+        going to be calling one stub from another by the fact that
+        the symbol name has '_stub_' (arg. reloc. stub) or '_lb_stub_'
+        prepended to the name.  Alternatively, the section of the
+        symbol will be '.hppa_linker_stubs'.  This is only an issue
+        for long-calls; they are the only stubs allowed to call another
+        stub.  */
+      if ((strncmp ((*orig_sym)->name, "_stub_", 6) == 0)
+         || (strncmp ((*orig_sym)->name, "_lb_stub_", 9) == 0))
+       {
+         BFD_ASSERT (strcmp ((*orig_sym)->section->name, ".hppa_linker_stubs")
+                     == 0);
+         rtn_adjust = false;
+       }
+    }
+
+  /* Create the stub section if necessary.  */
   if (!stub_sec)
     {
       BFD_ASSERT (stub_desc == NULL);
-      stub_sec = bfd_make_section (abfd, ".hppa_linker_stubs");
-      bfd_set_section_flags (abfd,
-                            stub_sec,
-                            SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD
-                            | SEC_RELOC | SEC_CODE | SEC_READONLY);
-      stub_sec->output_section = output_text_section->output_section;
-      stub_sec->output_offset = 0;
-      bfd_set_section_alignment (abfd, stub_sec, 2);
-      stub_desc = new_stub (abfd, stub_sec);
+      hppa_elf_create_stub_sec (abfd, output_bfd, &stub_sec, link_info);
+      stub_desc = new_stub (abfd, stub_sec, link_info);
     }
 
   /* Make the stub if we did not find one already.  */
   if (!stub_desc)
-    stub_desc = new_stub (abfd, stub_sec);
+    stub_desc = new_stub (abfd, stub_sec, link_info);
 
   /* Allocate space to write the stub.
-     FIXME.  Why using realloc?!?  */
+     FIXME:  Why using realloc?!?  */
   if (!stub_desc->stub_contents)
     {
       stub_desc->allocated_size = STUB_BUFFER_INCR;
-      stub_desc->stub_contents = (char *) bfd_xmalloc (STUB_BUFFER_INCR);
+      stub_desc->stub_contents = (char *) malloc (STUB_BUFFER_INCR);
     }
   else if ((stub_desc->allocated_size - stub_desc->real_size) < STUB_MAX_SIZE)
     {
@@ -2342,249 +2157,360 @@ hppa_elf_build_arg_reloc_stub (abfd, output_bfd, reloc_entry,
                                                   stub_desc->allocated_size);
     }
 
+  /* If no memory die.  (I seriously doubt the other routines
+     are prepared to get a NULL return value).  */
+  if (!stub_desc->stub_contents)
+    {
+      bfd_set_error (bfd_error_no_memory);
+      abort ();
+    }
+
+  /* Generate an appropriate name for this stub.  */
+  if (linker_stub_type == HPPA_STUB_ARG_RELOC)
+    sprintf (stub_sym_name,
+            "_stub_%s_%02d_%02d_%02d_%02d_%02d_%s",
+            reloc_entry->sym_ptr_ptr[0]->name,
+            stub_types[0], stub_types[1], stub_types[2],
+            stub_types[3], stub_types[4],
+            rtn_adjust ? "RA" : "");
+  else
+    sprintf (stub_sym_name,
+            "_lb_stub_%s_%s", reloc_entry->sym_ptr_ptr[0]->name,
+            rtn_adjust ? "RA" : "");
+
+
   stub_desc->stub_secp
     = (int *) (stub_desc->stub_contents + stub_desc->real_size);
-
-  sprintf (stub_sym_name,
-          "_stub_%s_%02d_%02d_%02d_%02d_%02d_%s",
-          reloc_entry->sym_ptr_ptr[0]->name,
-          stub_types[0], stub_types[1], stub_types[2],
-          stub_types[3], stub_types[4],
-          rtn_adjust ? "RA" : "");
   stub_entry = find_stub_by_name (abfd, stub_sec, stub_sym_name);
 
+  /* See if we already have one by this name.  */
   if (stub_entry)
     {
+      /* Yes, re-use it.  Redirect the original relocation from the
+        old symbol (a function symbol) to the stub (the stub will call
+        the original function).  */
       stub_sym = stub_entry->sym;
-      /* Redirect the original relocation from the old symbol (a function)
-        to the stub (the stub calls the function).  Should we need to
-        change the relocation type?  */
-      reloc_entry->sym_ptr_ptr = (asymbol **) bfd_zalloc (stub_desc->this_bfd,
-                                                         sizeof (asymbol *));
+      reloc_entry->sym_ptr_ptr = (asymbol **) bfd_zalloc (abfd,
+                                                         sizeof (asymbol **));
+      if (reloc_entry->sym_ptr_ptr == NULL)
+       {
+         bfd_set_error (bfd_error_no_memory);
+         abort ();
+       }
       reloc_entry->sym_ptr_ptr[0] = stub_sym;
-      if (reloc_entry->howto->type != R_HPPA_PLABEL_32
-         && (get_opcode(insn) == BLE || get_opcode (insn) == BE))
+      if (linker_stub_type == HPPA_STUB_LONG_CALL
+         || (reloc_entry->howto->type != R_HPPA_PLABEL_32
+             && (get_opcode(insn) == BLE
+                 || get_opcode (insn) == BE
+                 || get_opcode (insn) == BL)))
        reloc_entry->howto = bfd_reloc_type_lookup (abfd, R_HPPA_STUB_CALL_17);
     }
   else
     {
       /* Create a new symbol to point to this stub.  */
       stub_sym = bfd_make_empty_symbol (abfd);
+      if (!stub_sym)
+       {
+         bfd_set_error (bfd_error_no_memory);
+         abort ();
+       }
       stub_sym->name = bfd_zalloc (abfd, strlen (stub_sym_name) + 1);
+      if (!stub_sym->name)
+       {
+         bfd_set_error (bfd_error_no_memory);
+         abort ();
+       }
       strcpy ((char *) stub_sym->name, stub_sym_name);
       stub_sym->value
-       = (int) stub_desc->stub_secp - (int) stub_desc->stub_contents;
+       = (char *) stub_desc->stub_secp - (char *) stub_desc->stub_contents;
       stub_sym->section = stub_sec;
       stub_sym->flags = BSF_LOCAL | BSF_FUNCTION;
-      stub_entry = add_stub_by_name (abfd, stub_sec, stub_sym);
+      stub_entry = add_stub_by_name (abfd, stub_sec, stub_sym, link_info);
 
       /* Redirect the original relocation from the old symbol (a function)
-        to the stub (the stub calls the function).  Change the type of
-        relocation to be the internal use only stub R_HPPA_STUB_CALL_17.  */
-      reloc_entry->sym_ptr_ptr = (asymbol **) bfd_zalloc (stub_desc->this_bfd,
-                                                         sizeof (asymbol *));
+        to the stub (the stub calls the function).  */
+      reloc_entry->sym_ptr_ptr = (asymbol **) bfd_zalloc (abfd,
+                                                         sizeof (asymbol **));
+      if (reloc_entry->sym_ptr_ptr == NULL)
+       {
+         bfd_set_error (bfd_error_no_memory);
+         abort ();
+       }
       reloc_entry->sym_ptr_ptr[0] = stub_sym;
-      if (reloc_entry->howto->type != R_HPPA_PLABEL_32
-         && (get_opcode (insn) == BLE || get_opcode (insn) == BE))
+      if (linker_stub_type == HPPA_STUB_LONG_CALL
+         || (reloc_entry->howto->type != R_HPPA_PLABEL_32
+             && (get_opcode (insn) == BLE
+                 || get_opcode (insn) == BE
+                 || get_opcode (insn) == BL)))
        reloc_entry->howto = bfd_reloc_type_lookup (abfd, R_HPPA_STUB_CALL_17);
 
-      /* Generate common code for all stubs.  */
+      /* Now generate the code for the stub.  Starting with two
+        common instructions.
+
+        FIXME:  Do we still need the SP adjustment?
+                Do we still need to muck with space registers?  */
+      NEW_INSTRUCTION (stub_entry, LDSID_31_1)
+      NEW_INSTRUCTION (stub_entry, MTSP_1_SR0)
+
+      if (linker_stub_type == HPPA_STUB_ARG_RELOC)
+       {
+         NEW_INSTRUCTION (stub_entry, ADDI_8_SP)
+
+         /* Examine each argument, generating code to relocate it
+            into a different register if necessary.  */
+           for (i = ARG0; i < ARG3; i++)
+             {
+               switch (stub_types[i])
+                 {
+
+                 case NO_ARG_RELOC:
+                   continue;
+
+                 case R_TO_FR:
+                   switch (i)
+                     {
+                     case ARG0:
+                       NEW_INSTRUCTION (stub_entry, STWS_ARG0_M8SP)
+                       NEW_INSTRUCTION (stub_entry, FLDWS_M8SP_FARG0)
+                         break;
+                     case ARG1:
+                       NEW_INSTRUCTION (stub_entry, STWS_ARG1_M8SP)
+                       NEW_INSTRUCTION (stub_entry, FLDWS_M8SP_FARG1)
+                         break;
+                     case ARG2:
+                       NEW_INSTRUCTION (stub_entry, STWS_ARG2_M8SP)
+                       NEW_INSTRUCTION (stub_entry, FLDWS_M8SP_FARG2)
+                         break;
+                     case ARG3:
+                       NEW_INSTRUCTION (stub_entry, STWS_ARG3_M8SP)
+                       NEW_INSTRUCTION (stub_entry, FLDWS_M8SP_FARG3)
+                         break;
+                     }
+                   continue;
+             
+                 case R01_TO_FR:
+                   switch (i)
+                     {
+                     case ARG0:
+                       NEW_INSTRUCTION (stub_entry, STWS_ARG0_M4SP)
+                       NEW_INSTRUCTION (stub_entry, STWS_ARG1_M8SP)
+                       NEW_INSTRUCTION (stub_entry, FLDDS_M8SP_FARG1)
+                         break;
+                     default:
+                       abort ();
+                       break;
+                     }
+                   continue;
+
+                 case R23_TO_FR:
+                   switch (i)
+                     {
+                     case ARG2:
+                       NEW_INSTRUCTION (stub_entry, STWS_ARG2_M4SP)
+                       NEW_INSTRUCTION (stub_entry, STWS_ARG3_M8SP)
+                       NEW_INSTRUCTION (stub_entry, FLDDS_M8SP_FARG3)
+                         break;
+                     default:
+                       abort ();
+                       break;
+                     }
+                   continue;
 
-      NEW_INSTRUCTION (stub_entry, LDSID_31_1);
-      NEW_INSTRUCTION (stub_entry, MTSP_1_SR0);
-      NEW_INSTRUCTION (stub_entry, ADDI_8_SP);
+                 case FR_TO_R:
+                   switch (i)
+                     {
+                     case ARG0:
+                       NEW_INSTRUCTION (stub_entry, FSTWS_FARG0_M8SP)
+                       NEW_INSTRUCTION (stub_entry, LDWS_M4SP_ARG0)
+                         break;
+                     case ARG1:
+                       NEW_INSTRUCTION (stub_entry, FSTWS_FARG1_M8SP)
+                       NEW_INSTRUCTION (stub_entry, LDWS_M4SP_ARG1)
+                         break;
+                     case ARG2:
+                       NEW_INSTRUCTION (stub_entry, FSTWS_FARG2_M8SP)
+                       NEW_INSTRUCTION (stub_entry, LDWS_M4SP_ARG2)
+                         break;
+                     case ARG3:
+                       NEW_INSTRUCTION (stub_entry, FSTWS_FARG3_M8SP)
+                       NEW_INSTRUCTION (stub_entry, LDWS_M4SP_ARG3)
+                         break;
+                     }
+                   continue;
+             
+                 case FR_TO_R01:
+                   switch (i)
+                     {
+                     case ARG0:
+                       NEW_INSTRUCTION (stub_entry, FSTDS_FARG1_M8SP)
+                       NEW_INSTRUCTION (stub_entry, LDWS_M4SP_ARG0)
+                       NEW_INSTRUCTION (stub_entry, LDWS_M8SP_ARG1)
+                         break;
+                     default:
+                       abort ();
+                       break;
+                     }
+                   continue;
+             
+                 case FR_TO_R23:
+                   switch (i)
+                     {
+                     case ARG2:
+                       NEW_INSTRUCTION (stub_entry, FSTDS_FARG3_M8SP)
+                       NEW_INSTRUCTION (stub_entry, LDWS_M4SP_ARG2)
+                       NEW_INSTRUCTION (stub_entry, LDWS_M8SP_ARG3)
+                         break;
+                     default:
+                       abort ();
+                       break;
+                     }
+                   continue;
+
+                 default:
+                   abort ();
+                   break;
+                 }
+             }
+
+         /* Put the stack pointer back.  FIXME:  Is this still necessary?  */
+         NEW_INSTRUCTION (stub_entry, ADDI_M8_SP_SP)
+       }
 
-      /* Generate code to move the arguments around.  */
-      for (i = ARG0; i < ARG3; i++)
+      /* Common code again.  Return pointer adjustment and the like.  */
+      if (!dyncall)
        {
-         if (stub_types[i] != NO_ARG_RELOC)
+         /* This isn't dyncall.  */ 
+         if (!milli)
            {
-             switch (stub_types[i])
-               {
-               case R_TO_FR:
-                 switch (i)
-                   {
-                   case ARG0:
-                     NEW_INSTRUCTION (stub_entry, STWS_ARG0_M8SP);
-                     NEW_INSTRUCTION (stub_entry, FLDWS_M8SP_FARG0);
-                     break;
-                   case ARG1:
-                     NEW_INSTRUCTION (stub_entry, STWS_ARG1_M8SP);
-                     NEW_INSTRUCTION (stub_entry, FLDWS_M8SP_FARG1);
-                     break;
-                   case ARG2:
-                     NEW_INSTRUCTION (stub_entry, STWS_ARG2_M8SP);
-                     NEW_INSTRUCTION (stub_entry, FLDWS_M8SP_FARG2);
-                     break;
-                   case ARG3:
-                     NEW_INSTRUCTION (stub_entry, STWS_ARG3_M8SP);
-                     NEW_INSTRUCTION (stub_entry, FLDWS_M8SP_FARG3);
-                     break;
-                   }
-                 continue;
-                 
-               case R01_TO_FR:
-                 switch (i)
-                   {
-                   case ARG0:
-                     NEW_INSTRUCTION (stub_entry, STWS_ARG0_M4SP);
-                     NEW_INSTRUCTION (stub_entry, STWS_ARG1_M8SP);
-                     NEW_INSTRUCTION (stub_entry, FLDDS_M8SP_FARG1);
-                     break;
-                   default:
-                     AR_WARN (stub_types[i],i);
-                     break;
-                   }
-                 continue;
-                 
-               case R23_TO_FR:
-                 switch (i)
-                   {
-                   case ARG2:
-                     NEW_INSTRUCTION (stub_entry, STWS_ARG2_M4SP);
-                     NEW_INSTRUCTION (stub_entry, STWS_ARG3_M8SP);
-                     NEW_INSTRUCTION (stub_entry, FLDDS_M8SP_FARG3);
-                     break;
-                   default:
-                     AR_WARN (stub_types[i],i);
-                     break;
-                   }
-                 continue;
-                 
-               case FR_TO_R:
-                 switch (i)
-                   {
-                   case ARG0:
-                     NEW_INSTRUCTION (stub_entry, FSTWS_FARG0_M8SP);
-                     NEW_INSTRUCTION (stub_entry, LDWS_M4SP_ARG0);
-                     break;
-                   case ARG1:
-                     NEW_INSTRUCTION (stub_entry, FSTWS_FARG1_M8SP);
-                     NEW_INSTRUCTION (stub_entry, LDWS_M4SP_ARG1);
-                     break;
-                   case ARG2:
-                     NEW_INSTRUCTION (stub_entry, FSTWS_FARG2_M8SP);
-                     NEW_INSTRUCTION (stub_entry, LDWS_M4SP_ARG2);
-                     break;
-                   case ARG3:
-                     NEW_INSTRUCTION (stub_entry, FSTWS_FARG3_M8SP);
-                     NEW_INSTRUCTION (stub_entry, LDWS_M4SP_ARG3);
-                     break;
-                   }
-                 continue;
-                 
-               case FR_TO_R01:
-                 switch (i)
-                   {
-                   case ARG0:
-                     NEW_INSTRUCTION (stub_entry, FSTDS_FARG1_M8SP);
-                     NEW_INSTRUCTION (stub_entry, LDWS_M4SP_ARG0);
-                     NEW_INSTRUCTION (stub_entry, LDWS_M8SP_ARG1);
-                     break;
-                   default:
-                     AR_WARN (stub_types[i],i);
-                     break;
-                   }
-                 continue;
-                 
-               case FR_TO_R23:
-                 switch (i)
-                   {
-                   case ARG2:
-                     NEW_INSTRUCTION (stub_entry, FSTDS_FARG3_M8SP);
-                     NEW_INSTRUCTION (stub_entry, LDWS_M4SP_ARG2);
-                     NEW_INSTRUCTION (stub_entry, LDWS_M8SP_ARG3);
-                     break;
-                   default:
-                     AR_WARN (stub_types[i],i);
-                     break;
-                   }
-                 continue;
-                 
-               }
+             /* It's not a millicode call, so get the correct return
+                value into %r2 (aka RP).  */
+             if (rtn_adjust)
+               NEW_INSTRUCTION (stub_entry, ADDI_M4_31_RP)
+             else
+               NEW_INSTRUCTION (stub_entry, COPY_31_2)
+           }
+         else
+           {
+             /* It is a millicode call, so get the correct return
+                value into %r1?!?.  FIXME:  Shouldn't this be
+                %r31?  Yes, and a little re-arrangement of the
+                code below would make that possible.  */
+             if (rtn_adjust)
+               NEW_INSTRUCTION (stub_entry, ADDI_M4_31_1)
+             else
+               NEW_INSTRUCTION (stub_entry, COPY_31_1)
            }
        }
-
-      NEW_INSTRUCTION (stub_entry, ADDI_M8_SP_SP);
-
-      /* Adjust the return address if necessary.  */
-      if (rtn_adjust)
+      else
        {
-         NEW_INSTRUCTION (stub_entry, ADDI_M4_31_RP);
+         /* This is dyncall, so the code is a little different as the
+            return pointer is already in %r2 (aka RP).  */
+         if (rtn_adjust)
+           NEW_INSTRUCTION (stub_entry, ADDI_M4_31_RP)
        }
 
       /* Save the return address.  */
-      NEW_INSTRUCTION (stub_entry, STW_RP_M8SP);
+      if (linker_stub_type == HPPA_STUB_ARG_RELOC)
+       NEW_INSTRUCTION (stub_entry, STW_RP_M8SP)
 
       /* Long branch to the target function.  */
-      NEW_INSTRUCTION (stub_entry, LDIL_XXX_31);
+      NEW_INSTRUCTION (stub_entry, LDIL_XXX_31)
       hppa_elf_stub_reloc (stub_entry->stub_desc,
-                          abfd,
-                          target_sym,
+                          abfd, orig_sym,
                           CURRENT_STUB_OFFSET (stub_entry),
                           R_HPPA_L21);
-      NEW_INSTRUCTION (stub_entry, BLE_XXX_0_31);
+      NEW_INSTRUCTION (stub_entry, BLE_XXX_0_31)
       hppa_elf_stub_reloc (stub_entry->stub_desc,
-                          abfd,
-                          target_sym,
+                          abfd, orig_sym,
                           CURRENT_STUB_OFFSET (stub_entry),
                           R_HPPA_ABS_CALL_R17);
-      NEW_INSTRUCTION (stub_entry, COPY_31_2);
-      
 
-      /* Restore the return address.  */
-      NEW_INSTRUCTION (stub_entry, LDW_M8SP_RP);
+      if (linker_stub_type == HPPA_STUB_ARG_RELOC)
+       {
+         /* In delay slot of long-call, copy %r31 into %r2 so that
+            the callee can return in the normal fashion.  */
+         NEW_INSTRUCTION (stub_entry, COPY_31_2)
+
+         /* Restore the return address.  */
+         NEW_INSTRUCTION (stub_entry, LDW_M8SP_RP)
       
-      /* Generate the code to move the return value around.  */
-      i = RETVAL;
-      if (stub_types[i] != NO_ARG_RELOC)
+         /* Generate the code to move the return value around.  */
+           switch (stub_types[RETVAL])
+             {
+             case NO_ARG_RELOC:
+               break;
+         
+             case R_TO_FR:
+               NEW_INSTRUCTION (stub_entry, STWS_RET0_M8SP)
+               NEW_INSTRUCTION (stub_entry, FLDWS_M8SP_FRET0)
+                 break;
+         
+             case FR_TO_R:
+               NEW_INSTRUCTION (stub_entry, FSTWS_FRET0_M8SP)
+               NEW_INSTRUCTION (stub_entry, LDWS_M4SP_RET0)
+                 break;
+
+             default:
+               abort ();
+               break;
+             }
+
+         /* Return back to the main code stream.  */
+         NEW_INSTRUCTION (stub_entry, BV_N_0_RP)
+       }
+      else
        {
-         switch (stub_types[i])
+         if (!dyncall)
            {
-           case R_TO_FR:
-             NEW_INSTRUCTION (stub_entry, STWS_RET0_M8SP);
-             NEW_INSTRUCTION (stub_entry, FLDWS_M8SP_FRET0);
-             break;
-             
-           case FR_TO_R:
-             NEW_INSTRUCTION (stub_entry, FSTWS_FRET0_M8SP);
-             NEW_INSTRUCTION (stub_entry, LDWS_M4SP_RET0);
-             break;
+             /* Get return address into %r31.  Both variants may be necessary
+                (I think) as we could be cascading into another stub.  */
+             if (!milli)
+               NEW_INSTRUCTION (stub_entry, COPY_2_31)
+             else
+               NEW_INSTRUCTION (stub_entry, COPY_1_31)
            }
+         else
+           {
+             /* Get the return address into %r31 too.  Might be necessary
+                (I think) as we could be cascading into another stub.  */
+             NEW_INSTRUCTION (stub_entry, COPY_2_31)
+           }
+
+         /* No need for a return to the main stream.  */
        }
-      NEW_INSTRUCTION (stub_entry, BV_N_0_RP);
     }
-
   return stub_sym;
 }
 
-int
+/* Return nonzero if an argument relocation will be needed to call
+   the function (symbol in RELOC_ENTRY) assuming the caller has
+   argument relocation bugs CALLER_AR.  */
+
+static int
 hppa_elf_arg_reloc_needed_p (abfd, reloc_entry, stub_types, caller_ar)
      bfd *abfd;
      arelent *reloc_entry;
-     int stub_types[5];
+     arg_reloc_type stub_types[5];
      symext_entryS caller_ar;
 {
-  /* If the symbol is still undefined, there is        */
-  /* no way to know if a stub is required.     */
-
-  if (reloc_entry->sym_ptr_ptr[0] && reloc_entry->sym_ptr_ptr[0]->section != &bfd_und_section)
+  /* If the symbol is still undefined, then it's impossible to know
+     if an argument relocation is needed.  */
+  if (reloc_entry->sym_ptr_ptr[0] 
+      && reloc_entry->sym_ptr_ptr[0]->section != &bfd_und_section)
     {
       symext_entryS callee_ar = elf32_hppa_get_sym_extn (abfd,
                                                reloc_entry->sym_ptr_ptr[0],
                                                         HPPA_SXT_ARG_RELOC);
 
-      /* Now, determine if a stub is */
-      /* required.  A stub is required if they the callee and caller   */
-      /* argument relocation bits are both nonzero and not equal.      */
-
+      /* Now examine all the argument and return value location
+        information to determine if a relocation stub will be needed.  */
       if (caller_ar && callee_ar)
        {
-         /* Both are non-zero, we need to do further checking. */
-         /* First, check if there is a return value relocation to be done */
-         int caller_loc[5];
-         int callee_loc[5];
+         arg_location caller_loc[5];
+         arg_location callee_loc[5];
 
+         /* Extract the location information for the return value
+            and argument registers separately.  */
          callee_loc[RETVAL] = EXTRACT_ARBITS (callee_ar, RETVAL);
          caller_loc[RETVAL] = EXTRACT_ARBITS (caller_ar, RETVAL);
          callee_loc[ARG0] = EXTRACT_ARBITS (callee_ar, ARG0);
@@ -2596,9 +2522,11 @@ hppa_elf_arg_reloc_needed_p (abfd, reloc_entry, stub_types, caller_ar)
          callee_loc[ARG3] = EXTRACT_ARBITS (callee_ar, ARG3);
          caller_loc[ARG3] = EXTRACT_ARBITS (caller_ar, ARG3);
 
-         /* Check some special combinations.  For */
-         /* example, if FU appears in ARG1 or ARG3, we */
-         /* can move it to ARG0 or ARG2, respectively. */
+         /* Check some special combinations.  For example, if FU 
+            appears in ARG1 or ARG3, we can move it to ARG0 or ARG2,
+            respectively.  (I guess this braindamage is correct?  It'd
+            take an hour or two of reading PA calling conventions to
+            really know).  */
 
          if (caller_loc[ARG0] == AR_FU || caller_loc[ARG1] == AR_FU)
            {
@@ -2621,328 +2549,110 @@ hppa_elf_arg_reloc_needed_p (abfd, reloc_entry, stub_types, caller_ar)
              callee_loc[ARG3] = AR_NO;
            }
 
-         stub_types[ARG0] = type_of_mismatch (caller_loc[ARG0], callee_loc[ARG0], ARGUMENTS);
-         stub_types[ARG1] = type_of_mismatch (caller_loc[ARG1], callee_loc[ARG1], ARGUMENTS);
-         stub_types[ARG2] = type_of_mismatch (caller_loc[ARG2], callee_loc[ARG2], ARGUMENTS);
-         stub_types[ARG3] = type_of_mismatch (caller_loc[ARG3], callee_loc[ARG3], ARGUMENTS);
-         stub_types[RETVAL] = type_of_mismatch (caller_loc[RETVAL], callee_loc[RETVAL], RETURN_VALUE);
-
-         /* Steps involved in building stubs: */
-         /* 1. Determine what argument registers need to relocated.  This */
-         /*    step is already done here. */
-         /* 2. Build the appropriate stub in the .hppa_linker_stubs section. */
-         /*    This section should never appear in an object file.  It is */
-         /*    only used internally.  The output_section of the */
-         /*    .hppa_linker_stubs section is the .text section of the */
-         /*    executable.     */
-         /* 3. Build a symbol that is used (internally only) as the entry */
-         /*    point of the stub. */
-         /* 4. Change the instruction of the original branch into a branch to */
-         /*    the stub routine. */
-         /* 5. Build a relocation entry for the instruction of the original */
-         /*    branch to be R_HPPA_PCREL_CALL to the stub routine. */
-
-
-         if (stub_types[0]
-             || stub_types[1]
-             || stub_types[2]
-             || stub_types[3]
-             || stub_types[4])
-           {
-#ifdef DETECT_STUBS
-             int i;
-
-             fprintf (stderr, "Stub needed for %s @ %s+0x%x: callee/caller ar=0x%x/0x%x ",
-                      reloc_entry->sym_ptr_ptr[0]->name,
-                      abfd->filename, reloc_entry->address,
-                      callee_ar, caller_ar);
-             for (i = ARG0; i < RETVAL; i++)
-               {
-                 if (stub_types[i] != NO_ARG_RELOC)
-                   {
-                     fprintf (stderr, "%s%d: %s ",
-                              i == RETVAL ? "ret" : "arg",
-                              i == RETVAL ? 0 : i,
-                              reloc_type_strings[stub_types[i]]);
-                   }
-               }
-             fprintf (stderr, "\n");
-#endif
-             return 1;
-           }
-
+         /* Now look up potential mismatches.  */
+         stub_types[ARG0] = type_of_mismatch (caller_loc[ARG0],
+                                              callee_loc[ARG0],
+                                              ARGUMENTS);
+         stub_types[ARG1] = type_of_mismatch (caller_loc[ARG1],
+                                              callee_loc[ARG1],
+                                              ARGUMENTS);
+         stub_types[ARG2] = type_of_mismatch (caller_loc[ARG2],
+                                              callee_loc[ARG2],
+                                              ARGUMENTS);
+         stub_types[ARG3] = type_of_mismatch (caller_loc[ARG3],
+                                              callee_loc[ARG3],
+                                              ARGUMENTS);
+         stub_types[RETVAL] = type_of_mismatch (caller_loc[RETVAL],
+                                                callee_loc[RETVAL],
+                                                RETURN_VALUE);
+
+         /* If any of the arguments or return value need an argument
+            relocation, then we will need an argument relocation stub.  */
+         if (stub_types[ARG0] != NO_ARG_RELOC
+             || stub_types[ARG1] != NO_ARG_RELOC
+             || stub_types[ARG2] != NO_ARG_RELOC
+             || stub_types[ARG3] != NO_ARG_RELOC
+             || stub_types[RETVAL] != NO_ARG_RELOC)
+           return 1;
        }
     }
   return 0;
 }
 
-asymbol *
-hppa_elf_build_long_branch_stub (abfd, output_bfd, reloc_entry, symbol, data)
+/* Create the linker stub section.  */
+
+static void
+hppa_elf_create_stub_sec (abfd, output_bfd, secptr, link_info)
      bfd *abfd;
      bfd *output_bfd;
-     arelent *reloc_entry;
-     asymbol *symbol;
-     unsigned *data;
+     asection **secptr;
+     struct bfd_link_info *link_info;
 {
-  asection *stub_sec = bfd_get_section_by_name (abfd, ".hppa_linker_stubs");
-  elf32_hppa_stub_description *stub_desc = find_stubs (abfd, stub_sec);
-  asymbol *stub_sym = NULL;
-  asymbol *target_sym = reloc_entry->sym_ptr_ptr[0];
-  asection *output_text_section = bfd_get_section_by_name (output_bfd, ".text");
-  char stub_sym_name[128];
-  int milli = false;
-  int dyncall = false;
-  elf32_hppa_stub_name_list *stub_entry;
-  int rtn_adjust = true;
-  int rtn_reg;
-  unsigned insn;
-
-  /* Create the stub section if it does not already exist.  */
-  if (!stub_sec)
-    {
-      BFD_ASSERT (stub_desc == NULL);
-      stub_sec = bfd_make_section (abfd, ".hppa_linker_stubs");
-      bfd_set_section_flags (abfd,
-                            stub_sec,
-                            SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD
-                            | SEC_RELOC | SEC_CODE | SEC_READONLY);
-      stub_sec->output_section = output_text_section->output_section;
-      stub_sec->output_offset = 0;
-
-      /* Set up the ELF section header for this new section.  This
-        is basically the same processing as elf_make_sections().  
-        elf_make_sections is static and therefore not accessable
-        here.  */
+  asection *output_text_section;
+  
+  output_text_section = bfd_get_section_by_name (output_bfd, ".text");
+  *secptr = bfd_make_section (abfd, ".hppa_linker_stubs");
+  bfd_set_section_flags (abfd, *secptr,
+                        SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD
+                        | SEC_RELOC | SEC_CODE | SEC_READONLY);
+  (*secptr)->output_section = output_text_section->output_section;
+  (*secptr)->output_offset = 0;
+  
+  /* Set up the ELF section header for this new section.  This
+     is basically the same processing as elf_make_sections().  
+     elf_make_sections is static and therefore not accessable
+     here.  */
+  {
+    Elf_Internal_Shdr *this_hdr;
+    this_hdr = &elf_section_data ((*secptr))->this_hdr;
+    
+    /* Set the sizes of this section.  The contents have already
+       been set up ?!?  */
+    this_hdr->sh_addr = (*secptr)->vma;
+    this_hdr->sh_size = (*secptr)->_raw_size;
+    
+    /* Set appropriate flags for sections with relocations.  */
+    if ((*secptr)->flags & SEC_RELOC)
       {
-       Elf_Internal_Shdr *this_hdr;
-       this_hdr = &elf_section_data (stub_sec)->this_hdr;
+       Elf_Internal_Shdr *rela_hdr;
+       int use_rela_p = get_elf_backend_data (abfd)->use_rela_p;
        
-       /* Set the sizes of this section.  The contents have already
-          been set up ?!?  */
-       this_hdr->sh_addr = stub_sec->vma;
-       this_hdr->sh_size = stub_sec->_raw_size;
+       rela_hdr = &elf_section_data ((*secptr))->rel_hdr;
        
-       /* Set appropriate flags for sections with relocations.  */
-       if (stub_sec->flags & SEC_RELOC)
+       if (use_rela_p)
          {
-           Elf_Internal_Shdr *rela_hdr;
-           int use_rela_p = get_elf_backend_data (abfd)->use_rela_p;
-           
-           rela_hdr = &elf_section_data (stub_sec)->rel_hdr;
-           
-           if (use_rela_p)
-             {
-               rela_hdr->sh_type = SHT_RELA;
-               rela_hdr->sh_entsize = sizeof (Elf32_External_Rela);
-             }
-           else
-             {
-               rela_hdr->sh_type = SHT_REL;
-               rela_hdr->sh_entsize = sizeof (Elf32_External_Rel);
-             }
-           rela_hdr->sh_flags = 0;
-           rela_hdr->sh_addr = 0;
-           rela_hdr->sh_offset = 0;
-           rela_hdr->sh_addralign = 0;
-           rela_hdr->size = 0;
+           rela_hdr->sh_type = SHT_RELA;
+           rela_hdr->sh_entsize = sizeof (Elf32_External_Rela);
          }
-
-       if (stub_sec->flags & SEC_ALLOC)
+       else
          {
-           this_hdr->sh_flags |= SHF_ALLOC;
-           /* FIXME.  If SEC_LOAD is true should we do something with
-              with sh_type?  */
+           rela_hdr->sh_type = SHT_REL;
+           rela_hdr->sh_entsize = sizeof (Elf32_External_Rel);
          }
-
-       if (!(stub_sec->flags & SEC_READONLY))
-         this_hdr->sh_flags |= SHF_WRITE;
-       
-       if (stub_sec->flags & SEC_CODE)
-         this_hdr->sh_flags |= SHF_EXECINSTR;
+       rela_hdr->sh_flags = 0;
+       rela_hdr->sh_addr = 0;
+       rela_hdr->sh_offset = 0;
+       rela_hdr->sh_addralign = 0;
+       rela_hdr->size = 0;
       }
-      
-      bfd_set_section_alignment (abfd, stub_sec, 2);
-      stub_desc = new_stub (abfd, stub_sec);
-    }
-  
-  if (!stub_desc)
-    stub_desc = new_stub (abfd, stub_sec);
-  
-  /* Allocate memory to contain the stub.  FIXME.  Why isn't this using
-     the BFD memory allocation routines?  */
-  if (!stub_desc->stub_contents)
-    {
-      stub_desc->allocated_size = STUB_BUFFER_INCR;
-      stub_desc->stub_contents = (char *) malloc (STUB_BUFFER_INCR);
-    }
-  else if ((stub_desc->allocated_size - stub_desc->real_size) < STUB_MAX_SIZE)
-    {
-      stub_desc->allocated_size = stub_desc->allocated_size + STUB_BUFFER_INCR;
-      stub_desc->stub_contents = (char *) realloc (stub_desc->stub_contents,
-                                                  stub_desc->allocated_size);
-    }
-  
-  stub_desc->stub_secp
-    = (int *) (stub_desc->stub_contents + stub_desc->real_size);
-  
-  /* Is this a millicode call?  If so, the return address
-     comes in on r31 rather than r2 (rp) so a slightly
-     different code sequence is needed.  */
-  
-  insn = data[0];
-  rtn_reg = (insn & 0x03e00000) >> 21;
-  if (rtn_reg == 31)
-    milli = true;
-  
-  if (strcmp (symbol->name, "$$dyncall") == 0)
-    dyncall = true;
-  
-  /* Check to see if we modify the return pointer
-     in the delay slot of the branch.  */
-  {
-    unsigned delay_insn = data[1];
     
-    /* If we nullify the delay slot, or if the delay slot contains an
-       instruction that modifies the return pointer, then no additional
-       modification of the return pointer is necessary.  */
-    if (insn & 2 || insn == 0)
-      rtn_adjust = false;
-    else
-      {
-       if (get_opcode (delay_insn) == LDO
-           && (((delay_insn & 0x001f0000) >> 16) == rtn_reg))
-         rtn_adjust = false;
-      }
+    if ((*secptr)->flags & SEC_ALLOC)
+      this_hdr->sh_flags |= SHF_ALLOC;
+    
+    if (!((*secptr)->flags & SEC_READONLY))
+      this_hdr->sh_flags |= SHF_WRITE;
+    
+    if ((*secptr)->flags & SEC_CODE)
+      this_hdr->sh_flags |= SHF_EXECINSTR;
   }
   
-  sprintf (stub_sym_name,
-          "_lb_stub_%s_%s", reloc_entry->sym_ptr_ptr[0]->name,
-          rtn_adjust ? "RA" : "");
-  stub_entry = find_stub_by_name(abfd, stub_sec, stub_sym_name);
-
-  /* If a copy of this stub already exists re-use it.  */
-  if (stub_entry)
-    {
-      stub_sym = stub_entry->sym;
-
-      /* Change symbol associated with the original relocation to point
-        to the stub.
-
-        FIXME.  Is there a need to change the relocation type too?  */
-      reloc_entry->sym_ptr_ptr = (asymbol **) bfd_zalloc (stub_desc->this_bfd,
-                                                         sizeof (asymbol *));
-      reloc_entry->sym_ptr_ptr[0] = stub_sym;
-      reloc_entry->howto = bfd_reloc_type_lookup (abfd, R_HPPA_STUB_CALL_17);
-    }
-  else
-    {
-      /* We will need to allocate a new stub.  */
-      stub_sym = bfd_make_empty_symbol (abfd);
-      stub_sym->name = bfd_zalloc (abfd, strlen (stub_sym_name) + 1);
-      strcpy ((char *) stub_sym->name, stub_sym_name);
-      stub_sym->value
-       = (int) stub_desc->stub_secp - (int) stub_desc->stub_contents;
-      stub_sym->section = stub_sec;
-      stub_sym->flags = BSF_LOCAL | BSF_FUNCTION;
-      stub_entry = add_stub_by_name (abfd, stub_sec, stub_sym);
-      
-      /* Change symbol associated with the original relocation to point
-        to the stub.
-
-        FIXME.  Is there a need to change the relocation type too?  */
-      reloc_entry->sym_ptr_ptr = (asymbol **) bfd_zalloc (stub_desc->this_bfd,
-                                                         sizeof (asymbol *));
-      reloc_entry->sym_ptr_ptr[0] = stub_sym;
-      reloc_entry->howto = bfd_reloc_type_lookup (abfd, R_HPPA_STUB_CALL_17);
-      
-      /* Build the stub.  */
-      
-      /* 1. initialization for the call. */
-      NEW_INSTRUCTION (stub_entry, LDSID_31_1);
-      NEW_INSTRUCTION (stub_entry, MTSP_1_SR0);
-      
-      if (!dyncall)
-       {
-         if (!milli)
-           {
-             if (rtn_adjust)
-               {
-                 NEW_INSTRUCTION (stub_entry, ADDI_M4_31_RP);
-               }
-             else
-               {
-                 NEW_INSTRUCTION (stub_entry, COPY_31_2);
-               }
-           }
-         else
-           {
-             if (rtn_adjust)
-               {
-                 NEW_INSTRUCTION (stub_entry, ADDI_M4_31_1);
-               }
-             else
-               {
-                 NEW_INSTRUCTION (stub_entry, COPY_31_1);
-               }
-           }
-         
-         NEW_INSTRUCTION (stub_entry, LDIL_XXX_31);
-         hppa_elf_stub_reloc (stub_desc,
-                              abfd,
-                              target_sym,
-                              CURRENT_STUB_OFFSET (stub_entry),
-                              R_HPPA_L21);
-         
-         /* 2. Make the call. */
-         if (!milli)
-           {
-             NEW_INSTRUCTION (stub_entry, BE_N_XXX_0_31);
-             hppa_elf_stub_reloc (stub_desc,
-                                  abfd,
-                                  target_sym,
-                                  CURRENT_STUB_OFFSET (stub_entry),
-                                  R_HPPA_ABS_CALL_R17);
-           }
-         else
-           {
-             NEW_INSTRUCTION (stub_entry, BE_XXX_0_31);
-             hppa_elf_stub_reloc (stub_desc,
-                                  abfd,
-                                  target_sym,
-                                  CURRENT_STUB_OFFSET (stub_entry),
-                                  R_HPPA_ABS_CALL_R17);
-             NEW_INSTRUCTION (stub_entry, COPY_1_31);
-           }
-       }
-      else
-       {
-         /* 3. Branch back to the original location.
-            (For non-millicode calls, this is accomplished with the
-            COPY_31_2 instruction.  For millicode calls, the return
-            location is already in r2.)  */
-         if (rtn_adjust)
-           {
-             NEW_INSTRUCTION (stub_entry, ADDI_M4_31_RP);
-           }
-         NEW_INSTRUCTION (stub_entry, LDIL_XXX_31);
-         hppa_elf_stub_reloc (stub_desc,
-                              abfd,
-                              target_sym,
-                              CURRENT_STUB_OFFSET (stub_entry),
-                              R_HPPA_L21);
-         
-         NEW_INSTRUCTION (stub_entry, BE_N_XXX_0_31);
-         hppa_elf_stub_reloc (stub_desc,
-                              abfd,
-                              target_sym,
-                              CURRENT_STUB_OFFSET (stub_entry),
-                              R_HPPA_ABS_CALL_R17);
-       }
-    }
-  return stub_sym;
+  bfd_set_section_alignment (abfd, *secptr, 2);
 }
 
-int
+/* Return nonzero if a long-call stub will be needed to call the
+   function (symbol in RELOC_ENTRY).  */
+
+static int
 hppa_elf_long_branch_needed_p (abfd, asec, reloc_entry, symbol, insn)
      bfd *abfd;
      asection *asec;
@@ -2950,65 +2660,89 @@ hppa_elf_long_branch_needed_p (abfd, asec, reloc_entry, symbol, insn)
      asymbol *symbol;
      unsigned insn;
 {
-  long sym_value = get_symbol_value(symbol);
+  long sym_value = get_symbol_value (symbol);
   int fmt = reloc_entry->howto->bitsize;
-  unsigned char op = get_opcode(insn);
+  unsigned char op = get_opcode (insn);
   unsigned raddr;
 
-#define too_far(val,num_bits)  ((int)(val) > (1<<(num_bits))-1) || ((int)(val) < (-1<<(num_bits)))
+#define too_far(val,num_bits) \
+  ((int)(val) > (1 << (num_bits)) - 1) || ((int)(val) < (-1 << (num_bits)))
 
   switch (op)
     {
     case BL:
       raddr =
        reloc_entry->address + asec->output_offset + asec->output_section->vma;
-      if ( too_far(sym_value - raddr,fmt+1) )
-       {
-#ifdef DETECT_STUBS
-         fprintf(stderr,"long_branch needed on BL insn: abfd=%s,sym=%s,distance=0x%x\n",abfd->filename,symbol->name,sym_value - reloc_entry->address);
-#endif
+      /* If the symbol and raddr (relocated addr?) are too far away from
+        each other, then a long-call stub will be needed.  */
+      if (too_far (sym_value - raddr, fmt + 1))
          return 1;
-       }
       break;
     }  
   return 0;
 }
 
-#define STUB_SYM_BUFFER_INC    5
+/* Search the given section and determine if linker stubs will be
+   needed for any calls within that section.
+
+   Return any new stub symbols created.
 
+   Used out of hppaelf.em in the linker.  */
+   
 asymbol *
 hppa_look_for_stubs_in_section (stub_bfd, abfd, output_bfd, asec,
-                               syms, new_sym_cnt)
+                               new_sym_cnt, link_info)
      bfd *stub_bfd;
      bfd *abfd;
      bfd *output_bfd;
      asection *asec;
-     asymbol **syms;
      int *new_sym_cnt;
+     struct bfd_link_info *link_info;
 {
   int i;
-  int stub_types[5];
-  asymbol *new_syms = (asymbol *) NULL;
+  arg_reloc_type stub_types[5];
+  asymbol *new_syms = NULL;
   int new_cnt = 0;
   int new_max = 0;
 
   /* Relocations are in different places depending on whether this is
      an output section or an input section.  Also, the relocations are
-     in different forms.  Sigh.  Luckily, we have
-     bfd_canonicalize_reloc() to straighten this out for us . */
-
+     in different forms.  Sigh.  Luckily, we have bfd_canonicalize_reloc()
+     to straighten this out for us . */
   if (asec->reloc_count > 0)
     {
       arelent **reloc_vector
        = (arelent **) alloca (asec->reloc_count * (sizeof (arelent *) + 1));
 
-      bfd_canonicalize_reloc (abfd, asec, reloc_vector, syms);
+      /* Make sure the canonical symbols are hanging around in a convient
+        location.  */
+      if (bfd_get_outsymbols (abfd) == NULL)
+       {
+         size_t symsize;
+
+         symsize = get_symtab_upper_bound (abfd);
+         abfd->outsymbols = (asymbol **) bfd_alloc (abfd, symsize);
+         if (!abfd->outsymbols)
+           {
+             bfd_set_error (bfd_error_no_memory);
+             abort ();
+           }
+         abfd->symcount = bfd_canonicalize_symtab (abfd, abfd->outsymbols);
+       }
+
+      /* Now get the relocations.  */
+      bfd_canonicalize_reloc (abfd, asec, reloc_vector,
+                             bfd_get_outsymbols (abfd));
+
+      /* Examine each relocation entry in this section.  */
       for (i = 0; i < asec->reloc_count; i++)
        {
          arelent *rle = reloc_vector[i];
 
          switch (rle->howto->type)
            {
+           /* Any call could need argument relocation stubs, and
+              some may need long-call stubs.  */
            case R_HPPA_ABS_CALL_11:
            case R_HPPA_ABS_CALL_14:
            case R_HPPA_ABS_CALL_17:
@@ -3051,8 +2785,11 @@ hppa_look_for_stubs_in_section (stub_bfd, abfd, output_bfd, asec,
                  = (symext_entryS) HPPA_R_ARG_RELOC (rle->addend);
                unsigned insn[2];
 
+               /* We'll need this for the long-call checks.  */
                bfd_get_section_contents (abfd, asec, insn, rle->address,
                                          sizeof(insn));
+
+               /* See if this call needs an argument relocation stub.  */
                if (hppa_elf_arg_reloc_needed_p (abfd, rle, stub_types,
                                                 caller_ar))
                  {
@@ -3064,21 +2801,19 @@ hppa_look_for_stubs_in_section (stub_bfd, abfd, output_bfd, asec,
                        new_max += STUB_SYM_BUFFER_INC;
                        new_syms = (asymbol *)
                          realloc (new_syms, new_max * sizeof (asymbol));
+                       if (new_syms == NULL)
+                         abort ();
                      }
 
-                   /* The rtn_adjust argument is true here because we
-                      know that we have a branch and (with a few exceptions
-                      detailed under the relocation code for relocation type
-                      R_HPPA_STUB_CALL_17) it will be possible to perform
-                      the code reorientation.  */
-                   r = hppa_elf_build_arg_reloc_stub (stub_bfd, output_bfd,
-                                                      rle, stub_types,
-                                                      true, insn);
+                   /* Build the argument relocation stub.  */
+                   r = hppa_elf_build_linker_stub (stub_bfd, output_bfd,
+                                                   link_info, rle,
+                                                   stub_types, true, insn, 
+                                                   HPPA_STUB_ARG_RELOC);
                    new_syms[new_cnt++] = *r;
                  }
 
-               /* We need to retrieve the section contents to check for
-                  long branch stubs.  */
+               /* See if this call needs a long-call stub.  */
                if (hppa_elf_long_branch_needed_p (abfd, asec, rle,
                                                   rle->sym_ptr_ptr[0],
                                                   insn[0]))
@@ -3091,16 +2826,21 @@ hppa_look_for_stubs_in_section (stub_bfd, abfd, output_bfd, asec,
                        new_max += STUB_SYM_BUFFER_INC;
                        new_syms = (asymbol *)
                          realloc (new_syms, (new_max * sizeof (asymbol)));
+                       if (! new_syms)
+                         abort ();
                      }
-                   r = hppa_elf_build_long_branch_stub (stub_bfd, output_bfd,
-                                                        rle,
-                                                        rle->sym_ptr_ptr[0],
-                                                        insn);
+
+                   /* Build the long-call stub.  */
+                   r = hppa_elf_build_linker_stub (stub_bfd, output_bfd,
+                                                   link_info, rle,
+                                                   NULL, true, insn, 
+                                                   HPPA_STUB_LONG_CALL);
                    new_syms[new_cnt++] = *r;
                  }
              }
              break;
 
+           /* PLABELs may need argument relocation stubs.  */
            case R_HPPA_PLABEL_32:
            case R_HPPA_PLABEL_11:
            case R_HPPA_PLABEL_14:
@@ -3109,14 +2849,17 @@ hppa_look_for_stubs_in_section (stub_bfd, abfd, output_bfd, asec,
            case R_HPPA_PLABEL_R14:
              {
                /* On a plabel relocation, assume the arguments of the
-                  caller are set up in general registers.
-                  NOTE:  0x155 = ARGW0=CR,ARGW1=GR,ARGW2=GR,RETVAL=GR */
+                  caller are set up in general registers (indirect
+                  calls only use general registers.
+                  NOTE:  0x155 = ARGW0=GR,ARGW1=GR,ARGW2=GR,RETVAL=GR.  */
                symext_entryS caller_ar = (symext_entryS) 0x155;
                unsigned insn[2];
 
+               /* Do we really need this?  */
                bfd_get_section_contents (abfd, asec, insn, rle->address,
                                          sizeof(insn));
 
+               /* See if this call needs an argument relocation stub.  */
                if (hppa_elf_arg_reloc_needed_p (abfd, rle, stub_types,
                                                 caller_ar))
                  {
@@ -3136,7 +2879,6 @@ hppa_look_for_stubs_in_section (stub_bfd, abfd, output_bfd, asec,
                       (see the relocation code for relocation type 
                       R_HPPA_STUB_CALL_17) is possible.  Basically,
                       determine whether we are looking at a branch or not.  */
-                                                             
                    if (rle->howto->type == R_HPPA_PLABEL_32)
                      rtn_adjust = false;
                    else
@@ -3151,9 +2893,12 @@ hppa_look_for_stubs_in_section (stub_bfd, abfd, output_bfd, asec,
                            rtn_adjust = false;
                          }
                      }
-                   r = hppa_elf_build_arg_reloc_stub (stub_bfd, output_bfd,
-                                                      rle, stub_types,
-                                                      rtn_adjust, insn);
+
+                   /* Build the argument relocation stub.  */
+                   r = hppa_elf_build_linker_stub (stub_bfd, output_bfd,
+                                                   link_info, rle, stub_types,
+                                                   rtn_adjust, insn,
+                                                   HPPA_STUB_ARG_RELOC);
                    new_syms[new_cnt++] = *r;
                  }
              }
@@ -3161,43 +2906,46 @@ hppa_look_for_stubs_in_section (stub_bfd, abfd, output_bfd, asec,
 
            default:
              break;
-
            }
        }
     }
+
+  /* Return the new symbols and update the counters.  */
   *new_sym_cnt = new_cnt;
   return new_syms;
 }
 
+/* Set the contents of a particular section at a particular location.  */
 
-char *linker_stubs = NULL;
-int linker_stubs_size = 0;
-int linker_stubs_max_size = 0;
-#define STUB_ALLOC_INCR        100
-
-boolean
-DEFUN (hppa_elf_set_section_contents, (abfd, section, location, offset, count),
-       bfd * abfd AND
-       sec_ptr section AND
-       PTR location AND
-       file_ptr offset AND
-       bfd_size_type count)
+static boolean
+hppa_elf_set_section_contents (abfd, section, location, offset, count)
+     bfd *abfd;
+     sec_ptr section;
+     PTR location;
+     file_ptr offset;
+     bfd_size_type count;
 {
-  if ( strcmp(section->name, ".hppa_linker_stubs") == 0 )
+  /* Linker stubs are handled a little differently.  */
+  if (! strcmp (section->name, ".hppa_linker_stubs"))
     {
-      if ( linker_stubs_max_size < offset + count )
+      if (linker_stubs_max_size < offset + count)
        {
          linker_stubs_max_size = offset + count + STUB_ALLOC_INCR;
-         linker_stubs = (char *)realloc(linker_stubs, linker_stubs_max_size);
+         linker_stubs = (char *)realloc (linker_stubs, linker_stubs_max_size);
+         if (! linker_stubs)
+           abort ();
        }
 
-      if ( offset + count > linker_stubs_size )
+      if (offset + count > linker_stubs_size)
        linker_stubs_size = offset + count;
 
-      memcpy(linker_stubs + offset,location,count);
+      /* Set the contents.  */
+      memcpy(linker_stubs + offset, location, count);
       return (true);
     }
   else
+    /* For everything but the linker stub section, use the generic
+       code.  */
     return bfd_elf32_set_section_contents (abfd, section, location,
                                           offset, count);
 }
@@ -3259,17 +3007,18 @@ hppa_elf_get_section_contents (abfd, section, location, offset, count)
        {
          int i;
          int *symtab_map =
-           (int *) elf_sym_extra(section->output_section->owner);
+           (int *) elf_sym_extra (section->output_section->owner);
          
-         for (i = 0; i < section->output_section->owner->symcount; i++ )
+         for (i = 0; i < section->output_section->owner->symcount; i++)
            {
-             elf_hppa_tc_symbol(section->output_section->owner,
-                                ((elf_symbol_type *)
-                                 section->output_section->owner->outsymbols[i]),
-                                symtab_map[i]);
+             elf_hppa_tc_symbol (section->output_section->owner,
+                                 ((elf_symbol_type *)
+                                  section->output_section->owner->outsymbols[i]),
+                                 symtab_map[i], &symext_rootP, &symext_lastP);
            }
          symext_chain_built++;
-         elf_hppa_tc_make_sections (section->output_section->owner, NULL);
+         elf_hppa_tc_make_sections (section->output_section->owner, 
+                                    symext_rootP);
        }
 
       /* At this point we know that the symbol extension section has been
@@ -3283,33 +3032,39 @@ hppa_elf_get_section_contents (abfd, section, location, offset, count)
        return (false);
       
       memcpy (location,
-             ((char *)symextn_contents + section->output_offset + offset),
+             (char *)symextn_contents + section->output_offset + offset,
              count);
       return (true);
     }
   else
+    /* It's not the symbol extension or linker stub sections, use
+       the generic routines.  */
     return bfd_generic_get_section_contents (abfd, section, location,
                                             offset, count);
 }
 
+/* Translate from an elf into field into a howto relocation pointer.  */
+
 static void
-DEFUN (elf_info_to_howto, (abfd, cache_ptr, dst),
-       bfd * abfd AND
-       arelent * cache_ptr AND
-       Elf32_Internal_Rela * dst)
+elf_info_to_howto (abfd, cache_ptr, dst)
+     bfd *abfd;
+     arelent *cache_ptr;
+     Elf32_Internal_Rela *dst;
 {
   BFD_ASSERT (ELF32_R_TYPE(dst->r_info) < (unsigned int) R_HPPA_UNIMPLEMENTED);
-  cache_ptr->howto = &elf_hppa_howto_table[ELF32_R_TYPE(dst->r_info)];
+  cache_ptr->howto = &elf_hppa_howto_table[ELF32_R_TYPE (dst->r_info)];
 }
 
+/* Do PA ELF specific processing for symbols.  Needed to find the
+   value of $global$.  */
+
 static void
-DEFUN (elf32_hppa_backend_symbol_processing, (abfd, sym),
-       bfd * abfd AND
-       asymbol * sym)
+elf32_hppa_backend_symbol_processing (abfd, sym)
+     bfd *abfd;
+     asymbol *sym;
 {
   /* Is this a definition of $global$?  If so, keep it because it will be
     needed if any relocations are performed.  */
-
   if (!strcmp (sym->name, "$global$")
       && sym->section != &bfd_und_section)
     {
@@ -3317,79 +3072,67 @@ DEFUN (elf32_hppa_backend_symbol_processing, (abfd, sym),
     }
 }
 
-#define elf_backend_symbol_processing  elf32_hppa_backend_symbol_processing
-
-struct elf32_hppa_symextn_map_struct
-{
-  int old_index;
-  bfd *bfd;
-  asymbol *sym;
-  int new_index;
-};
-
-static struct elf32_hppa_symextn_map_struct *elf32_hppa_symextn_map;
-static int elf32_hppa_symextn_map_size;
-
+/* Do some PA ELF specific work after reading in the symbol table.
+   In particular attach the argument relocation from the 
+   symbol extension section to the appropriate symbols.  */
 static boolean
-DEFUN (elf32_hppa_backend_symbol_table_processing, (abfd, esyms,symcnt),
-       bfd             * abfd AND
-       elf_symbol_type *esyms AND
-       int             symcnt)
+elf32_hppa_backend_symbol_table_processing (abfd, esyms,symcnt)
+     bfd *abfd;
+     elf_symbol_type *esyms;
+     int symcnt;
 {
-  Elf32_Internal_Shdr *symextn_hdr = bfd_elf_find_section (abfd, SYMEXTN_SECTION_NAME);
-  int i;
-  int current_sym_idx = 0;
+  Elf32_Internal_Shdr *symextn_hdr =
+    bfd_elf_find_section (abfd, SYMEXTN_SECTION_NAME);
+  int i, current_sym_idx = 0;
 
-  /* If the symbol extension section does not exist, all the symbol */
-  /* all the symbol extension information is assumed to be zero.       */
-
-  if ( symextn_hdr == NULL )
+  /* If no symbol extension existed, then all symbol extension information
+     is assumed to be zero.  */
+  if (symextn_hdr == NULL)
     {
-      for ( i = 0; i < symcnt; i++ )
-       {
-         esyms[i].tc_data.hppa_arg_reloc = 0;
-       }
+      for (i = 0; i < symcnt; i++)
+       esyms[i].tc_data.hppa_arg_reloc = 0;
       return (true);
     }
 
-  /* allocate a buffer of the appropriate size for the symextn section */
-
+  /* Allocate a buffer of the appropriate size for the symextn section.  */
   symextn_hdr->contents = bfd_zalloc(abfd,symextn_hdr->sh_size);
+  if (!symextn_hdr->contents)
+    {
+      bfd_set_error (bfd_error_no_memory);
+      return false;
+    }
   symextn_hdr->size = symextn_hdr->sh_size;
        
-  /* read in the symextn section */
-
+  /* Read in the symextn section.  */
   if (bfd_seek (abfd, symextn_hdr->sh_offset, SEEK_SET) == -1)
     {
-      bfd_error = system_call_error;
+      bfd_set_error (bfd_error_system_call);
       return (false);
     }
   if (bfd_read ((PTR) symextn_hdr->contents, 1, symextn_hdr->size, abfd) 
       != symextn_hdr->size)
     {
-      free ((PTR)symextn_hdr->contents);
-      bfd_error = system_call_error;
+      bfd_set_error (bfd_error_system_call);
       return (false);
     }  
 
-  /* parse the entries, updating the symtab entries as we go */
-
-  for ( i = 0; i < symextn_hdr->size / sizeof(symext_entryS); i++ )
+  /* Parse entries in the symbol extension section, updating the symtab
+     entries as we go */
+  for (i = 0; i < symextn_hdr->size / sizeof(symext_entryS); i++)
     {
       symext_entryS *seP = ((symext_entryS *)symextn_hdr->contents) + i;
-      int se_value = ELF32_HPPA_SX_VAL(*seP);
-      int se_type = ELF32_HPPA_SX_TYPE(*seP);
+      int se_value = ELF32_HPPA_SX_VAL (*seP);
+      int se_type = ELF32_HPPA_SX_TYPE (*seP);
 
-      switch ( se_type )
+      switch (se_type)
        {
        case HPPA_SXT_NULL:
          break;
 
        case HPPA_SXT_SYMNDX:
-         if ( se_value >= symcnt )
+         if (se_value >= symcnt)
            {
-             bfd_error = bad_value;
-             bfd_perror("elf32_hppa_backend_symbol_table_processing -- symbol index");
+             bfd_set_error (bfd_error_bad_value);
              return (false);
            }
          current_sym_idx = se_value - 1;
@@ -3400,48 +3143,50 @@ DEFUN (elf32_hppa_backend_symbol_table_processing, (abfd, esyms,symcnt),
          break;
 
        default:
-         bfd_error = bad_value;
-         bfd_perror("elf32_hppa_backend_symbol_table_processing");
+         bfd_set_error (bfd_error_bad_value);
          return (false);
        }
     }
   return (true);
 }
 
-#define elf_backend_symbol_table_processing    elf32_hppa_backend_symbol_table_processing
+/* Perform on PA ELF specific processing once a section has been
+   read in.  In particular keep the symbol indexes correct for
+   the symbol extension information.  */
 
 static boolean
-DEFUN (elf32_hppa_backend_section_processing, (abfd, secthdr),
-       bfd             * abfd AND
-       Elf32_Internal_Shdr *secthdr)
+elf32_hppa_backend_section_processing (abfd, secthdr)
+     bfd *abfd;
+     Elf32_Internal_Shdr *secthdr;
 {
-  int i,j,k;
+  int i, j, k;
 
-  if ( secthdr->sh_type == SHT_HPPA_SYMEXTN )
+  if (secthdr->sh_type == SHT_HPPA_SYMEXTN)
     {
-      for ( i = 0; i < secthdr->size / sizeof(symext_entryS); i++ )
+      for (i = 0; i < secthdr->size / sizeof (symext_entryS); i++)
        {
          symext_entryS *seP = ((symext_entryS *)secthdr->contents) + i;
-         int se_value = ELF32_HPPA_SX_VAL(*seP);
-         int se_type = ELF32_HPPA_SX_TYPE(*seP);
+         int se_value = ELF32_HPPA_SX_VAL (*seP);
+         int se_type = ELF32_HPPA_SX_TYPE (*seP);
          
-         switch ( se_type )
+         switch (se_type)
            {
            case HPPA_SXT_NULL:
              break;
              
            case HPPA_SXT_SYMNDX:
-             for ( j = 0; j < abfd->symcount; j++ )
+             for (j = 0; j < abfd->symcount; j++)
                {
-                 /* locate the map entry for this symbol, if there is one. */
-                 /* modify the symbol extension section symbol index entry */
-                 /* to reflect the new symbol table index */
-                 
-                 for ( k = 0; k < elf32_hppa_symextn_map_size; k++ )
+                 /* Locate the map entry for this symbol and modify the
+                    symbol extension section symbol index entry to reflect
+                    the new symbol table index.  */
+                 for (k = 0; k < elf32_hppa_symextn_map_size; k++)
                    {
-                     if ( elf32_hppa_symextn_map[k].old_index == se_value
-                         && elf32_hppa_symextn_map[k].bfd == abfd->outsymbols[j]->the_bfd
-                         && elf32_hppa_symextn_map[k].sym == abfd->outsymbols[j] )
+                     if (elf32_hppa_symextn_map[k].old_index == se_value
+                         && elf32_hppa_symextn_map[k].bfd
+                            == abfd->outsymbols[j]->the_bfd
+                         && elf32_hppa_symextn_map[k].sym
+                            == abfd->outsymbols[j])
                        {
                          bfd_put_32(abfd,
                                     ELF32_HPPA_SX_WORD (HPPA_SXT_SYMNDX, j),
@@ -3455,8 +3200,7 @@ DEFUN (elf32_hppa_backend_section_processing, (abfd, secthdr),
              break;
              
            default:
-             bfd_error = bad_value;
-             bfd_perror("elf32_hppa_backend_section_processing");
+             bfd_set_error (bfd_error_bad_value);
              return (false);
            }
        }
@@ -3464,21 +3208,23 @@ DEFUN (elf32_hppa_backend_section_processing, (abfd, secthdr),
   return true;
 }
 
-#define elf_backend_section_processing elf32_hppa_backend_section_processing
+/* What does this really do?  Just determine if there is an appropriate
+   mapping from ELF section headers to backend sections?  More symbol
+   extension braindamage.  */
 
 static boolean
-DEFUN (elf32_hppa_backend_section_from_shdr, (abfd, hdr, name),
-       bfd             * abfd AND
-       Elf32_Internal_Shdr *hdr AND
-       char            * name)
+elf32_hppa_backend_section_from_shdr (abfd, hdr, name)
+     bfd *abfd;
+     Elf32_Internal_Shdr *hdr;
+     char *name;
 {
   asection *newsect;
 
-  if ( hdr->sh_type == SHT_HPPA_SYMEXTN )
+  if (hdr->sh_type == SHT_HPPA_SYMEXTN)
     {
-      BFD_ASSERT ( strcmp(name,".hppa_symextn") == 0 );
+      BFD_ASSERT (strcmp (name, ".hppa_symextn") == 0);
 
-      /* Bits that get saved. This one is real. */
+      /* Bits that get saved. This one is real.  */
       if (!hdr->rawdata)
        {
          newsect = bfd_make_section (abfd, name);
@@ -3486,7 +3232,7 @@ DEFUN (elf32_hppa_backend_section_from_shdr, (abfd, hdr, name),
            {
              newsect->vma = hdr->sh_addr;
              newsect->_raw_size = hdr->sh_size;
-             newsect->filepos = hdr->sh_offset;        /* so we can read back the bits */
+             newsect->filepos = hdr->sh_offset;
              newsect->flags |= SEC_HAS_CONTENTS;
              newsect->alignment_power = hdr->sh_addralign;
 
@@ -3500,7 +3246,7 @@ DEFUN (elf32_hppa_backend_section_from_shdr, (abfd, hdr, name),
                newsect->flags |= SEC_READONLY;
 
              if (hdr->sh_flags & SHF_EXECINSTR)
-               newsect->flags |= SEC_CODE;     /* FIXME: may only contain SOME code */
+               newsect->flags |= SEC_CODE;
              else
                newsect->flags |= SEC_DATA;
 
@@ -3512,16 +3258,16 @@ DEFUN (elf32_hppa_backend_section_from_shdr, (abfd, hdr, name),
   return false;
 }
 
-#define elf_backend_section_from_shdr  elf32_hppa_backend_section_from_shdr
+/* Return true if the given section is a fake section.  */
 
 static boolean
-DEFUN (elf32_hppa_backend_fake_sections, (abfd, secthdr, asect),
-       bfd             * abfd AND
-       Elf_Internal_Shdr *secthdr AND
-       asection                *asect)
+elf32_hppa_backend_fake_sections (abfd, secthdr, asect)
+     bfd *abfd;
+     Elf_Internal_Shdr *secthdr;
+     asection *asect;
 {
 
-  if ( strcmp(asect->name, ".hppa_symextn") == 0 )
+  if (strcmp(asect->name, ".hppa_symextn") == 0)
     {
       secthdr->sh_type = SHT_HPPA_SYMEXTN;
       secthdr->sh_flags = 0;
@@ -3555,34 +3301,34 @@ DEFUN (elf32_hppa_backend_fake_sections, (abfd, secthdr, asect),
   return false;
 }
 
-#define elf_backend_fake_sections      elf32_hppa_backend_fake_sections
+/* Return true if there is a mapping from bfd section into a
+   backend section.  */
 
 static boolean
-DEFUN (elf32_hppa_backend_section_from_bfd_section, (abfd, hdr, asect, retval),
-       bfd                     *abfd AND
-       Elf32_Internal_Shdr     *hdr AND
-       asection                        *asect AND
-       int                     *retval)
+elf32_hppa_backend_section_from_bfd_section (abfd, hdr, asect, ignored)
+     bfd *abfd;
+     Elf32_Internal_Shdr *hdr;
+     asection *asect;
+     int *ignored;
 {
-
-  if ( hdr->sh_type == SHT_HPPA_SYMEXTN )
+  if (hdr->sh_type == SHT_HPPA_SYMEXTN)
     {
       if (hdr->rawdata)
        {
          if (((struct sec *) (hdr->rawdata)) == asect)
            {
-             BFD_ASSERT( strcmp(asect->name, ".hppa_symextn") == 0 );
+             BFD_ASSERT (strcmp (asect->name, ".hppa_symextn") == 0);
              return true;
            }
        }
     }
-  else if ( hdr->sh_type == SHT_STRTAB )
+  else if (hdr->sh_type == SHT_STRTAB)
     {
       if (hdr->rawdata)
        {
          if (((struct sec *) (hdr->rawdata)) == asect)
            {
-             BFD_ASSERT ( strcmp (asect->name, ".stabstr") == 0);
+             BFD_ASSERT (strcmp (asect->name, ".stabstr") == 0);
              return true;
            }
        }
@@ -3591,11 +3337,20 @@ DEFUN (elf32_hppa_backend_section_from_bfd_section, (abfd, hdr, asect, retval),
   return false;
 }
 
+#define bfd_elf32_bfd_reloc_type_lookup        elf_hppa_reloc_type_lookup
 #define elf_backend_section_from_bfd_section   elf32_hppa_backend_section_from_bfd_section
 
+#define elf_backend_symbol_processing  elf32_hppa_backend_symbol_processing
+#define elf_backend_symbol_table_processing    elf32_hppa_backend_symbol_table_processing
+
 #define bfd_generic_get_section_contents       hppa_elf_get_section_contents
 #define bfd_elf32_set_section_contents         hppa_elf_set_section_contents
 
+#define elf_backend_section_processing elf32_hppa_backend_section_processing
+
+#define elf_backend_section_from_shdr  elf32_hppa_backend_section_from_shdr
+#define elf_backend_fake_sections      elf32_hppa_backend_fake_sections
+
 #define TARGET_BIG_SYM         bfd_elf32_hppa_vec
 #define TARGET_BIG_NAME                "elf32-hppa"
 #define ELF_ARCH               bfd_arch_hppa
This page took 0.07118 seconds and 4 git commands to generate.