Fix problem where -relax could reorder multiple consecutive sets of the
[deliverable/binutils-gdb.git] / bfd / elf-hppa.h
index 65c009167c34dfd6a56c07daa2022d776fcb491b..99cc17e51f5d418175519016a22328b1cd4b3570 100644 (file)
@@ -69,6 +69,9 @@ static boolean elf_hppa_unmark_useless_dynamic_symbols
 static boolean elf_hppa_remark_useless_dynamic_symbols
   PARAMS ((struct elf_link_hash_entry *, PTR));
 
+static void elf_hppa_record_segment_addrs
+  PARAMS ((bfd *, asection *, PTR));
+
 /* ELF/PA relocation howto entries.  */
 
 static reloc_howto_type elf_hppa_howto_table[ELF_HOWTO_TABLE_SIZE] =
@@ -653,7 +656,13 @@ elf_hppa_final_write_processing (abfd, linker)
   else if (mach == 20)
     elf_elfheader (abfd)->e_flags |= EFA_PARISC_2_0;
   else if (mach == 25)
-    elf_elfheader (abfd)->e_flags |= EF_PARISC_WIDE | EFA_PARISC_2_0;
+    elf_elfheader (abfd)->e_flags |= (EF_PARISC_WIDE
+                                     | EFA_PARISC_2_0
+                                     /* The GNU tools have trapped without
+                                        option since 1993, so need to take
+                                        a step backwards with the ELF
+                                        based toolchains.  */
+                                     | EF_PARISC_TRAPNIL);
 }
 
 /* Return true if SYM represents a local label symbol.  */
@@ -810,6 +819,30 @@ elf_hppa_remark_useless_dynamic_symbols (h, data)
   return true;
 }
 
+/* Record the lowest address for the data and text segments.  */
+static void
+elf_hppa_record_segment_addrs (abfd, section, data)
+     bfd *abfd ATTRIBUTE_UNUSED;
+     asection *section;
+     PTR data;
+{
+  struct elf64_hppa_link_hash_table *hppa_info;
+  bfd_vma value;
+  hppa_info = (struct elf64_hppa_link_hash_table *)data;
+
+  value = section->vma - section->filepos;
+
+  if ((section->flags & (SEC_ALLOC | SEC_LOAD | SEC_READONLY)
+       == (SEC_ALLOC | SEC_LOAD | SEC_READONLY))
+      && value < hppa_info->text_segment_base)
+    hppa_info->text_segment_base = value;
+  else if ((section->flags & (SEC_ALLOC | SEC_LOAD | SEC_READONLY)
+       == (SEC_ALLOC | SEC_LOAD))
+      && value < hppa_info->data_segment_base)
+    hppa_info->data_segment_base = value;
+}
+
 /* Called after we have seen all the input files/sections, but before
    final symbol resolution and section placement has been determined.
 
@@ -823,35 +856,74 @@ elf_hppa_final_link (abfd, info)
 {
   boolean retval;
 
-  /* Make sure we've got ourselves a suitable __gp value.  */
-  if (!info->relocateable)
+  if (! info->relocateable)
     {
       struct elf_link_hash_entry *gp;
-      bfd_vma gp_val = 0;
-      asection *os;
+      bfd_vma gp_val;
+      struct elf64_hppa_link_hash_table *hppa_info;
+
+      hppa_info = elf64_hppa_hash_table (info);
 
-      /* Find the .opd section.  __gp's value should be the same as
-        the start of .PARISC.global section.  */
-      for (os = abfd->sections; os ; os = os->next)
+      /* The linker script defines a value for __gp iff it was referenced
+        by one of the objects being linked.  First try to find the symbol
+        in the hash table.  If that fails, just compute the value __gp
+        should have had.  */
+      gp = elf_link_hash_lookup (elf_hash_table (info), "__gp", false,
+                                false, false);
+
+      if (gp)
        {
-         /* This would be cleaner if we marked sections with an attribute
-            indicating they are short sections.  */
-         if (strcmp (os->name, ".PARISC.global") == 0)
-           break;
+
+         /* Adjust the value of __gp as we may want to slide it into the
+            .plt section so that the stubs can access PLT entries without
+            using an addil sequence.  */
+         gp->root.u.def.value += elf64_hppa_hash_table (info)->gp_offset;
+
+         gp_val = (gp->root.u.def.section->output_section->vma
+                   + gp->root.u.def.section->output_offset
+                   + gp->root.u.def.value);
        }
+      else
+       {
+         asection *sec;
+  
+
+         /* First look for a .plt section.  If found, then __gp is the
+            address of the .plt + gp_offset.
+
+            If no .plt is found, then look for .dlt, .opd and .data (in
+            that order) and set __gp to the base address of whichever section
+           is found first.  */
 
-      BFD_ASSERT (os != NULL)
+         sec = hppa_info->plt_sec;
+         if (sec)
+           gp_val = (sec->output_offset
+                     + sec->output_section->vma
+                     + hppa_info->gp_offset);
+         else
+           {
+             sec = hppa_info->dlt_sec;
+             if (!sec)
+               sec = hppa_info->opd_sec;
+             if (!sec)
+               sec = bfd_get_section_by_name (abfd, ".data");
+             if (!sec)
+               return false;
+
+             gp_val = sec->output_offset + sec->output_section->vma;
+           }
+       }
 
-      gp_val = (os->output_section->vma + os->output_offset);
-                  
-      gp = elf_link_hash_lookup (elf_hash_table (info), "__gp", true,
-                                true, false);
-      gp->root.type = bfd_link_hash_defined;
-      gp->root.u.def.section = os;
-      gp->root.u.def.value = 0;
+      /* Install whatever value we found/computed for __gp.  */
       _bfd_set_gp_value (abfd, gp_val);
     }
 
