* elf-bfd.h (struct elf_reloc_cookie): Remove locsym_shndx,
[deliverable/binutils-gdb.git] / bfd / elf32-hppa.c
index ea8bb3202e8d5dcc2e29e54ad0530383b823dcc1..7a244eca30799b96ffaedb84fad70c59e539dd35 100644 (file)
@@ -1,6 +1,6 @@
 /* BFD back-end for HP PA-RISC ELF files.
-   Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1999, 2000, 2001
-   Free Software Foundation, Inc.
+   Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1999, 2000, 2001,
+   2002 Free Software Foundation, Inc.
 
    Original code by
        Center for Software Science
@@ -32,8 +32,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 #include "libhppa.h"
 #include "elf32-hppa.h"
 #define ARCH_SIZE              32
-#include "elf-hppa.h"
 #include "elf32-hppa.h"
+#include "elf-hppa.h"
 
 /* In order to gain some understanding of code in this file without
    knowing all the intricate details of the linker, note the
@@ -71,14 +71,14 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
    (single sub-space version)
    :           addil LR'lt_ptr+ltoff,%dp       ; get procedure entry point
    :           ldw RR'lt_ptr+ltoff(%r1),%r21
-   :            bv %r0(%r21)
+   :           bv %r0(%r21)
    :           ldw RR'lt_ptr+ltoff+4(%r1),%r19 ; get new dlt value.
 
    Import stub to call shared library routine from shared library
    (single sub-space version)
    :           addil LR'ltoff,%r19             ; get procedure entry point
    :           ldw RR'ltoff(%r1),%r21
-   :            bv %r0(%r21)
+   :           bv %r0(%r21)
    :           ldw RR'ltoff+4(%r1),%r19        ; get new dlt value.
 
    Import stub to call shared library routine from normal object file
@@ -203,9 +203,6 @@ struct elf32_hppa_link_hash_entry {
 #endif
   } *dyn_relocs;
 
-  /* Set during a static link if we detect a function is PIC.  */
-  unsigned int maybe_pic_call:1;
-
   /* Set if the only reason we need a .plt entry is for a non-PIC to
      PIC function call.  */
   unsigned int pic_call:1;
@@ -239,6 +236,12 @@ struct elf32_hppa_link_hash_table {
     asection *stub_sec;
   } *stub_group;
 
+  /* Assorted information used by elf32_hppa_size_stubs.  */
+  unsigned int bfd_count;
+  int top_index;
+  asection **input_list;
+  Elf_Internal_Sym **all_local_syms;
+
   /* Short-cuts to get to dynamic linker sections.  */
   asection *sgot;
   asection *srelgot;
@@ -255,10 +258,11 @@ struct elf32_hppa_link_hash_table {
   /* Whether we support multiple sub-spaces for shared libs.  */
   unsigned int multi_subspace:1;
 
-  /* Flags set when PCREL12F and PCREL17F branches detected.  Used to
+  /* Flags set when various size branches are detected.  Used to
      select suitable defaults for the stub group size.  */
   unsigned int has_12bit_branch:1;
   unsigned int has_17bit_branch:1;
+  unsigned int has_22bit_branch:1;
 
   /* Set if we need a .plt stub to support lazy dynamic linking.  */
   unsigned int need_plt_stub:1;
@@ -284,6 +288,9 @@ static struct bfd_hash_entry *hppa_link_hash_newfunc
 static struct bfd_link_hash_table *elf32_hppa_link_hash_table_create
   PARAMS ((bfd *));
 
+static void elf32_hppa_link_hash_table_free
+  PARAMS ((struct bfd_link_hash_table *));
+
 /* Stub handling functions.  */
 static char *hppa_stub_name
   PARAMS ((const asection *, const asection *,
@@ -327,7 +334,7 @@ static boolean elf32_hppa_check_relocs
           asection *, const Elf_Internal_Rela *));
 
 static asection *elf32_hppa_gc_mark_hook
-  PARAMS ((bfd *, struct bfd_link_info *, Elf_Internal_Rela *,
+  PARAMS ((asection *, struct bfd_link_info *, Elf_Internal_Rela *,
           struct elf_link_hash_entry *, Elf_Internal_Sym *));
 
 static boolean elf32_hppa_gc_sweep_hook
@@ -335,7 +342,7 @@ static boolean elf32_hppa_gc_sweep_hook
           asection *, const Elf_Internal_Rela *));
 
 static void elf32_hppa_hide_symbol
-  PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *));
+  PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *, boolean));
 
 static boolean elf32_hppa_adjust_dynamic_symbol
   PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *));
@@ -358,6 +365,12 @@ static boolean clobber_millicode_symbols
 static boolean elf32_hppa_size_dynamic_sections
   PARAMS ((bfd *, struct bfd_link_info *));
 
+static void group_sections
+  PARAMS ((struct elf32_hppa_link_hash_table *, bfd_size_type, boolean));
+
+static int get_local_syms
+  PARAMS ((bfd *, bfd *, struct bfd_link_info *));
+
 static boolean elf32_hppa_final_link
   PARAMS ((bfd *, struct bfd_link_info *));
 
@@ -373,9 +386,6 @@ static boolean elf32_hppa_relocate_section
   PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *,
           bfd_byte *, Elf_Internal_Rela *, Elf_Internal_Sym *, asection **));
 
-static int hppa_unwind_entry_compare
-  PARAMS ((const PTR, const PTR));
-
 static boolean elf32_hppa_finish_dynamic_symbol
   PARAMS ((bfd *, struct bfd_link_info *,
           struct elf_link_hash_entry *, Elf_Internal_Sym *));
@@ -460,7 +470,6 @@ hppa_link_hash_newfunc (entry, table, string)
       eh = (struct elf32_hppa_link_hash_entry *) entry;
       eh->stub_cache = NULL;
       eh->dyn_relocs = NULL;
-      eh->maybe_pic_call = 0;
       eh->pic_call = 0;
       eh->plabel = 0;
     }
@@ -479,13 +488,13 @@ elf32_hppa_link_hash_table_create (abfd)
   struct elf32_hppa_link_hash_table *ret;
   bfd_size_type amt = sizeof (*ret);
 
-  ret = (struct elf32_hppa_link_hash_table *) bfd_alloc (abfd, amt);
+  ret = (struct elf32_hppa_link_hash_table *) bfd_malloc (amt);
   if (ret == NULL)
     return NULL;
 
   if (!_bfd_elf_link_hash_table_init (&ret->elf, abfd, hppa_link_hash_newfunc))
     {
-      bfd_release (abfd, ret);
+      free (ret);
       return NULL;
     }
 
@@ -508,12 +517,26 @@ elf32_hppa_link_hash_table_create (abfd)
   ret->multi_subspace = 0;
   ret->has_12bit_branch = 0;
   ret->has_17bit_branch = 0;
+  ret->has_22bit_branch = 0;
   ret->need_plt_stub = 0;
   ret->sym_sec.abfd = NULL;
 
   return &ret->elf.root;
 }
 
+/* Free the derived linker hash table.  */
+
+static void
+elf32_hppa_link_hash_table_free (hash)
+     struct bfd_link_hash_table *hash;
+{
+  struct elf32_hppa_link_hash_table *ret
+    = (struct elf32_hppa_link_hash_table *) hash;
+
+  bfd_hash_table_free (&ret->stub_hash_table);
+  _bfd_generic_link_hash_table_free (hash);
+}
+
 /* Build a name for an entry in the stub hash table.  */
 
 static char *
