]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - bfd/elfxx-ia64.c
bfd/
[thirdparty/binutils-gdb.git] / bfd / elfxx-ia64.c
index 7c1837b656b134599543e6ad987ce21a9cbd5836..f3674b4514691f65aa090f3ecd9f7fc40c3e8262 100644 (file)
@@ -1,5 +1,5 @@
 /* IA-64 support for 64-bit ELF
-   Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+   Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
    Free Software Foundation, Inc.
    Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
 
@@ -19,8 +19,8 @@
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
 
-#include "bfd.h"
 #include "sysdep.h"
+#include "bfd.h"
 #include "libbfd.h"
 #include "elf-bfd.h"
 #include "opcode/ia64.h"
@@ -80,9 +80,6 @@ struct elfNN_ia64_dyn_sym_info
   /* The addend for which this entry is relevant.  */
   bfd_vma addend;
 
-  /* Next addend in the list.  */
-  struct elfNN_ia64_dyn_sym_info *next;
-
   bfd_vma got_offset;
   bfd_vma fptr_offset;
   bfd_vma pltoff_offset;
@@ -133,6 +130,13 @@ struct elfNN_ia64_local_hash_entry
 {
   int id;
   unsigned int r_sym;
+  /* The number of elements in elfNN_ia64_dyn_sym_info array.  */
+  unsigned int count;
+  /* The number of sorted elements in elfNN_ia64_dyn_sym_info array.  */
+  unsigned int sorted_count;
+  /* The size of elfNN_ia64_dyn_sym_info array.  */
+  unsigned int size;
+  /* The array of elfNN_ia64_dyn_sym_info.  */
   struct elfNN_ia64_dyn_sym_info *info;
 
   /* TRUE if this hash entry's addends was translated for
@@ -143,6 +147,13 @@ struct elfNN_ia64_local_hash_entry
 struct elfNN_ia64_link_hash_entry
 {
   struct elf_link_hash_entry root;
+  /* The number of elements in elfNN_ia64_dyn_sym_info array.  */
+  unsigned int count;
+  /* The number of sorted elements in elfNN_ia64_dyn_sym_info array.  */
+  unsigned int sorted_count;
+  /* The size of elfNN_ia64_dyn_sym_info array.  */
+  unsigned int size;
+  /* The array of elfNN_ia64_dyn_sym_info.  */
   struct elfNN_ia64_dyn_sym_info *info;
 };
 
@@ -204,10 +215,6 @@ static bfd_boolean elfNN_ia64_add_symbol_hook
   PARAMS ((bfd *abfd, struct bfd_link_info *info, Elf_Internal_Sym *sym,
           const char **namep, flagword *flagsp, asection **secp,
           bfd_vma *valp));
-static int elfNN_ia64_additional_program_headers
-  PARAMS ((bfd *abfd));
-static bfd_boolean elfNN_ia64_modify_segment_map
-  PARAMS ((bfd *, struct bfd_link_info *));
 static bfd_boolean elfNN_ia64_is_local_label_name
   PARAMS ((bfd *abfd, const char *name));
 static bfd_boolean elfNN_ia64_dynamic_symbol_p
@@ -216,7 +223,7 @@ static struct bfd_hash_entry *elfNN_ia64_new_elf_hash_entry
   PARAMS ((struct bfd_hash_entry *entry, struct bfd_hash_table *table,
           const char *string));
 static void elfNN_ia64_hash_copy_indirect
-  PARAMS ((const struct elf_backend_data *, struct elf_link_hash_entry *,
+  PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *,
           struct elf_link_hash_entry *));
 static void elfNN_ia64_hash_hide_symbol
   PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *, bfd_boolean));
@@ -606,6 +613,22 @@ elfNN_ia64_reloc_type_lookup (abfd, bfd_code)
   return lookup_howto (rtype);
 }
 
+static reloc_howto_type *
+elfNN_ia64_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
+                             const char *r_name)
+{
+  unsigned int i;
+
+  for (i = 0;
+       i < sizeof (ia64_howto_table) / sizeof (ia64_howto_table[0]);
+       i++)
+    if (ia64_howto_table[i].name != NULL
+       && strcasecmp (ia64_howto_table[i].name, r_name) == 0)
+      return &ia64_howto_table[i];
+
+  return NULL;
+}
+
 /* Given a ELF reloc, return the matching HOWTO structure.  */
 
 static void
@@ -852,6 +875,12 @@ elfNN_ia64_relax_brl (bfd_byte *contents, bfd_vma off)
   bfd_putl64 (t0, hit_addr);
   bfd_putl64 (t1, hit_addr + 8);
 }
+
+/* Rename some of the generic section flags to better document how they
+   are used here.  */
+#define skip_relax_pass_0 need_finalize_relax
+#define skip_relax_pass_1 has_gp_reloc
+
 \f
 /* These functions do relaxation for IA-64 ELF.  */
 
@@ -880,6 +909,8 @@ elfNN_ia64_relax_section (abfd, sec, link_info, again)
   bfd_boolean changed_contents = FALSE;
   bfd_boolean changed_relocs = FALSE;
   bfd_boolean changed_got = FALSE;
+  bfd_boolean skip_relax_pass_0 = TRUE;
+  bfd_boolean skip_relax_pass_1 = TRUE;
   bfd_vma gp = 0;
 
   /* Assume we're not going to change any sizes, and we'll only need
@@ -891,11 +922,11 @@ elfNN_ia64_relax_section (abfd, sec, link_info, again)
     return FALSE;
 
   /* Nothing to do if there are no relocations or there is no need for
-     the relax finalize pass.  */
+     the current pass.  */
   if ((sec->flags & SEC_RELOC) == 0
       || sec->reloc_count == 0
-      || (!link_info->need_relax_finalize
-         && sec->need_finalize_relax == 0))
+      || (link_info->relax_pass == 0 && sec->skip_relax_pass_0)
+      || (link_info->relax_pass == 1 && sec->skip_relax_pass_1))
     return TRUE;
 
   symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
@@ -936,20 +967,19 @@ elfNN_ia64_relax_section (abfd, sec, link_info, again)
        case R_IA64_PCREL21BI:
        case R_IA64_PCREL21M:
        case R_IA64_PCREL21F:
-         /* In the finalize pass, all br relaxations are done. We can
-            skip it. */
-         if (!link_info->need_relax_finalize)
+         /* In pass 1, all br relaxations are done. We can skip it. */
+         if (link_info->relax_pass == 1)
            continue;
+         skip_relax_pass_0 = FALSE;
          is_branch = TRUE;
          break;
 
        case R_IA64_PCREL60B:
-         /* We can't optimize brl to br before the finalize pass since
-            br relaxations will increase the code size. Defer it to
-            the finalize pass.  */
-         if (link_info->need_relax_finalize)
+         /* We can't optimize brl to br in pass 0 since br relaxations
+            will increase the code size. Defer it to pass 1.  */
+         if (link_info->relax_pass == 0)
            {
-             sec->need_finalize_relax = 1;
+             skip_relax_pass_1 = FALSE;
              continue;
            }
          is_branch = TRUE;
@@ -957,12 +987,11 @@ elfNN_ia64_relax_section (abfd, sec, link_info, again)
 
        case R_IA64_LTOFF22X:
        case R_IA64_LDXMOV:
-         /* We can't relax ldx/mov before the finalize pass since
-            br relaxations will increase the code size. Defer it to
-            the finalize pass.  */
-         if (link_info->need_relax_finalize)
+         /* We can't relax ldx/mov in pass 0 since br relaxations will
+            increase the code size. Defer it to pass 1.  */
+         if (link_info->relax_pass == 0)
            {
-             sec->need_finalize_relax = 1;
+             skip_relax_pass_1 = FALSE;
              continue;
            }
          is_branch = FALSE;
@@ -1338,7 +1367,8 @@ elfNN_ia64_relax_section (abfd, sec, link_info, again)
       elfNN_ia64_dyn_sym_traverse (ia64_info, allocate_local_got, &data);
       ia64_info->got_sec->size = data.ofs;
 
-      if (ia64_info->root.dynamic_sections_created)
+      if (ia64_info->root.dynamic_sections_created
+         && ia64_info->rel_got_sec != NULL)
        {
          /* Resize .rela.got.  */
          ia64_info->rel_got_sec->size = 0;
@@ -1351,8 +1381,12 @@ elfNN_ia64_relax_section (abfd, sec, link_info, again)
        }
     }
 
-  if (!link_info->need_relax_finalize)
-    sec->need_finalize_relax = 0;
+  if (link_info->relax_pass == 0)
+    {
+      /* Pass 0 is only needed to relax br.  */
+      sec->skip_relax_pass_0 = skip_relax_pass_0;
+      sec->skip_relax_pass_1 = skip_relax_pass_1;
+    }
 
   *again = changed_contents || changed_relocs;
   return TRUE;
@@ -1368,6 +1402,8 @@ elfNN_ia64_relax_section (abfd, sec, link_info, again)
     free (internal_relocs);
   return FALSE;
 }
+#undef skip_relax_pass_0
+#undef skip_relax_pass_1
 
 static void
 elfNN_ia64_relax_ldxmov (contents, off)
@@ -1404,22 +1440,15 @@ elfNN_ia64_relax_ldxmov (contents, off)
 /* Return TRUE if NAME is an unwind table section name.  */
 
 static inline bfd_boolean
-is_unwind_section_name (abfd, name)
-       bfd *abfd;
-       const char *name;
+is_unwind_section_name (bfd *abfd, const char *name)
 {
-  size_t len1, len2, len3;
-
   if (elfNN_ia64_hpux_vec (abfd->xvec)
       && !strcmp (name, ELF_STRING_ia64_unwind_hdr))
     return FALSE;
 
-  len1 = sizeof (ELF_STRING_ia64_unwind) - 1;
-  len2 = sizeof (ELF_STRING_ia64_unwind_info) - 1;
-  len3 = sizeof (ELF_STRING_ia64_unwind_once) - 1;
-  return ((strncmp (name, ELF_STRING_ia64_unwind, len1) == 0
-          && strncmp (name, ELF_STRING_ia64_unwind_info, len2) != 0)
-         || strncmp (name, ELF_STRING_ia64_unwind_once, len3) == 0);
+  return ((CONST_STRNEQ (name, ELF_STRING_ia64_unwind)
+          && ! CONST_STRNEQ (name, ELF_STRING_ia64_unwind_info))
+         || CONST_STRNEQ (name, ELF_STRING_ia64_unwind_once));
 }
 
 /* Handle an IA-64 specific section when reading an object file.  This
@@ -1523,6 +1552,11 @@ elfNN_ia64_fake_sections (abfd, hdr, sec)
   if (sec->flags & SEC_SMALL_DATA)
     hdr->sh_flags |= SHF_IA_64_SHORT;
 
+  /* Some HP linkers look for the SHF_IA_64_HP_TLS flag instead of SHF_TLS. */
+
+  if (elfNN_ia64_hpux_vec (abfd->xvec) && (sec->flags & SHF_TLS))
+    hdr->sh_flags |= SHF_IA_64_HP_TLS;
+
   return TRUE;
 }
 
@@ -1608,8 +1642,8 @@ elfNN_ia64_add_symbol_hook (abfd, info, sym, namep, flagsp, secp, valp)
 /* Return the number of additional phdrs we will need.  */
 
 static int
-elfNN_ia64_additional_program_headers (abfd)
-     bfd *abfd;
+elfNN_ia64_additional_program_headers (bfd *abfd,
+                                      struct bfd_link_info *info ATTRIBUTE_UNUSED)
 {
   asection *s;
   int ret = 0;
@@ -1628,9 +1662,8 @@ elfNN_ia64_additional_program_headers (abfd)
 }
 
 static bfd_boolean
-elfNN_ia64_modify_segment_map (abfd, info)
-     bfd *abfd;
-     struct bfd_link_info *info ATTRIBUTE_UNUSED;
+elfNN_ia64_modify_segment_map (bfd *abfd,
+                              struct bfd_link_info *info ATTRIBUTE_UNUSED)
 {
   struct elf_segment_map *m, **pm;
   Elf_Internal_Shdr *hdr;
@@ -1713,17 +1746,30 @@ elfNN_ia64_modify_segment_map (abfd, info)
        }
     }
 
