* elf32-hppa.c: (elf_hppa_howto_table): PLABEL and DLT
authorJeff Law <law@redhat.com>
Sun, 5 Dec 1993 03:46:12 +0000 (03:46 +0000)
committerJeff Law <law@redhat.com>
Sun, 5 Dec 1993 03:46:12 +0000 (03:46 +0000)
        relocations are not pc-relative.

bfd/ChangeLog
bfd/elf32-hppa.c

index 9d521013ada97fa20661ee3c1e9780defd6e474a..f51e257871c1ec81835feaebf5d8e97bc032c55d 100644 (file)
@@ -2,6 +2,9 @@ Sat Dec  4 19:40:32 1993  Jeffrey A. Law  (law@snake.cs.utah.edu)
 
        Fri Dec  3 09:55:17 1993  Pete Hoogenboom  (hoogen@cs.utah.edu)
 
+       * elf32-hppa.c: (elf_hppa_howto_table):  PLABEL and DLT
+       relocations are not pc-relative.
+
        * hppa_stubs.h: (BLE_N_XXX_0_31):  New instruction used in
        linker stub code. 
        (COPY_2_31):  Likewise.
index 87cc948ab32195090440313b8292b7b7d21f9574..b677e4db391f0c497f830cd2723fbf51c9f9794c 100644 (file)
@@ -36,14 +36,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
        November 19, 1992.
 */
 
-/*
-       Written by:
-
-       Center for Software Science
-       Department of Computer Science
-       University of Utah
-*/
-
 #include "elf32-hppa.h"
 #include "libhppa.h"
 #include "aout/aout64.h"
@@ -133,20 +125,20 @@ static reloc_howto_type elf_hppa_howto_table[ELF_HOWTO_TABLE_SIZE] =
   {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, true, 0, complain_overflow_signed, hppa_elf_reloc, "R_HPPA_PLABEL_32"},