@@ -591,20 +614,8 @@ hppa_get_stub_entry (input_section, sym_sec, hash, rel, htab)
 
       stub_entry = hppa_stub_hash_lookup (&htab->stub_hash_table,
                                          stub_name, false, false);
-      if (stub_entry == NULL)
-       {
-         if (hash == NULL || hash->elf.root.type != bfd_link_hash_undefweak)
-           (*_bfd_error_handler) (_("%s(%s+0x%lx): cannot find stub entry %s"),
-                                  bfd_archive_filename (input_section->owner),
-                                  input_section->name,
-                                  (long) rel->r_offset,
-                                  stub_name);
-       }
-      else
-       {
-         if (hash != NULL)
-           hash->stub_cache = stub_entry;
-       }
+      if (hash != NULL)
+       hash->stub_cache = stub_entry;
 
       free (stub_name);
     }
@@ -632,16 +643,18 @@ hppa_add_stub (stub_name, section, htab)
       stub_sec = htab->stub_group[link_sec->id].stub_sec;
       if (stub_sec == NULL)
        {
+         size_t namelen;
          bfd_size_type len;
          char *s_name;
 
-         len = strlen (link_sec->name) + sizeof (STUB_SUFFIX);
+         namelen = strlen (link_sec->name);
+         len = namelen + sizeof (STUB_SUFFIX);
          s_name = bfd_alloc (htab->stub_bfd, len);
          if (s_name == NULL)
            return NULL;
 
-         strcpy (s_name, link_sec->name);
-         strcpy (s_name + len - sizeof (STUB_SUFFIX), STUB_SUFFIX);
+         memcpy (s_name, link_sec->name, namelen);
+         memcpy (s_name + namelen, STUB_SUFFIX, sizeof (STUB_SUFFIX));
          stub_sec = (*htab->add_stub_section) (s_name, link_sec);
          if (stub_sec == NULL)
            return NULL;
@@ -682,21 +695,12 @@ hppa_type_of_stub (input_sec, rel, hash, destination)
   unsigned int r_type;
 
   if (hash != NULL
-      && (((hash->elf.root.type == bfd_link_hash_defined
-           || hash->elf.root.type == bfd_link_hash_defweak)
-          && hash->elf.root.u.def.section->output_section == NULL)
-         || (hash->elf.root.type == bfd_link_hash_defweak
-             && hash->elf.dynindx != -1
-             && hash->elf.plt.offset != (bfd_vma) -1)
-         || hash->elf.root.type == bfd_link_hash_undefweak
-         || hash->elf.root.type == bfd_link_hash_undefined
-         || (hash->maybe_pic_call && !(input_sec->flags & SEC_HAS_GOT_REF))))
+      && hash->elf.plt.offset != (bfd_vma) -1
+      && (hash->elf.dynindx != -1 || hash->pic_call)
+      && !hash->plabel)
     {
-      /* If output_section is NULL, then it's a symbol defined in a
-        shared library.  We will need an import stub.  Decide between
-        hppa_stub_import and hppa_stub_import_shared later.  For
-        shared links we need stubs for undefined or weak syms too;
-        They will presumably be resolved by the dynamic linker.  */
+      /* We need an import stub.  Decide between hppa_stub_import
+        and hppa_stub_import_shared later.  */
       return hppa_stub_import;
     }
 
@@ -754,6 +758,7 @@ hppa_type_of_stub (input_sec, rel, hash, destination)
 #define BE_SR0_R21     0xe2a00000      /* be    0(%sr0,%r21)           */
 #define STW_RP         0x6bc23fd1      /* stw   %rp,-24(%sr0,%sp)      */
 
+#define BL22_RP                0xe800a002      /* b,l,n XXX,%rp                */
 #define BL_RP          0xe8400002      /* b,l,n XXX,%rp                */
 #define NOP            0x08000240      /* nop                          */
 #define LDW_RP         0x4bc23fd1      /* ldw   -24(%sr0,%sp),%rp      */
@@ -943,7 +948,9 @@ hppa_build_one_stub (gen_entry, in_arg)
                    + stub_sec->output_offset
                    + stub_sec->output_section->vma);
 
-      if (sym_value - 8 + 0x40000 >= 0x80000)
+      if (sym_value - 8 + (1 << (17 + 1)) >= (1 << (17 + 2))
+         && (!htab->has_22bit_branch
+             || sym_value - 8 + (1 << (22 + 1)) >= (1 << (22 + 2))))
        {
          (*_bfd_error_handler)
            (_("%s(%s+0x%lx): cannot reach %s, recompile with -ffunction-sections"),
@@ -956,7 +963,10 @@ hppa_build_one_stub (gen_entry, in_arg)
        }
 
       val = hppa_field_adjust (sym_value, (bfd_signed_vma) -8, e_fsel) >> 2;
-      insn = hppa_rebuild_insn ((int) BL_RP, val, 17);
+      if (!htab->has_22bit_branch)
+       insn = hppa_rebuild_insn ((int) BL_RP, val, 17);
+      else
+       insn = hppa_rebuild_insn ((int) BL22_RP, val, 22);
       bfd_put_32 (stub_bfd, insn, loc);
 
       bfd_put_32 (stub_bfd, (bfd_vma) NOP,         loc + 4);
@@ -1275,12 +1285,16 @@ elf32_hppa_check_relocs (abfd, info, sec, relocs)
 
        case R_PARISC_PCREL12F:
          htab->has_12bit_branch = 1;
-         /* Fall thru.  */
+         goto branch_common;
+
        case R_PARISC_PCREL17C:
        case R_PARISC_PCREL17F:
          htab->has_17bit_branch = 1;
-         /* Fall thru.  */
+         goto branch_common;
+
        case R_PARISC_PCREL22F:
+         htab->has_22bit_branch = 1;
+       branch_common:
          /* Function calls might need to go through the .plt, and
             might require long branch stubs.  */
          if (h == NULL)
@@ -1334,7 +1348,7 @@ elf32_hppa_check_relocs (abfd, info, sec, relocs)
        case R_PARISC_DIR14F: /* Used for load/store from absolute locn.  */
        case R_PARISC_DIR14R:
        case R_PARISC_DIR21L: /* As above, and for ext branches too.  */
-#if 1
+#if 0
          /* Help debug shared library creation.  Any of the above
             relocs can be used in shared libs, but they may cause
             pages to become unshared.  */
@@ -1618,8 +1632,8 @@ elf32_hppa_check_relocs (abfd, info, sec, relocs)
    for a given relocation.  */
 
 static asection *
-elf32_hppa_gc_mark_hook (abfd, info, rel, h, sym)
-     bfd *abfd;
+elf32_hppa_gc_mark_hook (sec, info, rel, h, sym)
+     asection *sec;
      struct bfd_link_info *info ATTRIBUTE_UNUSED;
      Elf_Internal_Rela *rel;
      struct elf_link_hash_entry *h;
@@ -1649,15 +1663,7 @@ elf32_hppa_gc_mark_hook (abfd, info, rel, h, sym)
        }
     }
   else
-    {
-      if (!(elf_bad_symtab (abfd)
-           && ELF_ST_BIND (sym->st_info) != STB_LOCAL)
-         && ! ((sym->st_shndx <= 0 || sym->st_shndx >= SHN_LORESERVE)
-               && sym->st_shndx != SHN_COMMON))
-       {
-         return bfd_section_from_elf_index (abfd, sym->st_shndx);
-       }
-    }
+    return bfd_section_from_elf_index (sec->owner, sym->st_shndx);
 
   return NULL;
 }