-  /* Turn on PF_IA_64_NORECOV if needed.  This involves traversing all of
-     the input sections for each output section in the segment and testing
-     for SHF_IA_64_NORECOV on each.  */
-  for (m = elf_tdata (abfd)->segment_map; m != NULL; m = m->next)
+  return TRUE;
+}
+
+/* Turn on PF_IA_64_NORECOV if needed.  This involves traversing all of
+   the input sections for each output section in the segment and testing
+   for SHF_IA_64_NORECOV on each.  */
+
+static bfd_boolean
+elfNN_ia64_modify_program_headers (bfd *abfd,
+                                  struct bfd_link_info *info ATTRIBUTE_UNUSED)
+{
+  struct elf_obj_tdata *tdata = elf_tdata (abfd);
+  struct elf_segment_map *m;
+  Elf_Internal_Phdr *p;
+
+  for (p = tdata->phdr, m = tdata->segment_map; m != NULL; m = m->next, p++)
     if (m->p_type == PT_LOAD)
       {
        int i;
        for (i = m->count - 1; i >= 0; --i)
          {
            struct bfd_link_order *order = m->sections[i]->map_head.link_order;
-           while (order)
+
+           while (order != NULL)
              {
                if (order->type == bfd_indirect_link_order)
                  {
@@ -1731,7 +1777,7 @@ elfNN_ia64_modify_segment_map (abfd, info)
                    bfd_vma flags = elf_section_data(is)->this_hdr.sh_flags;
                    if (flags & SHF_IA_64_NORECOV)
                      {
-                       m->p_flags |= PF_IA_64_NORECOV;
+                       p->p_flags |= PF_IA_64_NORECOV;
                        goto found;
                      }
                  }
@@ -1793,12 +1839,15 @@ elfNN_ia64_new_elf_hash_entry (entry, table, string)
                                     table, string));
 
   ret->info = NULL;
+  ret->count = 0;
+  ret->sorted_count = 0;
+  ret->size = 0;
   return (struct bfd_hash_entry *) ret;
 }
 
 static void
-elfNN_ia64_hash_copy_indirect (bed, xdir, xind)
-     const struct elf_backend_data *bed ATTRIBUTE_UNUSED;
+elfNN_ia64_hash_copy_indirect (info, xdir, xind)
+     struct bfd_link_info *info;
      struct elf_link_hash_entry *xdir, *xind;
 {
   struct elfNN_ia64_link_hash_entry *dir, *ind;
@@ -1820,29 +1869,43 @@ elfNN_ia64_hash_copy_indirect (bed, xdir, xind)
   /* Copy over the got and plt data.  This would have been done
      by check_relocs.  */
 
-  if (dir->info == NULL)
+  if (ind->info != NULL)
     {
       struct elfNN_ia64_dyn_sym_info *dyn_i;
+      unsigned int count;
+
+      if (dir->info)
+       free (dir->info);
+
+      dir->info = ind->info;
+      dir->count = ind->count;
+      dir->sorted_count = ind->sorted_count;
+      dir->size = ind->size;
 
-      dir->info = dyn_i = ind->info;
       ind->info = NULL;
+      ind->count = 0;
+      ind->sorted_count = 0;
+      ind->size = 0;
 
       /* Fix up the dyn_sym_info pointers to the global symbol.  */
-      for (; dyn_i; dyn_i = dyn_i->next)
+      for (count = dir->count, dyn_i = dir->info;
+          count != 0;
+          count--, dyn_i++)
        dyn_i->h = &dir->root;
     }
-  BFD_ASSERT (ind->info == NULL);
 
   /* Copy over the dynindx.  */
 
-  if (dir->root.dynindx == -1)
+  if (ind->root.dynindx != -1)
     {
+      if (dir->root.dynindx != -1)
+       _bfd_elf_strtab_delref (elf_hash_table (info)->dynstr,
+                               dir->root.dynstr_index);
       dir->root.dynindx = ind->root.dynindx;
       dir->root.dynstr_index = ind->root.dynstr_index;
       ind->root.dynindx = -1;
       ind->root.dynstr_index = 0;
     }
-  BFD_ASSERT (ind->root.dynindx == -1);
 }
 
 static void
@@ -1853,12 +1916,15 @@ elfNN_ia64_hash_hide_symbol (info, xh, force_local)
 {
   struct elfNN_ia64_link_hash_entry *h;
   struct elfNN_ia64_dyn_sym_info *dyn_i;
+  unsigned int count;
 
   h = (struct elfNN_ia64_link_hash_entry *)xh;
 
   _bfd_elf_link_hash_hide_symbol (info, &h->root, force_local);
 
-  for (dyn_i = h->info; dyn_i; dyn_i = dyn_i->next)
+  for (count = h->count, dyn_i = h->info;
+       count != 0;
+       count--, dyn_i++)
     {
       dyn_i->want_plt2 = 0;
       dyn_i->want_plt = 0;
@@ -1907,7 +1973,8 @@ elfNN_ia64_hash_table_create (abfd)
     return 0;
 
   if (!_bfd_elf_link_hash_table_init (&ret->root, abfd,
-                                     elfNN_ia64_new_elf_hash_entry))
+                                     elfNN_ia64_new_elf_hash_entry,
+                                     sizeof (struct elfNN_ia64_link_hash_entry)))
     {
       free (ret);
       return 0;
@@ -1925,6 +1992,51 @@ elfNN_ia64_hash_table_create (abfd)
   return &ret->root.root;
 }
 
+/* Free the global elfNN_ia64_dyn_sym_info array.  */
+
+static bfd_boolean
+elfNN_ia64_global_dyn_info_free (void **xentry,
+                               PTR unused ATTRIBUTE_UNUSED)
+{
+  struct elfNN_ia64_link_hash_entry *entry
+    = (struct elfNN_ia64_link_hash_entry *) xentry;
+
+  if (entry->root.root.type == bfd_link_hash_warning)
+    entry = (struct elfNN_ia64_link_hash_entry *) entry->root.root.u.i.link;
+
+  if (entry->info)
+    {
+      free (entry->info);
+      entry->info = NULL;
+      entry->count = 0;
+      entry->sorted_count = 0;
+      entry->size = 0;
+    }
+
+  return TRUE;
+}
+
+/* Free the local elfNN_ia64_dyn_sym_info array.  */
+
+static bfd_boolean
+elfNN_ia64_local_dyn_info_free (void **slot,
+                               PTR unused ATTRIBUTE_UNUSED)
+{
+  struct elfNN_ia64_local_hash_entry *entry
+    = (struct elfNN_ia64_local_hash_entry *) *slot;
+
+  if (entry->info)
+    {
+      free (entry->info);
+      entry->info = NULL;
+      entry->count = 0;
+      entry->sorted_count = 0;
+      entry->size = 0;
+    }
+
+  return TRUE;
+}
+
 /* Destroy IA-64 linker hash table.  */
 
 static void
@@ -1934,9 +2046,15 @@ elfNN_ia64_hash_table_free (hash)
   struct elfNN_ia64_link_hash_table *ia64_info
     = (struct elfNN_ia64_link_hash_table *) hash;
   if (ia64_info->loc_hash_table)
-    htab_delete (ia64_info->loc_hash_table);
+    {
+      htab_traverse (ia64_info->loc_hash_table,
+                    elfNN_ia64_local_dyn_info_free, NULL);
+      htab_delete (ia64_info->loc_hash_table);
+    }
   if (ia64_info->loc_hash_memory)
     objalloc_free ((struct objalloc *) ia64_info->loc_hash_memory);
+  elf_link_hash_traverse (&ia64_info->root,
+                         elfNN_ia64_global_dyn_info_free, NULL);
   _bfd_generic_link_hash_table_free (hash);
 }
 
