From a36b6f1d05754890fe380571cff36c54fcc20065 Mon Sep 17 00:00:00 2001
From: Jeff Law <law@redhat.com>
Date: Tue, 14 Dec 1993 07:36:15 +0000
Subject: [PATCH]         * elf32-hppa.c (hppa_elf_gen_reloc_type): Handle 'T'
 field         selectors for PIC code.

        * som.c (hppa_som_gen_reloc_type): Handle 'T' field selectors.
        (som_write_fixups): Handle R_DLT_REL, R_FSEL, R_RSEL, R_LSEL
        relocations needed by PIC.
---
 bfd/ChangeLog    |  9 +++++
 bfd/elf32-hppa.c | 95 ++++++++++++++++++++++++++++++++++++++++++------
 bfd/som.c        | 46 +++++++++++++++++------
 3 files changed, 128 insertions(+), 22 deletions(-)

diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index c29f2fe72d..b045532686 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,3 +1,12 @@
+Mon Dec 13 23:34:48 1993  Jeffrey A. Law  (law@snake.cs.utah.edu)
+
+	* elf32-hppa.c (hppa_elf_gen_reloc_type): Handle 'T' field
+	selectors for PIC code.
+
+	* som.c (hppa_som_gen_reloc_type): Handle 'T' field selectors.
+	(som_write_fixups): Handle R_DLT_REL, R_FSEL, R_RSEL, R_LSEL
+	relocations needed by PIC.
+
 Tue Dec  7 15:47:51 1993  Stu Grossman  (grossman at cygnus.com)
 
 	* nlmcode.h:  Fixes to avoid compiler warnings...
diff --git a/bfd/elf32-hppa.c b/bfd/elf32-hppa.c
index b677e4db39..4f15c6280d 100644
--- a/bfd/elf32-hppa.c
+++ b/bfd/elf32-hppa.c
@@ -524,11 +524,15 @@ hppa_elf_gen_reloc_type (abfd, base_type, format, field)
 	    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:
+	      final_type = R_HPPA_DLT_R11;
+	      break;
 
+	    case e_lpsel:
+	    case e_ltsel:
 	    case e_lsel:
 	    case e_lrsel:
 	    case e_lssel:
@@ -564,10 +568,15 @@ hppa_elf_gen_reloc_type (abfd, base_type, format, field)
 	    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:
+	      final_type = R_HPPA_DLT_R14;
+	      break;
+
+	    case e_lpsel:
+	    case e_ltsel:
 
 	    case e_fsel:
 	    case e_lsel:
@@ -626,6 +635,9 @@ hppa_elf_gen_reloc_type (abfd, base_type, format, field)
 	    case e_lpsel:
 	      final_type = R_HPPA_PLABEL_L21;
 	      break;
+	    case e_ltsel:
+	      final_type = R_HPPA_PLABEL_L21;
+	      break;
 	    case e_rsel:
 	    case e_rssel:
 	    case e_rdsel:
@@ -646,6 +658,9 @@ 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;
@@ -1561,7 +1576,16 @@ hppa_elf_reloc (abfd, reloc_entry, symbol_in, data, input_section, output_bfd)
 	 jump after the call returns (GCC optimization).  */
 	 
       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, symbol_in, sym_value,
+					 r_addend, r_type, r_format,
+					 r_field, r_pcrel);
+        }
       else
 	{
 	  unsigned long old_delay_slot_insn = bfd_get_32 (abfd, hit_data + 4);
@@ -1584,16 +1608,29 @@ hppa_elf_reloc (abfd, reloc_entry, symbol_in, data, input_section, output_bfd)
 		  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);
+		  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, symbol_in, sym_value,
+					         r_addend, r_type, 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
@@ -1619,6 +1656,20 @@ hppa_elf_reloc (abfd, reloc_entry, symbol_in, data, input_section, output_bfd)
 		  return bfd_reloc_ok;
 		}
 	    }
+          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, symbol_in, sym_value,
+					     r_addend, r_type, 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
@@ -2363,7 +2414,9 @@ hppa_elf_build_arg_reloc_stub (abfd, output_bfd, reloc_entry,
 							  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))
+	  && (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
@@ -2385,7 +2438,9 @@ hppa_elf_build_arg_reloc_stub (abfd, output_bfd, reloc_entry,
 							  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))
