[binutils-gdb] hppa64: Improve relocation handling for local symbols and add gc_section support

John David Anglin danglin@sourceware.org
Tue Jan 20 19:28:35 GMT 2026


https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=b2c74dcb465ccec1289dde0e1c8d299d85bb34f8

commit b2c74dcb465ccec1289dde0e1c8d299d85bb34f8
Author: John David Anglin <danglin@gcc.gnu.org>
Date:   Tue Jan 20 14:27:49 2026 -0500

    hppa64: Improve relocation handling for local symbols and add gc_section support
    
    With this patch, gcc-16 can be built and there are significant
    improvements in test results.  I spent a lot of time trying to
    fix the EH exception support.  While there are still issues with
    handling relocations in linkonce sessions, exception handling
    mostly works if pc-relative and text relative encoding is used
    in .eh_frame.  The main problems are the HP-UX dynamic linker
    relocates the text and data segements indpendently, and it does
    not support unaligned dynamic relocations.
    
    Due to a configure bug in libstdc++-v3, the lack of gc_section
    support caused many test failures, so I added the gc_section
    support form elf32-hppa.c.
    
    I also move the HP_LOAD_MAP scratchpad to the end of the .bss
    section and fixed a number of issues with the linker scripts.
    
    2026-01-20  John David Anglin  <danglin@gcc.gnu.org>
    
    bfd/ChangeLog:
    
            * elf64-hppa.c (elf64_hppa_check_relocs): Drop NEED_PLT
            from R_PARISC_LTOFF_FPTR relocations.  Revise R_PARISC_FPTR64
            relocation to use maybe_dynamic.  Add support for
            R_PARISC_GNU_VTINHERIT and R_PARISC_GNU_VTENTRY relocations.
            Add code to handle dynamic relocations of local symbols.
            (elf64_hppa_gc_mark_hook): New.
            (ensure_undef_dynamic): New.
            (allocate_dynrel_entries): Revise checks to determine when
            to discard relocs.
            (elf64_hppa_late_size_sections): Revise allocation of local
            PLT, DLT and OPD entries.
            (elf64_hppa_finalize_opd): Remove assert.
            (elf64_hppa_finalize_dlt): Change type of dynindx to long.
            (elf64_hppa_finalize_dynreloc): Likewise.  Add check for
            discarded sections.  Correct handling of  R_PARISC_FPTR64
            relocation.  Remove assert.  Add new assert to check that
            we don't allocate more relocs in .rela.data than it can
            hold.
            (elf64_hppa_finish_dynamic_sections): Move allocation for
            DT_HP_LOAD_MAP to end of .bss section.  Only allocate on
            HP-UX.
            (elf_hppa_dlt_dynrel_reloc): Add dynrel_type argument.
            Change type of dynindx.  Drop use of value.  Remove assert.
            (elf_hppa_opd_dynrel_relocs): Rename to elf_hppa_opd_eplt_reloc.
            Drop code to to emit R_PARISC_FPTR64 relocation.
            (elf_hppa_opd_fptr_reloc): New.
            (elf_hppa_final_link_relocate): Add SYM arguement.  Move
            check for SEC_DEBUGGING.  Rework DLT, LTOFF, FPTR and DIR64
            relocation handling.
            (elf64_hppa_relocate_section): Add asserts to ensure symbol
            isn't undefined and input_section hasn't been discarded.
            (elf_backend_gc_mark_hook): Define.
            (elf_backend_can_gc_sections): Define.
    
    ld/ChangeLog:
    
            * emulparams/elf64hppa.sh (DATA_ADDR): Revise value to match
            HP-UX 11 value.
            (SHLIB_DATA_ADDR): Likewise.
            (NOP): Define.
            (OTHER_READONLY_SECTIONS): Add .data.rel, .HP.init, .preinit,
            .init and .fini sections to list.
            (__SYSTEM_ID_D, __TLS_SIZE_D, __FPU_REVISION, __FPU_MODEL,
            __CPU_REVISION, __CPU_KEYBITS_1, __LOAD_INFO, __ARGC, __ARGV,
            __ENVP, __libdl_jmp_tbl, __systab): Provide.
            (DATA_START_SYMBOLS, OTHER_SYMBOLS, INIT_START): Delete.
            (PREINIT_START, PREINIT_END, INIT_START): Define.
            emulparams/hppa64linux.sh (NOP): Define.
            (DATA_START_SYMBOLS): Delete.
            scripttempl/elf64hppa.sc: Delete .init and .fini sections
            from script.  Allocate 16 bytes at end of .bss for HP_LOAD_MAP.

Diff:
---
 bfd/elf64-hppa.c             | 725 +++++++++++++++++++++++++++++++------------
 ld/emulparams/elf64hppa.sh   |  62 +++-
 ld/emulparams/hppa64linux.sh |   6 +-
 ld/scripttempl/elf64hppa.sc  |  17 +-
 4 files changed, 583 insertions(+), 227 deletions(-)

diff --git a/bfd/elf64-hppa.c b/bfd/elf64-hppa.c
index 2df62923ee5..c35dcf02976 100644
--- a/bfd/elf64-hppa.c
+++ b/bfd/elf64-hppa.c
@@ -749,9 +749,9 @@ elf64_hppa_check_relocs (bfd *abfd,
 	case R_PARISC_LTOFF_FPTR16WF:
 	case R_PARISC_LTOFF_FPTR16DF:
 	  if (bfd_link_pic (info) || maybe_dynamic)
-	    need_entry = (NEED_DLT | NEED_OPD | NEED_PLT | NEED_DYNREL);
+	    need_entry = (NEED_DLT | NEED_OPD | NEED_DYNREL);
 	  else
-	    need_entry = (NEED_DLT | NEED_OPD | NEED_PLT);
+	    need_entry = (NEED_DLT | NEED_OPD);
 	  dynrel_type = R_PARISC_FPTR64;
 	  break;
 
@@ -760,13 +760,27 @@ elf64_hppa_check_relocs (bfd *abfd,
 	  /* We need dynamic EPLT and FPTR64 relocations when building
 	     a shared library.  We also need these relocations if we have
 	     a global symbol which is not defined in this executable.  */
-	  if (bfd_link_pic (info) || hh)
+	  if (bfd_link_pic (info) || maybe_dynamic)
 	    need_entry = (NEED_OPD | NEED_DYNREL);
 	  else
 	    need_entry = (NEED_OPD);
 	  dynrel_type = R_PARISC_FPTR64;
 	  break;
 
+	/* This relocation describes the C++ object vtable hierarchy.
+	   Reconstruct it for later use during GC.  */
+	case R_PARISC_GNU_VTINHERIT:
+	  if (!bfd_elf_gc_record_vtinherit (abfd, sec, &hh->eh, rel->r_offset))
+	    return false;
+	  continue;
+
+	/* This relocation describes which C++ vtable entries are actually
+	   used.  Record for later use during GC.  */
+	case R_PARISC_GNU_VTENTRY:
+	  if (!bfd_elf_gc_record_vtentry (abfd, sec, &hh->eh, rel->r_addend))
+	    return false;
+	  continue;
+
 	/* Add more cases as needed.  */
 	}
 
@@ -874,17 +888,57 @@ elf64_hppa_check_relocs (bfd *abfd,
 				   sec_symndx, rel->r_offset, rel->r_addend))
 	    goto err_out;
 
+	  /* Add global symbol to dynamic symbol table.  */
+	  if (hh != NULL
+	      && hh->eh.dynindx == -1
+	      && ! (bfd_elf_link_record_dynamic_symbol (info, &hh->eh)))
+	    goto err_out;
+
 	  /* Add local symbol to local dynamic symbol table.  */
 	  if (hh == NULL
 	      && ! (bfd_elf_link_record_local_dynamic_symbol
 		     (info, abfd, r_symndx)))
 	    goto err_out;
 