@@ -1958,11 +2076,14 @@ elfNN_ia64_global_dyn_sym_thunk (xentry, xdata)
   struct elfNN_ia64_dyn_sym_traverse_data *data
     = (struct elfNN_ia64_dyn_sym_traverse_data *) xdata;
   struct elfNN_ia64_dyn_sym_info *dyn_i;
+  unsigned int count;
 
   if (entry->root.root.type == bfd_link_hash_warning)
     entry = (struct elfNN_ia64_link_hash_entry *) entry->root.root.u.i.link;
 
-  for (dyn_i = entry->info; dyn_i; dyn_i = dyn_i->next)
+  for (count = entry->count, dyn_i = entry->info;
+       count != 0;
+       count--, dyn_i++)
     if (! (*data->func) (dyn_i, data->data))
       return FALSE;
   return TRUE;
@@ -1978,11 +2099,14 @@ elfNN_ia64_local_dyn_sym_thunk (slot, xdata)
   struct elfNN_ia64_dyn_sym_traverse_data *data
     = (struct elfNN_ia64_dyn_sym_traverse_data *) xdata;
   struct elfNN_ia64_dyn_sym_info *dyn_i;
+  unsigned int count;
 
-  for (dyn_i = entry->info; dyn_i; dyn_i = dyn_i->next)
+  for (count = entry->count, dyn_i = entry->info;
+       count != 0;
+       count--, dyn_i++)
     if (! (*data->func) (dyn_i, data->data))
-      return 0;
-  return 1;
+      return FALSE;
+  return TRUE;
 }
 
 static void
@@ -2091,8 +2215,129 @@ get_local_sym_hash (ia64_info, abfd, rel, create)
   return ret;
 }
 
+/* Used to sort elfNN_ia64_dyn_sym_info array.  */
+
+static int
+addend_compare (const void *xp, const void *yp)
+{
+  const struct elfNN_ia64_dyn_sym_info *x
+    = (const struct elfNN_ia64_dyn_sym_info *) xp;
+  const struct elfNN_ia64_dyn_sym_info *y
+    = (const struct elfNN_ia64_dyn_sym_info *) yp;
+
+  return x->addend < y->addend ? -1 : x->addend > y->addend ? 1 : 0;
+}
+
+/* Sort elfNN_ia64_dyn_sym_info array and remove duplicates.  */
+
+static unsigned int
+sort_dyn_sym_info (struct elfNN_ia64_dyn_sym_info *info,
+                  unsigned int count)
+{
+  bfd_vma curr, prev;
+  unsigned int i, dup, diff, dest, src, len;
+
+  qsort (info, count, sizeof (*info), addend_compare);
+
+  /* Find the first duplicate.  */
+  prev = info [0].addend;
+  for (i = 1; i < count; i++)
+    {
+      curr = info [i].addend;
+      if (curr == prev)
+       break;
+      prev = curr;
+    }
+
+  /* Remove duplicates.  */
+  if (i < count)
+    {
+      /* We need to move a block of elements to here.  */
+      dest = i++;
+      while (i < count)
+       {
+         curr = info [i].addend;
+
+         /* Move a block of elements whose first one is different from
+            the previous.  */
+         if (curr == prev)
+           {
+             for (src = i + 1; src < count; src++)
+               if (info [src].addend != curr)
+                 break;
+           }
+         else
+           src = i;
+
+         if (src >= count)
+           break;
+
+         /* Find the next duplicate.  */
+         prev = info [src].addend;
+         for (dup = src + 1; dup < count; dup++)
+           {
+             curr = info [dup].addend;
+             if (curr == prev)
+               break;
+             prev = curr;
+           }
+
+         /* How much to move.  */
+         len = dup - src;
+         i = dup + 1;
+
+         if (len == 1 && dup < count)
+           {
+             /* If we only move 1 element, we combine it with the next
+                one.  Find the next different one.  */
+             for (diff = dup + 1, src++; diff < count; diff++, src++)
+               if (info [diff].addend != curr)
+                 break;
+
+             if (diff < count)
+               {
+                 /* Find the next duplicate.  */
+                 prev = info [diff].addend;
+                 for (dup = diff + 1; dup < count; dup++)
+                   {
+                     curr = info [dup].addend;
+                     if (curr == prev)
+                       break;
+                     prev = curr;
+                     diff++;
+                   }
+
+                 len = diff - src + 1;
+                 i = diff + 1;
+               }
+           }
+
+         memmove (&info [dest], &info [src], len * sizeof (*info));
+
+         dest += len;
+       }
+
+      count = dest;
+    }
+
+  return count;
+}
+
 /* Find and/or create a descriptor for dynamic symbol info.  This will
-   vary based on global or local symbol, and the addend to the reloc.  */
+   vary based on global or local symbol, and the addend to the reloc.
+
+   We don't sort when inserting.  Also, we sort and eliminate
+   duplicates if there is an unsorted section.  Typically, this will
+   only happen once, because we do all insertions before lookups.  We
+   then use bsearch to do a lookup.  This also allows lookups to be
+   fast.  So we have fast insertion (O(log N) due to duplicate check),
+   fast lookup (O(log N)) and one sort (O(N log N) expected time).
+   Previously, all lookups were O(N) because of the use of the linked
+   list and also all insertions were O(N) because of the check for
+   duplicates.  There are some complications here because the array
+   size grows occasionally, which may add an O(N) factor, but this
+   should be rare.  Also,  we free the excess array allocation, which
+   requires a copy which is O(N), but this only happens once.  */
 
 static struct elfNN_ia64_dyn_sym_info *
 get_dyn_sym_info (ia64_info, h, abfd, rel, create)
@@ -2102,12 +2347,22 @@ get_dyn_sym_info (ia64_info, h, abfd, rel, create)
      const Elf_Internal_Rela *rel;
      bfd_boolean create;
 {
-  struct elfNN_ia64_dyn_sym_info **pp;
-  struct elfNN_ia64_dyn_sym_info *dyn_i;
+  struct elfNN_ia64_dyn_sym_info **info_p, *info, *dyn_i, key;
+  unsigned int *count_p, *sorted_count_p, *size_p;
+  unsigned int count, sorted_count, size;
   bfd_vma addend = rel ? rel->r_addend : 0;
+  bfd_size_type amt;
 
   if (h)
-    pp = &((struct elfNN_ia64_link_hash_entry *)h)->info;
+    {
+      struct elfNN_ia64_link_hash_entry *global_h;
+
+      global_h = (struct elfNN_ia64_link_hash_entry *) h;
+      info_p = &global_h->info;
+      count_p = &global_h->count;
+      sorted_count_p = &global_h->sorted_count;
+      size_p = &global_h->size;
+    }
   else
     {
       struct elfNN_ia64_local_hash_entry *loc_h;
@@ -2119,18 +2374,107 @@ get_dyn_sym_info (ia64_info, h, abfd, rel, create)
          return NULL;
        }
 
-      pp = &loc_h->info;
+      info_p = &loc_h->info;
+      count_p = &loc_h->count;
+      sorted_count_p = &loc_h->sorted_count;
+      size_p = &loc_h->size;
     }
 