@@ -1804,12 +1810,22 @@ elf32_hppa_gc_sweep_hook (abfd, info, sec, relocs)
    plabels.  */
 
 static void
-elf32_hppa_hide_symbol (info, h)
-     struct bfd_link_info *info ATTRIBUTE_UNUSED;
+elf32_hppa_hide_symbol (info, h, force_local)
+     struct bfd_link_info *info;
      struct elf_link_hash_entry *h;
+     boolean force_local;
 {
-  if ((h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) != 0)
-    h->dynindx = -1;
+  if (force_local)
+    {
+      h->elf_link_hash_flags |= ELF_LINK_FORCED_LOCAL;
+      if (h->dynindx != -1)
+       {
+         h->dynindx = -1;
+         _bfd_elf_strtab_delref (elf_hash_table (info)->dynstr,
+                                 h->dynstr_index);
+       }
+    }
+
   if (! ((struct elf32_hppa_link_hash_entry *) h)->plabel)
     {
       h->elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT;
@@ -1846,19 +1862,10 @@ elf32_hppa_adjust_dynamic_symbol (info, h)
   unsigned int power_of_two;
 
   /* If this is a function, put it in the procedure linkage table.  We
-     will fill in the contents of the procedure linkage table later,
-     when we know the address of the .got section.  */
+     will fill in the contents of the procedure linkage table later.  */
   if (h->type == STT_FUNC
       || (h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0)
     {
-      if (!info->shared
-         && h->plt.refcount > 0
-         && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0
-         && (h->root.u.def.section->flags & SEC_HAS_GOT_REF) != 0)
-       {
-         ((struct elf32_hppa_link_hash_entry *) h)->maybe_pic_call = 1;
-       }
-
       if (h->plt.refcount <= 0
          || ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0
              && h->root.type != bfd_link_hash_defweak
@@ -1875,7 +1882,10 @@ elf32_hppa_adjust_dynamic_symbol (info, h)
 
          /* As a special sop to the hppa ABI, we keep a .plt entry
             for functions in sections containing PIC code.  */
-         if (((struct elf32_hppa_link_hash_entry *) h)->maybe_pic_call)
+         if (!info->shared
+             && h->plt.refcount > 0
+             && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0
+             && (h->root.u.def.section->flags & SEC_HAS_GOT_REF) != 0)
            ((struct elf32_hppa_link_hash_entry *) h)->pic_call = 1;
          else
            {
@@ -1926,7 +1936,7 @@ elf32_hppa_adjust_dynamic_symbol (info, h)
     }
 
   /* If we didn't find any dynamic relocs in read-only sections, then
-     we'll be keeping the dynamic relocs and avoiding the copy reloc.  */ 
+     we'll be keeping the dynamic relocs and avoiding the copy reloc.  */
   if (p == NULL)
     {
       h->elf_link_hash_flags &= ~ELF_LINK_NON_GOT_REF;
@@ -1990,6 +2000,9 @@ mark_PIC_calls (h, inf)
      struct elf_link_hash_entry *h;
      PTR inf ATTRIBUTE_UNUSED;
 {
+  if (h->root.type == bfd_link_hash_warning)
+    h = (struct elf_link_hash_entry *) h->root.u.i.link;
+
   if (! (h->plt.refcount > 0
         && (h->root.type == bfd_link_hash_defined
             || h->root.type == bfd_link_hash_defweak)
@@ -2001,7 +2014,6 @@ mark_PIC_calls (h, inf)
     }
 
   h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT;
-  ((struct elf32_hppa_link_hash_entry *) h)->maybe_pic_call = 1;
   ((struct elf32_hppa_link_hash_entry *) h)->pic_call = 1;
 
   return true;
@@ -2019,16 +2031,19 @@ allocate_plt_static (h, inf)
   struct elf32_hppa_link_hash_table *htab;
   asection *s;
 
-  if (h->root.type == bfd_link_hash_indirect
-      || h->root.type == bfd_link_hash_warning)
+  if (h->root.type == bfd_link_hash_indirect)
     return true;
 
+  if (h->root.type == bfd_link_hash_warning)
+    h = (struct elf_link_hash_entry *) h->root.u.i.link;
+
   info = (struct bfd_link_info *) inf;
   htab = hppa_link_hash_table (info);
   if (((struct elf32_hppa_link_hash_entry *) h)->pic_call)
     {
       /* Make an entry in the .plt section for non-pic code that is
         calling pic code.  */
+      ((struct elf32_hppa_link_hash_entry *) h)->plabel = 0;
       s = htab->splt;
       h->plt.offset = s->_raw_size;
       s->_raw_size += PLT_ENTRY_SIZE;
@@ -2048,7 +2063,11 @@ allocate_plt_static (h, inf)
 
       if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, info, h))
        {
-         /* Allocate these later.  */
+         /* Allocate these later.  From this point on, h->plabel
+            means that the plt entry is only used by a plabel.
+            We'll be using a normal plt entry for this symbol, so
+            clear the plabel indicator.  */
+         ((struct elf32_hppa_link_hash_entry *) h)->plabel = 0;
        }
       else if (((struct elf32_hppa_link_hash_entry *) h)->plabel)
        {
@@ -2088,16 +2107,18 @@ allocate_dynrelocs (h, inf)
   struct elf32_hppa_link_hash_entry *eh;
   struct elf32_hppa_dyn_reloc_entry *p;
 
-  if (h->root.type == bfd_link_hash_indirect
-      || h->root.type == bfd_link_hash_warning)
+  if (h->root.type == bfd_link_hash_indirect)
     return true;
 
+  if (h->root.type == bfd_link_hash_warning)
+    h = (struct elf_link_hash_entry *) h->root.u.i.link;
+
   info = (struct bfd_link_info *) inf;
   htab = hppa_link_hash_table (info);
   if (htab->elf.dynamic_sections_created
       && h->plt.offset != (bfd_vma) -1
       && !((struct elf32_hppa_link_hash_entry *) h)->pic_call
-      && WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, info, h))
+      && !((struct elf32_hppa_link_hash_entry *) h)->plabel)
     {
       /* Make an entry in the .plt section.  */
       s = htab->splt;
@@ -2221,15 +2242,13 @@ clobber_millicode_symbols (h, info)
      struct elf_link_hash_entry *h;
      struct bfd_link_info *info;
 {
-  /* We only want to remove these from the dynamic symbol table.
-     Therefore we do not leave ELF_LINK_FORCED_LOCAL set.  */
-  if (h->type == STT_PARISC_MILLI)
+  if (h->root.type == bfd_link_hash_warning)
+    h = (struct elf_link_hash_entry *) h->root.u.i.link;
+
+  if (h->type == STT_PARISC_MILLI
+      && (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0)
     {
-      unsigned short oldflags = h->elf_link_hash_flags;
-      h->elf_link_hash_flags |= ELF_LINK_FORCED_LOCAL;
-      elf32_hppa_hide_symbol (info, h);
-      h->elf_link_hash_flags &= ~ELF_LINK_FORCED_LOCAL;
-      h->elf_link_hash_flags |= oldflags & ELF_LINK_FORCED_LOCAL;
+      elf32_hppa_hide_symbol (info, h, true);
     }
   return true;
 }
@@ -2244,6 +2263,9 @@ readonly_dynrelocs (h, inf)
   struct elf32_hppa_link_hash_entry *eh;
   struct elf32_hppa_dyn_reloc_entry *p;
 
+  if (h->root.type == bfd_link_hash_warning)
+    h = (struct elf_link_hash_entry *) h->root.u.i.link;
+
   eh = (struct elf32_hppa_link_hash_entry *) h;
   for (p = eh->dyn_relocs; p != NULL; p = p->next)
     {
@@ -2338,10 +2360,12 @@ elf32_hppa_size_dynamic_sections (output_bfd, info)
                     linker script /DISCARD/, so we'll be discarding
                     the relocs too.  */
                }
-             else
+             else if (p->count != 0)
                {
                  srel = elf_section_data (p->sec)->sreloc;
                  srel->_raw_size += p->count * sizeof (Elf32_External_Rela);
+                 if ((p->sec->output_section->flags & SEC_READONLY) != 0)
+                   info->flags |= DF_TEXTREL;
                }
            }
        }
@@ -2514,7 +2538,9 @@ elf32_hppa_size_dynamic_sections (output_bfd, info)
 
          /* If any dynamic relocs apply to a read-only section,
             then we need a DT_TEXTREL entry.  */
-         elf_link_hash_traverse (&htab->elf, readonly_dynrelocs, (PTR) info);
+         if ((info->flags & DF_TEXTREL) == 0)
+           elf_link_hash_traverse (&htab->elf, readonly_dynrelocs,
+                                   (PTR) info);
 
          if ((info->flags & DF_TEXTREL) != 0)
            {
@@ -2530,57 +2556,25 @@ elf32_hppa_size_dynamic_sections (output_bfd, info)
 
 /* External entry points for sizing and building linker stubs.  */
 
-/* Determine and set the size of the stub section for a final link.
-
-   The basic idea here is to examine all the relocations looking for
-   PC-relative calls to a target that is unreachable with a "bl"
-   instruction.  */
+/* Set up various things so that we can make a list of input sections
+   for each output section included in the link.  Returns -1 on error,
+   0 when no stubs will be needed, and 1 on success.  */
 
-boolean
-elf32_hppa_size_stubs (output_bfd, stub_bfd, info, multi_subspace, group_size,
-                      add_stub_section, layout_sections_again)
+int
+elf32_hppa_setup_section_lists (output_bfd, info)
      bfd *output_bfd;
-     bfd *stub_bfd;
      struct bfd_link_info *info;
-     boolean multi_subspace;
-     bfd_signed_vma group_size;
-     asection * (*add_stub_section) PARAMS ((const char *, asection *));
-     void (*layout_sections_again) PARAMS ((void));
 {
   bfd *input_bfd;
+  unsigned int bfd_count;
+  int top_id, top_index;
   asection *section;
   asection **input_list, **list;
-  Elf_Internal_Sym *local_syms, **all_local_syms;
-  unsigned int bfd_indx, bfd_count;
-  int top_id, top_index;
-  struct elf32_hppa_link_hash_table *htab;
-  bfd_size_type stub_group_size;
-  boolean stubs_always_before_branch;
-  boolean stub_changed = 0;
-  boolean ret = 0;
   bfd_size_type amt;
+  struct elf32_hppa_link_hash_table *htab = hppa_link_hash_table (info);
 
-  htab = hppa_link_hash_table (info);
-
-  /* Stash our params away.  */
-  htab->stub_bfd = stub_bfd;
-  htab->multi_subspace = multi_subspace;
-  htab->add_stub_section = add_stub_section;
-  htab->layout_sections_again = layout_sections_again;
-  stubs_always_before_branch = group_size < 0;
-  if (group_size < 0)
-    stub_group_size = -group_size;
-  else
-    stub_group_size = group_size;
-  if (stub_group_size == 1)
-    {
-      /* Default values.  */
-      stub_group_size = 8000000;
-      if (htab->has_17bit_branch || htab->multi_subspace)
-       stub_group_size = 250000;
-      if (htab->has_12bit_branch)
-       stub_group_size = 7812;
-    }
+  if (htab->elf.root.creator->flavour != bfd_target_elf_flavour)
+    return 0;
 
   /* Count the number of input BFDs and find the top input section id.  */
   for (input_bfd = info->input_bfds, bfd_count = 0, top_id = 0;
@@ -2596,16 +2590,14 @@ elf32_hppa_size_stubs (output_bfd, stub_bfd, info, multi_subspace, group_size,
            top_id = section->id;
        }
     }
+  htab->bfd_count = bfd_count;
 
   amt = sizeof (struct map_stub) * (top_id + 1);
   htab->stub_group = (struct map_stub *) bfd_zmalloc (amt);
   if (htab->stub_group == NULL)
-    return false;
-
-  /* Make a list of input sections for each output section included in
-     the link.
+    return -1;
 
-     We can't use output_bfd->section_count here to find the top output
+  /* We can't use output_bfd->section_count here to find the top output
      section index as some sections may have been removed, and
      _bfd_strip_section_from_output doesn't renumber the indices.  */
   for (section = output_bfd->sections, top_index = 0;
@@ -2616,10 +2608,12 @@ elf32_hppa_size_stubs (output_bfd, stub_bfd, info, multi_subspace, group_size,
        top_index = section->index;
     }
 
+  htab->top_index = top_index;
   amt = sizeof (asection *) * (top_index + 1);
   input_list = (asection **) bfd_malloc (amt);
+  htab->input_list = input_list;
   if (input_list == NULL)
-    return false;
+    return -1;
 
   /* For sections we aren't interested in, mark their entries with a
      value we can check later.  */
@@ -2636,40 +2630,50 @@ elf32_hppa_size_stubs (output_bfd, stub_bfd, info, multi_subspace, group_size,
        input_list[section->index] = NULL;
     }
 
-  /* Now actually build the lists.  */
-  for (input_bfd = info->input_bfds;
-       input_bfd != NULL;
-       input_bfd = input_bfd->link_next)
+  return 1;
+}
+
+/* The linker repeatedly calls this function for each input section,
+   in the order that input sections are linked into output sections.
+   Build lists of input sections to determine groupings between which
+   we may insert linker stubs.  */
+
+void
+elf32_hppa_next_input_section (info, isec)
+     struct bfd_link_info *info;
+     asection *isec;
+{
+  struct elf32_hppa_link_hash_table *htab = hppa_link_hash_table (info);
+
+  if (isec->output_section->index <= htab->top_index)
     {
-      for (section = input_bfd->sections;
-          section != NULL;
-          section = section->next)
+      asection **list = htab->input_list + isec->output_section->index;
+      if (*list != bfd_abs_section_ptr)
        {
-         if (section->output_section != NULL
-             && section->output_section->owner == output_bfd
-             && section->output_section->index <= top_index)
-           {
-             list = input_list + section->output_section->index;
-             if (*list != bfd_abs_section_ptr)
-               {
-                 /* Steal the link_sec pointer for our list.  */
+         /* Steal the link_sec pointer for our list.  */
 #define PREV_SEC(sec) (htab->stub_group[(sec)->id].link_sec)
-                 /* This happens to make the list in reverse order,
-                    which is what we want.  */
-                 PREV_SEC (section) = *list;
-                 *list = section;
-               }
-           }
+         /* This happens to make the list in reverse order,
+            which is what we want.  */
+         PREV_SEC (isec) = *list;
+         *list = isec;
        }
     }
+}
 
-  /* See whether we can group stub sections together.  Grouping stub
-     sections may result in fewer stubs.  More importantly, we need to
-     put all .init* and .fini* stubs at the beginning of the .init or
-     .fini output sections respectively, because glibc splits the
-     _init and _fini functions into multiple parts.  Putting a stub in
-     the middle of a function is not a good idea.  */
-  list = input_list + top_index;
+/* See whether we can group stub sections together.  Grouping stub
+   sections may result in fewer stubs.  More importantly, we need to
+   put all .init* and .fini* stubs at the beginning of the .init or
+   .fini output sections respectively, because glibc splits the
+   _init and _fini functions into multiple parts.  Putting a stub in
+   the middle of a function is not a good idea.  */
+
+static void
+group_sections (htab, stub_group_size, stubs_always_before_branch)
+     struct elf32_hppa_link_hash_table *htab;
+     bfd_size_type stub_group_size;
+     boolean stubs_always_before_branch;
+{
+  asection **list = htab->input_list + htab->top_index;
   do
     {
       asection *tail = *list;
@@ -2692,16 +2696,18 @@ elf32_hppa_size_stubs (output_bfd, stub_bfd, info, multi_subspace, group_size,
            curr = prev;
 
          /* OK, the size from the start of CURR to the end is less
-            than 250000 bytes and thus can be handled by one stub
+            than 240000 bytes and thus can be handled by one stub
             section.  (or the tail section is itself larger than
-            250000 bytes, in which case we may be toast.)
+            240000 bytes, in which case we may be toast.)
             We should really be keeping track of the total size of
             stubs added here, as stubs contribute to the final output
             section size.  That's a little tricky, and this way will
-            only break if stubs added total more than 12144 bytes, or
-            1518 long branch stubs.  It seems unlikely for more than
-            1518 different functions to be called, especially from
-            code only 250000 bytes long.  */
+            only break if stubs added total more than 22144 bytes, or
+            2768 long branch stubs.  It seems unlikely for more than
+            2768 different functions to be called, especially from
+            code only 240000 bytes long.  This limit used to be
+            250000, but c++ code tends to generate lots of little
+            functions, and sometimes violated the assumption.  */
          do
            {
              prev = PREV_SEC (tail);
@@ -2710,7 +2716,7 @@ elf32_hppa_size_stubs (output_bfd, stub_bfd, info, multi_subspace, group_size,
            }
          while (tail != curr && (tail = prev) != NULL);
 
-         /* But wait, there's more!  Input sections up to 250000
+         /* But wait, there's more!  Input sections up to 240000
             bytes before the stub section can be handled by it too.  */
          if (!stubs_always_before_branch)
            {
@@ -2727,68 +2733,63 @@ elf32_hppa_size_stubs (output_bfd, stub_bfd, info, multi_subspace, group_size,
          tail = prev;
        }
     }
-  while (list-- != input_list);
-  free (input_list);
+  while (list-- != htab->input_list);
+  free (htab->input_list);
 #undef PREV_SEC
+}
+
+/* Read in all local syms for all input bfds, and create hash entries
+   for export stubs if we are building a multi-subspace shared lib.
+   Returns -1 on error, 1 if export stubs created, 0 otherwise.  */
+
+static int
+get_local_syms (output_bfd, input_bfd, info)
+     bfd *output_bfd;
+     bfd *input_bfd;
+     struct bfd_link_info *info;
+{
+  unsigned int bfd_indx;
+  Elf_Internal_Sym *local_syms, **all_local_syms;
+  int stub_changed = 0;
+  struct elf32_hppa_link_hash_table *htab = hppa_link_hash_table (info);
 
   /* We want to read in symbol extension records only once.  To do this
      we need to read in the local symbols in parallel and save them for
      later use; so hold pointers to the local symbols in an array.  */
-  amt = sizeof (Elf_Internal_Sym *) * bfd_count;
+  bfd_size_type amt = sizeof (Elf_Internal_Sym *) * htab->bfd_count;
   all_local_syms = (Elf_Internal_Sym **) bfd_zmalloc (amt);
+  htab->all_local_syms = all_local_syms;
   if (all_local_syms == NULL)
-    return false;
+    return -1;
 
   /* Walk over all the input BFDs, swapping in local symbols.
      If we are creating a shared library, create hash entries for the
      export stubs.  */
-  for (input_bfd = info->input_bfds, bfd_indx = 0;
+  for (bfd_indx = 0;
        input_bfd != NULL;
        input_bfd = input_bfd->link_next, bfd_indx++)
     {
       Elf_Internal_Shdr *symtab_hdr;
-      Elf_Internal_Sym *isym;
-      Elf32_External_Sym *ext_syms, *esym, *end_sy;
-      bfd_size_type sec_size;
 
       /* We'll need the symbol table in a second.  */
       symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
       if (symtab_hdr->sh_info == 0)
        continue;
 
-      /* We need an array of the local symbols attached to the input bfd.
-        Unfortunately, we're going to have to read & swap them in.  */
-      sec_size = symtab_hdr->sh_info;
-      sec_size *= sizeof (Elf_Internal_Sym);
-      local_syms = (Elf_Internal_Sym *) bfd_malloc (sec_size);
+      /* We need an array of the local symbols attached to the input bfd.  */
+      local_syms = (Elf_Internal_Sym *) symtab_hdr->contents;
       if (local_syms == NULL)
        {
-         goto error_ret_free_local;
-       }
-      all_local_syms[bfd_indx] = local_syms;
-      sec_size = symtab_hdr->sh_info;
-      sec_size *= sizeof (Elf32_External_Sym);
-      ext_syms = (Elf32_External_Sym *) bfd_malloc (sec_size);
-      if (ext_syms == NULL)
-       {
-         goto error_ret_free_local;
+         local_syms = bfd_elf_get_elf_syms (input_bfd, symtab_hdr,
+                                            symtab_hdr->sh_info, 0,
+                                            NULL, NULL, NULL);
+         /* Cache them for elf_link_input_bfd.  */
+         symtab_hdr->contents = (unsigned char *) local_syms;
        }
+      if (local_syms == NULL)
+       return -1;
 
-      if (bfd_seek (input_bfd, symtab_hdr->sh_offset, SEEK_SET) != 0
-         || (bfd_bread (ext_syms, sec_size, input_bfd) != sec_size))
-       {
-         free (ext_syms);
-         goto error_ret_free_local;
-       }
-
-      /* Swap the local symbols in.  */
-      isym = local_syms;
-      esym = ext_syms;
-      for (end_sy = esym + symtab_hdr->sh_info; esym < end_sy; esym++, isym++)
-       bfd_elf32_swap_symbol_in (input_bfd, esym, isym);
-
-      /* Now we can free the external symbols.  */
-      free (ext_syms);
+      all_local_syms[bfd_indx] = local_syms;
 
       if (info->shared && htab->multi_subspace)
        {
@@ -2841,7 +2842,7 @@ elf32_hppa_size_stubs (output_bfd, stub_bfd, info, multi_subspace, group_size,
                    {
                      stub_entry = hppa_add_stub (stub_name, sec, htab);
                      if (!stub_entry)
-                       goto error_ret_free_local;
+                       return -1;
 
                      stub_entry->target_value = hash->elf.root.u.def.value;
                      stub_entry->target_section = hash->elf.root.u.def.section;
@@ -2860,8 +2861,73 @@ elf32_hppa_size_stubs (output_bfd, stub_bfd, info, multi_subspace, group_size,
        }
     }
 
+  return stub_changed;
+}
+
+/* Determine and set the size of the stub section for a final link.
+
+   The basic idea here is to examine all the relocations looking for
+   PC-relative calls to a target that is unreachable with a "bl"
+   instruction.  */
+
+boolean
+elf32_hppa_size_stubs (output_bfd, stub_bfd, info, multi_subspace, group_size,
+                      add_stub_section, layout_sections_again)
+     bfd *output_bfd;
+     bfd *stub_bfd;
+     struct bfd_link_info *info;
+     boolean multi_subspace;
+     bfd_signed_vma group_size;
+     asection * (*add_stub_section) PARAMS ((const char *, asection *));
+     void (*layout_sections_again) PARAMS ((void));
+{
+  bfd_size_type stub_group_size;
+  boolean stubs_always_before_branch;
+  boolean stub_changed;
+  struct elf32_hppa_link_hash_table *htab = hppa_link_hash_table (info);
+
+  /* Stash our params away.  */
+  htab->stub_bfd = stub_bfd;
+  htab->multi_subspace = multi_subspace;
+  htab->add_stub_section = add_stub_section;
+  htab->layout_sections_again = layout_sections_again;
+  stubs_always_before_branch = group_size < 0;
+  if (group_size < 0)
+    stub_group_size = -group_size;
+  else
+    stub_group_size = group_size;
+  if (stub_group_size == 1)
+    {
+      /* Default values.  */
+      stub_group_size = 7680000;
+      if (htab->has_17bit_branch || htab->multi_subspace)
+       stub_group_size = 240000;
+      if (htab->has_12bit_branch)
+       stub_group_size = 7500;
+    }
+
+  group_sections (htab, stub_group_size, stubs_always_before_branch);
+
+  switch (get_local_syms (output_bfd, info->input_bfds, info))
+    {
+    default:
+      if (htab->all_local_syms)
+       goto error_ret_free_local;
+      return false;
+
+    case 0:
+      stub_changed = false;
+      break;
+
+    case 1:
+      stub_changed = true;
+      break;
+    }
+
   while (1)
     {
+      bfd *input_bfd;
+      unsigned int bfd_indx;
       asection *stub_sec;
 
       for (input_bfd = info->input_bfds, bfd_indx = 0;
@@ -2869,21 +2935,21 @@ elf32_hppa_size_stubs (output_bfd, stub_bfd, info, multi_subspace, group_size,
           input_bfd = input_bfd->link_next, bfd_indx++)
        {
          Elf_Internal_Shdr *symtab_hdr;
+         asection *section;
+         Elf_Internal_Sym *local_syms;
 
          /* We'll need the symbol table in a second.  */
          symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
          if (symtab_hdr->sh_info == 0)
            continue;
 
-         local_syms = all_local_syms[bfd_indx];
+         local_syms = htab->all_local_syms[bfd_indx];
 
          /* Walk over each section attached to the input bfd.  */
          for (section = input_bfd->sections;
               section != NULL;
               section = section->next)
            {
-             Elf_Internal_Shdr *input_rel_hdr;
-             Elf32_External_Rela *external_relocs, *erelaend, *erela;
              Elf_Internal_Rela *internal_relocs, *irelaend, *irela;
 
              /* If there aren't any relocs, then there's nothing more
@@ -2898,47 +2964,13 @@ elf32_hppa_size_stubs (output_bfd, stub_bfd, info, multi_subspace, group_size,
                  || section->output_section->owner != output_bfd)
                continue;
 
-             /* Allocate space for the external relocations.  */
-             amt = section->reloc_count;
-             amt *= sizeof (Elf32_External_Rela);
-             external_relocs = (Elf32_External_Rela *) bfd_malloc (amt);
-             if (external_relocs == NULL)
-               {
-                 goto error_ret_free_local;
-               }
-
-             /* Likewise for the internal relocations.  */
-             amt = section->reloc_count;
-             amt *= sizeof (Elf_Internal_Rela);
-             internal_relocs = (Elf_Internal_Rela *) bfd_malloc (amt);
+             /* Get the relocs.  */
+             internal_relocs
+               = _bfd_elf32_link_read_relocs (input_bfd, section, NULL,
+                                              (Elf_Internal_Rela *) NULL,
+                                              info->keep_memory);
              if (internal_relocs == NULL)
-               {
-                 free (external_relocs);
-                 goto error_ret_free_local;
-               }
-
-             /* Read in the external relocs.  */
-             input_rel_hdr = &elf_section_data (section)->rel_hdr;
-             if (bfd_seek (input_bfd, input_rel_hdr->sh_offset, SEEK_SET) != 0
-                 || bfd_bread (external_relocs,
-                              input_rel_hdr->sh_size,
-                              input_bfd) != input_rel_hdr->sh_size)
-               {
-                 free (external_relocs);
-               error_ret_free_internal:
-                 free (internal_relocs);
-                 goto error_ret_free_local;
-               }
-
-             /* Swap in the relocs.  */
-             erela = external_relocs;
-             erelaend = erela + section->reloc_count;
-             irela = internal_relocs;
-             for (; erela < erelaend; erela++, irela++)
-               bfd_elf32_swap_reloca_in (input_bfd, erela, irela);
-
-             /* We're done with the external relocs, free them.  */
-             free (external_relocs);
+               goto error_ret_free_local;
 
              /* Now examine each relocation.  */
              irela = internal_relocs;
@@ -2961,7 +2993,10 @@ elf32_hppa_size_stubs (output_bfd, stub_bfd, info, multi_subspace, group_size,
                  if (r_type >= (unsigned int) R_PARISC_UNIMPLEMENTED)
                    {
                      bfd_set_error (bfd_error_bad_value);
-                     goto error_ret_free_internal;
+                   error_ret_free_internal:
+                     if (elf_section_data (section)->relocs == NULL)
+                       free (internal_relocs);
+                     goto error_ret_free_local;
                    }
 
                  /* Only look for stubs on call instructions.  */
@@ -3025,7 +3060,8 @@ elf32_hppa_size_stubs (output_bfd, stub_bfd, info, multi_subspace, group_size,
                          if (! (info->shared
                                 && !info->no_undefined
                                 && (ELF_ST_VISIBILITY (hash->elf.other)
-                                    == STV_DEFAULT)))
+                                    == STV_DEFAULT)
+                                && hash->elf.type != STT_PARISC_MILLI))
                            continue;
                        }
                      else
@@ -3063,7 +3099,7 @@ elf32_hppa_size_stubs (output_bfd, stub_bfd, info, multi_subspace, group_size,
                  if (stub_entry == NULL)
                    {
                      free (stub_name);
-                     goto error_ret_free_local;
+                     goto error_ret_free_internal;
                    }
 
                  stub_entry->target_value = sym_value;
@@ -3077,11 +3113,12 @@ elf32_hppa_size_stubs (output_bfd, stub_bfd, info, multi_subspace, group_size,
                        stub_entry->stub_type = hppa_stub_long_branch_shared;
                    }
                  stub_entry->h = hash;
-                 stub_changed = 1;
+                 stub_changed = true;
                }
 
              /* We're done with the internal relocs, free them.  */
-             free (internal_relocs);
+             if (elf_section_data (section)->relocs == NULL)
+               free (internal_relocs);
            }
        }
 
@@ -3102,18 +3139,15 @@ elf32_hppa_size_stubs (output_bfd, stub_bfd, info, multi_subspace, group_size,
 
       /* Ask the linker to do its stuff.  */
       (*htab->layout_sections_again) ();
-      stub_changed = 0;
+      stub_changed = false;
     }
 
-  ret = 1;
+  free (htab->all_local_syms);
+  return true;
 
  error_ret_free_local:
-  while (bfd_count-- > 0)
-    if (all_local_syms[bfd_count])
-      free (all_local_syms[bfd_count]);
-  free (all_local_syms);
-
-  return ret;
+  free (htab->all_local_syms);
+  return false;
 }
 
 /* For a final link, this function is called after we have sized the
@@ -3124,23 +3158,39 @@ elf32_hppa_set_gp (abfd, info)
      bfd *abfd;
      struct bfd_link_info *info;
 {
+  struct bfd_link_hash_entry *h;
+  asection *sec = NULL;
+  bfd_vma gp_val = 0;
   struct elf32_hppa_link_hash_table *htab;
-  struct elf_link_hash_entry *h;
-  asection *sec;
-  bfd_vma gp_val;
 
   htab = hppa_link_hash_table (info);
-  h = elf_link_hash_lookup (&htab->elf, "$global$", false, false, false);
+  h = bfd_link_hash_lookup (&htab->elf.root, "$global$", false, false, false);
 
   if (h != NULL
-      && (h->root.type == bfd_link_hash_defined
-         || h->root.type == bfd_link_hash_defweak))
+      && (h->type == bfd_link_hash_defined
+         || h->type == bfd_link_hash_defweak))
     {
-      gp_val = h->root.u.def.value;
-      sec = h->root.u.def.section;
+      gp_val = h->u.def.value;
+      sec = h->u.def.section;
     }
   else
     {
+      asection *splt;
+      asection *sgot;
+
+      if (htab->elf.root.creator->flavour == bfd_target_elf_flavour)
+       {
+         splt = htab->splt;
+         sgot = htab->sgot;
+       }
+      else
+       {
+         /* If we're not elf, look up the output sections in the
+            hope we may actually find them.  */
+         splt = bfd_get_section_by_name (abfd, ".plt");
+         sgot = bfd_get_section_by_name (abfd, ".got");
+       }
+
       /* Choose to point our LTP at, in this order, one of .plt, .got,
         or .data, if these sections exist.  In the case of choosing
         .plt try to make the LTP ideal for addressing anywhere in the
@@ -3149,21 +3199,18 @@ elf32_hppa_set_gp (abfd, info)
         if either the .plt or .got is larger than 0x2000.  If both
         the .plt and .got are smaller than 0x2000, choose the end of
         the .plt section.  */
-
-      sec = htab->splt;
+      sec = splt;
       if (sec != NULL)
        {
          gp_val = sec->_raw_size;
-         if (gp_val > 0x2000
-             || (htab->sgot && htab->sgot->_raw_size > 0x2000))
+         if (gp_val > 0x2000 || (sgot && sgot->_raw_size > 0x2000))
            {
              gp_val = 0x2000;
            }
        }
       else
        {
-         gp_val = 0;
-         sec = htab->sgot;
+         sec = sgot;
          if (sec != NULL)
            {
              /* We know we don't have a .plt.  If .got is large,
@@ -3180,12 +3227,12 @@ elf32_hppa_set_gp (abfd, info)
 
       if (h != NULL)
        {
-         h->root.type = bfd_link_hash_defined;
-         h->root.u.def.value = gp_val;
+         h->type = bfd_link_hash_defined;
+         h->u.def.value = gp_val;
          if (sec != NULL)
-           h->root.u.def.section = sec;
+           h->u.def.section = sec;
          else
-           h->root.u.def.section = bfd_abs_section_ptr;
+           h->u.def.section = bfd_abs_section_ptr;
        }
     }
 
@@ -3240,37 +3287,13 @@ elf32_hppa_final_link (abfd, info)
      bfd *abfd;
      struct bfd_link_info *info;
 {
-  asection *s;
-
   /* Invoke the regular ELF linker to do all the work.  */
   if (!bfd_elf32_bfd_final_link (abfd, info))
     return false;
 
   /* If we're producing a final executable, sort the contents of the
-     unwind section.  Magic section names, but this is much safer than
-     having elf32_hppa_relocate_section remember where SEGREL32 relocs
-     occurred.  Consider what happens if someone inept creates a
-     linker script that puts unwind information in .text.  */
-  s = bfd_get_section_by_name (abfd, ".PARISC.unwind");
-  if (s != NULL)
-    {
-      bfd_size_type size;
-      char *contents;
-
-      size = s->_raw_size;
-      contents = bfd_malloc (size);
-      if (contents == NULL)
-       return false;
-
-      if (! bfd_get_section_contents (abfd, s, contents, (file_ptr) 0, size))
-       return false;
-
-      qsort (contents, (size_t) (size / 16), 16, hppa_unwind_entry_compare);
-
-      if (! bfd_set_section_contents (abfd, s, contents, (file_ptr) 0, size))
-       return false;
-    }
-  return true;
+     unwind section.  */
+  return elf_hppa_sort_unwind (abfd);
 }
 
 /* Record the lowest address for the data and text segments.  */
@@ -3343,19 +3366,14 @@ final_link_relocate (input_section, contents, rel, value, htab, sym_sec, h)
     case R_PARISC_PCREL12F:
     case R_PARISC_PCREL17F:
     case R_PARISC_PCREL22F:
-      /* If this is a call to a function defined in another dynamic
-        library, or if it is a call to a PIC function in the same
-        object, or if this is a shared link and it is a call to a
-        weak symbol which may or may not be in the same object, then
-        find the import stub in the stub hash.  */
+      /* If this call should go via the plt, find the import stub in
+        the stub hash.  */
       if (sym_sec == NULL
          || sym_sec->output_section == NULL
          || (h != NULL
-             && ((h->maybe_pic_call
-                  && !(input_section->flags & SEC_HAS_GOT_REF))
-                 || (h->elf.root.type == bfd_link_hash_defweak
-                     && h->elf.dynindx != -1
-                     && h->elf.plt.offset != (bfd_vma) -1))))
+             && h->elf.plt.offset != (bfd_vma) -1
+             && (h->elf.dynindx != -1 || h->pic_call)
+             && !h->plabel))
        {
          stub_entry = hppa_get_stub_entry (input_section, sym_sec,
                                            h, rel, htab);
@@ -3378,7 +3396,7 @@ final_link_relocate (input_section, contents, rel, value, htab, sym_sec, h)
              addend = 8;
            }
          else
-           return bfd_reloc_notsupported;
+           return bfd_reloc_undefined;
        }
       /* Fall thru.  */
 
@@ -3410,7 +3428,7 @@ final_link_relocate (input_section, contents, rel, value, htab, sym_sec, h)
              == (((int) OP_ADDIL << 26) | (27 << 21)))
            {
              insn &= ~ (0x1f << 21);
-#if 1 /* debug them.  */
+#if 0 /* debug them.  */
              (*_bfd_error_handler)
                (_("%s(%s+0x%lx): fixing %s"),
                 bfd_archive_filename (input_bfd),
@@ -3457,21 +3475,27 @@ final_link_relocate (input_section, contents, rel, value, htab, sym_sec, h)
       r_field = e_fsel;
       break;
 
-    case R_PARISC_DIR21L:
+    case R_PARISC_DLTIND21L:
     case R_PARISC_PCREL21L:
-    case R_PARISC_DPREL21L:
     case R_PARISC_PLABEL21L:
-    case R_PARISC_DLTIND21L:
+      r_field = e_lsel;
+      break;
+
+    case R_PARISC_DIR21L:
+    case R_PARISC_DPREL21L:
       r_field = e_lrsel;
       break;
 
-    case R_PARISC_DIR17R:
     case R_PARISC_PCREL17R:
-    case R_PARISC_DIR14R:
     case R_PARISC_PCREL14R:
-    case R_PARISC_DPREL14R:
     case R_PARISC_PLABEL14R:
     case R_PARISC_DLTIND14R:
+      r_field = e_rsel;
+      break;
+
+    case R_PARISC_DIR17R:
+    case R_PARISC_DIR14R:
+    case R_PARISC_DPREL14R:
       r_field = e_rrsel;
       break;
 
@@ -3506,7 +3530,7 @@ final_link_relocate (input_section, contents, rel, value, htab, sym_sec, h)
          stub_entry = hppa_get_stub_entry (input_section, sym_sec,
                                            h, rel, htab);
          if (stub_entry == NULL)
-           return bfd_reloc_notsupported;
+           return bfd_reloc_undefined;
 
          /* Munge up the value and addend so that we call the stub
             rather than the procedure directly.  */
@@ -3605,6 +3629,7 @@ elf32_hppa_relocate_section (output_bfd, info, input_bfd, input_section,
       bfd_reloc_status_type r;
       const char *sym_name;
       boolean plabel;
+      boolean warned_undef;
 
       r_type = ELF32_R_TYPE (rel->r_info);
       if (r_type >= (unsigned int) R_PARISC_UNIMPLEMENTED)
@@ -3640,15 +3665,13 @@ elf32_hppa_relocate_section (output_bfd, info, input_bfd, input_section,
       h = NULL;
       sym = NULL;
       sym_sec = NULL;
+      warned_undef = false;
       if (r_symndx < symtab_hdr->sh_info)
        {
          /* This is a local symbol, h defaults to NULL.  */
          sym = local_syms + r_symndx;
          sym_sec = local_sections[r_symndx];
-         relocation = ((ELF_ST_TYPE (sym->st_info) == STT_SECTION
-                          ? 0 : sym->st_value)
-                        + sym_sec->output_offset
-                        + sym_sec->output_section->vma);
+         relocation = _bfd_elf_rela_local_sym (output_bfd, sym, sym_sec, rel);
        }
       else
        {
@@ -3681,10 +3704,13 @@ elf32_hppa_relocate_section (output_bfd, info, input_bfd, input_section,
                   && h->elf.type != STT_PARISC_MILLI)
            {
              if (info->symbolic && !info->allow_shlib_undefined)
-               if (!((*info->callbacks->undefined_symbol)
-                     (info, h->elf.root.root.string, input_bfd,
-                      input_section, rel->r_offset, false)))
-                 return false;
+               {
+                 if (!((*info->callbacks->undefined_symbol)
+                       (info, h->elf.root.root.string, input_bfd,
+                        input_section, rel->r_offset, false)))
+                   return false;
+                 warned_undef = true;
+               }
            }
          else
            {
@@ -3692,6 +3718,7 @@ elf32_hppa_relocate_section (output_bfd, info, input_bfd, input_section,
                    (info, h->elf.root.root.string, input_bfd,
                     input_section, rel->r_offset, true)))
                return false;
+             warned_undef = true;
            }
        }
 
@@ -3951,23 +3978,12 @@ elf32_hppa_relocate_section (output_bfd, info, input_bfd, input_section,
                 are copied into the output file to be resolved at run
                 time.  */
 
-             outrel.r_offset = rel->r_offset;
              outrel.r_addend = rel->r_addend;
-             skip = false;
-             if (elf_section_data (input_section)->stab_info != NULL)
-               {
-                 bfd_vma off;
-
-                 off = (_bfd_stab_section_offset
-                        (output_bfd, &htab->elf.stab_info,
-                         input_section,
-                         &elf_section_data (input_section)->stab_info,
-                         rel->r_offset));
-                 if (off == (bfd_vma) -1)
-                   skip = true;
-                 outrel.r_offset = off;
-               }
-
+             outrel.r_offset =
+               _bfd_elf_section_offset (output_bfd, info, input_section,
+                                        rel->r_offset);
+             skip = (outrel.r_offset == (bfd_vma) -1
+                     || outrel.r_offset == (bfd_vma) -2);
              outrel.r_offset += (input_section->output_offset
                                  + input_section->output_section->vma);
 
@@ -4058,15 +4074,18 @@ elf32_hppa_relocate_section (output_bfd, info, input_bfd, input_section,
 
       if (r == bfd_reloc_undefined || r == bfd_reloc_notsupported)
        {
-         (*_bfd_error_handler)
-           (_("%s(%s+0x%lx): cannot handle %s for %s"),
-            bfd_archive_filename (input_bfd),
-            input_section->name,
-            (long) rel->r_offset,
-            howto->name,
-            sym_name);
-         bfd_set_error (bfd_error_bad_value);
-         return false;
+         if (r == bfd_reloc_notsupported || !warned_undef)
+           {
+             (*_bfd_error_handler)
+               (_("%s(%s+0x%lx): cannot handle %s for %s"),
+                bfd_archive_filename (input_bfd),
+                input_section->name,
+                (long) rel->r_offset,
+                howto->name,
+                sym_name);
+             bfd_set_error (bfd_error_bad_value);
+             return false;
+           }
        }
       else
        {
@@ -4080,32 +4099,6 @@ elf32_hppa_relocate_section (output_bfd, info, input_bfd, input_section,
   return true;
 }
 
-/* Comparison function for qsort to sort unwind section during a
-   final link.  */
-
-static int
-hppa_unwind_entry_compare (a, b)
-     const PTR a;
-     const PTR b;
-{
-  const bfd_byte *ap, *bp;
-  unsigned long av, bv;
-
-  ap = (const bfd_byte *) a;
-  av = (unsigned long) ap[0] << 24;
-  av |= (unsigned long) ap[1] << 16;
-  av |= (unsigned long) ap[2] << 8;
-  av |= (unsigned long) ap[3];
-
-  bp = (const bfd_byte *) b;
-  bv = (unsigned long) bp[0] << 24;
-  bv |= (unsigned long) bp[1] << 16;
-  bv |= (unsigned long) bp[2] << 8;
-  bv |= (unsigned long) bp[3];
-
-  return av < bv ? -1 : av > bv ? 1 : 0;
-}
-
 /* Finish up dynamic symbol handling.  We set the contents of various
    dynamic sections here.  */
 
@@ -4449,6 +4442,7 @@ elf32_hppa_elf_get_symbol_type (elf_sym, type)
 /* Stuff for the BFD linker.  */
 #define bfd_elf32_bfd_final_link            elf32_hppa_final_link
 #define bfd_elf32_bfd_link_hash_table_create elf32_hppa_link_hash_table_create
+#define bfd_elf32_bfd_link_hash_table_free   elf32_hppa_link_hash_table_free
 #define elf_backend_add_symbol_hook         elf32_hppa_add_symbol_hook
 #define elf_backend_adjust_dynamic_symbol    elf32_hppa_adjust_dynamic_symbol
 #define elf_backend_copy_indirect_symbol     elf32_hppa_copy_indirect_symbol
This page took 0.042264 seconds and 4 git commands to generate.