-  {R_HPPA_PLABEL_11, 0, 3, 11, true, 0, complain_overflow_signed, hppa_elf_reloc, "R_HPPA_PLABEL_11"},
-  {R_HPPA_PLABEL_14, 0, 3, 14, true, 0, complain_overflow_signed, hppa_elf_reloc, "R_HPPA_PLABEL_14"},
-  {R_HPPA_PLABEL_L21, 0, 3, 21, true, 0, complain_overflow_signed, hppa_elf_reloc, "R_HPPA_PLABEL_L21"},
-  {R_HPPA_PLABEL_R11, 0, 3, 11, true, 0, complain_overflow_signed, hppa_elf_reloc, "R_HPPA_PLABEL_R11"},
-  {R_HPPA_PLABEL_R14, 0, 3, 14, true, 0, complain_overflow_signed, hppa_elf_reloc, "R_HPPA_PLABEL_R14"},
+  {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, true, 0, complain_overflow_signed, hppa_elf_reloc, "R_HPPA_DLT_32"},
-  {R_HPPA_DLT_11, 0, 3, 11, true, 0, complain_overflow_signed, hppa_elf_reloc, "R_HPPA_DLT_11"},
-  {R_HPPA_DLT_14, 0, 3, 14, true, 0, complain_overflow_signed, hppa_elf_reloc, "R_HPPA_DLT_14"},
-  {R_HPPA_DLT_L21, 0, 3, 21, true, 0, complain_overflow_signed, hppa_elf_reloc, "R_HPPA_DLT_L21"},
-  {R_HPPA_DLT_R11, 0, 3, 11, true, 0, complain_overflow_signed, hppa_elf_reloc, "R_HPPA_DLT_R11"},
-  {R_HPPA_DLT_R14, 0, 3, 14, true, 0, complain_overflow_signed, hppa_elf_reloc, "R_HPPA_DLT_R14"},
+  {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"},
@@ -1177,28 +1169,24 @@ static asymbol *global_symbol;
 static int global_sym_defined;
 
 static bfd_reloc_status_type
-DEFUN (hppa_elf_reloc, (abfd, reloc_entry, symbol_in, data, input_section, output_bfd),
-       bfd * abfd AND
-       arelent * reloc_entry AND
-       asymbol * symbol_in AND
-       PTR data AND
-       asection * input_section AND
-       bfd * output_bfd)
+hppa_elf_reloc (abfd, reloc_entry, symbol_in, data, input_section, output_bfd)
+     bfd *abfd;
+     arelent *reloc_entry;
+     asymbol *symbol_in;
+     PTR data;
+     asection *input_section;
+     bfd *output_bfd;
 {
   unsigned long insn;
   long sym_value = 0;
-
-  unsigned long addr = reloc_entry->address;   /*+ input_section->vma*/
+  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;
   boolean r_pcrel = reloc_entry->howto->pc_relative;
-
-  /* howto->bitsize contains the format (11, 14, 21, etc) information */
   unsigned r_format = reloc_entry->howto->bitsize;
   long r_addend = reloc_entry->addend;
 
-
   if (output_bfd)
     {
       /* Partial linking - do nothing */
@@ -1206,16 +1194,14 @@ DEFUN (hppa_elf_reloc, (abfd, reloc_entry, symbol_in, data, input_section, outpu
       return bfd_reloc_ok;
     }
 
+  /* If performing final link and the symbol we're relocating against
+     is undefined, then return an error.  */ 
   if (symbol_in && symbol_in->section == &bfd_und_section)
     return bfd_reloc_undefined;
 
-  /* Check for stubs that might be required.  */
-  /* symbol_in = hppa_elf_stub_check (abfd, input_section->output_section->owner, reloc_entry); */
-
   sym_value = get_symbol_value (symbol_in);
 
-  /* compute value of $global$ if it is there. */
-
+  /* Compute the value of $global$.  */
   if (!global_sym_defined)
     {
       if (global_symbol)
@@ -1223,83 +1209,85 @@ DEFUN (hppa_elf_reloc, (abfd, reloc_entry, symbol_in, data, input_section, outpu
          global_value = (global_symbol->value
                          + global_symbol->section->output_section->vma
                          + global_symbol->section->output_offset);
-         GOT_value = global_value;     /* XXX: For HP-UX, GOT==DP */
+         GOT_value = global_value;
          global_sym_defined++;
        }
     }
 
-  /* get the instruction word */
+  /* Get the instruction word.  */
   insn = bfd_get_32 (abfd, hit_data);
 
-  /* relocate the value based on the relocation type */
+  /* Relocate the value based on one of the basic relocation types
 
-  /* basic_type_1:     relocation is relative to $global$              */
-  /* basic_type_2:     relocation is relative to the current GOT       */
-  /* basic_type_3:     relocation is an absolute call                  */
-  /* basic_type_4:     relocation is an PC-relative call               */
-  /* basic_type_5:     relocation is plabel reference                  */
-  /* basic_type_6:     relocation is an unwind table relocation        */
-  /* extended_type:    unimplemented                                   */
+   basic_type_1:       relocation is relative to $global$
+   basic_type_2:       relocation is relative to the current GOT
+   basic_type_3:       relocation is an absolute call
+   basic_type_4:       relocation is an PC-relative call
+   basic_type_5:       relocation is plabel reference
+   basic_type_6:       relocation is an unwind table relocation
+   extended_type:      unimplemented  */
 
   switch (r_type)
     {
     case R_HPPA_NONE:
       break;
-    case R_HPPA_32:            /*              Symbol + Addend         32      */
+
+    /* Handle all the basic type 1 relocations.  */
+    case R_HPPA_32:
       r_field = e_fsel;
       goto do_basic_type_1;
-    case R_HPPA_11:            /*              Symbol + Addend         11      */
+    case R_HPPA_11:
       r_field = e_fsel;
       goto do_basic_type_1;
-    case R_HPPA_14:            /*              Symbol + Addend         14      */
+    case R_HPPA_14:
       r_field = e_fsel;
       goto do_basic_type_1;
-    case R_HPPA_17:            /*              Symbol + Addend         17      */
+    case R_HPPA_17:
       r_field = e_fsel;
       goto do_basic_type_1;
-    case R_HPPA_L21:           /*              L (Symbol, Addend)      21      */
+    case R_HPPA_L21:
       r_field = e_lsel;
       goto do_basic_type_1;
-    case R_HPPA_R11:           /*              R (Symbol, Addend)      11      */
+    case R_HPPA_R11:
       r_field = e_rsel;
       goto do_basic_type_1;
-    case R_HPPA_R14:           /*              R (Symbol, Addend)      14      */
+    case R_HPPA_R14:
       r_field = e_rsel;
       goto do_basic_type_1;
-    case R_HPPA_R17:           /*              R (Symbol, Addend)      17      */
+    case R_HPPA_R17:
       r_field = e_rsel;
       goto do_basic_type_1;
-    case R_HPPA_LS21:          /*              LS(Symbol, Addend)      21      */
+    case R_HPPA_LS21:
       r_field = e_lssel;
       goto do_basic_type_1;
-    case R_HPPA_RS11:          /*              RS(Symbol, Addend)      11      */
+    case R_HPPA_RS11:
       r_field = e_rssel;
       goto do_basic_type_1;
-    case R_HPPA_RS14:          /*              RS(Symbol, Addend)      14      */
+    case R_HPPA_RS14:
       r_field = e_rssel;
       goto do_basic_type_1;
-    case R_HPPA_RS17:          /*              RS(Symbol, Addend)      17      */
+    case R_HPPA_RS17:
       r_field = e_ldsel;
       goto do_basic_type_1;
-    case R_HPPA_LD21:          /*              LD(Symbol, Addend)      21      */
+    case R_HPPA_LD21:
       r_field = e_ldsel;
       goto do_basic_type_1;
-    case R_HPPA_RD11:          /*              RD(Symbol, Addend)      11      */
+    case R_HPPA_RD11:
       r_field = e_rdsel;
       goto do_basic_type_1;
-    case R_HPPA_RD14:          /*              RD(Symbol, Addend)      14      */
+    case R_HPPA_RD14:
       r_field = e_rdsel;
       goto do_basic_type_1;
-    case R_HPPA_RD17:          /*              RD(Symbol, Addend)      17      */
+    case R_HPPA_RD17:
       r_field = e_rdsel;
       goto do_basic_type_1;
-    case R_HPPA_LR21:          /*              LR(Symbol, Addend)      21      */
+    case R_HPPA_LR21:
       r_field = e_lrsel;
       goto do_basic_type_1;
-    case R_HPPA_RR14:          /*              RR(Symbol, Addend)      14      */
+    case R_HPPA_RR14:
       r_field = e_rrsel;
       goto do_basic_type_1;
-    case R_HPPA_RR17:          /*              RR(Symbol, Addend)      17      */
+    case R_HPPA_RR17:
       r_field = e_rrsel;
 
     do_basic_type_1:
@@ -1308,44 +1296,46 @@ DEFUN (hppa_elf_reloc, (abfd, reloc_entry, symbol_in, data, input_section, outpu
                                     r_type, r_format, r_field, r_pcrel);
       break;
 
-    case R_HPPA_GOTOFF_11:     /*      Symbol - GOT + Addend   11      */
+    /* 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:     /*      Symbol - GOT + Addend   14      */
+    case R_HPPA_GOTOFF_14:
       r_field = e_fsel;
       goto do_basic_type_2;
-    case R_HPPA_GOTOFF_L21:    /*      L (Sym - GOT, Addend)   21      */
+    case R_HPPA_GOTOFF_L21:
       r_field = e_lsel;
       goto do_basic_type_2;
-    case R_HPPA_GOTOFF_R11:    /*      R (Sym - GOT, Addend)   11      */
+    case R_HPPA_GOTOFF_R11:
       r_field = e_rsel;
       goto do_basic_type_2;
-    case R_HPPA_GOTOFF_R14:    /*      R (Sym - GOT, Addend)   14      */
+    case R_HPPA_GOTOFF_R14:
       r_field = e_rsel;
       goto do_basic_type_2;
-    case R_HPPA_GOTOFF_LS21:   /*      LS(Sym - GOT, Addend)   21      */
+    case R_HPPA_GOTOFF_LS21:
       r_field = e_lssel;
       goto do_basic_type_2;
-    case R_HPPA_GOTOFF_RS11:   /*      RS(Sym - GOT, Addend)   11      */
+    case R_HPPA_GOTOFF_RS11:
       r_field = e_rssel;
       goto do_basic_type_2;
-    case R_HPPA_GOTOFF_RS14:   /*      RS(Sym - GOT, Addend)   14      */
+    case R_HPPA_GOTOFF_RS14:
       r_field = e_rssel;
       goto do_basic_type_2;
-    case R_HPPA_GOTOFF_LD21:   /*      LD(Sym - GOT, Addend)   21      */
+    case R_HPPA_GOTOFF_LD21:
       r_field = e_ldsel;
       goto do_basic_type_2;
-    case R_HPPA_GOTOFF_RD11:   /*      RD(Sym - GOT, Addend)   11      */
+    case R_HPPA_GOTOFF_RD11:
       r_field = e_rdsel;
       goto do_basic_type_2;
-    case R_HPPA_GOTOFF_RD14:   /*      RD(Sym - GOT, Addend)   14      */
+    case R_HPPA_GOTOFF_RD14:
       r_field = e_rdsel;
       goto do_basic_type_2;
-    case R_HPPA_GOTOFF_LR21:   /*      LR(Sym - GOT, Addend)   21      */
+    case R_HPPA_GOTOFF_LR21:
       r_field = e_lrsel;
       goto do_basic_type_2;
-    case R_HPPA_GOTOFF_RR14:   /*      RR(Sym - GOT, Addend)   14      */
+    case R_HPPA_GOTOFF_RR14:
       r_field = e_rrsel;
+
     do_basic_type_2:
       sym_value -= GOT_value;
       insn = hppa_elf_relocate_insn (abfd, input_section, insn, addr,
@@ -1353,124 +1343,129 @@ DEFUN (hppa_elf_reloc, (abfd, reloc_entry, symbol_in, data, input_section, outpu
                                     r_type, r_format, r_field, r_pcrel);
       break;
 
-    case R_HPPA_ABS_CALL_11:   /*      Symbol + Addend         11      */
+    /* 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:   /*      Symbol + Addend         14      */
+    case R_HPPA_ABS_CALL_14:
       r_field = e_fsel;
       goto do_basic_type_3;
-    case R_HPPA_ABS_CALL_17:   /*      Symbol + Addend         17      */
+    case R_HPPA_ABS_CALL_17:
       r_field = e_fsel;
       goto do_basic_type_3;
-    case R_HPPA_ABS_CALL_L21:  /*      L (Symbol, Addend)      21      */
+    case R_HPPA_ABS_CALL_L21:
       r_field = e_lsel;
       goto do_basic_type_3;
-    case R_HPPA_ABS_CALL_R11:  /*      R (Symbol, Addend)      11      */
+    case R_HPPA_ABS_CALL_R11:
       r_field = e_rsel;
       goto do_basic_type_3;
-    case R_HPPA_ABS_CALL_R14:  /*      R (Symbol, Addend)      14      */
+    case R_HPPA_ABS_CALL_R14:
       r_field = e_rsel;
       goto do_basic_type_3;
-    case R_HPPA_ABS_CALL_R17:  /*      R (Symbol, Addend)      17      */
+    case R_HPPA_ABS_CALL_R17:
       r_field = e_rsel;
       goto do_basic_type_3;
-    case R_HPPA_ABS_CALL_LS21: /*      LS(Symbol, Addend)      21      */
+    case R_HPPA_ABS_CALL_LS21:
       r_field = e_lssel;
       goto do_basic_type_3;
-    case R_HPPA_ABS_CALL_RS11: /*      RS(Symbol, Addend)      11      */
+    case R_HPPA_ABS_CALL_RS11:
       r_field = e_lssel;
       goto do_basic_type_3;
-    case R_HPPA_ABS_CALL_RS14: /*      RS(Symbol, Addend)      14      */
+    case R_HPPA_ABS_CALL_RS14:
       r_field = e_rssel;
       goto do_basic_type_3;
-    case R_HPPA_ABS_CALL_RS17: /*      RS(Symbol, Addend)      17      */
+    case R_HPPA_ABS_CALL_RS17:
       r_field = e_rssel;
       goto do_basic_type_3;
-    case R_HPPA_ABS_CALL_LD21: /*      LD(Symbol, Addend)      21      */
+    case R_HPPA_ABS_CALL_LD21:
       r_field = e_ldsel;
       goto do_basic_type_3;
-    case R_HPPA_ABS_CALL_RD11: /*      RD(Symbol, Addend)      11      */
+    case R_HPPA_ABS_CALL_RD11:
       r_field = e_rdsel;
       goto do_basic_type_3;
-    case R_HPPA_ABS_CALL_RD14: /*      RD(Symbol, Addend)      14      */
+    case R_HPPA_ABS_CALL_RD14:
       r_field = e_rdsel;
       goto do_basic_type_3;
-    case R_HPPA_ABS_CALL_RD17: /*      RD(Symbol, Addend)      17      */
+    case R_HPPA_ABS_CALL_RD17:
       r_field = e_rdsel;
       goto do_basic_type_3;
-    case R_HPPA_ABS_CALL_LR21: /*      LR(Symbol, Addend)      21      */
+    case R_HPPA_ABS_CALL_LR21:
       r_field = e_lrsel;
       goto do_basic_type_3;
-    case R_HPPA_ABS_CALL_RR14: /*      RR(Symbol, Addend)      14      */
+    case R_HPPA_ABS_CALL_RR14:
       r_field = e_rrsel;
       goto do_basic_type_3;
-    case R_HPPA_ABS_CALL_RR17: /*      RR(Symbol, Addend)      17      */
+    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);
       break;
 
-    case R_HPPA_PCREL_CALL_11: /*      Symbol - PC + Addend    11      */
+    /* 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: /*      Symbol - PC + Addend    14      */
+    case R_HPPA_PCREL_CALL_14:
       r_field = e_fsel;
       goto do_basic_type_4;
-    case R_HPPA_PCREL_CALL_17: /*      Symbol - PC + Addend    17      */
+    case R_HPPA_PCREL_CALL_17:
       r_field = e_fsel;
       goto do_basic_type_4;
-    case R_HPPA_PCREL_CALL_L21:/*      L (Symbol - PC, Addend) 21      */
+    case R_HPPA_PCREL_CALL_L21:
       r_field = e_lsel;
       goto do_basic_type_4;
-    case R_HPPA_PCREL_CALL_R11:/*      R (Symbol - PC, Addend) 11      */
+    case R_HPPA_PCREL_CALL_R11:
       r_field = e_rsel;
       goto do_basic_type_4;
-    case R_HPPA_PCREL_CALL_R14:/*      R (Symbol - PC, Addend) 14      */
+    case R_HPPA_PCREL_CALL_R14:
       r_field = e_rsel;
       goto do_basic_type_4;
-    case R_HPPA_PCREL_CALL_R17:/*      R (Symbol - PC, Addend) 17      */
+    case R_HPPA_PCREL_CALL_R17:
       r_field = e_rsel;
       goto do_basic_type_4;
-    case R_HPPA_PCREL_CALL_LS21:       /*      LS(Symbol - PC, Addend) 21      */
+    case R_HPPA_PCREL_CALL_LS21:
       r_field = e_lssel;
       goto do_basic_type_4;
-    case R_HPPA_PCREL_CALL_RS11:       /*      RS(Symbol - PC, Addend) 11      */
+    case R_HPPA_PCREL_CALL_RS11:
       r_field = e_rssel;
       goto do_basic_type_4;
-    case R_HPPA_PCREL_CALL_RS14:       /*      RS(Symbol - PC, Addend) 14      */
+    case R_HPPA_PCREL_CALL_RS14:
       r_field = e_rssel;
       goto do_basic_type_4;
-    case R_HPPA_PCREL_CALL_RS17:       /*      RS(Symbol - PC, Addend) 17      */
+    case R_HPPA_PCREL_CALL_RS17:
       r_field = e_rssel;
       goto do_basic_type_4;
-    case R_HPPA_PCREL_CALL_LD21:       /*      LD(Symbol - PC, Addend) 21      */
+    case R_HPPA_PCREL_CALL_LD21:
       r_field = e_ldsel;
       goto do_basic_type_4;
-    case R_HPPA_PCREL_CALL_RD11:       /*      RD(Symbol - PC, Addend) 11      */
+    case R_HPPA_PCREL_CALL_RD11:
       r_field = e_rdsel;
       goto do_basic_type_4;
-    case R_HPPA_PCREL_CALL_RD14:       /*      RD(Symbol - PC, Addend) 14      */
+    case R_HPPA_PCREL_CALL_RD14:
       r_field = e_rdsel;
       goto do_basic_type_4;
-    case R_HPPA_PCREL_CALL_RD17:       /*      RD(Symbol - PC, Addend) 17      */
+    case R_HPPA_PCREL_CALL_RD17:
       r_field = e_rdsel;
       goto do_basic_type_4;
-    case R_HPPA_PCREL_CALL_LR21:       /*      LR(Symbol - PC, Addend) 21      */
+    case R_HPPA_PCREL_CALL_LR21:
       r_field = e_lrsel;
       goto do_basic_type_4;
-    case R_HPPA_PCREL_CALL_RR14:       /*      RR(Symbol - PC, Addend) 14      */
+    case R_HPPA_PCREL_CALL_RR14:
       r_field = e_rrsel;
       goto do_basic_type_4;
-    case R_HPPA_PCREL_CALL_RR17:       /*      RR(Symbol - PC, Addend) 17      *//* #69 */
+    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);
       break;
 
+    /* Handle all the basic type 5 relocations.  */  
     case R_HPPA_PLABEL_32:
     case R_HPPA_PLABEL_11:
     case R_HPPA_PLABEL_14:
@@ -1488,69 +1483,98 @@ DEFUN (hppa_elf_reloc, (abfd, reloc_entry, symbol_in, data, input_section, outpu
                                     r_type, 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);
-      return (bfd_reloc_ok);
-
-    case R_HPPA_PUSH_CONST:    /*      push Addend                     -   -   */
-    case R_HPPA_PUSH_PC:       /*      push PC + Addend                -   -   */
-    case R_HPPA_PUSH_SYM:      /*      push Symbol + Addend            -   -   */
-    case R_HPPA_PUSH_GOTOFF:   /*      push Symbol - GOT + Addend      -   -   */
-    case R_HPPA_PUSH_ABS_CALL: /*      push Symbol + Addend            -   -   */
-    case R_HPPA_PUSH_PCREL_CALL:       /*      push Symbol - PC + Addend       -   -   */
-    case R_HPPA_PUSH_PLABEL:   /*      [TBD]                           -   -   */
-    case R_HPPA_MAX:           /*      pop A and B, push max(B,A)      -   -   */
-    case R_HPPA_MIN:           /*      pop A and B, push min(B,A)      -   -   */
-    case R_HPPA_ADD:           /*      pop A and B, push B + A         -   -   */
-    case R_HPPA_SUB:           /*      pop A and B, push B - A         -   -   */
-    case R_HPPA_MULT:          /*      pop A and B, push B * A         -   -   */
-    case R_HPPA_DIV:           /*      pop A and B, push B / A         -   -   */
-    case R_HPPA_MOD:           /*      pop A and B, push B % A         -   -   */
-    case R_HPPA_AND:           /*      pop A and B, push B & A         -   -   */
-    case R_HPPA_OR:            /*      pop A and B, push B | A         -   -   */
-    case R_HPPA_XOR:           /*      pop A and B, push B ^ A         -   -   */
-    case R_HPPA_NOT:           /*      pop A, push ~A                  -   -   */
-    case R_HPPA_LSHIFT:        /*      pop A, push A << Addend         -   -   */
-    case R_HPPA_ARITH_RSHIFT:  /*      pop A, push A >> Addend         -   -   */
-    case R_HPPA_LOGIC_RSHIFT:  /*      pop A, push A >> Addend         -   -   */
-    case R_HPPA_EXPR_F:        /*      pop A, push A + Addend          L   -   */
-    case R_HPPA_EXPR_L:        /*      pop A, push L(A,Addend)         L   -   */
-    case R_HPPA_EXPR_R:        /*      pop A, push R(A,Addend)         R   -   */
-    case R_HPPA_EXPR_LS:       /*      pop A, push LS(A,Addend)        LS  -   */
-    case R_HPPA_EXPR_RS:       /*      pop A, push RS(A,Addend)        RS  -   */
-    case R_HPPA_EXPR_LD:       /*      pop A, push LD(A,Addend)        LD  -   */
-    case R_HPPA_EXPR_RD:       /*      pop A, push RD(A,Addend)        RD  -   */
-    case R_HPPA_EXPR_LR:       /*      pop A, push LR(A,Addend)        LR  -   */
-    case R_HPPA_EXPR_RR:       /*      pop A, push RR(A,Addend)        RR  -   */
-
-    case R_HPPA_EXPR_32:       /*      pop                             -   32  */
-    case R_HPPA_EXPR_21:       /*      pop                             -   21  */
-    case R_HPPA_EXPR_11:       /*      pop                             -   11  */
-    case R_HPPA_EXPR_14:       /*      pop                             -   14  */
-    case R_HPPA_EXPR_17:       /*      pop                             -   17  */
-    case R_HPPA_EXPR_12:       /*      pop                             -   12  */
+      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);
+      return bfd_reloc_notsupported;
+
+    /* This is a linker internal relocation.  */
     case R_HPPA_STUB_CALL_17:
-      /* yes, a branch to a long branch stub. Change instruction to a BLE */
-      /* or BLE,N */
-      if ( insn & 2 )
+      /* 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.
+        The original instruction stream is
+
+           bl <foo>,r          ; call foo using register r as
+                               ; the return pointer
+           XXX                 ; delay slot instruction
+
+        The new instruction stream will be:
+
+           XXX                 ; delay slot instruction
+           ble <foo_stub>      ; call the long call stub for foo
+                               ; using r31 as the return pointer
+
+        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.
+
+        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).  */
+        
+      if (insn & 2)
        insn = BLE_N_XXX_0_0;
       else
        {
          unsigned long old_delay_slot_insn = bfd_get_32 (abfd, hit_data + 4);
          unsigned rtn_reg = (insn & 0x03e00000) >> 21;
 
-         if (get_opcode(old_delay_slot_insn) == LDO)
+         if (get_opcode (old_delay_slot_insn) == LDO)
            {
              unsigned ldo_src_reg = (old_delay_slot_insn & 0x03e00000) >> 21;
              unsigned ldo_target_reg = (old_delay_slot_insn & 0x001f0000) >> 16;
 
+             /* 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.  */
              if (ldo_target_reg == rtn_reg)
                {
                  unsigned long new_delay_slot_insn = old_delay_slot_insn;
@@ -1558,31 +1582,80 @@ DEFUN (hppa_elf_reloc, (abfd, reloc_entry, symbol_in, data, input_section, outpu
                  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);
+                 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);
+                 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.  */
+                 arelent * next_reloc_entry = reloc_entry+1;
+
+                 if (next_reloc_entry->address == reloc_entry->address + 4)
+                   next_reloc_entry->address -= 4;
+
+                 insn = old_delay_slot_insn;
+                 bfd_put_32 (abfd, insn, hit_data);
+                 insn = BLE_N_XXX_0_0;
+                 bfd_put_32 (abfd, insn, hit_data + 4);
+                 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, r_field, r_pcrel);
+                 bfd_put_32 (abfd, insn, hit_data + 4);
+                 return bfd_reloc_ok;
                }
            }
-         insn = BLE_XXX_0_0;
+         else
+           {
+             /* Check to see if the delay slot instruction has a
+                relocation.  If so, we need to change its address
+                field  because the instruction it relocates is going
+                to be moved.  */
+             arelent * next_reloc_entry = reloc_entry+1;
+
+             if (next_reloc_entry->address == reloc_entry->address + 4)
+               next_reloc_entry->address -= 4;
+
+             insn = old_delay_slot_insn;
+             bfd_put_32 (abfd, insn, hit_data);
+             insn = BLE_N_XXX_0_0;
+             bfd_put_32 (abfd, insn, hit_data + 4);
+             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,
+                                            r_field, r_pcrel);
+             bfd_put_32 (abfd, insn, hit_data + 4);
+             return bfd_reloc_ok;
+           }
        }
-      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);
       break;
       
     default:
       fprintf (stderr, "Relocation problem : ");
       fprintf (stderr, "Unrecognized reloc type %d, in module %s\n",
               r_type, abfd->filename);
-      return (bfd_reloc_dangerous);
+      return bfd_reloc_dangerous;
     }
 
-  /* update the instruction word */
+  /* Update the instruction word.  */
   bfd_put_32 (abfd, insn, hit_data);
-
   return (bfd_reloc_ok);
-
 }
 
 static const reloc_howto_type *
@@ -2003,15 +2076,18 @@ type_of_mismatch (caller_bits, callee_bits, type)
 #define EXTRACT_ARBITS(ar,which)       ((ar) >> (8-(which*2))) & 3
 
 #define NEW_INSTRUCTION(entry,insn)    \
+{ \
   *((entry)->stub_desc->stub_secp)++ = (insn); \
   (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);
+                      (entry)->stub_desc->real_size);  \
+}
 
 #define CURRENT_STUB_OFFSET(entry)     \
-  ((int)(entry)->stub_desc->stub_secp - (int)(entry)->stub_desc->stub_contents - 4)
+  ((int)(entry)->stub_desc->stub_secp \
+   - (int)(entry)->stub_desc->stub_contents - 4)
 
 static boolean stubs_finished = false;
 
@@ -2198,11 +2274,14 @@ elf32_hppa_reloc_type type;
 }
 
 asymbol *