+  /* We need to know the base of the text and data segments so that we
+     can perform SEGREL relocations.  We will recore the base addresses
+     when we encounter the first SEGREL relocation.  */
+  elf64_hppa_hash_table (info)->text_segment_base = (bfd_vma)-1;
+  elf64_hppa_hash_table (info)->data_segment_base = (bfd_vma)-1;
+
   /* HP's shared libraries have references to symbols that are not
      defined anywhere.  The generic ELF BFD linker code will complaim
      about such symbols.
@@ -979,7 +1051,6 @@ elf_hppa_relocate_section (output_bfd, info, input_bfd, input_section,
            {
              sym_sec = h->root.u.def.section;
 
-
              /* If this symbol has an entry in the PA64 dynamic hash
                 table, then get it.  */
              dyn_name = get_dyn_name (input_bfd, h, rel,
@@ -1007,6 +1078,26 @@ elf_hppa_relocate_section (output_bfd, info, input_bfd, input_section,
              else
                relocation = 0;
            }
+         /* Allow undefined symbols in shared libraries.  */
+          else if (info->shared && !info->symbolic && !info->no_undefined)
+           {
+             /* If this symbol has an entry in the PA64 dynamic hash
+                table, then get it.  */
+             dyn_name = get_dyn_name (input_bfd, h, rel,
+                                      &dynh_buf, &dynh_buflen);
+             dyn_h = elf64_hppa_dyn_hash_lookup (&hppa_info->dyn_hash_table,
+                                                 dyn_name, false, false);
+
+             if (dyn_h == NULL)
+               {
+                 (*_bfd_error_handler)
+                   (_("%s: warning: unresolvable relocation against symbol `%s' from %s section"),
+                    bfd_get_filename (input_bfd), h->root.root.string,
+                    bfd_get_section_name (input_bfd, input_section));
+                 relocation = 0;
+               }
+             relocation = 0;
+           }
          else if (h->root.type == bfd_link_hash_undefweak)
            relocation = 0;
          else
@@ -1097,13 +1188,6 @@ elf_hppa_final_link_relocate (rel, input_bfd, output_bfd,
 
   insn = bfd_get_32 (input_bfd, hit_data);
 
-/* For reference here a quick summary of the relocations found in the
-   HPUX 11.00 PA64 .o and .a files, but not yet implemented.  This is mostly
-   a guide to help prioritize what relocation support is worked on first.
-   The list will be deleted eventually.
-
-   27210 R_PARISC_SEGREL32  */
-
   switch (r_type)
     {
     case R_PARISC_NONE:
@@ -1132,8 +1216,9 @@ elf_hppa_final_link_relocate (rel, input_bfd, output_bfd,
        /* 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->output_section == NULL)
-         value = dyn_h->stub_offset;
+       if (sym_sec == NULL || sym_sec->output_section == NULL)
+         value = (dyn_h->stub_offset + hppa_info->stub_sec->output_offset
+                  + hppa_info->stub_sec->output_section->vma);
   
        /* Turn VALUE into a proper PC relative address.  */
        value -= (offset + input_section->output_offset
@@ -1166,7 +1251,7 @@ elf_hppa_final_link_relocate (rel, input_bfd, output_bfd,
        /* 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->output_section == NULL)
+       if (sym_sec == NULL || sym_sec->output_section == NULL)
          value = (dyn_h->stub_offset + hppa_info->stub_sec->output_offset
                   + hppa_info->stub_sec->output_section->vma);
   
@@ -1254,8 +1339,14 @@ elf_hppa_final_link_relocate (rel, input_bfd, output_bfd,
          }
 
        /* We want the value of the DLT offset for this symbol, not
-          the symbol's actual address.  */
-       value = dyn_h->dlt_offset + hppa_info->dlt_sec->output_offset;
+          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 = (dyn_h->dlt_offset
+                + hppa_info->dlt_sec->output_offset
+                + hppa_info->dlt_sec->output_section->vma);
+       value -= _bfd_get_gp_value (output_bfd);
+
 
        /* All DLTIND relocations are basically the same at this point,
           except that we need different field selectors for the 21bit
@@ -1356,8 +1447,13 @@ elf_hppa_final_link_relocate (rel, input_bfd, output_bfd,
     case R_PARISC_PLTOFF16DF:
       {
        /* We want the value of the PLT offset for this symbol, not
-          the symbol's actual address.  */
-       value = dyn_h->plt_offset + hppa_info->plt_sec->output_offset;
+          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 = (dyn_h->plt_offset
+                + hppa_info->plt_sec->output_offset
+                + hppa_info->plt_sec->output_section->vma);
+       value -= _bfd_get_gp_value (output_bfd);
 
        /* All PLTOFF relocations are basically the same at this point,
           except that we need different field selectors for the 21bit
@@ -1398,8 +1494,13 @@ elf_hppa_final_link_relocate (rel, input_bfd, output_bfd,
          }
 
        /* We want the value of the DLT offset for this symbol, not
-          the symbol's actual address.  */
-       value = dyn_h->dlt_offset + hppa_info->dlt_sec->output_offset;
+          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 = (dyn_h->dlt_offset
+                + hppa_info->dlt_sec->output_offset
+                + hppa_info->dlt_sec->output_section->vma);
+       value -= _bfd_get_gp_value (output_bfd);
        bfd_put_32 (input_bfd, value, hit_data);
        return bfd_reloc_ok;
       }
@@ -1427,8 +1528,13 @@ elf_hppa_final_link_relocate (rel, input_bfd, output_bfd,
          }
 
        /* We want the value of the DLT offset for this symbol, not
-          the symbol's actual address.  */
-       value = dyn_h->dlt_offset + hppa_info->dlt_sec->output_offset;
+          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 = (dyn_h->dlt_offset
+                + hppa_info->dlt_sec->output_offset
+                + hppa_info->dlt_sec->output_section->vma);
+       value -= _bfd_get_gp_value (output_bfd);
        bfd_put_64 (input_bfd, value, hit_data);
        return bfd_reloc_ok;
       }
@@ -1451,9 +1557,14 @@ elf_hppa_final_link_relocate (rel, input_bfd, output_bfd,
       return bfd_reloc_ok;
 
     case R_PARISC_LTOFF64:
-      /* We want the value of the DLT offset for this symbol, not
-          the symbol's actual address.  */
-      value = dyn_h->dlt_offset + hppa_info->dlt_sec->output_offset;
+       /* 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 = (dyn_h->dlt_offset
+              + hppa_info->dlt_sec->output_offset
+              + hppa_info->dlt_sec->output_section->vma);
+      value -= _bfd_get_gp_value (output_bfd);
 
       bfd_put_64 (input_bfd, value + addend, hit_data);
       return bfd_reloc_ok;
@@ -1463,8 +1574,9 @@ elf_hppa_final_link_relocate (rel, input_bfd, output_bfd,
        /* 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->output_section == NULL)
-         value = dyn_h->stub_offset;
+       if (sym_sec == NULL || sym_sec->output_section == NULL)
+         value = (dyn_h->stub_offset + hppa_info->stub_sec->output_offset
+                  + hppa_info->stub_sec->output_section->vma);
   
        /* Turn VALUE into a proper PC relative address.  */
        value -= (offset + input_section->output_offset
@@ -1481,8 +1593,10 @@ elf_hppa_final_link_relocate (rel, input_bfd, output_bfd,
        /* 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->output_section == NULL)
-         value = dyn_h->stub_offset;
+       if (sym_sec == NULL || sym_sec->output_section == NULL)
+         value = (dyn_h->stub_offset + hppa_info->stub_sec->output_offset
+                  + hppa_info->stub_sec->output_section->vma);
+  
   
        /* Turn VALUE into a proper PC relative address.  */
        value -= (offset + input_section->output_offset
@@ -1534,7 +1648,34 @@ elf_hppa_final_link_relocate (rel, input_bfd, output_bfd,
       return bfd_reloc_ok;
 
     case R_PARISC_SEGREL32:
-      return bfd_reloc_ok;
+    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,
+                                elf64_hppa_hash_table (info));
+
+       /* VALUE holds the absolute address.  We want to include the
+          addend, then turn it into a segment relative address.
+
+          The segment is derived from SYM_SEC.  We assume that there are
+          only two segments of note in the resulting executable/shlib.
+          A readonly segment (.text) and a readwrite segment (.data).  */
+       value += addend;
+
+       if (sym_sec->flags & SEC_CODE)
+         value -= hppa_info->text_segment_base;
+       else
+         value -= hppa_info->data_segment_base;
+
+       if (r_type == R_PARISC_SEGREL32)
+         bfd_put_32 (input_bfd, value, hit_data);
+       else
+         bfd_put_64 (input_bfd, value, hit_data);
+        return bfd_reloc_ok;
+      }
+      
 
     /* Something we don't know how to handle.  */
     default:
This page took 0.026707 seconds and 4 git commands to generate.