-  for (dyn_i = *pp; dyn_i && dyn_i->addend != addend; dyn_i = *pp)
-    pp = &dyn_i->next;
-
-  if (dyn_i == NULL && create)
+  count = *count_p;
+  sorted_count = *sorted_count_p;
+  size = *size_p;
+  info = *info_p;
+  if (create)
     {
-      dyn_i = ((struct elfNN_ia64_dyn_sym_info *)
-              bfd_zalloc (abfd, (bfd_size_type) sizeof *dyn_i));
-      *pp = dyn_i;
+      /* When we create the array, we don't check for duplicates,
+         except in the previously sorted section if one exists, and
+        against the last inserted entry.  This allows insertions to
+        be fast.  */
+      if (info)
+       {
+         if (sorted_count)
+           {
+             /* Try bsearch first on the sorted section.  */
+             key.addend = addend;
+             dyn_i = bsearch (&key, info, sorted_count,
+                              sizeof (*info), addend_compare);
+
+             if (dyn_i)
+               {
+                 return dyn_i;
+               }
+           }
+
+         /* Do a quick check for the last inserted entry.  */
+         dyn_i = info + count - 1;
+         if (dyn_i->addend == addend)
+           {
+             return dyn_i;
+           }
+       }
+
+      if (size == 0)
+       {
+         /* It is the very first element. We create the array of size
+            1.  */
+         size = 1;
+         amt = size * sizeof (*info);
+         info = bfd_malloc (amt);
+       }
+      else if (size <= count)
+       {
+         /* We double the array size every time when we reach the
+            size limit.  */
+         size += size;
+         amt = size * sizeof (*info);
+         info = bfd_realloc (info, amt);
+       }
+      else
+       goto has_space;
+
+      if (info == NULL)
+       return NULL;
+      *size_p = size;
+      *info_p = info;
+
+has_space:
+      /* Append the new one to the array.  */
+      dyn_i = info + count;
+      memset (dyn_i, 0, sizeof (*dyn_i));
       dyn_i->addend = addend;
+      
+      /* We increment count only since the new ones are unsorted and
+        may have duplicate.  */
+      (*count_p)++;
+    }
+  else
+    {
+      /* It is a lookup without insertion.  Sort array if part of the
+        array isn't sorted.  */
+      if (count != sorted_count)
+       {
+         count = sort_dyn_sym_info (info, count);
+         *count_p = count;
+         *sorted_count_p = count;
+       }
+
+      /* Free unused memory.  */
+      if (size != count)
+       {
+         amt = count * sizeof (*info);
+         info = bfd_malloc (amt);
+         if (info != NULL)
+           {
+             memcpy (info, *info_p, amt);
+             free (*info_p);
+             *size_p = count;
+             *info_p = info;
+           }
+       }
+
+      key.addend = addend;
+      dyn_i = bsearch (&key, info, count,
+                      sizeof (*info), addend_compare);
     }
 
   return dyn_i;
@@ -2286,10 +2630,10 @@ get_reloc_section (abfd, ia64_info, sec, create)
   if (srel_name == NULL)
     return NULL;
 