-	  /* Add global symbol to dynamic symbol table.  */
-	  if (hh != NULL
-	      && hh->eh.dynindx == -1
-	      && ! (bfd_elf_link_record_dynamic_symbol (info, &hh->eh)))
-	    goto err_out;
+	  /* Handle dynamic relocation for a local symbol.  */
+	  if (hh == NULL)
+	    {
+	      struct elf64_hppa_dyn_reloc_entry *hdh_p;
+	      struct elf64_hppa_dyn_reloc_entry **hdh_head;
+	      asection *sr;
+	      void *vpp;
+	      Elf_Internal_Sym *isym;
+
+	      isym = bfd_sym_from_r_symndx (&hppa_info->root.sym_cache,
+					    abfd, r_symndx);
+	      if (isym == NULL)
+		return false;
+
+	      sr = bfd_section_from_elf_index (abfd, isym->st_shndx);
+	      if (sr == NULL)
+		sr = sec;
+
+	      vpp = &elf_section_data (sr)->local_dynrel;
+	      hdh_head = (struct elf64_hppa_dyn_reloc_entry **) vpp;
+
+	      hdh_p = *hdh_head;
+	      if (hdh_p == NULL || hdh_p->sec != sec)
+		{
+		  hdh_p = bfd_alloc (hppa_info->root.dynobj, sizeof *hdh_p);
+		  if (hdh_p == NULL)
+		    return false;
+		  hdh_p->next = *hdh_head;
+		  *hdh_head = hdh_p;
+		  hdh_p->type = dynrel_type;
+		  hdh_p->sec = sec;
+		  hdh_p->count = 0;
+		  hdh_p->sec_symndx = sec_symndx;
+		  hdh_p->offset = rel->r_offset;
+		  hdh_p->addend = rel->r_addend;
+		}
+
+	      hdh_p->count += 1;
+	    }
 	}
     }
 
@@ -894,6 +948,27 @@ elf64_hppa_check_relocs (bfd *abfd,
   return false;
 }
 
+/* Return the section that should be marked against garbage collection
+   for a given relocation.  */
+
+static asection *
+elf64_hppa_gc_mark_hook (asection *sec,
+			 struct bfd_link_info *info,
+			 struct elf_reloc_cookie *cookie,
+			 struct elf_link_hash_entry *hh,
+			 unsigned int symndx)
+{
+  if (hh != NULL)
+    switch (ELF64_R_TYPE (cookie->rel->r_info))
+      {
+      case R_PARISC_GNU_VTINHERIT:
+      case R_PARISC_GNU_VTENTRY:
+	return NULL;
+      }
+
+  return _bfd_elf_gc_mark_hook (sec, info, cookie, hh, symndx);
+}
+
 struct elf64_hppa_allocate_data
 {
   struct bfd_link_info *info;
@@ -1347,6 +1422,30 @@ elf64_hppa_create_dynamic_sections (bfd *abfd,
   return true;
 }
 
+/* If EH is undefined, make it dynamic if that makes sense.  */
+
+static bool
+ensure_undef_dynamic (struct bfd_link_info *info,
+		      struct elf_link_hash_entry *eh)
+{
+  struct elf64_hppa_link_hash_table *hppa_info;
+
+  hppa_info = hppa_link_hash_table (info);
+  if (hppa_info == NULL)
+    return false;
+
+  if (hppa_info->root.dynamic_sections_created
+      && (eh->root.type == bfd_link_hash_undefweak
+	  || eh->root.type == bfd_link_hash_undefined)
+      && eh->dynindx == -1
+      && !eh->forced_local
+      && eh->type != STT_PARISC_MILLI
+      && !UNDEFWEAK_NO_DYNAMIC_RELOC (info, eh)
+      && ELF_ST_VISIBILITY (eh->other) == STV_DEFAULT)
+    return bfd_elf_link_record_dynamic_symbol (info, eh);
+  return true;
+}
+
 /* Allocate dynamic relocations for those symbols that turned out
    to be dynamic.  */
 
@@ -1366,30 +1465,6 @@ allocate_dynrel_entries (struct elf_link_hash_entry *eh, void *data)
   dynamic_symbol = elf64_hppa_dynamic_symbol_p (eh, x->info);
   shared = bfd_link_pic (x->info);
 
-  /* Take care of the normal data relocations.  */
-
-  for (rent = hh->reloc_entries; rent; rent = rent->next)
-    {
-      switch (rent->type)
-	{
-	case R_PARISC_FPTR64:
-	  /* Allocate one if we are building a shared library, or
-	     we don't want an OPD entry.  Ignore text relocations.  */
-	  if ((hh->want_opd && !shared)
-	      || (rent->sec->flags & SEC_READONLY))
-	    continue;
-	  break;
-	case R_PARISC_DIR64:
-	  if (!dynamic_symbol && !shared)
-	    continue;
-	  break;
-	default:
-	  abort();
-	}
-      if (!discarded_section (hppa_info->other_rel_sec))
-	hppa_info->other_rel_sec->size += sizeof (Elf64_External_Rela);
-    }
-
   /* Take care of the GOT and PLT relocations.  */
 
   if ((dynamic_symbol || shared) && hh->want_dlt)
@@ -1416,6 +1491,66 @@ allocate_dynrel_entries (struct elf_link_hash_entry *eh, void *data)
       hppa_info->root.srelplt->size += t;
     }
 
+  /* If no dynamic sections we can't have dynamic relocs.  */
+  if (!hppa_info->root.dynamic_sections_created)
+    hh->reloc_entries = NULL;
+
+  /* Discard relocs on undefined syms with non-default visibility.  */
+  else if ((eh->root.type == bfd_link_hash_undefined
+	    && ELF_ST_VISIBILITY (eh->other) != STV_DEFAULT)
+	   || UNDEFWEAK_NO_DYNAMIC_RELOC (x->info, eh))
+    hh->reloc_entries = NULL;
+
+  if (hh->reloc_entries == NULL)
+    return true;
+
+  if (bfd_link_pic (x->info))
+    {
+      /* Discard space for relocs that have become local due to
+	 symbol visibility changes.  */
+      if (!ensure_undef_dynamic (x->info, eh))
+	return false;
+    }
+
+  /* Take care of the normal data relocations.  */
+
+  for (rent = hh->reloc_entries; rent; rent = rent->next)
+    {
+      switch (rent->type)
+	{
+	case R_PARISC_FPTR64:
+	  /* Allocate one if we are building a shared library, or
+	     we don't want an OPD entry.  Ignore text relocations.  */
+	  if ((hh->want_opd && !shared)
+	      || (rent->sec->flags & SEC_READONLY))
+	    continue;
+	  break;
+	case R_PARISC_DIR64:
+	  if (!dynamic_symbol && !shared)
+	    continue;
+	  break;
+	default:
+	  abort();
+	}
+
+      if (discarded_section (rent->sec)
+	  || discarded_section (hppa_info->other_rel_sec))
+	continue;
+
+      if (eh->dynindx == -1)
+	{
+	  if (rent->type == R_PARISC_FPTR64)
+	    {
+	      if (!hh->want_opd)
+		continue;
+	    }
+	  else if (discarded_section (eh->root.u.def.section))
+	    continue;
+        }
+
+      hppa_info->other_rel_sec->size += sizeof (Elf64_External_Rela);
+    }
+
   return true;
 }
 
@@ -1542,13 +1677,15 @@ elf64_hppa_late_size_sections (bfd *output_bfd, struct bfd_link_info *info)
       bfd_signed_vma *start_local_dlt;
       bfd_signed_vma *end_local_dlt;
       bfd_signed_vma *local_plt;
+      bfd_signed_vma *start_local_plt;
       bfd_signed_vma *end_local_plt;
       bfd_signed_vma *local_opd;
       bfd_signed_vma *start_local_opd;
       bfd_signed_vma *end_local_opd;
       bfd_size_type locsymcount;
       Elf_Internal_Shdr *symtab_hdr;
-      asection *srel, *srel_other;
+      asection *srel;
+      long indx;
 
       if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour)
 	continue;