-hppa_elf_build_arg_reloc_stub (abfd, output_bfd, reloc_entry, stub_types)
+hppa_elf_build_arg_reloc_stub (abfd, output_bfd, reloc_entry,
+                              stub_types, rtn_adjust, data)
      bfd *abfd;
      bfd *output_bfd;
      arelent *reloc_entry;
      int stub_types[5];
+     int rtn_adjust;
+     unsigned *data;
 {
   asection *stub_sec = bfd_get_section_by_name (abfd, ".hppa_linker_stubs");
   elf32_hppa_stub_description *stub_desc = find_stubs (abfd, stub_sec);
@@ -2212,27 +2291,45 @@ hppa_elf_build_arg_reloc_stub (abfd, output_bfd, reloc_entry, stub_types)
   int i;
   char stub_sym_name[128];
   elf32_hppa_stub_name_list *stub_entry;
+  unsigned insn = data[0];
+
+  /* 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
+     pointer, then the branch instructions should not be rearranged
+     (rtn_adjust is false).  */
+  if (insn & 2 || insn == 0)
+    rtn_adjust = false;
+  else
+    {
+      unsigned delay_insn = data[1];
 
+      if (get_opcode (delay_insn) == LDO
+         && (((insn & 0x03e00000) >> 21) == ((delay_insn & 0x001f0000) >> 16)))
+       rtn_adjust = false;
+    }
+
+  /* See if the proper stub entry has already been made.  */
   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);