-  BFD_ASSERT ((strncmp (srel_name, ".rela", 5) == 0
+  BFD_ASSERT ((CONST_STRNEQ (srel_name, ".rela")
               && strcmp (bfd_get_section_name (abfd, sec),
                          srel_name+5) == 0)
-             || (strncmp (srel_name, ".rel", 4) == 0
+             || (CONST_STRNEQ (srel_name, ".rel")
                  && strcmp (bfd_get_section_name (abfd, sec),
                             srel_name+4) == 0));
 
@@ -2356,6 +2700,23 @@ elfNN_ia64_check_relocs (abfd, info, sec, relocs)
   Elf_Internal_Shdr *symtab_hdr;
   const Elf_Internal_Rela *rel;
   asection *got, *fptr, *srel, *pltoff;
+  enum {
+    NEED_GOT = 1,
+    NEED_GOTX = 2,
+    NEED_FPTR = 4,
+    NEED_PLTOFF = 8,
+    NEED_MIN_PLT = 16,
+    NEED_FULL_PLT = 32,
+    NEED_DYNREL = 64,
+    NEED_LTOFF_FPTR = 128,
+    NEED_TPREL = 256,
+    NEED_DTPMOD = 512,
+    NEED_DTPREL = 1024
+  };
+  int need_entry;
+  struct elf_link_hash_entry *h;
+  unsigned long r_symndx;
+  bfd_boolean maybe_dynamic;
 
   if (info->relocatable)
     return TRUE;
@@ -2366,29 +2727,181 @@ elfNN_ia64_check_relocs (abfd, info, sec, relocs)
   got = fptr = srel = pltoff = NULL;
 
   relend = relocs + sec->reloc_count;
+
+  /* We scan relocations first to create dynamic relocation arrays.  We
+     modified get_dyn_sym_info to allow fast insertion and support fast
+     lookup in the next loop.  */
+  for (rel = relocs; rel < relend; ++rel)
+    {
+      r_symndx = ELFNN_R_SYM (rel->r_info);
+      if (r_symndx >= symtab_hdr->sh_info)
+       {
+         long indx = r_symndx - symtab_hdr->sh_info;
+         h = elf_sym_hashes (abfd)[indx];
+         while (h->root.type == bfd_link_hash_indirect
+                || h->root.type == bfd_link_hash_warning)
+           h = (struct elf_link_hash_entry *) h->root.u.i.link;
+       }
+      else
+       h = NULL;
+
+      /* We can only get preliminary data on whether a symbol is
+        locally or externally defined, as not all of the input files
+        have yet been processed.  Do something with what we know, as
+        this may help reduce memory usage and processing time later.  */
+      maybe_dynamic = (h && ((!info->executable
+                             && (!SYMBOLIC_BIND (info, h)
+                                 || info->unresolved_syms_in_shared_libs == RM_IGNORE))
+                            || !h->def_regular
+                            || h->root.type == bfd_link_hash_defweak));
+
+      need_entry = 0;
+      switch (ELFNN_R_TYPE (rel->r_info))
+       {
+       case R_IA64_TPREL64MSB:
+       case R_IA64_TPREL64LSB:
+         if (info->shared || maybe_dynamic)
+           need_entry = NEED_DYNREL;
+         break;
+
+       case R_IA64_LTOFF_TPREL22:
+         need_entry = NEED_TPREL;
+         if (info->shared)
+           info->flags |= DF_STATIC_TLS;
+         break;
+
+       case R_IA64_DTPREL32MSB:
+       case R_IA64_DTPREL32LSB:
+       case R_IA64_DTPREL64MSB:
+       case R_IA64_DTPREL64LSB:
+         if (info->shared || maybe_dynamic)
+           need_entry = NEED_DYNREL;
+         break;
+
+       case R_IA64_LTOFF_DTPREL22:
+         need_entry = NEED_DTPREL;
+         break;
+
+       case R_IA64_DTPMOD64MSB:
+       case R_IA64_DTPMOD64LSB:
+         if (info->shared || maybe_dynamic)
+           need_entry = NEED_DYNREL;
+         break;
+
+       case R_IA64_LTOFF_DTPMOD22:
+         need_entry = NEED_DTPMOD;
+         break;
+
+       case R_IA64_LTOFF_FPTR22:
+       case R_IA64_LTOFF_FPTR64I:
+       case R_IA64_LTOFF_FPTR32MSB:
+       case R_IA64_LTOFF_FPTR32LSB:
+       case R_IA64_LTOFF_FPTR64MSB:
+       case R_IA64_LTOFF_FPTR64LSB:
+         need_entry = NEED_FPTR | NEED_GOT | NEED_LTOFF_FPTR;
+         break;
+
+       case R_IA64_FPTR64I:
+       case R_IA64_FPTR32MSB:
+       case R_IA64_FPTR32LSB:
+       case R_IA64_FPTR64MSB:
+       case R_IA64_FPTR64LSB:
+         if (info->shared || h)
+           need_entry = NEED_FPTR | NEED_DYNREL;
+         else
+           need_entry = NEED_FPTR;
+         break;
+
+       case R_IA64_LTOFF22:
+       case R_IA64_LTOFF64I:
+         need_entry = NEED_GOT;
+         break;
+
+       case R_IA64_LTOFF22X:
+         need_entry = NEED_GOTX;
+         break;
+
+       case R_IA64_PLTOFF22:
+       case R_IA64_PLTOFF64I:
+       case R_IA64_PLTOFF64MSB:
+       case R_IA64_PLTOFF64LSB:
+         need_entry = NEED_PLTOFF;
+         if (h)
+           {
+             if (maybe_dynamic)
+               need_entry |= NEED_MIN_PLT;
+           }
+         else
+           {
+             (*info->callbacks->warning)
+               (info, _("@pltoff reloc against local symbol"), 0,
+                abfd, 0, (bfd_vma) 0);
+           }
+         break;
+
+       case R_IA64_PCREL21B:
+        case R_IA64_PCREL60B:
+         /* Depending on where this symbol is defined, we may or may not
+            need a full plt entry.  Only skip if we know we'll not need
+            the entry -- static or symbolic, and the symbol definition
+            has already been seen.  */
+         if (maybe_dynamic && rel->r_addend == 0)
+           need_entry = NEED_FULL_PLT;
+         break;
+
+       case R_IA64_IMM14:
+       case R_IA64_IMM22:
+       case R_IA64_IMM64:
+       case R_IA64_DIR32MSB:
+       case R_IA64_DIR32LSB:
+       case R_IA64_DIR64MSB:
+       case R_IA64_DIR64LSB:
+         /* Shared objects will always need at least a REL relocation.  */
+         if (info->shared || maybe_dynamic)
+           need_entry = NEED_DYNREL;
+         break;
+
+       case R_IA64_IPLTMSB:
+       case R_IA64_IPLTLSB:
+         /* Shared objects will always need at least a REL relocation.  */
+         if (info->shared || maybe_dynamic)
+           need_entry = NEED_DYNREL;
+         break;
+
+       case R_IA64_PCREL22:
+       case R_IA64_PCREL64I:
+       case R_IA64_PCREL32MSB:
+       case R_IA64_PCREL32LSB:
+       case R_IA64_PCREL64MSB:
+       case R_IA64_PCREL64LSB:
+         if (maybe_dynamic)
+           need_entry = NEED_DYNREL;
+         break;
+       }
+
+      if (!need_entry)
+       continue;
+
+      if ((need_entry & NEED_FPTR) != 0
+         && rel->r_addend)
+       {
+         (*info->callbacks->warning)
+           (info, _("non-zero addend in @fptr reloc"), 0,
+            abfd, 0, (bfd_vma) 0);
+       }
+
+      if (get_dyn_sym_info (ia64_info, h, abfd, rel, TRUE) == NULL)
+       return FALSE;
+    }
+
+  /* Now, we only do lookup without insertion, which is very fast
+     with the modified get_dyn_sym_info.  */ 
   for (rel = relocs; rel < relend; ++rel)
     {
-      enum {
-       NEED_GOT = 1,
-       NEED_GOTX = 2,
-       NEED_FPTR = 4,
-       NEED_PLTOFF = 8,
-       NEED_MIN_PLT = 16,
-       NEED_FULL_PLT = 32,
-       NEED_DYNREL = 64,
-       NEED_LTOFF_FPTR = 128,
-       NEED_TPREL = 256,
-       NEED_DTPMOD = 512,
-       NEED_DTPREL = 1024
-      };
-
-      struct elf_link_hash_entry *h = NULL;
-      unsigned long r_symndx = ELFNN_R_SYM (rel->r_info);
       struct elfNN_ia64_dyn_sym_info *dyn_i;
-      int need_entry;
-      bfd_boolean maybe_dynamic;
       int dynrel_type = R_IA64_NONE;
 
+      r_symndx = ELFNN_R_SYM (rel->r_info);
       if (r_symndx >= symtab_hdr->sh_info)
        {
          /* We're dealing with a global symbol -- find its hash entry
@@ -2401,18 +2914,18 @@ elfNN_ia64_check_relocs (abfd, info, sec, relocs)
 
          h->ref_regular = 1;
        }
+      else
+       h = NULL;
 
       /* We can only get preliminary data on whether a symbol is
         locally or externally defined, as not all of the input files
         have yet been processed.  Do something with what we know, as
         this may help reduce memory usage and processing time later.  */
-      maybe_dynamic = FALSE;
-      if (h && ((!info->executable
-                && (!info->symbolic
-                    || info->unresolved_syms_in_shared_libs == RM_IGNORE))
-               || !h->def_regular
-               || h->root.type == bfd_link_hash_defweak))
-       maybe_dynamic = TRUE;
+      maybe_dynamic = (h && ((!info->executable
+                             && (!SYMBOLIC_BIND (info, h)
+                                 || info->unresolved_syms_in_shared_libs == RM_IGNORE))
+                            || !h->def_regular
+                            || h->root.type == bfd_link_hash_defweak));
 
       need_entry = 0;
       switch (ELFNN_R_TYPE (rel->r_info))
@@ -2496,12 +3009,6 @@ elfNN_ia64_check_relocs (abfd, info, sec, relocs)
              if (maybe_dynamic)
                need_entry |= NEED_MIN_PLT;
            }
-         else
-           {
-             (*info->callbacks->warning)
-               (info, _("@pltoff reloc against local symbol"), 0,
-                abfd, 0, (bfd_vma) 0);
-           }
          break;
 
        case R_IA64_PCREL21B:
@@ -2550,15 +3057,7 @@ elfNN_ia64_check_relocs (abfd, info, sec, relocs)
       if (!need_entry)
        continue;
 
-      if ((need_entry & NEED_FPTR) != 0
-         && rel->r_addend)
-       {
-         (*info->callbacks->warning)
-           (info, _("non-zero addend in @fptr reloc"), 0,
-            abfd, 0, (bfd_vma) 0);
-       }
-
-      dyn_i = get_dyn_sym_info (ia64_info, h, abfd, rel, TRUE);
+      dyn_i = get_dyn_sym_info (ia64_info, h, abfd, rel, FALSE);
 
       /* Record whether or not this is a local symbol.  */
       dyn_i->h = h;
@@ -2774,7 +3273,8 @@ allocate_fptr (dyn_i, data)
       if (!x->info->executable
          && (!h
              || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
-             || h->root.type != bfd_link_hash_undefweak))
+             || (h->root.type != bfd_link_hash_undefweak
+                 && h->root.type != bfd_link_hash_undefined)))
        {
          if (h && h->dynindx == -1)
            {
@@ -3211,7 +3711,7 @@ elfNN_ia64_size_dynamic_sections (output_bfd, info)
 
          if (strcmp (name, ".got.plt") == 0)
            strip = FALSE;
-         else if (strncmp (name, ".rel", 4) == 0)
+         else if (CONST_STRNEQ (name, ".rel"))
            {
              if (!strip)
                {
@@ -3875,7 +4375,7 @@ elfNN_ia64_choose_gp (abfd, info)
        continue;
 
       lo = os->vma;
-      hi = os->vma + os->size;
+      hi = os->vma + (os->rawsize ? os->rawsize : os->size);
       if (hi < lo)
        hi = (bfd_vma) -1;
 
@@ -3916,14 +4416,16 @@ elfNN_ia64_choose_gp (abfd, info)
        gp_val = got_sec->output_section->vma;
       else if (max_short_vma != 0)
        gp_val = min_short_vma;
-      else
+      else if (max_vma - min_vma < 0x200000)
        gp_val = min_vma;
+      else
+       gp_val = max_vma - 0x200000 + 8;
 
       /* If it is possible to address the entire image, but we
         don't with the choice above, adjust.  */
       if (max_vma - min_vma < 0x400000
-         && max_vma - gp_val <= 0x200000
-         && gp_val - min_vma > 0x200000)
+         && (max_vma - gp_val >= 0x200000
+             || gp_val - min_vma > 0x200000))
        gp_val = min_vma + 0x200000;
       else if (max_short_vma != 0)
        {
@@ -3980,15 +4482,15 @@ elfNN_ia64_final_link (abfd, info)
   /* Make sure we've got ourselves a nice fat __gp value.  */
   if (!info->relocatable)
     {
-      bfd_vma gp_val = _bfd_get_gp_value (abfd);
+      bfd_vma gp_val;
       struct elf_link_hash_entry *gp;
 
-      if (gp_val == 0)
-       {
-         if (! elfNN_ia64_choose_gp (abfd, info))
-           return FALSE;
-         gp_val = _bfd_get_gp_value (abfd);
-       }
+      /* We assume after gp is set, section size will only decrease. We
+        need to adjust gp for it.  */
+      _bfd_set_gp_value (abfd, 0);
+      if (! elfNN_ia64_choose_gp (abfd, info))
+       return FALSE;
+      gp_val = _bfd_get_gp_value (abfd);
 
       gp = elf_link_hash_lookup (elf_hash_table (info), "__gp", FALSE,
                                 FALSE, FALSE);
@@ -4071,7 +4573,6 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section,
 
       elf_section_data(input_section->output_section)
        ->this_hdr.sh_flags |= flags;
-      return TRUE;
     }
 
   gp_val = _bfd_get_gp_value (output_bfd);
@@ -4120,7 +4621,8 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section,
          sym_sec = local_sections[r_symndx];
          msec = sym_sec;
          value = _bfd_elf_rela_local_sym (output_bfd, sym, &msec, rel);
-         if ((sym_sec->flags & SEC_MERGE)
+         if (!info->relocatable
+             && (sym_sec->flags & SEC_MERGE) != 0
              && ELF_ST_TYPE (sym->st_info) == STT_SECTION
              && sym_sec->sec_info_type == ELF_INFO_TYPE_MERGE)
            {
@@ -4130,8 +4632,11 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section,
              if (loc_h && ! loc_h->sec_merge_done)
                {
                  struct elfNN_ia64_dyn_sym_info *dynent;
+                 unsigned int count;
 
-                 for (dynent = loc_h->info; dynent; dynent = dynent->next)
+                 for (count = loc_h->count, dynent = loc_h->info;
+                      count != 0;
+                      count--, dynent++)
                    {
                      msec = sym_sec;
                      dynent->addend =
@@ -4146,6 +4651,10 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section,
                                        - sym_sec->output_section->vma
                                        - sym_sec->output_offset;
                    }
+                 
+                 qsort (loc_h->info, loc_h->count,
+                        sizeof (*loc_h->info), addend_compare);
+
                  loc_h->sec_merge_done = 1;
                }
            }
@@ -4167,6 +4676,20 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section,
            continue;
        }
 
+      /* For relocs against symbols from removed linkonce sections,
+        or sections discarded by a linker script, we just want the
+        section contents zeroed.  Avoid any special processing.  */
+      if (sym_sec != NULL && elf_discarded_section (sym_sec))
+       {
+         _bfd_clear_contents (howto, input_bfd, contents + rel->r_offset);
+         rel->r_info = 0;
+         rel->r_addend = 0;
+         continue;
+       }
+
+      if (info->relocatable)
+       continue;
+
       hit_addr = contents + rel->r_offset;
       value += rel->r_addend;
       dynamic_symbol_p = elfNN_ia64_dynamic_symbol_p (h, info, r_type);
@@ -4498,13 +5021,6 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section,
        case R_IA64_SEGREL32LSB:
        case R_IA64_SEGREL64MSB:
        case R_IA64_SEGREL64LSB:
-         if (r_symndx == 0)
-           {
-             /* If the input section was discarded from the output, then
-                do nothing.  */
-             r = bfd_reloc_ok;
-           }
-         else
            {
              struct elf_segment_map *m;
              Elf_Internal_Phdr *p;
@@ -4823,8 +5339,8 @@ elfNN_ia64_finish_dynamic_symbol (output_bfd, info, h, sym)
 
   /* Mark some specially defined symbols as absolute.  */
   if (strcmp (h->root.root.string, "_DYNAMIC") == 0
-      || strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0
-      || strcmp (h->root.root.string, "_PROCEDURE_LINKAGE_TABLE_") == 0)
+      || h == ia64_info->root.hgot
+      || h == ia64_info->root.hplt)
     sym->st_shndx = SHN_ABS;
 
   return TRUE;
@@ -5069,9 +5585,9 @@ elfNN_ia64_reloc_type_class (rela)
 
 static const struct bfd_elf_special_section elfNN_ia64_special_sections[] =
 {
-  { ".sbss",  5, -1, SHT_NOBITS,   SHF_ALLOC + SHF_WRITE + SHF_IA_64_SHORT },
-  { ".sdata", 6, -1, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE + SHF_IA_64_SHORT },
-  { NULL,        0, 0, 0,            0 }
+  { STRING_COMMA_LEN (".sbss"),  -1, SHT_NOBITS,   SHF_ALLOC + SHF_WRITE + SHF_IA_64_SHORT },
+  { STRING_COMMA_LEN (".sdata"), -1, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE + SHF_IA_64_SHORT },
+  { NULL,                    0,   0, 0,            0 }
 };
 
 static bfd_boolean
@@ -5098,7 +5614,7 @@ elfNN_ia64_object_p (bfd *abfd)
       if (elf_sec_group (sec) == NULL
          && ((sec->flags & (SEC_LINK_ONCE | SEC_CODE | SEC_GROUP))
              == (SEC_LINK_ONCE | SEC_CODE))
-         && strncmp (sec->name, ".gnu.linkonce.t.", 16) == 0)
+         && CONST_STRNEQ (sec->name, ".gnu.linkonce.t."))
        {
          name = sec->name + 16;
 
@@ -5181,7 +5697,7 @@ elfNN_hpux_post_process_headers (abfd, info)
 {
   Elf_Internal_Ehdr *i_ehdrp = elf_elfheader (abfd);
 
-  i_ehdrp->e_ident[EI_OSABI] = ELFOSABI_HPUX;
+  i_ehdrp->e_ident[EI_OSABI] = get_elf_backend_data (abfd)->elf_osabi;
   i_ehdrp->e_ident[EI_ABIVERSION] = 1;
 }
 
@@ -5225,6 +5741,7 @@ elfNN_hpux_backend_symbol_processing (bfd *abfd ATTRIBUTE_UNUSED,
 #define ELF_MACHINE_ALT1               1999    /* EAS2.3 */
 #define ELF_MACHINE_ALT2               1998    /* EAS2.2 */
 #define ELF_MAXPAGESIZE                        0x10000 /* 64KB */
+#define ELF_COMMONPAGESIZE             0x4000  /* 16KB */
 
 #define elf_backend_section_from_shdr \
        elfNN_ia64_section_from_shdr
@@ -5240,11 +5757,15 @@ elfNN_hpux_backend_symbol_processing (bfd *abfd ATTRIBUTE_UNUSED,
        elfNN_ia64_additional_program_headers
 #define elf_backend_modify_segment_map \
        elfNN_ia64_modify_segment_map
+#define elf_backend_modify_program_headers \
+       elfNN_ia64_modify_program_headers
 #define elf_info_to_howto \
        elfNN_ia64_info_to_howto
 
 #define bfd_elfNN_bfd_reloc_type_lookup \
        elfNN_ia64_reloc_type_lookup
+#define bfd_elfNN_bfd_reloc_name_lookup \
+       elfNN_ia64_reloc_name_lookup
 #define bfd_elfNN_bfd_is_local_label_name \
        elfNN_ia64_is_local_label_name
 #define bfd_elfNN_bfd_relax_section \
@@ -5266,6 +5787,8 @@ elfNN_hpux_backend_symbol_processing (bfd *abfd ATTRIBUTE_UNUSED,
        elfNN_ia64_adjust_dynamic_symbol
 #define elf_backend_size_dynamic_sections \
        elfNN_ia64_size_dynamic_sections
+#define elf_backend_omit_section_dynsym \
+  ((bfd_boolean (*) (bfd *, struct bfd_link_info *, asection *)) bfd_true)
 #define elf_backend_relocate_section \
        elfNN_ia64_relocate_section
 #define elf_backend_finish_dynamic_symbol \
@@ -5293,12 +5816,14 @@ elfNN_hpux_backend_symbol_processing (bfd *abfd ATTRIBUTE_UNUSED,
 #define elf_backend_want_dynbss                0
 #define elf_backend_copy_indirect_symbol elfNN_ia64_hash_copy_indirect
 #define elf_backend_hide_symbol                elfNN_ia64_hash_hide_symbol
+#define elf_backend_fixup_symbol       _bfd_elf_link_hash_fixup_symbol
 #define elf_backend_reloc_type_class   elfNN_ia64_reloc_type_class
 #define elf_backend_rela_normal                1
 #define elf_backend_special_sections   elfNN_ia64_special_sections
+#define elf_backend_default_execstack  0
 
 /* FIXME: PR 290: The Intel C compiler generates SHT_IA_64_UNWIND with
-   SHF_LINK_ORDER. But it doesn't set theh sh_link or sh_info fields.
+   SHF_LINK_ORDER. But it doesn't set the sh_link or sh_info fields.
    We don't want to flood users with so many error messages. We turn
    off the warning for now. It will be turned on later when the Intel
    compiler is fixed.   */
@@ -5330,7 +5855,10 @@ elfNN_hpux_backend_symbol_processing (bfd *abfd ATTRIBUTE_UNUSED,
 #define elf_backend_want_p_paddr_set_to_zero 1
 
 #undef  ELF_MAXPAGESIZE
-#define ELF_MAXPAGESIZE                 0x1000  /* 1K */
+#define ELF_MAXPAGESIZE                 0x1000  /* 4K */
+#undef ELF_COMMONPAGESIZE
+#undef ELF_OSABI
+#define ELF_OSABI                      ELFOSABI_HPUX
 
 #undef  elfNN_bed
 #define elfNN_bed elfNN_ia64_hpux_bed