[binutils-gdb] hppa64: Mostly fix symbol versioning support

John David Anglin danglin@sourceware.org
Sun Oct 26 22:21:15 GMT 2025


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

commit 883e39544f5c65ff04eb18a40bf712dea8048693
Author: John David Anglin <danglin@gcc.gnu.org>
Date:   Sun Oct 26 18:20:37 2025 -0400

    hppa64: Mostly fix symbol versioning support
    
    The dot prefix used for R_PARISC_EPLT relocations causes issues
    for symbol version support as no version section is defined for
    these symbols.  This causes the linker to exit with an error.
    
    This change modifies the handling of EPLT relocations to use
    offsets relative to a __text_seg base symbol.  This symbol is
    defined in the same way as the HP linker (a section symbol for
    the .dynamic section).
    
    This mostly fixes the symbol versioning support.  There are
    still issues caused by the munging of the value and section
    of dynamic symbols.  The value modifies the sorting of the
    dynamic table by number.  The section changes the type of
    text symbols to data symbols.  I don't think the section munging
    is actually needed but that's an issue for another patch.
    
    2025-10-26  John David Anglin  <danglin@gcc.gnu.org>
    
    bfd/ChangeLog:
    
            * elf64-hppa.c (USE_DOT_ELPT_PREFIX): Define.
            (struct elf_link_hash_entry): Add text_segment field.
            (allocate_global_data_opd): Compute hppa_info.
            Condition old dot prefix code on USE_DOT_ELPT_PREFIX.
            Add new code to setup __text_seg hash table entry.
            (elf64_hppa_finalize_opd): Check hh.  Rework to output
            relocation using __text_seg base.
            (elf64_hppa_finish_dynamic_sections): Remove duplicate
            comment.
            (elf_hppa_final_link_relocate): Move code to initialize
            the segment base values forward.

Diff:
---
 bfd/elf64-hppa.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 77 insertions(+), 12 deletions(-)

diff --git a/bfd/elf64-hppa.c b/bfd/elf64-hppa.c
index 77c1505606f..5bfa0d58883 100644
--- a/bfd/elf64-hppa.c
+++ b/bfd/elf64-hppa.c
@@ -39,6 +39,10 @@ extern const bfd_target hppa_elf64_linux_vec;
 
 #define ELF_DYNAMIC_INTERPRETER "/usr/lib/pa20_64/dld.sl"
 
+/* Use dot prefix code for EPLT relocations.  Breaks symbol version
+   support but helps in debugging .rela.opd section.  */
+#define USE_DOT_ELPT_PREFIX	0
+
 /* The stub is supposed to load the target address and target's DP
    value out of the PLT, then do an external branch to the target
    address.
@@ -137,6 +141,9 @@ struct elf64_hppa_link_hash_table
   bfd_vma text_segment_base;
   bfd_vma data_segment_base;
 
+  /* Hash entry for __text_seg.  */
+  struct elf_link_hash_entry *text_segment;
+
   /* We build tables to map from an input section back to its
      symbol index.  This is the BFD for which we currently have
      a map.  */
@@ -1076,6 +1083,11 @@ allocate_global_data_opd (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;
+  struct elf64_hppa_link_hash_table *hppa_info;
+
+  hppa_info = hppa_link_hash_table (x->info);
+  if (hppa_info == NULL)
+    return false;
 
   if (hh->want_opd)
     {
@@ -1120,7 +1132,7 @@ allocate_global_data_opd (struct elf_link_hash_entry *eh, void *data)
 	     in dynamic relocs.  But name munging does make the result
 	     much easier to debug.  ie, the EPLT reloc will reference
 	     a symbol like .foobar, instead of .text + offset.  */
-	  if (bfd_link_pic (x->info) && eh)
+	  if (USE_DOT_ELPT_PREFIX && bfd_link_pic (x->info))
 	    {
 	      char *new_name;
 	      struct elf_link_hash_entry *nh;
@@ -1137,7 +1149,35 @@ allocate_global_data_opd (struct elf_link_hash_entry *eh, void *data)
 
 	      if (! bfd_elf_link_record_dynamic_symbol (x->info, nh))
 		return false;
-	     }
+	    }
+
+	  /* Add __text_seg symbol to dynamic table.  */
+	  if (!USE_DOT_ELPT_PREFIX
+	      && bfd_link_pic (x->info)
+	      && !hppa_info->text_segment)
+	    {
+	      struct elf_link_hash_entry *nh;
+
+	      nh = elf_link_hash_lookup (elf_hash_table (x->info),
+					 "__text_seg", true, false, false);
+	      if (nh != NULL)
+		{
+		  asection *s;
+
+		  s = bfd_get_section_by_name (x->info->output_bfd,
+					       ".dynamic");
+
+		  nh->type = STT_SECTION;
+		  nh->root.type = bfd_link_hash_defined;
+		  nh->root.u.def.value = 0;
+		  nh->root.u.def.section = s;
+		  nh->forced_local = 1;
+		  nh->other = STV_DEFAULT;
+		  bfd_elf_link_record_dynamic_symbol (x->info, nh);
+		  hppa_info->text_segment = nh;
+		}
+	    }
+
 	  hh->opd_offset = x->ofs;
 	  x->ofs += OPD_ENTRY_SIZE;
 	}