+                            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);
     }
 
-  /* make sure we have a stub descriptor structure */
-
+  /* Make the stub if we did not find one already.  */
   if (!stub_desc)
     stub_desc = new_stub (abfd, stub_sec);
 
-  /* allocate some space to write the stub */
-
+  /* Allocate space to write the stub.
+     FIXME.  Why using realloc?!?  */
   if (!stub_desc->stub_contents)
     {
       stub_desc->allocated_size = STUB_BUFFER_INCR;
@@ -2243,55 +2340,65 @@ hppa_elf_build_arg_reloc_stub (abfd, output_bfd, reloc_entry, stub_types)
       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);
-      if (stub_desc->stub_contents == NULL)
-       abort ();
     }
 
-  stub_desc->stub_secp = (int *) (stub_desc->stub_contents + stub_desc->real_size);
+  stub_desc->stub_secp
+    = (int *) (stub_desc->stub_contents + stub_desc->real_size);
 
   sprintf (stub_sym_name,
-          "_stub_%s_%02d_%02d_%02d_%02d_%02d",
+          "_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]);
-  stub_entry = find_stub_by_name(abfd, stub_sec, stub_sym_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);
 
   if (stub_entry)
     {
       stub_sym = stub_entry->sym;
-      /* redirect the original relocation from the old symbol (a function) */
-      /* to the stub (the stub calls the function).    */
-      /* XXX do we need to change the relocation type? */
-      reloc_entry->sym_ptr_ptr = (asymbol **) bfd_zalloc (stub_desc->this_bfd, sizeof (asymbol *));
+      /* 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[0] = stub_sym;
+      if (reloc_entry->howto->type != R_HPPA_PLABEL_32
+         && (get_opcode(insn) == BLE || get_opcode (insn) == BE))
+       reloc_entry->howto = bfd_reloc_type_lookup (abfd, R_HPPA_STUB_CALL_17);
     }
   else
     {
-      /* Stub does not already exist.  Create a new stub.  */
-      /* Create a new symbol to point to this stub */ 
+      /* Create a new symbol to point to this 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->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);
+      stub_entry = add_stub_by_name (abfd, stub_sec, stub_sym);
 
-      /* redirect the original relocation from the old symbol (a function) */
-      /* to the stub (the stub calls the function).    */
-      /* XXX do we need to change the relocation type? */
-      reloc_entry->sym_ptr_ptr = (asymbol **) bfd_zalloc (stub_desc->this_bfd, sizeof (asymbol *));
+      /* 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 *));
       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))
+       reloc_entry->howto = bfd_reloc_type_lookup (abfd, R_HPPA_STUB_CALL_17);
 
-      /* generate the beginning common section for all stubs */
+      /* Generate common code for all stubs.  */
 
+      NEW_INSTRUCTION (stub_entry, LDSID_31_1);
+      NEW_INSTRUCTION (stub_entry, MTSP_1_SR0);
       NEW_INSTRUCTION (stub_entry, ADDI_8_SP);
 
-      /* generate the code to move the arguments around */
+      /* Generate code to move the arguments around.  */
       for (i = ARG0; i < ARG3; i++)
        {
          if (stub_types[i] != NO_ARG_RELOC)
            {
-             /* A stub is needed */
              switch (stub_types[i])
                {
                case R_TO_FR:
@@ -2320,12 +2427,12 @@ hppa_elf_build_arg_reloc_stub (abfd, output_bfd, reloc_entry, stub_types)
                  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);
+                     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);
+                     AR_WARN (stub_types[i],i);
                      break;
                    }
                  continue;
@@ -2334,12 +2441,12 @@ hppa_elf_build_arg_reloc_stub (abfd, output_bfd, reloc_entry, stub_types)
                  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);
+                     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);
+                     AR_WARN (stub_types[i],i);
                      break;
                    }
                  continue;
