[binutils-gdb] hppa64: Improve HP-UX support and fix some relocation issues

John David Anglin danglin@sourceware.org
Sun Mar 15 01:04:37 GMT 2026


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

commit b219e706ece645ba5d03eaa90b0215f3e2ed8dee
Author: John David Anglin <danglin@gcc.gnu.org>
Date:   Sat Mar 14 21:03:31 2026 -0400

    hppa64: Improve HP-UX support and fix some relocation issues
    
    With this patch, gcc-16 test results are now similar to those
    using the HP ld.
    
    The change fixes dynamic symbol handling.  At the moment, we
    only have a single stub section and no support for long pc-relative
    calls.  So, we only need to redirect pc-relative branches through
    the PLT when the call is to a dynamic function.
    
    The change to elf64_hppa_finalize_dynreloc() fixes C++ VTT support.
    This fixed many tests in the gcc g++ and libstdc++ testsuites.
    
    The next step is to add support for long pc-relative branches via
    the PLT.
    
    2026-03-14  John David Anglin  <danglin@gcc.gnu.org>
    
    bfd/ChangeLog:
    
            * elf64-hppa.c (elf64_hppa_check_relocs): Only set NEED_PLT
            and NEED_STUB for symbols with function types.
            (elf64_hppa_dynamic_symbol_p): Return false for millicode
            symbols.
            (allocate_global_data_dlt): Only allocate DLT entries for
            symbols that are dynamic or defined.  Clear hh->want_dlt
            if we don't want a DLT entry.
            (allocate_global_data_plt): Only allocate PLT entries for
            dynamic symbols.
            (allocate_global_data_stub): Likewise, Only allocate stubs
            for dynamic symbols.
            (elf64_hppa_create_dynamic_sections): Fix flags for .dynamic
            section and remove duplicated flags for other dynamic
            sections.
            (allocate_dynrel_entries): Fix DLT and PLT allocations.
            (elf64_hppa_late_size_sections): Don't sort relocations.
            Tweak code to set section used to set __text_seg.
            (elf64_hppa_finish_dynamic_symbol): Use eh->dynindx instead
            of hh->eh.dynindx.  Don't call elf64_hppa_dynamic_symbol_p
            to determine whether PLT entries and stubs need initialization.
            (elf64_hppa_finalize_dynreloc): Add rent->addend to value
            calculation.
            (elf_hppa_remark_useless_dynamic_symbols): Revise symbols
            checked.
            (elf_hppa_final_link_relocate): Revise code to redirect
            pc-relative calls to stubs.
            (elf_backend_want_p_paddr_set_to_zero): Define to 1 on HP-UX
            target.

Diff:
---
 bfd/elf64-hppa.c | 180 +++++++++++++++++++++++++------------------------------
 1 file changed, 82 insertions(+), 98 deletions(-)