@@ -2134,7 +2174,7 @@ elf64_hppa_finalize_opd (struct elf_link_hash_entry *eh, void *data)
   /* If we are generating a shared library, we must generate EPLT relocations
      for each entry in the .opd, even for static functions (they may have
      had their address taken).  */
-  if (bfd_link_pic (info) && hh->want_opd)
+  if (bfd_link_pic (info) && hh && hh->want_opd)
     {
       Elf_Internal_Rela rel;
       bfd_byte *loc;
@@ -2154,6 +2194,7 @@ elf64_hppa_finalize_opd (struct elf_link_hash_entry *eh, void *data)
 	 .opd entry for this symbol.  */
       rel.r_offset = (hh->opd_offset + sopd->output_offset
 		      + sopd->output_section->vma);
+      rel.r_addend = 0;
 
       /* If H is non-null, then we have an external symbol.
 
@@ -2179,10 +2220,13 @@ elf64_hppa_finalize_opd (struct elf_link_hash_entry *eh, void *data)
 	 function can not be directly referenced outside of its shared
 	 library.
 
+	 The downside of using dot prefixes is it breaks symbol version
+	 support.  Thus, we don't use it by default.
+
 	 We do have to play similar games for FPTR relocations in shared
 	 libraries, including those for static symbols.  See the FPTR
 	 handling in elf64_hppa_finalize_dynreloc.  */
-      if (eh)
+      if (USE_DOT_ELPT_PREFIX)
 	{
 	  char *new_name;
 	  struct elf_link_hash_entry *nh;
@@ -2198,8 +2242,29 @@ elf64_hppa_finalize_opd (struct elf_link_hash_entry *eh, void *data)
 	    dynindx = nh->dynindx;
 	  free (new_name);
 	}
+      else
+	{
+	  bfd_vma value, value2;
 
-      rel.r_addend = 0;
+	  /* First compute the address of this symbol.  */
+	  value = (eh->root.u.def.value
+		   + eh->root.u.def.section->output_section->vma
+		   + eh->root.u.def.section->output_offset);
+
+	  /* Compute the base address of the segmentwith this symbol.  */
+	  value2 = hppa_info->text_segment_base;
+
+	  /* Compute the difference between the symbol and the
+	     test segment base address.  */
+	  value -= value2;
+
+	  /* The result becomes the addend of the relocation.  */
+	  rel.r_addend += value;
+
+	  dynindx = hppa_info->text_segment->dynindx;
+	}
+
+      BFD_ASSERT (dynindx != -1);
       rel.r_info = ELF64_R_INFO (dynindx, R_PARISC_EPLT);
 
       loc = sopdrel->contents;
@@ -2467,8 +2532,8 @@ elf64_hppa_finish_dynamic_sections (bfd *output_bfd,
 			  elf64_hppa_finalize_dynreloc,
 			  info);
 
-  /* Finalize the contents of the .dlt section.  */
   dynobj = elf_hash_table (info)->dynobj;
+
   /* Finalize the contents of the .dlt section.  */
   elf_link_hash_traverse (elf_hash_table (info),
 			  elf64_hppa_finalize_dlt,
@@ -3183,6 +3248,12 @@ elf_hppa_final_link_relocate (Elf_Internal_Rela *rel,
   if (hppa_info == NULL)
     return bfd_reloc_notsupported;
 
+  /* Initialize the segment base values.  Needed for EPLT and SEGREL
+     relocations.  */
+  if (hppa_info->text_segment_base == (bfd_vma) -1)
+    bfd_map_over_sections (output_bfd, elf_hppa_record_segment_addrs,
+			   hppa_info);
+
   symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
   local_offsets = elf_local_got_offsets (input_bfd);
   insn = bfd_get_32 (input_bfd, hit_data);
@@ -3729,12 +3800,6 @@ elf_hppa_final_link_relocate (Elf_Internal_Rela *rel,
     case R_PARISC_SEGREL32:
     case R_PARISC_SEGREL64:
       {
-	/* If this is the first SEGREL relocation, then initialize
-	   the segment base values.  */
-	if (hppa_info->text_segment_base == (bfd_vma) -1)
-	  bfd_map_over_sections (output_bfd, elf_hppa_record_segment_addrs,
-				 hppa_info);
-
 	/* VALUE holds the absolute address.  We want to include the
 	   addend, then turn it into a segment relative address.


More information about the Binutils-cvs mailing list