+	  && (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.  */
@@ -2796,6 +2851,20 @@ hppa_elf_build_long_branch_stub (abfd, output_bfd, reloc_entry, symbol, data)
   
   if (strcmp (symbol->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'.  */
+
+  if ((strncmp (symbol->name, "_stub_", 6) == 0)
+      || (strncmp (symbol->name, "_lb_stub_", 9) == 0))
+    {
+      BFD_ASSERT (strcmp (symbol->section->name, ".hppa_linker_stubs") == 0);
+      rtn_adjust = false;
+    }
   
   /* Check to see if we modify the return pointer
      in the delay slot of the branch.  */
@@ -2812,6 +2881,8 @@ hppa_elf_build_long_branch_stub (abfd, output_bfd, reloc_entry, symbol, data)
 	if (get_opcode (delay_insn) == LDO
 	    && (((delay_insn & 0x001f0000) >> 16) == rtn_reg))
 	  rtn_adjust = false;
+        if (milli)
+          rtn_adjust = false;
       }
   }
   
@@ -2896,12 +2967,13 @@ hppa_elf_build_long_branch_stub (abfd, output_bfd, reloc_entry, symbol, data)
 	  /* 2. Make the call. */
 	  if (!milli)
 	    {
-	      NEW_INSTRUCTION (stub_entry, BE_N_XXX_0_31);
+	      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_2_31);
 	    }
 	  else
 	    {
@@ -2931,12 +3003,13 @@ hppa_elf_build_long_branch_stub (abfd, output_bfd, reloc_entry, symbol, data)
 			       CURRENT_STUB_OFFSET (stub_entry),
 			       R_HPPA_L21);
 	  
-	  NEW_INSTRUCTION (stub_entry, BE_N_XXX_0_31);
+	  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_2_31);
 	}
     }
   return stub_sym;
diff --git a/bfd/som.c b/bfd/som.c
index 08ef81122e..de23ef4772 100644
--- a/bfd/som.c
+++ b/bfd/som.c
@@ -1356,11 +1356,18 @@ hppa_som_gen_reloc_type (abfd, base_type, format, field)
       case e_psel:
       case e_lpsel:
       case e_rpsel:
+	final_types[0] = final_type;
+	final_types[1] = NULL;
+	final_types[2] = NULL;
+	*final_type = base_type;
+	break;
+
       case e_tsel:
       case e_ltsel:
       case e_rtsel:
-	final_types[0] = final_type;
-	final_types[1] = NULL;
+	final_types[0] = (int *) bfd_alloc_by_size_t (abfd, sizeof (int));
+	*final_types[0] = R_FSEL;
+	final_types[1] = final_type;
 	final_types[2] = NULL;
 	*final_type = base_type;
 	break;
@@ -1409,15 +1416,20 @@ hppa_som_gen_reloc_type (abfd, base_type, format, field)
       if (field == e_psel
 	  || field == e_lpsel
 	  || field == e_rpsel)
-	  {
-	    /* A PLABEL relocation that has a size of 32 bits must
-	       be a R_DATA_PLABEL.  All others are R_CODE_PLABELs.  */
-	    if (format == 32)
-	      *final_type = R_DATA_PLABEL;
-	    else
-	      *final_type = R_CODE_PLABEL;
-	  }
-      /* A relocatoin in the data space is always a full 32bits.  */
+	{
+	  /* A PLABEL relocation that has a size of 32 bits must
+	     be a R_DATA_PLABEL.  All others are R_CODE_PLABELs.  */
+	  if (format == 32)
+	    *final_type = R_DATA_PLABEL;
+	  else
+	    *final_type = R_CODE_PLABEL;
+	}
+      /* PIC stuff.  */
+      else if (field == e_tsel
+	  || field == e_ltsel
+	  || field == e_rtsel)
+	*final_type = R_DLT_REL;
+      /* A relocation in the data space is always a full 32bits.  */
       else if (format == 32)
 	*final_type = R_DATA_ONE_SYMBOL;
 
@@ -2197,6 +2209,9 @@ som_write_fixups (abfd, current_offset, total_reloc_sizep)
 		case R_S_MODE:
 		case R_D_MODE:
 		case R_R_MODE:
+		case R_FSEL:
+		case R_LSEL:
+		case R_RSEL:
 		  reloc_offset = bfd_reloc->address;
 		  break;
 
@@ -2249,6 +2264,7 @@ som_write_fixups (abfd, current_offset, total_reloc_sizep)
 		case R_DATA_ONE_SYMBOL:
 		case R_DATA_PLABEL:
 		case R_CODE_PLABEL:
+		case R_DLT_REL:
 		  /* Account for any addend.  */
 		  if (bfd_reloc->addend)
 		    p = som_reloc_addend (abfd, bfd_reloc->addend, p, 
@@ -2306,6 +2322,14 @@ som_write_fixups (abfd, current_offset, total_reloc_sizep)
 		    }
 		  break;
 
+		case R_FSEL:
+		case R_LSEL:
+		case R_RSEL:
+		  bfd_put_8 (abfd, bfd_reloc->howto->type, p);
+		  subspace_reloc_size += 1;
+		  p += 1;
+		  break;
+
 		/* Put a "R_RESERVED" relocation in the stream if
 		   we hit something we do not understand.  The linker
 		   will complain loudly if this ever happens.  */