]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
hppa64: Mostly fix symbol versioning support
authorJohn David Anglin <danglin@gcc.gnu.org>
Sun, 26 Oct 2025 22:20:37 +0000 (18:20 -0400)
committerJohn David Anglin <danglin@gcc.gnu.org>
Sun, 26 Oct 2025 22:20:37 +0000 (18:20 -0400)
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.

bfd/elf64-hppa.c

index 77c1505606f4ef0de54aabc9f00499e24f1c47d6..5bfa0d588839ee0e19cc12913390660b56042ea2 100644 (file)
@@ -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.