@@ -2370,12 +2477,12 @@ hppa_elf_build_arg_reloc_stub (abfd, output_bfd, reloc_entry, stub_types)
                  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);
+                     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);
+                     AR_WARN (stub_types[i],i);
                      break;
                    }
                  continue;
@@ -2384,12 +2491,12 @@ hppa_elf_build_arg_reloc_stub (abfd, output_bfd, reloc_entry, stub_types)
                  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);
+                     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);
+                     AR_WARN (stub_types[i],i);
                      break;
                    }
                  continue;
@@ -2398,37 +2505,40 @@ hppa_elf_build_arg_reloc_stub (abfd, output_bfd, reloc_entry, stub_types)
            }
        }
 
-      NEW_INSTRUCTION (stub_entry, ADDI_M8_SP);
+      NEW_INSTRUCTION (stub_entry, ADDI_M8_SP_SP);
+
+      /* Adjust the return address if necessary.  */
+      if (rtn_adjust)
+       {
+         NEW_INSTRUCTION (stub_entry, ADDI_M4_31_RP);
+       }
 
-      /* generate the branch to the target routine */
-      NEW_INSTRUCTION (stub_entry, STW_RP_M8SP);       /* First, save the return address */
+      /* Save the return address.  */
+      NEW_INSTRUCTION (stub_entry, STW_RP_M8SP);
 
-      /* Branch to the target function. */
-      /* (Make it a long call, so we do not */
-         /* have to worry about generating a */
-         /* long call stub.)   */
-      NEW_INSTRUCTION(stub_entry, LDIL_XXX_31);
+      /* Long branch to the target function.  */
+      NEW_INSTRUCTION (stub_entry, LDIL_XXX_31);
       hppa_elf_stub_reloc (stub_entry->stub_desc,
-                          abfd,        /* the output bfd */
-                          target_sym,  /* the target symbol */
-                          CURRENT_STUB_OFFSET(stub_entry),     /* offset in stub buffer */
+                          abfd,
+                          target_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,        /* the output bfd */
-                          target_sym,  /* the target symbol */
-                          CURRENT_STUB_OFFSET(stub_entry),     /* offset in stub buffer */
+                          abfd,
+                          target_sym,
+                          CURRENT_STUB_OFFSET (stub_entry),
                           R_HPPA_ABS_CALL_R17);
-      NEW_INSTRUCTION(stub_entry,COPY_31_2);
-      
-      /* generate the code to move the return value around */
+      NEW_INSTRUCTION (stub_entry, COPY_31_2);
       
-      NEW_INSTRUCTION (stub_entry, LDW_M8SP_RP);       /* restore return address */
+
+      /* 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)
        {
-         /* A stub is needed */
          switch (stub_types[i])
            {
            case R_TO_FR:
@@ -2442,10 +2552,6 @@ hppa_elf_build_arg_reloc_stub (abfd, output_bfd, reloc_entry, stub_types)
              break;
            }
        }
-      
-      /* generate the ending common section for all stubs */
-      
-      /* XXX: can we assume this is a save return? */
       NEW_INSTRUCTION (stub_entry, BV_N_0_RP);
     }
 
@@ -2587,45 +2693,49 @@ hppa_elf_build_long_branch_stub (abfd, output_bfd, reloc_entry, symbol, data)
   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);
+                            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 so it is not accessible from */
-      /* here.) */
 
+      /* 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 (stub_sec)->this_hdr;
-
+       
+       /* 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;
-       /* contents already set by elf_set_section_contents */
-
+       
+       /* Set appropriate flags for sections with relocations.  */
        if (stub_sec->flags & SEC_RELOC)
          {
-           /* emit a reloc section, and thus strtab and symtab... */
            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;
-
-           /* orelocation has the data, reloc_count has the count... */
+           
            if (use_rela_p)
              {
                rela_hdr->sh_type = SHT_RELA;
                rela_hdr->sh_entsize = sizeof (Elf32_External_Rela);
              }
            else
-             /* REL relocations */
              {
                rela_hdr->sh_type = SHT_REL;
                rela_hdr->sh_entsize = sizeof (Elf32_External_Rel);
@@ -2636,30 +2746,30 @@ hppa_elf_build_long_branch_stub (abfd, output_bfd, reloc_entry, symbol, data)
            rela_hdr->sh_addralign = 0;
            rela_hdr->size = 0;
          }
+
        if (stub_sec->flags & SEC_ALLOC)
          {
            this_hdr->sh_flags |= SHF_ALLOC;
-           if (stub_sec->flags & SEC_LOAD)
-             {
-               /* @@ Do something with sh_type? */
-             }
+           /* FIXME.  If SEC_LOAD is true should we do something with
+              with sh_type?  */
          }
+
        if (!(stub_sec->flags & SEC_READONLY))
          this_hdr->sh_flags |= SHF_WRITE;
-
+       
        if (stub_sec->flags & SEC_CODE)
          this_hdr->sh_flags |= SHF_EXECINSTR;
       }
-
+      
       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 some space to write the stub */