diff --git a/bfd/elf64-hppa.c b/bfd/elf64-hppa.c
index fbe29e2b6b4..470c28f75d3 100644
--- a/bfd/elf64-hppa.c
+++ b/bfd/elf64-hppa.c
@@ -713,7 +713,10 @@ elf64_hppa_check_relocs (bfd *abfd,
 	case R_PARISC_PCREL16DF:
 	  /* Function calls might need to go through the .plt, and
 	     might need a long branch stub.  */
-	  if (hh != NULL && hh->eh.type != STT_PARISC_MILLI)
+	  if (hh != NULL
+	      && (hh->eh.type == STT_FUNC
+		  || hh->eh.type == STT_PARISC_MILLI
+		  || hh->eh.type == STT_NOTYPE))
 	    need_entry = (NEED_PLT | NEED_STUB);
 	  else
 	    need_entry = 0;
@@ -727,6 +730,10 @@ elf64_hppa_check_relocs (bfd *abfd,
 	case R_PARISC_PLTOFF16F:
 	case R_PARISC_PLTOFF16WF:
 	case R_PARISC_PLTOFF16DF:
+	  BFD_ASSERT (hh != NULL
+		      && (hh->eh.type == STT_FUNC
+			  || hh->eh.type == STT_PARISC_MILLI
+			  || hh->eh.type == STT_NOTYPE));
 	  need_entry = (NEED_PLT);
 	  break;
 
@@ -981,19 +988,13 @@ static bool
 elf64_hppa_dynamic_symbol_p (struct elf_link_hash_entry *eh,
 			     struct bfd_link_info *info)
 {
+  if (eh->type == STT_PARISC_MILLI)
+    return false;
+
   /* ??? What, if anything, needs to happen wrt STV_PROTECTED symbols
      and relocations that retrieve a function descriptor?  Assume the
      worst for now.  */
-  if (_bfd_elf_dynamic_symbol_p (eh, info, 1))
-    {
-      /* ??? Why is this here and not elsewhere is_local_label_name.  */
-      if (eh->root.root.string[0] == '$' && eh->root.root.string[1] == '$')
-	return false;
-
-      return true;
-    }
-  else
-    return false;
+  return _bfd_elf_dynamic_symbol_p (eh, info, 1);
 }
 
 /* Mark all functions exported by this file so that we can later allocate
@@ -1038,11 +1039,16 @@ allocate_global_data_dlt (struct elf_link_hash_entry *eh, void *data)
   struct elf64_hppa_link_hash_entry *hh = hppa_elf_hash_entry (eh);
   struct elf64_hppa_allocate_data *x = (struct elf64_hppa_allocate_data *)data;
 
-  if (hh->want_dlt)
+  if (hh->want_dlt
+      && (eh->dynindx != -1
+	  || eh->root.type == bfd_link_hash_defined
+	  || eh->root.type == bfd_link_hash_defweak))
     {
       hh->dlt_offset = x->ofs;
       x->ofs += DLT_ENTRY_SIZE;
     }
+  else
+    hh->want_dlt = 0;
   return true;
 }
 
@@ -1054,11 +1060,10 @@ allocate_global_data_plt (struct elf_link_hash_entry *eh, void *data)
   struct elf64_hppa_link_hash_entry *hh = hppa_elf_hash_entry (eh);
   struct elf64_hppa_allocate_data *x = (struct elf64_hppa_allocate_data *) data;
 
-  if (hh->want_plt
-      && elf64_hppa_dynamic_symbol_p (eh, x->info)
-      && !((eh->root.type == bfd_link_hash_defined
-	    || eh->root.type == bfd_link_hash_defweak)
-	   && eh->root.u.def.section->output_section != NULL))
+  /* Allocate a PLT entry if the function is dynamic.  Currently, we
+     only have one stub section, so there is no point in allocating
+     PLT entries and stubs for long branch support.  */
+  if (hh->want_plt && elf64_hppa_dynamic_symbol_p (eh, x->info))
     {
       hh->plt_offset = x->ofs;
       x->ofs += PLT_ENTRY_SIZE;
@@ -1087,11 +1092,10 @@ allocate_global_data_stub (struct elf_link_hash_entry *eh, void *data)
   struct elf64_hppa_link_hash_entry *hh = hppa_elf_hash_entry (eh);
   struct elf64_hppa_allocate_data *x = (struct elf64_hppa_allocate_data *)data;
 
-  if (hh->want_stub
-      && elf64_hppa_dynamic_symbol_p (eh, x->info)
-      && !((eh->root.type == bfd_link_hash_defined
-	    || eh->root.type == bfd_link_hash_defweak)
-	   && eh->root.u.def.section->output_section != NULL))
+  /* Allocate a stub if the function is dynamic.  Currently, we
+    only have one stub section, so there is no point in allocating
+    PLT entries and stubs for long branch support.  */
+  if (hh->want_stub && elf64_hppa_dynamic_symbol_p (eh, x->info))
     {
       hh->stub_offset = x->ofs;
       x->ofs += sizeof (plt_stub);
@@ -1357,12 +1361,24 @@ elf64_hppa_create_dynamic_sections (bfd *abfd,
 				    struct bfd_link_info *info)
 {
   asection *s;
+  flagword flags;
   struct elf64_hppa_link_hash_table *hppa_info;
 
   hppa_info = hppa_link_hash_table (info);
   if (hppa_info == NULL)
     return false;
 
+  flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
+	   | SEC_LINKER_CREATED | SEC_READONLY);
+
+  /* We need a read-only .dynamic section.  */
+  s = bfd_get_linker_section (abfd, ".dynamic");
+  if (s != NULL)
+    {
+      if (!bfd_set_section_flags (s, flags))
+	return false;
+    }
+
   if (! get_stub (abfd, info, hppa_info))
     return false;
 
@@ -1375,45 +1391,25 @@ elf64_hppa_create_dynamic_sections (bfd *abfd,
   if (! get_opd (abfd, info, hppa_info))
     return false;
 
-  s = bfd_make_section_anyway_with_flags (abfd, ".rela.dlt",
-					  (SEC_ALLOC | SEC_LOAD
-					   | SEC_HAS_CONTENTS
-					   | SEC_IN_MEMORY
-					   | SEC_READONLY
-					   | SEC_LINKER_CREATED));
+  s = bfd_make_section_anyway_with_flags (abfd, ".rela.dlt", flags);
   if (s == NULL
       || !bfd_set_section_alignment (s, 3))
     return false;
   hppa_info->dlt_rel_sec = s;
 
-  s = bfd_make_section_anyway_with_flags (abfd, ".rela.plt",
-					  (SEC_ALLOC | SEC_LOAD
-					   | SEC_HAS_CONTENTS
-					   | SEC_IN_MEMORY
-					   | SEC_READONLY
-					   | SEC_LINKER_CREATED));
+  s = bfd_make_section_anyway_with_flags (abfd, ".rela.plt", flags);
   if (s == NULL
       || !bfd_set_section_alignment (s, 3))
     return false;
   hppa_info->root.srelplt = s;
 
-  s = bfd_make_section_anyway_with_flags (abfd, ".rela.data",
-					  (SEC_ALLOC | SEC_LOAD
-					   | SEC_HAS_CONTENTS
-					   | SEC_IN_MEMORY
-					   | SEC_READONLY
-					   | SEC_LINKER_CREATED));
+  s = bfd_make_section_anyway_with_flags (abfd, ".rela.data", flags);
   if (s == NULL
       || !bfd_set_section_alignment (s, 3))
     return false;
   hppa_info->other_rel_sec = s;
 
-  s = bfd_make_section_anyway_with_flags (abfd, ".rela.opd",
-					  (SEC_ALLOC | SEC_LOAD
-					   | SEC_HAS_CONTENTS
-					   | SEC_IN_MEMORY
-					   | SEC_READONLY
-					   | SEC_LINKER_CREATED));
+  s = bfd_make_section_anyway_with_flags (abfd, ".rela.opd", flags);
   if (s == NULL
       || !bfd_set_section_alignment (s, 3))
     return false;
@@ -1468,29 +1464,18 @@ allocate_dynrel_entries (struct elf_link_hash_entry *eh, void *data)
 
   /* Take care of the GOT and PLT relocations.  */
 
-  if ((dynamic_symbol || shared) && hh->want_dlt)
-    hppa_info->dlt_rel_sec->size += sizeof (Elf64_External_Rela);
-
   /* If we are building a shared library, then every symbol that has an
      opd entry will need an EPLT relocation to relocate the symbol's address
      and __gp value based on the runtime load address.  */
-  if (shared && hh->want_opd)
+  if (hh->want_opd && shared)
     hppa_info->opd_rel_sec->size += sizeof (Elf64_External_Rela);
 
-  if (hh->want_plt && dynamic_symbol)
-    {
-      bfd_size_type t = 0;
-
-      /* Dynamic symbols get one IPLT relocation.  Local symbols in
-	 shared libraries get two REL relocations.  Local symbols in
-	 main applications get nothing.  */
-      if (dynamic_symbol)
-	t = sizeof (Elf64_External_Rela);
-      else if (shared)
-	t = 2 * sizeof (Elf64_External_Rela);
+  if (hh->want_dlt && (dynamic_symbol || shared))
+    hppa_info->dlt_rel_sec->size += sizeof (Elf64_External_Rela);
 
-      hppa_info->root.srelplt->size += t;
-    }
+  /* Currently, we only allocate PLT slots for dynamic symbols.  */
+  if (hh->want_plt)
+    hppa_info->root.srelplt->size += sizeof (Elf64_External_Rela);
 
   /* If no dynamic sections we can't have dynamic relocs.  */
   if (!hppa_info->root.dynamic_sections_created)
@@ -1651,6 +1636,9 @@ elf64_hppa_late_size_sections (bfd *output_bfd, struct bfd_link_info *info)
   if (dynobj == NULL)
     return true;
 
+  /* Don't sort relocations.  */
+  info->combreloc = 0;
+
   /* Mark each function this program exports so that we will allocate
      space in the .opd section for each function's FPTR.  If we are
      creating dynamic sections, change the dynamic index of millicode
@@ -1837,7 +1825,7 @@ elf64_hppa_late_size_sections (bfd *output_bfd, struct bfd_link_info *info)
       asection *s;
 
       s = bfd_get_section_by_name (info->output_bfd, ".dynamic");
-      if (s == NULL)
+      if (s == NULL || (s->flags & SEC_CODE) == 0)
 	s = bfd_get_section_by_name (info->output_bfd, ".text");
       if (s != NULL)
 	{
@@ -2141,8 +2129,7 @@ elf64_hppa_finish_dynamic_symbol (bfd *output_bfd,
     }
 
   /* Initialize a .plt entry if requested.  */
-  if (hh->want_plt
-      && elf64_hppa_dynamic_symbol_p (eh, info))
+  if (hh->want_plt)
     {
       bfd_vma value;
       Elf_Internal_Rela rel;
@@ -2188,7 +2175,7 @@ elf64_hppa_finish_dynamic_symbol (bfd *output_bfd,
 	 address.  */
       rel.r_offset = (hh->plt_offset + splt->output_offset
 		      + splt->output_section->vma);
-      rel.r_info = ELF64_R_INFO (hh->eh.dynindx, R_PARISC_IPLT);
+      rel.r_info = ELF64_R_INFO (eh->dynindx, R_PARISC_IPLT);
       rel.r_addend = 0;
 
       loc = spltrel->contents;
@@ -2197,8 +2184,7 @@ elf64_hppa_finish_dynamic_symbol (bfd *output_bfd,
     }
 
   /* Initialize an external call stub entry if requested.  */
-  if (hh->want_stub
-      && elf64_hppa_dynamic_symbol_p (eh, info))
+  if (hh->want_stub)
     {
       bfd_vma value;
       int insn;
@@ -2545,6 +2531,7 @@ elf64_hppa_finalize_dynreloc (struct elf_link_hash_entry *eh,
 	        {
 		  if (!hh->want_opd)
 		    continue;
+		  BFD_ASSERT (rent->addend == 0);
 		  sopd = hppa_info->opd_sec;
 		  value = (hh->opd_offset + sopd->output_offset
 		  	   + sopd->output_section->vma);
@@ -2563,7 +2550,8 @@ elf64_hppa_finalize_dynreloc (struct elf_link_hash_entry *eh,
 
 		  value = (eh->root.u.def.value
 			   + eh->root.u.def.section->output_section->vma
-			   + eh->root.u.def.section->output_offset);
+			   + eh->root.u.def.section->output_offset
+			   + rent->addend);
 
 		  if (eh->root.u.def.section->flags & SEC_READONLY)
 		    baseh = hppa_info->text_hash_entry;
@@ -3056,17 +3044,14 @@ elf_hppa_remark_useless_dynamic_symbols (struct elf_link_hash_entry *h,
 static bool
 elf_hppa_is_dynamic_loader_symbol (const char *name)
 {
-  return (! strcmp (name, "__CPU_REVISION")
-	  || ! strcmp (name, "__CPU_KEYBITS_1")
-	  || ! strcmp (name, "__SYSTEM_ID_D")
-	  || ! strcmp (name, "__FPU_MODEL")
-	  || ! strcmp (name, "__FPU_REVISION")
-	  || ! strcmp (name, "__ARGC")
-	  || ! strcmp (name, "__ARGV")
-	  || ! strcmp (name, "__ENVP")
-	  || ! strcmp (name, "__TLS_SIZE_D")
-	  || ! strcmp (name, "__LOAD_INFO")
-	  || ! strcmp (name, "__systab"));
+  /* HP-UX linker provided symbols.  */
+  return (! strcmp (name, "__SYSTEM_ID")
+	  || ! strcmp (name, "_FPU_STATUS")
+	  || ! strcmp (name, "__TLS_SIZE")
+	  || ! strcmp (name, "__TLS_INIT_SIZE")
+	  || ! strcmp (name, "__TLS_INIT_START")
+	  || ! strcmp (name, "__TLS_INIT_A")
+	  || ! strcmp (name, "__TLS_PREALLOC_DTV_A"));
 }
 
 /* Record the lowest address for the data and text segments.  */
@@ -3528,10 +3513,9 @@ elf_hppa_final_link_relocate (Elf_Internal_Rela *rel,
     case R_PARISC_PCREL16WF:
     case R_PARISC_PCREL16DF:
       {
-	/* If this is a call to a function defined in another dynamic
-	   library, then redirect the call to the local stub for this
-	   function.  */
-	if (sym_sec == NULL || sym_sec->output_section == NULL)
+	/* If this is a pc-relative call to a dynamic function, then
+	   redirect the call to the local stub for this function.  */
+	if (hh && hh->want_stub)
 	  value = (hh->stub_offset + hppa_info->stub_sec->output_offset
 		   + hppa_info->stub_sec->output_section->vma);
 
@@ -3562,10 +3546,9 @@ elf_hppa_final_link_relocate (Elf_Internal_Rela *rel,
     case R_PARISC_PCREL17C:
     case R_PARISC_PCREL17R:
       {
-	/* If this is a call to a function defined in another dynamic
-	   library, then redirect the call to the local stub for this
-	   function.  */
-	if (sym_sec == NULL || sym_sec->output_section == NULL)
+	/* If this is a pc-relative call to a dynamic function, then
+	   redirect the call to the local stub for this function.  */
+	if (hh && hh->want_stub)
 	  value = (hh->stub_offset + hppa_info->stub_sec->output_offset
 		   + hppa_info->stub_sec->output_section->vma);
 
@@ -4132,10 +4115,9 @@ elf_hppa_final_link_relocate (Elf_Internal_Rela *rel,
 
     case R_PARISC_PCREL32:
       {
-	/* If this is a call to a function defined in another dynamic
-	   library, then redirect the call to the local stub for this
-	   function.  */
-	if (sym_sec == NULL || sym_sec->output_section == NULL)
+	/* If this is a pc-relative call to a dynamic function, then
+	   redirect the call to the local stub for this function.  */
+	if (hh && hh->want_stub)
 	  value = (hh->stub_offset + hppa_info->stub_sec->output_offset
 		   + hppa_info->stub_sec->output_section->vma);
 
@@ -4151,10 +4133,9 @@ elf_hppa_final_link_relocate (Elf_Internal_Rela *rel,
 
     case R_PARISC_PCREL64:
       {
-	/* If this is a call to a function defined in another dynamic
-	   library, then redirect the call to the local stub for this
-	   function.  */
-	if (sym_sec == NULL || sym_sec->output_section == NULL)
+	/* If this is a pc-relative call to a dynamic function, then
+	   redirect the call to the local stub for this function.  */
+	if (hh && hh->want_stub)
 	  value = (hh->stub_offset + hppa_info->stub_sec->output_offset
 		   + hppa_info->stub_sec->output_section->vma);
 
@@ -4523,7 +4504,8 @@ static const struct elf_size_info hppa64_elf_size_info =
 #define ELF_TARGET_ID			HPPA64_ELF_DATA
 #define ELF_MACHINE_CODE		EM_PARISC
 /* This is not strictly correct.  The maximum page size for PA2.0 is
-   64M.  But everything still uses 4k.  */
+   64M.  But everything still uses 4k.  However, the HP-UX linker
+   aligns the file offset for the data segment to 256k.  */
 #define ELF_MAXPAGESIZE			0x1000
 #define ELF_OSABI			ELFOSABI_HPUX
 #define ELF_OSABI_EXACT			1
@@ -4598,6 +4580,7 @@ static const struct elf_size_info hppa64_elf_size_info =
 #define elf_backend_special_sections	elf64_hppa_special_sections
 #define elf_backend_action_discarded	elf_hppa_action_discarded
 #define elf_backend_section_from_phdr   elf64_hppa_section_from_phdr
+#define elf_backend_want_p_paddr_set_to_zero 1
 
 #define elf64_bed			elf64_hppa_hpux_bed
 
@@ -4613,5 +4596,6 @@ static const struct elf_size_info hppa64_elf_size_info =
 #define elf64_bed			elf64_hppa_linux_bed
 #undef elf_backend_special_sections
 #define elf_backend_special_sections	(elf64_hppa_special_sections + 1)
+#undef elf_backend_want_p_paddr_set_to_zero
 
 #include "elf64-target.h"


More information about the Binutils-cvs mailing list