@@ -1557,6 +1694,9 @@ elf64_hppa_late_size_sections (bfd *output_bfd, struct bfd_link_info *info)
 	{
 	  struct elf64_hppa_dyn_reloc_entry *hdh_p;
 
+	  if (discarded_section (sec))
+	    continue;
+
 	  for (hdh_p = ((struct elf64_hppa_dyn_reloc_entry *)
 		    elf_section_data (sec)->local_dynrel);
 	       hdh_p != NULL;
@@ -1572,7 +1712,7 @@ elf64_hppa_late_size_sections (bfd *output_bfd, struct bfd_link_info *info)
 		}
 	      else if (hdh_p->count != 0)
 		{
-		  srel = elf_section_data (hdh_p->sec)->sreloc;
+		  srel = hppa_info->other_rel_sec;
 		  srel->size += hdh_p->count * sizeof (Elf64_External_Rela);
 		  if ((hdh_p->sec->output_section->flags & SEC_READONLY) != 0)
 		    info->flags |= DF_TEXTREL;
@@ -1586,44 +1726,45 @@ elf64_hppa_late_size_sections (bfd *output_bfd, struct bfd_link_info *info)
 
       symtab_hdr = &elf_tdata (ibfd)->symtab_hdr;
       locsymcount = symtab_hdr->sh_info;
+
       end_local_dlt = start_local_dlt + locsymcount;
+      start_local_plt = end_local_dlt;
+      end_local_plt = start_local_plt + locsymcount;
+      start_local_opd = end_local_plt;
+      end_local_opd = start_local_opd + locsymcount;
+
       sec = hppa_info->dlt_sec;
       srel = hppa_info->dlt_rel_sec;
-      for (local_dlt = start_local_dlt;
+      for (local_dlt = start_local_dlt, indx = 0;
 	   local_dlt < end_local_dlt;
-	   ++local_dlt)
+	   ++local_dlt, ++indx)
 	{
 	  if (*local_dlt > 0)
 	    {
-	      long indx;
-	      long dynindx = -1;
-
-	      indx = local_dlt - start_local_dlt;
-	      if (!bfd_link_pic (info))
-		dynindx = _bfd_elf_link_lookup_local_dynindx (info, ibfd,
-							      indx);
 	      *local_dlt = sec->size;
 	      sec->size += DLT_ENTRY_SIZE;
-	      if (bfd_link_pic (info) || dynindx != -1)
+	      if (bfd_link_pic (info) || start_local_opd[indx] > 0)
 		srel->size += sizeof (Elf64_External_Rela);
 	    }
 	  else
 	    *local_dlt = (bfd_vma) -1;
 	}
 
-      local_plt = end_local_dlt;
-      end_local_plt = local_plt + locsymcount;
       if (! hppa_info->root.dynamic_sections_created)
 	{
 	  /* Won't be used, but be safe.  */
-	  for (; local_plt < end_local_plt; ++local_plt)
+	  for (local_plt = start_local_plt;
+	       local_plt < end_local_plt;
+	       ++local_plt)
 	    *local_plt = (bfd_vma) -1;
 	}
       else
 	{
 	  sec = hppa_info->root.splt;
 	  srel = hppa_info->root.srelplt;
-	  for (; local_plt < end_local_plt; ++local_plt)
+	  for (local_plt = start_local_plt;
+	       local_plt < end_local_plt;
+	       ++local_plt)
 	    {
 	      if (*local_plt > 0)
 		{
@@ -1637,8 +1778,6 @@ elf64_hppa_late_size_sections (bfd *output_bfd, struct bfd_link_info *info)
 	    }
 	}
 
-      start_local_opd = end_local_plt;
-      end_local_opd = start_local_opd + locsymcount;
       if (! hppa_info->root.dynamic_sections_created)
 	{
 	  /* Won't be used, but be safe.  */
@@ -1651,7 +1790,6 @@ elf64_hppa_late_size_sections (bfd *output_bfd, struct bfd_link_info *info)
 	{
 	  sec = hppa_info->opd_sec;
 	  srel = hppa_info->opd_rel_sec;
-	  srel_other = hppa_info->other_rel_sec;
 	  for (local_opd = start_local_opd;
 	       local_opd < end_local_opd;
 	       ++local_opd)
@@ -1663,12 +1801,10 @@ elf64_hppa_late_size_sections (bfd *output_bfd, struct bfd_link_info *info)
 		  *local_opd = sec->size - OPD_ENTRY_SIZE;
 		  sec->size += OPD_ENTRY_SIZE;
 
-		  /* We need EPLT and FPTR64 relocations.  */
+		  /* We need a EPLT relocation if we are building a
+		     shared library.  */
 		  if (bfd_link_pic (info))
-		    {
-		      srel->size += sizeof (Elf64_External_Rela);
-		      srel_other->size += sizeof (Elf64_External_Rela);
-		    }
+		    srel->size += sizeof (Elf64_External_Rela);
 		}
 	      else
 		*local_opd = (bfd_vma) -1;
@@ -2144,7 +2280,7 @@ elf64_hppa_finalize_opd (struct elf_link_hash_entry *eh, void *data)
       bfd_vma value, value2;
       Elf_Internal_Rela rel;
       bfd_byte *loc;
-      int dynindx;
+      long dynindx;
       asection *sec;
 
       /* The offset of this relocation is the absolute address of the
@@ -2183,7 +2319,6 @@ elf64_hppa_finalize_opd (struct elf_link_hash_entry *eh, void *data)
       rel.r_addend += value;
 
       dynindx = hppa_info->text_hash_entry->dynindx;
-      BFD_ASSERT (dynindx != -1);
       rel.r_info = ELF64_R_INFO (dynindx, R_PARISC_EPLT);
 
       loc = sopdrel->contents;
@@ -2254,7 +2389,7 @@ elf64_hppa_finalize_dlt (struct elf_link_hash_entry *eh, void *data)
     {
       Elf_Internal_Rela rel;
       bfd_byte *loc;
-      int dynindx;
+      long dynindx;
       asection *sec;
       bfd_vma value, value2;
 
@@ -2326,7 +2461,7 @@ elf64_hppa_finalize_dynreloc (struct elf_link_hash_entry *eh,
   if (hh->reloc_entries)
     {
       struct elf64_hppa_dyn_reloc_entry *rent;
-      int dynindx;
+      long dynindx;
 
       for (rent = hh->reloc_entries; rent; rent = rent->next)
 	{
@@ -2350,6 +2485,10 @@ elf64_hppa_finalize_dynreloc (struct elf_link_hash_entry *eh,
 	      abort();
 	    }
 
+	  if (discarded_section (rent->sec)
+	      || discarded_section (hppa_info->other_rel_sec))
+	    continue;
+
 	  /* Create a dynamic relocation for this entry.
 
 	     We need the output offset for the reloc's section because
@@ -2360,24 +2499,41 @@ elf64_hppa_finalize_dynreloc (struct elf_link_hash_entry *eh,
 
 	  if (eh->dynindx == -1)
 	    {
-	      asection *sec;
+	      asection *sec, *sopd;
 	      bfd_vma value, value2;
 
-	      value = (eh->root.u.def.value
-		       + eh->root.u.def.section->output_section->vma
-		       + eh->root.u.def.section->output_offset);
+	      if (rent->type == R_PARISC_FPTR64)
+	        {
+		  if (!hh->want_opd)
+		    continue;
+		  sopd = hppa_info->opd_sec;
+		  value = (hh->opd_offset + sopd->output_offset
+		  	   + sopd->output_section->vma);
 
-	      if (eh->root.u.def.section->flags & SEC_READONLY)
-		{
-		  sec = hppa_info->text_hash_entry->root.u.def.section;
+		  sec = hppa_info->data_hash_entry->root.u.def.section;
 		  value2 = sec->output_offset + sec->output_section->vma;
-		  dynindx = hppa_info->text_hash_entry->dynindx;
+		  dynindx = hppa_info->data_hash_entry->dynindx;
 		}
 	      else
 		{
-		  sec = hppa_info->data_hash_entry->root.u.def.section;
-		  value2 = sec->output_offset + sec->output_section->vma;
-		  dynindx = hppa_info->data_hash_entry->dynindx;
+		  if (discarded_section (eh->root.u.def.section))
+		    continue;
+		  value = (eh->root.u.def.value
+			   + eh->root.u.def.section->output_section->vma
+			   + eh->root.u.def.section->output_offset);
+
+		  if (eh->root.u.def.section->flags & SEC_READONLY)
+		    {
+		      sec = hppa_info->text_hash_entry->root.u.def.section;
+		      value2 = sec->output_offset + sec->output_section->vma;
+		      dynindx = hppa_info->text_hash_entry->dynindx;
+		    }
+		  else
+		    {
+		      sec = hppa_info->data_hash_entry->root.u.def.section;
+		      value2 = sec->output_offset + sec->output_section->vma;
+		      dynindx = hppa_info->data_hash_entry->dynindx;
+		    }
 		}
 	      rel.r_addend = value - value2;
 	    }
@@ -2387,10 +2543,12 @@ elf64_hppa_finalize_dynreloc (struct elf_link_hash_entry *eh,
 	      dynindx = eh->dynindx;
 	    }
 
-	  BFD_ASSERT (dynindx != -1);
 	  rel.r_info = ELF64_R_INFO (dynindx, rent->type);
 
 	  loc = hppa_info->other_rel_sec->contents;
+	  BFD_ASSERT ((hppa_info->other_rel_sec->reloc_count
+		       * sizeof (Elf64_External_Rela))
+		      < hppa_info->other_rel_sec->size);
 	  loc += (hppa_info->other_rel_sec->reloc_count++
 		  * sizeof (Elf64_External_Rela));
 	  bfd_elf64_swap_reloca_out (info->output_bfd, &rel, loc);
@@ -2476,17 +2634,24 @@ elf64_hppa_finish_dynamic_sections (bfd *output_bfd,
 	      break;
 
 	    case DT_HP_LOAD_MAP:
-	      /* Compute the absolute address of 16byte scratchpad area
+	      /* Compute the absolute address of 16-byte scratchpad area
 		 for the dynamic linker.
 
 		 By convention the linker script will allocate the scratchpad
-		 area at the start of the .data section.  So all we have to
-		 to is find the start of the .data section.  */
-	      s = bfd_get_section_by_name (output_bfd, ".data");
-	      if (!s)
-		return false;
-	      dyn.d_un.d_ptr = s->vma;
-	      bfd_elf64_swap_dyn_out (output_bfd, &dyn, dyncon);
+		 area at the start of the .data section.
+
+		 In HPUX 11.11, HP ld now allocates the region at the end
+		 of the .bss section.  This avoids adding 16 bytes to the
+		 start of .data.  This may affect relocation offsets.  */
+	      if (output_bfd->xvec == & hppa_elf64_vec
+	          && ! bfd_link_pic (info))
+		{
+		  s = bfd_get_section_by_name (output_bfd, ".bss");
+		  if (!s)
+		    break;
+		  dyn.d_un.d_ptr = s->vma + s->size - 16;
+		  bfd_elf64_swap_dyn_out (output_bfd, &dyn, dyncon);
+		}
 	      break;
 
 	    case DT_PLTGOT:
@@ -3129,15 +3294,14 @@ elf_hppa_dlt_dynrel_reloc (Elf_Internal_Rela *rel,
 			   bfd_vma relocation,
 			   struct bfd_link_info *info,
 			   asection *sym_sec,
-			   bfd_vma dlt_offset)
+			   bfd_vma dlt_offset,
+			   int dynrel_type)
 {
   Elf_Internal_Rela rela;
   bfd_byte *loc;
-  int dynindx;
+  long dynindx;
   asection *sec;
   asection *sdlt, *sdltrel;
-  int dynrel_type;
-  bfd_vma value;
   bfd_signed_vma addend = rel->r_addend;
   struct elf64_hppa_link_hash_table *hppa_info = hppa_link_hash_table (info);
 
@@ -3152,23 +3316,18 @@ elf_hppa_dlt_dynrel_reloc (Elf_Internal_Rela *rel,
     {
       sec = hppa_info->text_hash_entry->root.u.def.section;
       dynindx = hppa_info->text_hash_entry->dynindx;
-      dynrel_type = R_PARISC_FPTR64;
     }
   else
     {
       sec = hppa_info->data_hash_entry->root.u.def.section;
       dynindx = hppa_info->data_hash_entry->dynindx;
-      dynrel_type = R_PARISC_DIR64;
     }
 
   /* Adjust addend using the difference of the symbol's
      location and the section symbol's address.  */
-  value = relocation + addend - sec->output_offset - sec->output_section->vma;
-
-  /* The result becomes the addend of the relocation.  */
-  rela.r_addend = value;
+  rela.r_addend = (relocation + addend - sec->output_offset
+		   - sec->output_section->vma);
 
-  BFD_ASSERT (dynindx != -1);
   rela.r_info = ELF64_R_INFO (dynindx, dynrel_type);
 
   loc = sdltrel->contents;
@@ -3176,54 +3335,73 @@ elf_hppa_dlt_dynrel_reloc (Elf_Internal_Rela *rel,
   bfd_elf64_swap_reloca_out (info->output_bfd, &rela, loc);
 }
 
-/* Output OPD EPLT and FPTR64 relocations for a local symbol.  */
+/* Output OPD EPLT relocation for a local symbol.  */
 
 static void
-elf_hppa_opd_dynrel_relocs (Elf_Internal_Rela *rel,
-			    asection *input_section,
-			    bfd_vma relocation,
-			    struct bfd_link_info *info,
-			    bfd_vma opd_offset)
+elf_hppa_opd_eplt_reloc (Elf_Internal_Rela *rel,
+			 bfd_vma relocation,
+			 struct bfd_link_info *info,
+			 bfd_vma opd_offset)
 {
   Elf_Internal_Rela rela;
   bfd_byte *loc;
-  int dynindx;
+  long dynindx;
   asection *sopd, *sopdrel;
-  asection *sec, *s;
+  asection *sec;
   bfd_vma value;
-  bfd_vma offset = rel->r_offset;
   bfd_signed_vma addend = rel->r_addend;
   struct elf64_hppa_link_hash_table *hppa_info = hppa_link_hash_table (info);
 
   sopd = hppa_info->opd_sec;
   sopdrel = hppa_info->opd_rel_sec;
 
-  /* The offset of the EPLT relocation is the absolute address
-     of the .opd entry for this symbol.  */
-  rela.r_offset = opd_offset + sopd->output_offset + sopd->output_section->vma;
+  /* We need a EPLT relocation if we are building a shared library.  */
+  if (bfd_link_pic (info))
+    {
+      /* The offset of the EPLT relocation is the absolute address
+	 of the .opd entry for this symbol.  */
+      rela.r_offset = (opd_offset + sopd->output_offset
+		       + sopd->output_section->vma);
 
-  /* Select text base segment and its dynindx.  */
-  sec = hppa_info->text_hash_entry->root.u.def.section;
-  dynindx = hppa_info->text_hash_entry->dynindx;
+      /* Select text base segment and its dynindx.  */
+      sec = hppa_info->text_hash_entry->root.u.def.section;
+      dynindx = hppa_info->text_hash_entry->dynindx;
 
-  /* Adjust the addend with the difference between the
-     symbol's address and the base segment's address.  */
-  value = relocation + addend - sec->output_offset - sec->output_section->vma;
+      /* Adjust the addend with the difference between the
+	 symbol's address and the base segment's address.  */
+      value = (relocation + addend - sec->output_offset
+	       - sec->output_section->vma);
 
-  /* The result becomes the addend of the relocation.  */
-  rela.r_addend = value;
+      /* The result becomes the addend of the relocation.  */
+      rela.r_addend = value;
 
-  BFD_ASSERT (dynindx != -1);
-  rela.r_info = ELF64_R_INFO (dynindx, R_PARISC_EPLT);
+      rela.r_info = ELF64_R_INFO (dynindx, R_PARISC_EPLT);
 
-  loc = sopdrel->contents;
-  loc += sopdrel->reloc_count++ * sizeof (Elf64_External_Rela);
-  bfd_elf64_swap_reloca_out (info->output_bfd, &rela, loc);
+      loc = sopdrel->contents;
+      loc += sopdrel->reloc_count++ * sizeof (Elf64_External_Rela);
+      bfd_elf64_swap_reloca_out (info->output_bfd, &rela, loc);
+    }
+}
 
-  /* The offset of the FPTR relocation is the absolute address
-     of this symbol.  */
-  rela.r_offset = (offset + input_section->output_offset
-		   + input_section->output_section->vma);
+/* Output OPD FPTR64 relocation for a local symbol.  */
+
+static void
+elf_hppa_opd_fptr_reloc (struct bfd_link_info *info,
+			 bfd_vma opd_offset,
+			 bfd_vma fptr_offset)
+{
+  Elf_Internal_Rela rela;
+  bfd_byte *loc;
+  long dynindx;
+  asection *sopd;
+  asection *sec, *s;
+  bfd_vma value;
+  struct elf64_hppa_link_hash_table *hppa_info = hppa_link_hash_table (info);
+
+  sopd = hppa_info->opd_sec;
+
+  /* FPTR offset.  */
+  rela.r_offset = fptr_offset;
 
   /* OPD's address.  */
   value = opd_offset + sopd->output_offset + sopd->output_section->vma;
@@ -3239,11 +3417,11 @@ elf_hppa_opd_dynrel_relocs (Elf_Internal_Rela *rel,
   /* The result becomes the addend of the relocation.  */
   rela.r_addend = value;
 
-  BFD_ASSERT (dynindx != -1);
   rela.r_info = ELF64_R_INFO (dynindx, R_PARISC_FPTR64);
 
   s = hppa_info->other_rel_sec;
   loc = s->contents;
+  BFD_ASSERT (s->reloc_count * sizeof (Elf64_External_Rela) < s->size);
   loc += s->reloc_count++ * sizeof (Elf64_External_Rela);
   bfd_elf64_swap_reloca_out (info->output_bfd, &rela, loc);
 }
@@ -3269,6 +3447,7 @@ elf_hppa_final_link_relocate (Elf_Internal_Rela *rel,
 			      bfd_byte *contents,
 			      bfd_vma value,
 			      struct bfd_link_info *info,
+			      Elf_Internal_Sym *sym,
 			      asection *sym_sec,
 			      struct elf_link_hash_entry *eh)
 {
@@ -3285,13 +3464,6 @@ elf_hppa_final_link_relocate (Elf_Internal_Rela *rel,
   unsigned int r_type = howto->type;
   bfd_byte *hit_data = contents + offset;
 
-  /* Dynamic relocs are not propagated for SEC_DEBUGGING
-     sections because such sections are not SEC_ALLOC and
-     thus ld.so will not process them.  */
-  if (bfd_link_pic (info)
-      && (input_section->flags & SEC_DEBUGGING) != 0)
-    return bfd_reloc_ok;
-
   if (hppa_info == NULL)
     return bfd_reloc_notsupported;
 
@@ -3426,9 +3598,11 @@ elf_hppa_final_link_relocate (Elf_Internal_Rela *rel,
     case R_PARISC_LTOFF16WF:
     case R_PARISC_LTOFF16DF:
       {
-	bfd_vma off;
+	bfd_vma dlt_off, fptr_off, opd_off;
 	bfd_vma relocation = value;
 	asection *sopd;
+	bool need_dlt_reloc = false;
+	int dynrel_type = R_PARISC_NONE;
 
 	sopd = hppa_info->opd_sec;
 
@@ -3449,6 +3623,32 @@ elf_hppa_final_link_relocate (Elf_Internal_Rela *rel,
 	    if (local_offsets == NULL)
 	      abort ();
 
+	    local_dlt_offsets = local_offsets;
+	    dlt_off = local_dlt_offsets[r_symndx];
+
+	    if ((dlt_off & 1) != 0)
+	      {
+		BFD_ASSERT (dlt_off != (bfd_vma) -1);
+		dlt_off &= ~1;
+	      }
+	    else
+	      {
+		local_dlt_offsets[r_symndx] |= 1;
+
+		if (bfd_link_pic (info))
+		  {
+		    if (ELF_ST_TYPE (sym->st_info) == STT_FUNC)
+		      dynrel_type = R_PARISC_FPTR64;
+		    else
+		      dynrel_type = R_PARISC_DIR64;
+		    need_dlt_reloc = true;
+		  }
+
+		bfd_put_64 (hppa_info->dlt_sec->owner,
+			    value + addend,
+			    hppa_info->dlt_sec->contents + dlt_off);
+	      }
+
 	    /* Now do .opd creation if needed.  */
 	    if (r_type == R_PARISC_LTOFF_FPTR14R
 		|| r_type == R_PARISC_LTOFF_FPTR14DR
@@ -3459,66 +3659,72 @@ elf_hppa_final_link_relocate (Elf_Internal_Rela *rel,
 		|| r_type == R_PARISC_LTOFF_FPTR16DF)
 	      {
 		local_opd_offsets = local_offsets + 2 * symtab_hdr->sh_info;
-		off = local_opd_offsets[r_symndx];
+		opd_off = local_opd_offsets[r_symndx];
 
 		/* The last bit records whether we've already initialised
 		   this local .opd entry.  */
-		if ((off & 1) != 0)
+		if ((opd_off & 1) != 0)
 		  {
-		    BFD_ASSERT (off != (bfd_vma) -1);
-		    off &= ~1;
+		    BFD_ASSERT (opd_off != (bfd_vma) -1);
+		    opd_off &= ~1;
 		  }
 		else
 		  {
 		    local_opd_offsets[r_symndx] |= 1;
 
-		    /* If we are building a shared library, we need a EPLT
-		       and FPTR64 relocation for each OPD entry.  */
-		    if (bfd_link_pic (info))
-		      elf_hppa_opd_dynrel_relocs (rel, input_section,
-						  relocation, info, off);
+		    /* If we are building a shared library, we need an EPLT
+		       relocation for each OPD entry.  */
+		    elf_hppa_opd_eplt_reloc (rel, relocation, info, opd_off);
+
+		    /* Adjust the relocation to point to the OPD.  */
+		    relocation = (opd_off + sopd->output_offset
+				  + sopd->output_section->vma);
+		    sym_sec = sopd;
+		    rel->r_addend = 0;
+		    need_dlt_reloc = true;
+		    dynrel_type = R_PARISC_FPTR64;
 
 		    /* The third word is the address of the function.  */
 		    bfd_put_64 (sopd->owner, value + addend,
-				sopd->contents + off + 16);
+				sopd->contents + opd_off + 16);
 
 		    /* The last word is our local __gp value.  */
 		    value = _bfd_get_gp_value (info->output_bfd);
 		    bfd_put_64 (sopd->owner, value,
-				sopd->contents + off + 24);
+				sopd->contents + opd_off + 24);
 		  }
-	      }
 
-	    local_dlt_offsets = local_offsets;
-	    off = local_dlt_offsets[r_symndx];
-
-	    if ((off & 1) != 0)
-	      {
-		BFD_ASSERT (off != (bfd_vma) -1);
-		off &= ~1;
-	      }
-	    else
-	      {
-		local_dlt_offsets[r_symndx] |= 1;
+		/* Output a FPTR64 relocation for dynamic local symbols.
+		   Note dynamic relocs are not propagated for SEC_DEBUGGING
+		   sections because such sections are not SEC_ALLOC and thus
+		   ld.so will not process them.  */
 		if (bfd_link_pic (info)
-		    || _bfd_elf_link_lookup_local_dynindx (info, input_bfd,
+		    && (input_section->flags & SEC_DEBUGGING) == 0
+		    && _bfd_elf_link_lookup_local_dynindx (info, input_bfd,
 							   r_symndx) != -1)
-		  elf_hppa_dlt_dynrel_reloc (rel, relocation, info,
-					     sym_sec, off);
+		  {
+		    /* FPTR offset is absolute address of DLT entry.  */
+		    fptr_off = (dlt_off
+				+ hppa_info->dlt_sec->output_offset
+				+ hppa_info->dlt_sec->output_section->vma);
 
-		bfd_put_64 (hppa_info->dlt_sec->owner,
-			    value + addend,
-			    hppa_info->dlt_sec->contents + off);
+		    /* Output FPTR64 relocation for local symbol.  */
+		    elf_hppa_opd_fptr_reloc (info, opd_off, fptr_off);
+		  }
 	      }
 	  }
 	else
-	  off = hh->dlt_offset;
+	  dlt_off = hh->dlt_offset;
+
+	if (need_dlt_reloc)
+	  elf_hppa_dlt_dynrel_reloc (rel, relocation, info, sym_sec,
+				     dlt_off, dynrel_type);
 
 	/* We want the value of the DLT offset for this symbol, not
 	   the symbol's actual address.  Note that __gp may not point
 	   to the start of the DLT, so we have to compute the absolute
 	   address, then subtract out the value of __gp.  */
-	value = (off
+	value = (dlt_off
 		 + hppa_info->dlt_sec->output_offset
 		 + hppa_info->dlt_sec->output_section->vma);
 	value -= _bfd_get_gp_value (output_bfd);
@@ -3681,11 +3887,34 @@ elf_hppa_final_link_relocate (Elf_Internal_Rela *rel,
       {
 	bfd_vma relocation = value;
 	bfd_vma *local_opd_offsets, *local_dlt_offsets;
-	bfd_vma dlt_off;
+	bfd_vma dlt_off, fptr_off;
 	bfd_vma opd_off = (bfd_vma) -1;
+	bool need_dlt_reloc = false;
+	int dynrel_type = R_PARISC_NONE;
 
 	if (eh == NULL)
 	  {
+	    local_dlt_offsets = local_offsets;
+	    dlt_off = local_dlt_offsets[r_symndx];
+
+	    if ((dlt_off & 1) != 0)
+	      {
+		BFD_ASSERT (dlt_off != (bfd_vma) -1);
+		dlt_off &= ~1;
+	      }
+	    else
+	      {
+		local_dlt_offsets[r_symndx] |= 1;
+		if (bfd_link_pic (info))
+		  {
+		    if (ELF_ST_TYPE (sym->st_info) == STT_FUNC)
+		      dynrel_type = R_PARISC_FPTR64;
+		    else
+		      dynrel_type = R_PARISC_DIR64;
+		    need_dlt_reloc = true;
+		  }
+	      }
+
 	    if (r_type == R_PARISC_LTOFF_FPTR64)
 	      {
 		local_opd_offsets = local_offsets + 2 * symtab_hdr->sh_info;
@@ -3700,32 +3929,40 @@ elf_hppa_final_link_relocate (Elf_Internal_Rela *rel,
 		  }
 		else
 		  {
+		    asection *sopd = hppa_info->opd_sec;
+
 		    local_opd_offsets[r_symndx] |= 1;
 
-		    /* If we are building a shared library, we need a EPLT
-		       and FPTR64 relocation for each OPD entry.  */
-		    if (bfd_link_pic (info))
-		      elf_hppa_opd_dynrel_relocs (rel, input_section,
-						  relocation, info, opd_off);
+		    /* If we are building a shared library, we need an EPLT
+		       relocation for each OPD entry.  */
+		    elf_hppa_opd_eplt_reloc (rel, relocation, info, opd_off);
+
+		    /* Adjust the DLT relocation to point to the OPD.  */
+		    relocation = (opd_off + sopd->output_offset
+				  + sopd->output_section->vma);
+		    sym_sec = sopd;
+		    rel->r_addend = 0;
+		    need_dlt_reloc = true;
+		    dynrel_type = R_PARISC_FPTR64;
 		  }
-	      }
 
-	    local_dlt_offsets = local_offsets;
-	    dlt_off = local_dlt_offsets[r_symndx];
-
-	    if ((dlt_off & 1) != 0)
-	      {
-		BFD_ASSERT (dlt_off != (bfd_vma) -1);
-		dlt_off &= ~1;
-	      }
-	    else
-	      {
-		local_dlt_offsets[r_symndx] |= 1;
+		/* Output a FPTR64 relocation for dynamic local symbols.
+		   Note dynamic relocs are not propagated for SEC_DEBUGGING
+		   sections because such sections are not SEC_ALLOC and thus
+		   ld.so will not process them.  */
 		if (bfd_link_pic (info)
-		    || _bfd_elf_link_lookup_local_dynindx (info, input_bfd,
+		    && (input_section->flags & SEC_DEBUGGING) == 0
+		    && _bfd_elf_link_lookup_local_dynindx (info, input_bfd,
 							   r_symndx) != -1)
-		  elf_hppa_dlt_dynrel_reloc (rel, relocation, info,
-					     sym_sec, dlt_off);
+		  {
+		    /* FPTR offset is absolute address of DLT entry.  */
+		    fptr_off = (dlt_off
+				+ hppa_info->dlt_sec->output_offset
+				+ hppa_info->dlt_sec->output_section->vma);
+
+		    /* Output FPTR64 relocation for local symbol.  */
+		    elf_hppa_opd_fptr_reloc (info, opd_off, fptr_off);
+		  }
 	      }
 	  }
 	else
@@ -3734,6 +3971,10 @@ elf_hppa_final_link_relocate (Elf_Internal_Rela *rel,
 	    dlt_off = hh->dlt_offset;
 	  }
 
+	if (need_dlt_reloc)
+	  elf_hppa_dlt_dynrel_reloc (rel, relocation, info, sym_sec,
+				     dlt_off, dynrel_type);
+
 	/* We may still need to create the FPTR itself if it was for
 	   a local symbol.  */
 	if (eh == NULL && r_type == R_PARISC_LTOFF_FPTR64)
@@ -3774,6 +4015,62 @@ elf_hppa_final_link_relocate (Elf_Internal_Rela *rel,
       return bfd_reloc_ok;
 
     case R_PARISC_DIR64:
+      if (hh == NULL)
+	{
+	  long dynindx;
+	  Elf_Internal_Rela rela;
+	  bfd_byte *loc;
+	  asection *s, *sec;
+
+	  /* Output a DIR64 relocation for dynamic local symbols.
+	     Note dynamic relocs are not propagated for SEC_DEBUGGING
+	     sections because such sections are not SEC_ALLOC and thus
+	     ld.so will not process them.  */
+	  if (bfd_link_pic (info)
+	      && (input_section->flags & SEC_DEBUGGING) == 0
+	      && _bfd_elf_link_lookup_local_dynindx (info, input_bfd,
+						     r_symndx) != -1)
+	    {
+	      bfd_vma out_off;
+
+	      out_off = _bfd_elf_section_offset (output_bfd, info,
+						 input_section,
+						 rel->r_offset);
+
+	      BFD_ASSERT (out_off != (bfd_vma) -1 && out_off != (bfd_vma) -2);
+
+	      /* This is the output relocation offset.  */
+	      rela.r_offset = (out_off
+			       + input_section->output_offset
+			       + input_section->output_section->vma);
+
+	      /* Select base segment.  */
+	      if (sym_sec->flags & SEC_READONLY)
+		{
+		  sec = hppa_info->text_hash_entry->root.u.def.section;
+		  dynindx = hppa_info->text_hash_entry->dynindx;
+		}
+	      else
+		{
+		  sec = hppa_info->data_hash_entry->root.u.def.section;
+		  dynindx = hppa_info->data_hash_entry->dynindx;
+		}
+
+	      /* Adjust addend using the difference of the symbol's
+		 location and the section symbol's address.  */
+	      rela.r_addend = (value + addend - sec->output_offset
+			       - sec->output_section->vma);
+
+	      /* We need a dynamic relocation for this symbol.  */
+	      rela.r_info = ELF64_R_INFO (dynindx, R_PARISC_DIR64);
+
+	      s = hppa_info->other_rel_sec;
+	      loc = s->contents;
+	      loc += s->reloc_count++ * sizeof (Elf64_External_Rela);
+	      bfd_elf64_swap_reloca_out (info->output_bfd, &rela, loc);
+	    }
+	}
+
       bfd_put_64 (output_bfd, value + addend, hit_data);
       return bfd_reloc_ok;
 
@@ -3838,7 +4135,7 @@ elf_hppa_final_link_relocate (Elf_Internal_Rela *rel,
 
     case R_PARISC_FPTR64:
       {
-	bfd_vma off;
+	bfd_vma fptr_off, opd_off;
 	bfd_vma relocation = value;
 	asection *sopd;
 
@@ -3854,40 +4151,68 @@ elf_hppa_final_link_relocate (Elf_Internal_Rela *rel,
 	      abort ();
 
 	    local_opd_offsets = local_offsets + 2 * symtab_hdr->sh_info;
-	    off = local_opd_offsets[r_symndx];
+	    opd_off = local_opd_offsets[r_symndx];
 
 	    /* The last bit records whether we've already initialised
 	       this local .opd entry.  */
-	    if ((off & 1) != 0)
+	    if ((opd_off & 1) != 0)
 	      {
-		BFD_ASSERT (off != (bfd_vma) -1);
-		off &= ~1;
+		BFD_ASSERT (opd_off != (bfd_vma) -1);
+		opd_off &= ~1;
 	      }
 	    else
 	      {
 		local_opd_offsets[r_symndx] |= 1;
 
-		/* If we are building a shared library, we need a EPLT
-		   and a FPTR64 relocation for each OPD entry.  */
-		if (bfd_link_pic (info))
-		  elf_hppa_opd_dynrel_relocs (rel, input_section,
-					      relocation, info, off);
+		if (input_section->flags & SEC_READONLY)
+		  {
+		    _bfd_error_handler
+		      /* xgettext:c-format */
+		      (_("%pB(%pA+%#" PRIx64
+			 "): R_PARISC_FPTR64 relocation in readonly section"),
+			input_bfd,
+			input_section,
+			(uint64_t) offset);
+		    return bfd_reloc_notsupported;
+		  }
+
+		/* If we are building a shared library, we need an EPLT
+		   relocation for each OPD entry.  */
+		elf_hppa_opd_eplt_reloc (rel, relocation, info, opd_off);
 
 		/* The third word is the address of the function.  */
 		bfd_put_64 (sopd->owner, value + addend,
-			    (sopd->contents + off + 16));
+			    (sopd->contents + opd_off + 16));
 
 		/* The last word is our local __gp value.  */
 		value = _bfd_get_gp_value (info->output_bfd);
-		bfd_put_64 (sopd->owner, value, sopd->contents + off + 24);
+		bfd_put_64 (sopd->owner, value, sopd->contents + opd_off + 24);
+	      }
+
+	    /* Output a FPTR64 relocation for dynamic local symbols.
+	       Note dynamic relocs are not propagated for SEC_DEBUGGING
+	       sections because such sections are not SEC_ALLOC and thus
+	       ld.so will not process them.  */
+	    if (bfd_link_pic (info)
+		&& (input_section->flags & SEC_DEBUGGING) == 0
+		&& _bfd_elf_link_lookup_local_dynindx (info, input_bfd,
+						       r_symndx) != -1)
+	      {
+		/* The offset of the FPTR relocation is the absolute address
+		   of this relocation.  */
+		fptr_off = (rel->r_offset + input_section->output_offset
+			    + input_section->output_section->vma);
+
+		/* Output FPTR64 relocation for local symbol.  */
+		elf_hppa_opd_fptr_reloc (info, opd_off, fptr_off);
 	      }
 	  }
 	else
-	  off = hh->opd_offset;
+	  opd_off = hh->opd_offset;
 
 	if (hh == NULL || hh->want_opd)
 	  /* We want the value of the OPD offset for this symbol.  */
-	  value = off + sopd->output_offset + sopd->output_section->vma;
+	  value = opd_off + sopd->output_offset + sopd->output_section->vma;
 	else
 	  /* We want the address of the symbol.  */
 	  value += addend;
@@ -4066,6 +4391,12 @@ elf64_hppa_relocate_section (bfd *output_bfd,
 	    }
 	}
 
+      /* Ensure symbol isn't undefined.  */
+      BFD_ASSERT (r_symndx != STN_UNDEF);
+
+      /* Ensure input section hasn't been discarded.  */
+      BFD_ASSERT (!discarded_section (input_section));
+
       if (sym_sec != NULL && discarded_section (sym_sec))
 	RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
 					 rel, 1, relend, R_PARISC_NONE,
@@ -4076,7 +4407,7 @@ elf64_hppa_relocate_section (bfd *output_bfd,
 
       r = elf_hppa_final_link_relocate (rel, input_bfd, output_bfd,
 					input_section, contents,
-					relocation, info, sym_sec,
+					relocation, info, sym, sym_sec,
 					eh);
 
       if (r != bfd_reloc_ok)
@@ -4202,6 +4533,7 @@ static const struct elf_size_info hppa64_elf_size_info =
 					elf64_hppa_finish_dynamic_sections
 #define elf_backend_grok_prstatus	elf64_hppa_grok_prstatus
 #define elf_backend_grok_psinfo		elf64_hppa_grok_psinfo
+#define elf_backend_gc_mark_hook	elf64_hppa_gc_mark_hook
 
 /* Stuff for the BFD linker: */
 #define bfd_elf64_bfd_link_hash_table_create \
@@ -4225,6 +4557,7 @@ static const struct elf_size_info hppa64_elf_size_info =
 #define elf_backend_link_output_symbol_hook \
 	elf64_hppa_link_output_symbol_hook
 
+#define elf_backend_can_gc_sections	1
 #define elf_backend_want_got_plt	0
 #define elf_backend_plt_readonly	0
 #define elf_backend_want_plt_sym	0
diff --git a/ld/emulparams/elf64hppa.sh b/ld/emulparams/elf64hppa.sh
index b0b43f7ecde..5afe0e2714a 100644
--- a/ld/emulparams/elf64hppa.sh
+++ b/ld/emulparams/elf64hppa.sh
@@ -3,7 +3,7 @@ ELFSIZE=64
 OUTPUT_FORMAT="elf64-hppa"
 NO_REL_RELOCS=yes
 TEXT_START_ADDR=0x4000000000001000
-DATA_ADDR=0x8000000000001000
+DATA_ADDR=0x8000000100000000
 TARGET_PAGE_SIZE=4096
 MAXPAGESIZE="CONSTANT (MAXPAGESIZE)"
 LIB_PATH="=/usr/lib/pa20_64:=/opt/langtools/lib/pa20_64"
@@ -12,10 +12,11 @@ LIB_PATH="=/usr/lib/pa20_64:=/opt/langtools/lib/pa20_64"
 # data to some reasonable value.  Of course nobody knows what reasoanble
 # really is, so we just use the same values that HP's linker uses.
 SHLIB_TEXT_START_ADDR=0x4000000000001000
-SHLIB_DATA_ADDR=0x8000000000001000
+SHLIB_DATA_ADDR=0x8000000100000000
 
 ARCH=hppa
 MACHINE=hppa2.0w
+NOP=0x08000240
 ENTRY="main"
 TEMPLATE_NAME=elf
 GENERATE_SHLIB_SCRIPT=yes
@@ -30,7 +31,33 @@ OTHER_READONLY_SECTIONS="
 OTHER_READWRITE_SECTIONS="
   .PARISC.pfa_count ${RELOCATING-0} : { *(.PARISC.pfa_count) }
   .PARISC.global ${RELOCATING-0} : { *(.PARISC.global) }
+  .data.rel     ${RELOCATING-0} : { *(.data.rel.local*) }
   .opd          ${RELOCATING-0} : { *(.opd) }
+  .HP.init      ${RELOCATING-0} :
+  {
+    KEEP (*(SORT_NONE(.HP.init)))
+  }
+  .preinit      ${RELOCATING-0} :
+  {
+    ${RELOCATING+${PREINIT_START}}
+    KEEP (*(SORT_NONE(.preinit)))
+    ${RELOCATING+${PREINIT_END}}
+  }
+
+# HP messed up the .init and .fini sections and they are expected
+# to contain arrays of function pointers.
+  .init         ${RELOCATING-0} :
+  {
+    ${RELOCATING+${INIT_START}}
+    KEEP (*(SORT_NONE(.init)))
+    ${RELOCATING+${INIT_END}}
+  }
+  .fini         ${RELOCATING-0} :
+  {
+    ${RELOCATING+${FINI_START}}
+    KEEP (*(SORT_NONE(.fini)))
+    ${RELOCATING+${FINI_END}}
+  }
   ${RELOCATING+PROVIDE (__gp = .);}
   .plt          ${RELOCATING-0} : { *(.plt) }
   .dlt          ${RELOCATING-0} : { *(.dlt) }"
@@ -42,35 +69,46 @@ OTHER_BSS_SECTIONS="
   .hbss         ${RELOCATING-0} : { *(.hbss) }
   .tbss         ${RELOCATING-0} : { *(.tbss) }"
 
-#OTHER_SYMBOLS='PROVIDE (__TLS_SIZE = SIZEOF (.tbss));'
+# OTHER_SYMBOLS='PROVIDE (__TLS_SIZE = SIZEOF (.tbss));'
+
+# These symbols need to be provided in final relocations.
 OTHER_SYMBOLS='
+  PROVIDE (__SYSTEM_ID = 0x214);
+  PROVIDE (_FPU_STATUS = 0x0);
   PROVIDE (__TLS_SIZE = 0);
   PROVIDE (__TLS_INIT_SIZE = 0);
   PROVIDE (__TLS_INIT_START = 0);
   PROVIDE (__TLS_INIT_A = 0);
-  PROVIDE (__TLS_PREALLOC_DTV_A = 0);'
+  PROVIDE (__TLS_PREALLOC_DTV_A = 0);
+  PROVIDE (__SYSTEM_ID_D = 0);
+  PROVIDE (__TLS_SIZE_D = 0);
+  PROVIDE (__FPU_REVISION = 0);
+  PROVIDE (__FPU_MODEL = 0);
+  PROVIDE (__CPU_REVISION = 0);
+  PROVIDE (__CPU_KEYBITS_1 = 0);
+  PROVIDE (__LOAD_INFO = 0);
+  PROVIDE (__ARGC = 0);
+  PROVIDE (__ARGV = 0);
+  PROVIDE (__ENVP = 0);
+  PROVIDE (__libdl_jmp_tbl = 0);
+  PROVIDE (__systab = 0);'
 
 # HPs use .dlt where systems use .got.  Sigh.
 OTHER_GOT_RELOC_SECTIONS="
   .rela.dlt     ${RELOCATING-0} : { *(.rela.dlt) }
   .rela.opd     ${RELOCATING-0} : { *(.rela.opd) }"
 
-# We're not actually providing a symbol anymore (due to the inability to be
-# safe in regards to shared libraries). So we just allocate the hunk of space
-# unconditionally, but do not mess around with the symbol table.
-DATA_START_SYMBOLS='. += 16;'
-
 DATA_PLT=
 PLT_BEFORE_GOT=
 
 # .dynamic should be at the start of the .text segment.
 TEXT_DYNAMIC=
 
-# The linker is required to define these two symbols.
-OTHER_SYMBOLS='PROVIDE (__SYSTEM_ID = 0x214); PROVIDE (_FPU_STATUS = 0x0);'
 # The PA64 ELF port needs two additional initializer sections and also wants
 # a start/end symbol pair for the .init and .fini sections.
-INIT_START='KEEP (*(.HP.init)); PROVIDE (__preinit_start = .); KEEP (*(.preinit)); PROVIDE (__preinit_end = .); PROVIDE (__init_start = .);'
+PREINIT_START='PROVIDE (__preinit_start = .);'
+PREINIT_END='PROVIDE (__preinit_end = .);'
+INIT_START='PROVIDE (__init_start = .);'
 INIT_END='PROVIDE (__init_end = .);'
 FINI_START='PROVIDE (__fini_start = .);'
 FINI_END='PROVIDE (__fini_end = .);'
diff --git a/ld/emulparams/hppa64linux.sh b/ld/emulparams/hppa64linux.sh
index 3caad892dbf..d72c6bb9a84 100644
--- a/ld/emulparams/hppa64linux.sh
+++ b/ld/emulparams/hppa64linux.sh
@@ -7,6 +7,7 @@ TARGET_PAGE_SIZE=0x10000
 MAXPAGESIZE="CONSTANT (MAXPAGESIZE)"
 ARCH=hppa
 MACHINE=hppa2.0w
+NOP=0x08000240
 ENTRY="main"
 TEMPLATE_NAME=elf
 GENERATE_SHLIB_SCRIPT=yes
@@ -40,11 +41,6 @@ OTHER_GOT_RELOC_SECTIONS="
   .rela.dlt     ${RELOCATING-0} : { *(.rela.dlt) }
   .rela.opd     ${RELOCATING-0} : { *(.rela.opd) }"
 
-# We're not actually providing a symbol anymore (due to the inability to be
-# safe in regards to shared libraries). So we just allocate the hunk of space
-# unconditionally, but do not mess around with the symbol table.
-DATA_START_SYMBOLS='. += 16;'
-
 DATA_PLT=
 PLT_BEFORE_GOT=
 
diff --git a/ld/scripttempl/elf64hppa.sc b/ld/scripttempl/elf64hppa.sc
index 6b92ba58f5a..d742675fb8c 100644
--- a/ld/scripttempl/elf64hppa.sc
+++ b/ld/scripttempl/elf64hppa.sc
@@ -12,7 +12,7 @@
 #	SMALL_DATA_DTOR - .dtors contains small data.
 #	DATA_ADDR - if end-of-text-plus-one-page isn't right for data start
 #	INITIAL_READONLY_SECTIONS - at start of text segment
-#	OTHER_READONLY_SECTIONS - other than .text .init .rodata ...
+#	OTHER_READONLY_SECTIONS - other than .text .rodata ...
 #		(e.g., .PARISC.milli)
 #	OTHER_TEXT_SECTIONS - these get put in .text when relocating
 #	OTHER_READWRITE_SECTIONS - other than .data .bss .ctors .sdata ...
@@ -400,13 +400,6 @@ if test -z "${NON_ALLOC_DYN}"; then
 fi
 
 cat <<EOF
-  .init         ${RELOCATING-0} :
-  {
-    ${RELOCATING+${INIT_START}}
-    KEEP (*(SORT_NONE(.init)))
-    ${RELOCATING+${INIT_END}}
-  } =${NOP-0}
-
   ${TEXT_PLT+${PLT}}
   ${TINY_READONLY_SECTION}
   .text         ${RELOCATING-0} :
@@ -417,12 +410,6 @@ cat <<EOF
     *(.gnu.warning)
     ${RELOCATING+${OTHER_TEXT_SECTIONS}}
   } =${NOP-0}
-  .fini         ${RELOCATING-0} :
-  {
-    ${RELOCATING+${FINI_START}}
-    KEEP (*(SORT_NONE(.fini)))
-    ${RELOCATING+${FINI_END}}
-  } =${NOP-0}
   ${RELOCATING+PROVIDE (__${ETEXT_NAME} = .);}
   ${RELOCATING+PROVIDE (_${ETEXT_NAME} = .);}
   ${RELOCATING+PROVIDE (${ETEXT_NAME} = .);}
@@ -500,6 +487,8 @@ cat <<EOF
     ${RELOCATING+*(.dynbss)}
     *(.bss${RELOCATING+ .bss.* .gnu.linkonce.b.*})
     ${RELOCATING+*(COMMON)
+    /* Provide 16 bytes for HP_LOAD map.  */
+    . += 16;
     /* Align here to ensure that the .bss section occupies space up to
        _end.  Align after .bss to ensure correct alignment even if the
        .bss section disappears because there are no input sections.


More information about the Binutils-cvs mailing list