-
+  
+  /* 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;
@@ -2669,121 +2779,166 @@ hppa_elf_build_long_branch_stub (abfd, output_bfd, reloc_entry, symbol, data)
     {
       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->allocated_size);
     }
-
-  stub_desc->stub_secp = (int *) (stub_desc->stub_contents + stub_desc->real_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;
+      }
+  }
+  
   sprintf (stub_sym_name,
-          "_lb_stub_%s", reloc_entry->sym_ptr_ptr[0]->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;
-      /* redirect the original relocation from the old symbol (a function) */
-      /* to the stub (the stub calls the function).    */
-      /* XXX do we need to change the relocation type? */
-      reloc_entry->sym_ptr_ptr = (asymbol **) bfd_zalloc (stub_desc->this_bfd, sizeof (asymbol *));
+
+      /* 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
     {
-      /* Stub does not already exist.  Create a new stub.  */
-      /* create a symbol to point to this stub */
+      /* 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->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);
+      stub_entry = add_stub_by_name (abfd, stub_sec, stub_sym);
+      
+      /* Change symbol associated with the original relocation to point
+        to the stub.
 
-      /* redirect the original relocation from the old symbol (a function) */
-      /* to the stub (the stub calls the function).    */
-      /* XXX do we need to change the relocation type? */
-      reloc_entry->sym_ptr_ptr = (asymbol **) bfd_zalloc (stub_desc->this_bfd, sizeof (asymbol *));
+        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 */
-
-      /* A millicode call? */
-      /* If so, the return address comes in on r31 rather than r2 (rp) so a    */      
-      /* slightly different code sequence is needed.   */
-      if ( ((*data & 0x03e00000) >> 21) == 31 )
-       milli = true;
-
-      if ( strcmp(symbol->name,"$$dyncall") == 0 )
-       dyncall = true;
-
+      
+      /* Build the stub.  */
+      
       /* 1. initialization for the call. */
-
-      NEW_INSTRUCTION(stub_entry, LDSID_31_1);
-      NEW_INSTRUCTION(stub_entry, MTSP_1_SR0);
-
-      if ( !dyncall )
+      NEW_INSTRUCTION (stub_entry, LDSID_31_1);
+      NEW_INSTRUCTION (stub_entry, MTSP_1_SR0);
+      
+      if (!dyncall)
        {
-         if ( !milli )
+         if (!milli)
            {
-             NEW_INSTRUCTION(stub_entry, COPY_31_2);
+             if (rtn_adjust)
+               {
+                 NEW_INSTRUCTION (stub_entry, ADDI_M4_31_RP);
+               }
+             else
+               {
+                 NEW_INSTRUCTION (stub_entry, COPY_31_2);
+               }
            }
          else
            {
-             NEW_INSTRUCTION(stub_entry, COPY_31_1);
+             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);
+         
+         NEW_INSTRUCTION (stub_entry, LDIL_XXX_31);
          hppa_elf_stub_reloc (stub_desc,
-                              abfd,    /* the output bfd */
-                              target_sym,      /* the target symbol */
-                              CURRENT_STUB_OFFSET(stub_entry), /* offset in stub buffer */
+                              abfd,
+                              target_sym,
+                              CURRENT_STUB_OFFSET (stub_entry),
                               R_HPPA_L21);
          
          /* 2. Make the call. */
-
-         if ( !milli )
+         if (!milli)
            {
-             NEW_INSTRUCTION(stub_entry,BE_N_XXX_0_31);
+             NEW_INSTRUCTION (stub_entry, BE_N_XXX_0_31);
              hppa_elf_stub_reloc (stub_desc,
-                                  abfd,        /* the output bfd */
-                                  target_sym,  /* the target symbol */
-                                  CURRENT_STUB_OFFSET(stub_entry),     /* offset in stub buffer */
+                                  abfd,
+                                  target_sym,
+                                  CURRENT_STUB_OFFSET (stub_entry),
                                   R_HPPA_ABS_CALL_R17);
            }
          else
            {
-             NEW_INSTRUCTION(stub_entry,BE_XXX_0_31);
+             NEW_INSTRUCTION (stub_entry, BE_XXX_0_31);
              hppa_elf_stub_reloc (stub_desc,
-                                  abfd,        /* the output bfd */
-                                  target_sym,  /* the target symbol */
-                                  CURRENT_STUB_OFFSET(stub_entry),     /* offset in stub buffer */
+                                  abfd,
+                                  target_sym,
+                                  CURRENT_STUB_OFFSET (stub_entry),
                                   R_HPPA_ABS_CALL_R17);
-             NEW_INSTRUCTION(stub_entry, COPY_1_31);
+             NEW_INSTRUCTION (stub_entry, COPY_1_31);
            }
-         /* 3. Branch back to the original location.           */
-         /*    (for non-millicode calls, accomplished with the COPY_31_2 instruction)  */
-         /*    (for millicode calls, return location is already in r2) */
        }
       else
        {
-         NEW_INSTRUCTION(stub_entry, LDIL_XXX_31);
+         /* 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,    /* the output bfd */
-                              target_sym,      /* the target symbol */
-                              CURRENT_STUB_OFFSET(stub_entry), /* offset in stub buffer */
+                              abfd,
+                              target_sym,
+                              CURRENT_STUB_OFFSET (stub_entry),
                               R_HPPA_L21);
-
-         NEW_INSTRUCTION(stub_entry,BE_N_XXX_0_31);
+         
+         NEW_INSTRUCTION (stub_entry, BE_N_XXX_0_31);
          hppa_elf_stub_reloc (stub_desc,
-                              abfd,    /* the output bfd */
-                              target_sym,      /* the target symbol */
-                              CURRENT_STUB_OFFSET(stub_entry), /* offset in stub buffer */
+                              abfd,
+                              target_sym,
+                              CURRENT_STUB_OFFSET (stub_entry),
                               R_HPPA_ABS_CALL_R17);
        }
     }
-
   return stub_sym;
 }
 
@@ -2819,86 +2974,11 @@ hppa_elf_long_branch_needed_p (abfd, asec, reloc_entry, symbol, insn)
   return 0;
 }
 
-asymbol *
-hppa_elf_stub_check (abfd, output_bfd, input_section, reloc_entry, symbol, hit_data)
-     bfd *abfd;
-     bfd *output_bfd;
-     asection *input_section;
-     arelent *reloc_entry;
-     asymbol *symbol;
-     bfd_byte *hit_data;
-{
-  int stub_types[5];
-
-  switch (reloc_entry->howto->type)
-    {
-    case R_HPPA_ABS_CALL_11:   /*      Symbol + Addend         11      */
-    case R_HPPA_ABS_CALL_14:   /*      Symbol + Addend         14      */
-    case R_HPPA_ABS_CALL_17:   /*      Symbol + Addend         17      */
-    case R_HPPA_ABS_CALL_L21:  /*      L (Symbol, Addend)      21      */
-    case R_HPPA_ABS_CALL_R11:  /*      R (Symbol, Addend)      11      */
-    case R_HPPA_ABS_CALL_R14:  /*      R (Symbol, Addend)      14      */
-    case R_HPPA_ABS_CALL_R17:  /*      R (Symbol, Addend)      17      */
-    case R_HPPA_ABS_CALL_LS21: /*      LS(Symbol, Addend)      21      */
-    case R_HPPA_ABS_CALL_RS11: /*      RS(Symbol, Addend)      11      */
-    case R_HPPA_ABS_CALL_RS14: /*      RS(Symbol, Addend)      14      */
-    case R_HPPA_ABS_CALL_RS17: /*      RS(Symbol, Addend)      17      */
-    case R_HPPA_ABS_CALL_LD21: /*      LD(Symbol, Addend)      21      */
-    case R_HPPA_ABS_CALL_RD11: /*      RD(Symbol, Addend)      11      */
-    case R_HPPA_ABS_CALL_RD14: /*      RD(Symbol, Addend)      14      */
-    case R_HPPA_ABS_CALL_RD17: /*      RD(Symbol, Addend)      17      */
-    case R_HPPA_ABS_CALL_LR21: /*      LR(Symbol, Addend)      21      */
-    case R_HPPA_ABS_CALL_RR14: /*      RR(Symbol, Addend)      14      */
-    case R_HPPA_ABS_CALL_RR17: /*      RR(Symbol, Addend)      17      */
-
-    case R_HPPA_PCREL_CALL_11: /*      Symbol - PC + Addend    11      */
-    case R_HPPA_PCREL_CALL_14: /*      Symbol - PC + Addend    14      */
-    case R_HPPA_PCREL_CALL_17: /*      Symbol - PC + Addend    17      */
-    case R_HPPA_PCREL_CALL_12: /*      Symbol - PC + Addend    12      */
-    case R_HPPA_PCREL_CALL_L21:        /*      L (Symbol - PC, Addend) 21      */
-    case R_HPPA_PCREL_CALL_R11:        /*      R (Symbol - PC, Addend) 11      */
-    case R_HPPA_PCREL_CALL_R14:        /*      R (Symbol - PC, Addend) 14      */
-    case R_HPPA_PCREL_CALL_R17:        /*      R (Symbol - PC, Addend) 17      */
-    case R_HPPA_PCREL_CALL_LS21: /*    LS(Symbol - PC, Addend) 21      */
-    case R_HPPA_PCREL_CALL_RS11: /*    RS(Symbol - PC, Addend) 11      */
-    case R_HPPA_PCREL_CALL_RS14: /*    RS(Symbol - PC, Addend) 14      */
-    case R_HPPA_PCREL_CALL_RS17: /*    RS(Symbol - PC, Addend) 17      */
-    case R_HPPA_PCREL_CALL_LD21: /*    LD(Symbol - PC, Addend) 21      */
-    case R_HPPA_PCREL_CALL_RD11: /*    RD(Symbol - PC, Addend) 11      */
-    case R_HPPA_PCREL_CALL_RD14: /*    RD(Symbol - PC, Addend) 14      */
-    case R_HPPA_PCREL_CALL_RD17: /*    RD(Symbol - PC, Addend) 17      */
-    case R_HPPA_PCREL_CALL_LR21: /*    LR(Symbol - PC, Addend) 21      */
-    case R_HPPA_PCREL_CALL_RR14: /*    RR(Symbol - PC, Addend) 14      */
-    case R_HPPA_PCREL_CALL_RR17: /*    RR(Symbol - PC, Addend) 17      */
-      {
-       symext_entryS caller_ar = (symext_entryS) HPPA_R_ARG_RELOC (reloc_entry->addend);
-       if (hppa_elf_arg_reloc_needed_p (abfd, reloc_entry, stub_types, caller_ar))
-         {
-           /* generate a stub */
-           return hppa_elf_build_arg_reloc_stub (abfd, output_bfd,
-                                                 reloc_entry, stub_types);
-         }
-       if (hppa_elf_long_branch_needed_p (abfd, input_section, reloc_entry,
-                                          symbol, *(unsigned *)hit_data))
-         {
-           /* generate a stub */
-           return hppa_elf_build_long_branch_stub (abfd, output_bfd,
-                                                   reloc_entry, symbol,
-                                                   (unsigned *)hit_data);
-         }
-      }
-      break;
-
-    default:
-      break;
-    }
-  return reloc_entry->sym_ptr_ptr[0];
-}
-
 #define STUB_SYM_BUFFER_INC    5
 
 asymbol *
-hppa_look_for_stubs_in_section (stub_bfd, abfd, output_bfd, asec, syms, new_sym_cnt)
+hppa_look_for_stubs_in_section (stub_bfd, abfd, output_bfd, asec,
+                               syms, new_sym_cnt)
      bfd *stub_bfd;
      bfd *abfd;
      bfd *output_bfd;
@@ -2915,152 +2995,165 @@ hppa_look_for_stubs_in_section (stub_bfd, abfd, output_bfd, asec, syms, new_sym_
   /* 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. */
+     bfd_canonicalize_reloc() to straighten this out for us . */
 
-  /* if ( asec->orelocation || asec->relocation ) { */
   if (asec->reloc_count > 0)
     {
-      arelent **reloc_vector = (arelent **) alloca (asec->reloc_count * (sizeof (arelent *) + 1));
+      arelent **reloc_vector
+       = (arelent **) alloca (asec->reloc_count * (sizeof (arelent *) + 1));
 
       bfd_canonicalize_reloc (abfd, asec, reloc_vector, syms);
       for (i = 0; i < asec->reloc_count; i++)
        {
-#if 0
-         arelent *rle;
-
-         if ( asec->orelocation )
-           rle = asec->orelocation[i];
-         else
-           rle = asec->relocation+i;
-#endif
-
          arelent *rle = reloc_vector[i];
 
          switch (rle->howto->type)
            {
-           case R_HPPA_ABS_CALL_11:    /*      Symbol + Addend         11 */
-           case R_HPPA_ABS_CALL_14:    /*      Symbol + Addend         14 */
-           case R_HPPA_ABS_CALL_17:    /*      Symbol + Addend         17 */
-           case R_HPPA_ABS_CALL_L21:   /*      L (Symbol, Addend)      21 */
-           case R_HPPA_ABS_CALL_R11:   /*      R (Symbol, Addend)      11 */
-           case R_HPPA_ABS_CALL_R14:   /*      R (Symbol, Addend)      14 */
-           case R_HPPA_ABS_CALL_R17:   /*      R (Symbol, Addend)      17 */
-           case R_HPPA_ABS_CALL_LS21:  /*      LS(Symbol, Addend)      21 */
-           case R_HPPA_ABS_CALL_RS11:  /*      RS(Symbol, Addend)      11 */
-           case R_HPPA_ABS_CALL_RS14:  /*      RS(Symbol, Addend)      14 */
-           case R_HPPA_ABS_CALL_RS17:  /*      RS(Symbol, Addend)      17 */
-           case R_HPPA_ABS_CALL_LD21:  /*      LD(Symbol, Addend)      21 */
-           case R_HPPA_ABS_CALL_RD11:  /*      RD(Symbol, Addend)      11 */
-           case R_HPPA_ABS_CALL_RD14:  /*      RD(Symbol, Addend)      14 */
-           case R_HPPA_ABS_CALL_RD17:  /*      RD(Symbol, Addend)      17 */
-           case R_HPPA_ABS_CALL_LR21:  /*      LR(Symbol, Addend)      21 */
-           case R_HPPA_ABS_CALL_RR14:  /*      RR(Symbol, Addend)      14 */
-           case R_HPPA_ABS_CALL_RR17:  /*      RR(Symbol, Addend)      17 */
-
-           case R_HPPA_PCREL_CALL_11:  /*      Symbol - PC + Addend    11 */
-           case R_HPPA_PCREL_CALL_14:  /*      Symbol - PC + Addend    14 */
-           case R_HPPA_PCREL_CALL_17:  /*      Symbol - PC + Addend    17 */
-           case R_HPPA_PCREL_CALL_12:  /*      Symbol - PC + Addend    12 */
-           case R_HPPA_PCREL_CALL_L21: /*      L (Symbol - PC, Addend) 21 */
-           case R_HPPA_PCREL_CALL_R11: /*      R (Symbol - PC, Addend) 11 */
-           case R_HPPA_PCREL_CALL_R14: /*      R (Symbol - PC, Addend) 14 */
-           case R_HPPA_PCREL_CALL_R17: /*      R (Symbol - PC, Addend) 17 */
-           case R_HPPA_PCREL_CALL_LS21: /*     LS(Symbol - PC, Addend) 21 */
-           case R_HPPA_PCREL_CALL_RS11: /*     RS(Symbol - PC, Addend) 11 */
-           case R_HPPA_PCREL_CALL_RS14: /*     RS(Symbol - PC, Addend) 14 */
-           case R_HPPA_PCREL_CALL_RS17: /*     RS(Symbol - PC, Addend) 17 */
-           case R_HPPA_PCREL_CALL_LD21: /*     LD(Symbol - PC, Addend) 21 */
-           case R_HPPA_PCREL_CALL_RD11: /*     RD(Symbol - PC, Addend) 11 */
-           case R_HPPA_PCREL_CALL_RD14: /*     RD(Symbol - PC, Addend) 14 */
-           case R_HPPA_PCREL_CALL_RD17: /*     RD(Symbol - PC, Addend) 17 */
-           case R_HPPA_PCREL_CALL_LR21: /*     LR(Symbol - PC, Addend) 21 */
-           case R_HPPA_PCREL_CALL_RR14: /*     RR(Symbol - PC, Addend) 14 */
-           case R_HPPA_PCREL_CALL_RR17: /*     RR(Symbol - PC, Addend) 17 */
+           case R_HPPA_ABS_CALL_11:
+           case R_HPPA_ABS_CALL_14:
+           case R_HPPA_ABS_CALL_17:
+           case R_HPPA_ABS_CALL_L21:
+           case R_HPPA_ABS_CALL_R11:
+           case R_HPPA_ABS_CALL_R14:
+           case R_HPPA_ABS_CALL_R17:
+           case R_HPPA_ABS_CALL_LS21:
+           case R_HPPA_ABS_CALL_RS11:
+           case R_HPPA_ABS_CALL_RS14:
+           case R_HPPA_ABS_CALL_RS17:
+           case R_HPPA_ABS_CALL_LD21:
+           case R_HPPA_ABS_CALL_RD11:
+           case R_HPPA_ABS_CALL_RD14:
+           case R_HPPA_ABS_CALL_RD17:
+           case R_HPPA_ABS_CALL_LR21:
+           case R_HPPA_ABS_CALL_RR14:
+           case R_HPPA_ABS_CALL_RR17:
+           case R_HPPA_PCREL_CALL_11:
+           case R_HPPA_PCREL_CALL_14:
+           case R_HPPA_PCREL_CALL_17:
+           case R_HPPA_PCREL_CALL_12:
+           case R_HPPA_PCREL_CALL_L21:
+           case R_HPPA_PCREL_CALL_R11:
+           case R_HPPA_PCREL_CALL_R14:
+           case R_HPPA_PCREL_CALL_R17:
+           case R_HPPA_PCREL_CALL_LS21:
+           case R_HPPA_PCREL_CALL_RS11:
+           case R_HPPA_PCREL_CALL_RS14:
+           case R_HPPA_PCREL_CALL_RS17:
+           case R_HPPA_PCREL_CALL_LD21:
+           case R_HPPA_PCREL_CALL_RD11:
+           case R_HPPA_PCREL_CALL_RD14:
+           case R_HPPA_PCREL_CALL_RD17:
+           case R_HPPA_PCREL_CALL_LR21:
+           case R_HPPA_PCREL_CALL_RR14:
+           case R_HPPA_PCREL_CALL_RR17:
              {
-               symext_entryS caller_ar = (symext_entryS) HPPA_R_ARG_RELOC (rle->addend);
+               symext_entryS caller_ar
+                 = (symext_entryS) HPPA_R_ARG_RELOC (rle->addend);
+               unsigned insn[2];
+
+               bfd_get_section_contents (abfd, asec, insn, rle->address,
+                                         sizeof(insn));
                if (hppa_elf_arg_reloc_needed_p (abfd, rle, stub_types,
                                                 caller_ar))
                  {
-                   /* generate a stub */
-                   /* keep track of the new symbol */
+                   /* Generate a stub and keep track of the new symbol.  */
                    asymbol *r;
 
                    if (new_cnt == new_max)
                      {
                        new_max += STUB_SYM_BUFFER_INC;
-                       new_syms = (asymbol *) realloc (new_syms, new_max * sizeof (asymbol));
+                       new_syms = (asymbol *)
+                         realloc (new_syms, new_max * sizeof (asymbol));
                      }
+
+                   /* 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);
+                                                      rle, stub_types,
+                                                      true, insn);
                    new_syms[new_cnt++] = *r;
                  }
-               /* We need to retrieve the section contents to check for
-                  plabel stubs. */
-               {
-                 unsigned insn;
 
-                 bfd_get_section_contents (abfd, asec, &insn, rle->address,
-                                           sizeof(insn));
-                 if (hppa_elf_long_branch_needed_p (abfd, asec, rle,
-                                                    rle->sym_ptr_ptr[0],
-                                                    insn))
-                   {
-                     /* generate a stub */
-                     /* keep track of the new symbol */
-                     asymbol *r;
+               /* We need to retrieve the section contents to check for
+                  long branch stubs.  */
+               if (hppa_elf_long_branch_needed_p (abfd, asec, rle,
+                                                  rle->sym_ptr_ptr[0],
+                                                  insn[0]))
+                 {
+                   /* Generate a stub and keep track of the new symbol.  */
+                   asymbol *r;
 
-                     if (new_cnt == new_max)
-                       {
-                         new_max += STUB_SYM_BUFFER_INC;
-                         new_syms = (asymbol *) realloc (new_syms, (new_max * sizeof (asymbol)));
-                       }
-                     r = hppa_elf_build_long_branch_stub (stub_bfd,
-                                                          output_bfd,
-                                                          rle,
-                                                          rle->sym_ptr_ptr[0],
-                                                          &insn);
-                     new_syms[new_cnt++] = *r;
-                   }
-               }
+                   if (new_cnt == new_max)
+                     {
+                       new_max += STUB_SYM_BUFFER_INC;
+                       new_syms = (asymbol *)
+                         realloc (new_syms, (new_max * sizeof (asymbol)));
+                     }
+                   r = hppa_elf_build_long_branch_stub (stub_bfd, output_bfd,
+                                                        rle,
+                                                        rle->sym_ptr_ptr[0],
+                                                        insn);
+                   new_syms[new_cnt++] = *r;
+                 }
              }
              break;
 
-             /* Plabels are designed to allow code pointers to be
-                passed between spaces.  These relocations correspond
-                to the P%, LP%, and RP% field selectors.  */
-
-           case R_HPPA_PLABEL_32: /*   F(Plabel(Symbol,Addend),0)      32 */
-           case R_HPPA_PLABEL_11: /*   F(Plabel(Symbol,Addend),0)      11 */
-           case R_HPPA_PLABEL_14: /*   F(Plabel(Symbol,Addend),0)      14 */
-           case R_HPPA_PLABEL_L21: /*  L(Plabel(Symbol,Addend),0)      21 */
-           case R_HPPA_PLABEL_R11: /*  R(Plabel(Symbol,Addend),0)      11 */
-           case R_HPPA_PLABEL_R14: /*  R(Plabel(Symbol,Addend),0)      14 */
-             /* We need to retrieve the section contents to check for
-                 long branch stubs.  */
+           case R_HPPA_PLABEL_32:
+           case R_HPPA_PLABEL_11:
+           case R_HPPA_PLABEL_14:
+           case R_HPPA_PLABEL_L21:
+           case R_HPPA_PLABEL_R11:
+           case R_HPPA_PLABEL_R14:
              {
                /* On a plabel relocation, assume the arguments of the
-                   caller are set up in general registers.  */
-               /* 0x155 = ARGW0=CR,ARGW1=GR,ARGW2=GR,RETVAL=GR */
+                  caller are set up in general registers.
+                  NOTE:  0x155 = ARGW0=CR,ARGW1=GR,ARGW2=GR,RETVAL=GR */
                symext_entryS caller_ar = (symext_entryS) 0x155;
+               unsigned insn[2];
+
+               bfd_get_section_contents (abfd, asec, insn, rle->address,
+                                         sizeof(insn));
 
                if (hppa_elf_arg_reloc_needed_p (abfd, rle, stub_types,
                                                 caller_ar))
                  {
-                   /* generate a plabel stub */
-                   /* keep track of the new symbol */
+                   /* Generate a plabel stub and keep track of the
+                      new symbol.  */
                    asymbol *r;
+                   int rtn_adjust;
 
                    if (new_cnt == new_max)
                      {
                        new_max += STUB_SYM_BUFFER_INC;
-                       new_syms = (asymbol *) realloc (new_syms,
-                                                       (new_max
-                                                        * sizeof (asymbol)));
+                       new_syms = (asymbol *) realloc (new_syms, new_max
+                                                       * sizeof (asymbol));
                      }
-                   r = hppa_elf_build_arg_reloc_stub (stub_bfd,
-                                                      output_bfd,
-                                                      rle,
-                                                      stub_types);
+
+                   /* Determine whether a return adjustment
+                      (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
+                     {
+                       switch (get_opcode(insn[0]))
+                         {
+                         case BLE:
+                         case BE:
+                           rtn_adjust = true;
+                           break;
+                         default:
+                           rtn_adjust = false;
+                         }
+                     }
+                   r = hppa_elf_build_arg_reloc_stub (stub_bfd, output_bfd,
+                                                      rle, stub_types,
+                                                      rtn_adjust, insn);
                    new_syms[new_cnt++] = *r;
                  }
              }
@@ -3150,7 +3243,7 @@ hppa_elf_get_section_contents (abfd, section, location, offset, count)
      be generated. */
   else if (strcmp (section->name, ".hppa_symextn") == 0)
     {
-      /* If there are no output sections, then read the contents of the 
+      /* If there are no output sections, then read the contents of the
         symbol extension section from disk.  */
       if (section->output_section == NULL
          && abfd->direction == read_direction)