* elf-bfd.h (elf_backend_data <elf_backend_section_from_bfd_section>):
[binutils-gdb.git] / bfd / elfxx-ia64.c
index 1e319bc34f593274a584037ef57cb51ca664ab03..ee49f5a9c17fed24f8e7cdad53707b353737d01e 100644 (file)
@@ -1,5 +1,5 @@
 /* IA-64 support for 64-bit ELF
-   Copyright 1998, 1999, 2000 Free Software Foundation, Inc.
+   Copyright 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
    Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
 
 This file is part of BFD, the Binary File Descriptor library.
@@ -25,7 +25,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 #include "opcode/ia64.h"
 #include "elf/ia64.h"
 
-
 /*
  * THE RULES for all the stuff the linker creates --
  *
@@ -83,7 +82,7 @@ struct elfNN_ia64_dyn_sym_info
 
   /* The symbol table entry, if any, that this was derrived from.  */
   struct elf_link_hash_entry *h;
-  
+
   /* Used to count non-got, non-plt relocations for delayed sizing
      of relocation sections.  */
   struct elfNN_ia64_dyn_reloc_entry
@@ -112,6 +111,10 @@ struct elfNN_ia64_local_hash_entry
 {
   struct bfd_hash_entry root;
   struct elfNN_ia64_dyn_sym_info *info;
+
+  /* True if this hash entry's addends was translated for
+     SHF_MERGE optimization.  */
+  unsigned sec_merge_done : 1;
 };
 
 struct elfNN_ia64_local_hash_table
@@ -139,6 +142,7 @@ struct elfNN_ia64_link_hash_table
   asection *rel_pltoff_sec;    /* dynamic relocation section for same */
 
   bfd_size_type minplt_entries;        /* number of minplt entries */
+  unsigned reltext : 1;                /* are there relocs against readonly sections? */
 
   struct elfNN_ia64_local_hash_table loc_hash_table;
 };
@@ -158,16 +162,32 @@ static void elfNN_ia64_info_to_howto
 static boolean elfNN_ia64_relax_section
   PARAMS((bfd *abfd, asection *sec, struct bfd_link_info *link_info,
          boolean *again));
+static boolean is_unwind_section_name
+  PARAMS ((bfd *abfd, const char *));
 static boolean elfNN_ia64_section_from_shdr
   PARAMS ((bfd *, ElfNN_Internal_Shdr *, char *));
+static boolean elfNN_ia64_section_flags
+  PARAMS ((flagword *, ElfNN_Internal_Shdr *));
 static boolean elfNN_ia64_fake_sections
   PARAMS ((bfd *abfd, ElfNN_Internal_Shdr *hdr, asection *sec));
+static void elfNN_ia64_final_write_processing
+  PARAMS ((bfd *abfd, boolean linker));
 static boolean elfNN_ia64_add_symbol_hook
   PARAMS ((bfd *abfd, struct bfd_link_info *info, const Elf_Internal_Sym *sym,
           const char **namep, flagword *flagsp, asection **secp,
           bfd_vma *valp));
+static boolean elfNN_ia64_aix_vec
+  PARAMS ((const bfd_target *vec));
+static boolean elfNN_ia64_aix_add_symbol_hook
+  PARAMS ((bfd *abfd, struct bfd_link_info *info, const Elf_Internal_Sym *sym,
+          const char **namep, flagword *flagsp, asection **secp,
+          bfd_vma *valp));
+static boolean elfNN_ia64_aix_link_add_symbols
+  PARAMS ((bfd *abfd, struct bfd_link_info *info));
 static int elfNN_ia64_additional_program_headers
   PARAMS ((bfd *abfd));
+static boolean elfNN_ia64_modify_segment_map
+  PARAMS ((bfd *));
 static boolean elfNN_ia64_is_local_label_name
   PARAMS ((bfd *abfd, const char *name));
 static boolean elfNN_ia64_dynamic_symbol_p
@@ -181,17 +201,28 @@ static struct bfd_hash_entry *elfNN_ia64_new_loc_hash_entry
 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 ((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 *));
 static struct bfd_link_hash_table *elfNN_ia64_hash_table_create
   PARAMS ((bfd *abfd));
 static struct elfNN_ia64_local_hash_entry *elfNN_ia64_local_hash_lookup
   PARAMS ((struct elfNN_ia64_local_hash_table *table, const char *string,
           boolean create, boolean copy));
+static boolean elfNN_ia64_global_dyn_sym_thunk
+  PARAMS ((struct bfd_hash_entry *, PTR));
+static boolean elfNN_ia64_local_dyn_sym_thunk
+  PARAMS ((struct bfd_hash_entry *, PTR));
 static void elfNN_ia64_dyn_sym_traverse
   PARAMS ((struct elfNN_ia64_link_hash_table *ia64_info,
-          boolean (*func)(struct elfNN_ia64_dyn_sym_info *, PTR),
+          boolean (*func) (struct elfNN_ia64_dyn_sym_info *, PTR),
           PTR info));
 static boolean elfNN_ia64_create_dynamic_sections
   PARAMS ((bfd *abfd, struct bfd_link_info *info));
+static struct elfNN_ia64_local_hash_entry * get_local_sym_hash
+  PARAMS ((struct elfNN_ia64_link_hash_table *ia64_info,
+          bfd *abfd, const Elf_Internal_Rela *rel, boolean create));
 static struct elfNN_ia64_dyn_sym_info * get_dyn_sym_info
   PARAMS ((struct elfNN_ia64_link_hash_table *ia64_info,
           struct elf_link_hash_entry *h,
@@ -216,7 +247,7 @@ static boolean elfNN_ia64_check_relocs
           const Elf_Internal_Rela *relocs));
 static boolean elfNN_ia64_adjust_dynamic_symbol
   PARAMS ((struct bfd_link_info *info, struct elf_link_hash_entry *h));
-static unsigned long global_sym_index
+static long global_sym_index
   PARAMS ((struct elf_link_hash_entry *h));
 static boolean allocate_fptr
   PARAMS ((struct elfNN_ia64_dyn_sym_info *dyn_i, PTR data));
@@ -254,6 +285,8 @@ static bfd_vma set_pltoff_entry
   PARAMS ((bfd *abfd, struct bfd_link_info *info,
           struct elfNN_ia64_dyn_sym_info *dyn_i,
           bfd_vma value, boolean));
+static int elfNN_ia64_unwind_entry_compare
+  PARAMS ((const PTR, const PTR));
 static boolean elfNN_ia64_final_link
   PARAMS ((bfd *abfd, struct bfd_link_info *info));
 static boolean elfNN_ia64_relocate_section
@@ -268,13 +301,18 @@ static boolean elfNN_ia64_finish_dynamic_sections
   PARAMS ((bfd *abfd, struct bfd_link_info *info));
 static boolean elfNN_ia64_set_private_flags
   PARAMS ((bfd *abfd, flagword flags));
-static boolean elfNN_ia64_copy_private_bfd_data
-  PARAMS ((bfd *ibfd, bfd *obfd));
 static boolean elfNN_ia64_merge_private_bfd_data
   PARAMS ((bfd *ibfd, bfd *obfd));
 static boolean elfNN_ia64_print_private_bfd_data
   PARAMS ((bfd *abfd, PTR ptr));
-
+static enum elf_reloc_type_class elfNN_ia64_reloc_type_class
+  PARAMS ((const Elf_Internal_Rela *));
+static boolean elfNN_ia64_hpux_vec
+  PARAMS ((const bfd_target *vec));
+static void elfNN_hpux_post_process_headers
+  PARAMS ((bfd *abfd, struct bfd_link_info *info));
+boolean elfNN_hpux_backend_section_from_bfd_section
+  PARAMS ((bfd *abfd, asection *sec, int *retval));
 \f
 /* ia64-specific relocation */
 
@@ -283,10 +321,10 @@ static boolean elfNN_ia64_print_private_bfd_data
 static bfd_reloc_status_type
 elfNN_ia64_reloc (abfd, reloc, sym, data, input_section,
                  output_bfd, error_message)
-     bfd *abfd;
+     bfd *abfd ATTRIBUTE_UNUSED;
      arelent *reloc;
-     asymbol *sym;
-     PTR data;
+     asymbol *sym ATTRIBUTE_UNUSED;
+     PTR data ATTRIBUTE_UNUSED;
      asection *input_section;
      bfd *output_bfd;
      char **error_message;
@@ -350,10 +388,11 @@ static reloc_howto_type ia64_howto_table[] =
 
     IA64_HOWTO (R_IA64_LTOFF_FPTR22, "LTOFF_FPTR22", 0, false, true),
     IA64_HOWTO (R_IA64_LTOFF_FPTR64I, "LTOFF_FPTR64I", 0, false, true),
+    IA64_HOWTO (R_IA64_LTOFF_FPTR32MSB, "LTOFF_FPTR32MSB", 2, false, true),
+    IA64_HOWTO (R_IA64_LTOFF_FPTR32LSB, "LTOFF_FPTR32LSB", 2, false, true),
     IA64_HOWTO (R_IA64_LTOFF_FPTR64MSB, "LTOFF_FPTR64MSB", 4, false, true),
     IA64_HOWTO (R_IA64_LTOFF_FPTR64LSB, "LTOFF_FPTR64LSB", 4, false, true),
 
-    IA64_HOWTO (R_IA64_SEGBASE,            "SEGBASE",     4, false, true),
     IA64_HOWTO (R_IA64_SEGREL32MSB, "SEGREL32MSB", 2, false, true),
     IA64_HOWTO (R_IA64_SEGREL32LSB, "SEGREL32LSB", 2, false, true),
     IA64_HOWTO (R_IA64_SEGREL64MSB, "SEGREL64MSB", 4, false, true),
@@ -380,8 +419,6 @@ static reloc_howto_type ia64_howto_table[] =
 
     IA64_HOWTO (R_IA64_IPLTMSB,            "IPLTMSB",     4, false, true),
     IA64_HOWTO (R_IA64_IPLTLSB,            "IPLTLSB",     4, false, true),
-    IA64_HOWTO (R_IA64_EPLTMSB,            "EPLTMSB",     4, false, true),
-    IA64_HOWTO (R_IA64_EPLTLSB,            "EPLTLSB",     4, false, true),
     IA64_HOWTO (R_IA64_COPY,       "COPY",        4, false, true),
     IA64_HOWTO (R_IA64_LTOFF22X,    "LTOFF22X",           0, false, true),
     IA64_HOWTO (R_IA64_LDXMOV,     "LDXMOV",      0, false, true),
@@ -421,7 +458,7 @@ lookup_howto (rtype)
 
 static reloc_howto_type*
 elfNN_ia64_reloc_type_lookup (abfd, bfd_code)
-     bfd *abfd;
+     bfd *abfd ATTRIBUTE_UNUSED;
      bfd_reloc_code_real_type bfd_code;
 {
   unsigned int rtype;
@@ -473,10 +510,11 @@ elfNN_ia64_reloc_type_lookup (abfd, bfd_code)
 
     case BFD_RELOC_IA64_LTOFF_FPTR22:  rtype = R_IA64_LTOFF_FPTR22; break;
     case BFD_RELOC_IA64_LTOFF_FPTR64I: rtype = R_IA64_LTOFF_FPTR64I; break;
+    case BFD_RELOC_IA64_LTOFF_FPTR32MSB: rtype = R_IA64_LTOFF_FPTR32MSB; break;
+    case BFD_RELOC_IA64_LTOFF_FPTR32LSB: rtype = R_IA64_LTOFF_FPTR32LSB; break;
     case BFD_RELOC_IA64_LTOFF_FPTR64MSB: rtype = R_IA64_LTOFF_FPTR64MSB; break;
     case BFD_RELOC_IA64_LTOFF_FPTR64LSB: rtype = R_IA64_LTOFF_FPTR64LSB; break;
 
-    case BFD_RELOC_IA64_SEGBASE:       rtype = R_IA64_SEGBASE; break;
     case BFD_RELOC_IA64_SEGREL32MSB:   rtype = R_IA64_SEGREL32MSB; break;
     case BFD_RELOC_IA64_SEGREL32LSB:   rtype = R_IA64_SEGREL32LSB; break;
     case BFD_RELOC_IA64_SEGREL64MSB:   rtype = R_IA64_SEGREL64MSB; break;
@@ -499,8 +537,6 @@ elfNN_ia64_reloc_type_lookup (abfd, bfd_code)
 
     case BFD_RELOC_IA64_IPLTMSB:       rtype = R_IA64_IPLTMSB; break;
     case BFD_RELOC_IA64_IPLTLSB:       rtype = R_IA64_IPLTLSB; break;
-    case BFD_RELOC_IA64_EPLTMSB:       rtype = R_IA64_EPLTMSB; break;
-    case BFD_RELOC_IA64_EPLTLSB:       rtype = R_IA64_EPLTLSB; break;
     case BFD_RELOC_IA64_COPY:          rtype = R_IA64_COPY; break;
     case BFD_RELOC_IA64_LTOFF22X:      rtype = R_IA64_LTOFF22X; break;
     case BFD_RELOC_IA64_LDXMOV:                rtype = R_IA64_LDXMOV; break;
@@ -519,11 +555,12 @@ elfNN_ia64_reloc_type_lookup (abfd, bfd_code)
 
 static void
 elfNN_ia64_info_to_howto (abfd, bfd_reloc, elf_reloc)
-     bfd *abfd;
+     bfd *abfd ATTRIBUTE_UNUSED;
      arelent *bfd_reloc;
      ElfNN_Internal_Rela *elf_reloc;
 {
-  bfd_reloc->howto = lookup_howto (ELFNN_R_TYPE (elf_reloc->r_info));
+  bfd_reloc->howto
+    = lookup_howto ((unsigned int) ELFNN_R_TYPE (elf_reloc->r_info));
 }
 \f
 #define PLT_HEADER_SIZE                (3 * 16)
@@ -562,6 +599,9 @@ static const bfd_byte plt_full_entry[PLT_FULL_ENTRY_SIZE] =
 };
 
 #define ELF_DYNAMIC_INTERPRETER "/usr/lib/ld.so.1"
+#define AIX_DYNAMIC_INTERPRETER "/usr/lib/ia64l64/libc.so.1"
+#define DYNAMIC_INTERPRETER(abfd) \
+  (elfNN_ia64_aix_vec (abfd->xvec) ? AIX_DYNAMIC_INTERPRETER : ELF_DYNAMIC_INTERPRETER)
 
 /* Select out of range branch fixup type.  Note that Itanium does
    not support brl, and so it gets emulated by the kernel.  */
@@ -608,13 +648,15 @@ elfNN_ia64_relax_section (abfd, sec, link_info, again)
     };
 
   Elf_Internal_Shdr *symtab_hdr;
+  Elf_Internal_Shdr *shndx_hdr;
   Elf_Internal_Rela *internal_relocs;
-  Elf_Internal_Rela *free_relocs;
+  Elf_Internal_Rela *free_relocs = NULL;
   Elf_Internal_Rela *irel, *irelend;
   bfd_byte *contents;
-  bfd_byte *free_contents;
+  bfd_byte *free_contents = NULL;
   ElfNN_External_Sym *extsyms;
-  ElfNN_External_Sym *free_extsyms;
+  ElfNN_External_Sym *free_extsyms = NULL;
+  Elf_External_Sym_Shndx *shndx_buf = NULL;
   struct elfNN_ia64_link_hash_table *ia64_info;
   struct one_fixup *fixups = NULL;
   boolean changed_contents = false;
@@ -642,7 +684,7 @@ elfNN_ia64_relax_section (abfd, sec, link_info, again)
                      link_info->keep_memory));
   if (internal_relocs == NULL)
     goto error_return;
-  free_relocs = NULL;
+
   if (! link_info->keep_memory)
     free_relocs = internal_relocs;
 
@@ -662,7 +704,6 @@ elfNN_ia64_relax_section (abfd, sec, link_info, again)
     }
 
   /* Get the section contents.  */
-  free_contents = NULL;
   if (elf_section_data (sec)->this_hdr.contents != NULL)
     contents = elf_section_data (sec)->this_hdr.contents;
   else
@@ -677,19 +718,34 @@ elfNN_ia64_relax_section (abfd, sec, link_info, again)
        goto error_return;
     }
 
-  /* Read this BFD's symbols.  */
-  free_extsyms = NULL;
+  /* Read this BFD's local symbols.  */
   if (symtab_hdr->contents != NULL)
     extsyms = (ElfNN_External_Sym *) symtab_hdr->contents;
   else
     {
-      extsyms = (ElfNN_External_Sym *) bfd_malloc (symtab_hdr->sh_size);
+      bfd_size_type amt;
+
+      amt = symtab_hdr->sh_info * sizeof (ElfNN_External_Sym);
+      extsyms = (ElfNN_External_Sym *) bfd_malloc (amt);
       if (extsyms == NULL)
        goto error_return;
       free_extsyms = extsyms;
       if (bfd_seek (abfd, symtab_hdr->sh_offset, SEEK_SET) != 0
-         || (bfd_read (extsyms, 1, symtab_hdr->sh_size, abfd)
-             != symtab_hdr->sh_size))
+         || bfd_bread (extsyms, amt, abfd) != amt)
+       goto error_return;
+    }
+
+  shndx_hdr = &elf_tdata (abfd)->symtab_shndx_hdr;
+  if (shndx_hdr->sh_size != 0)
+    {
+      bfd_size_type amt;
+
+      amt = symtab_hdr->sh_info * sizeof (Elf_External_Sym_Shndx);
+      shndx_buf = (Elf_External_Sym_Shndx *) bfd_malloc (amt);
+      if (shndx_buf == NULL)
+       goto error_return;
+      if (bfd_seek (abfd, shndx_hdr->sh_offset, SEEK_SET) != 0
+         || bfd_bread (shndx_buf, amt, abfd) != amt)
        goto error_return;
     }
 
@@ -699,6 +755,7 @@ elfNN_ia64_relax_section (abfd, sec, link_info, again)
       Elf_Internal_Sym isym;
       asection *tsec;
       struct one_fixup *f;
+      bfd_size_type amt;
 
       if (ELFNN_R_TYPE (irel->r_info) != (int) R_IA64_PCREL21B)
        continue;
@@ -706,20 +763,23 @@ elfNN_ia64_relax_section (abfd, sec, link_info, again)
       /* Get the value of the symbol referred to by the reloc.  */
       if (ELFNN_R_SYM (irel->r_info) < symtab_hdr->sh_info)
        {
+         ElfNN_External_Sym *esym;
+         Elf_External_Sym_Shndx *shndx;
+
          /* A local symbol.  */
-         bfd_elfNN_swap_symbol_in (abfd,
-                                   extsyms + ELFNN_R_SYM (irel->r_info),
-                                   &isym);
+         esym = extsyms + ELFNN_R_SYM (irel->r_info);
+         shndx = shndx_buf + (shndx_buf ? ELFNN_R_SYM (irel->r_info) : 0);
+         bfd_elfNN_swap_symbol_in (abfd, esym, shndx, &isym);
          if (isym.st_shndx == SHN_UNDEF)
            continue;   /* We can't do anthing with undefined symbols.  */
          else if (isym.st_shndx == SHN_ABS)
            tsec = bfd_abs_section_ptr;
          else if (isym.st_shndx == SHN_COMMON)
            tsec = bfd_com_section_ptr;
-         else if (isym.st_shndx > 0 && isym.st_shndx < SHN_LORESERVE)
+         else if (isym.st_shndx == SHN_IA_64_ANSI_COMMON)
+           tsec = bfd_com_section_ptr;
+         else
            tsec = bfd_section_from_elf_index (abfd, isym.st_shndx);
-         else 
-           continue;   /* who knows. */
 
          toff = isym.st_value;
        }
@@ -766,7 +826,7 @@ elfNN_ia64_relax_section (abfd, sec, link_info, again)
       roff = irel->r_offset;
       reladdr = (sec->output_section->vma
                 + sec->output_offset
-                + roff) & -4;
+                + roff) & (bfd_vma) -4;
 
       /* If the branch is in range, no need to do anything.  */
       if ((bfd_signed_vma) (symaddr - reladdr) >= -0x1000000
@@ -790,7 +850,7 @@ elfNN_ia64_relax_section (abfd, sec, link_info, again)
             make a copy of the FULL_PLT entry.  Otherwise, we'll have
             to use a `brl' insn to get where we're going.  */
 
-         int size;
+         size_t size;
 
          if (tsec == ia64_info->plt_sec)
            size = sizeof (plt_full_entry);
@@ -804,11 +864,12 @@ elfNN_ia64_relax_section (abfd, sec, link_info, again)
            }
 
          /* Resize the current section to make room for the new branch.  */
-         trampoff = (sec->_cooked_size + 15) & -16;
-         contents = (bfd_byte *) bfd_realloc (contents, trampoff + size);
+         trampoff = (sec->_cooked_size + 15) & (bfd_vma) -16;
+         amt = trampoff + size;
+         contents = (bfd_byte *) bfd_realloc (contents, amt);
          if (contents == NULL)
            goto error_return;
-         sec->_cooked_size = trampoff + size;
+         sec->_cooked_size = amt;
 
          if (tsec == ia64_info->plt_sec)
            {
@@ -836,7 +897,7 @@ elfNN_ia64_relax_section (abfd, sec, link_info, again)
            }
 
          /* Record the fixup so we don't do it again this section.  */
-         f = (struct one_fixup *) bfd_malloc (sizeof (*f));
+         f = (struct one_fixup *) bfd_malloc ((bfd_size_type) sizeof (*f));
          f->next = fixups;
          f->tsec = tsec;
          f->toff = toff;
@@ -852,7 +913,7 @@ elfNN_ia64_relax_section (abfd, sec, link_info, again)
       /* Fix up the existing branch to hit the trampoline.  Hope like
         hell this doesn't overflow too.  */
       if (elfNN_ia64_install_value (abfd, contents + roff,
-                                   f->trampoff - (roff & -4),
+                                   f->trampoff - (roff & (bfd_vma) -4),
                                    R_IA64_PCREL21B) != bfd_reloc_ok)
        goto error_return;
 
@@ -886,6 +947,9 @@ elfNN_ia64_relax_section (abfd, sec, link_info, again)
        }
     }
 
+  if (shndx_buf != NULL)
+    free (shndx_buf);
+
   if (free_extsyms != NULL)
     {
       if (! link_info->keep_memory)
@@ -893,7 +957,7 @@ elfNN_ia64_relax_section (abfd, sec, link_info, again)
       else
        {
          /* Cache the symbols for elf_link_input_bfd.  */
-         symtab_hdr->contents = extsyms;
+         symtab_hdr->contents = (unsigned char *) extsyms;
        }
     }
 
@@ -905,11 +969,34 @@ elfNN_ia64_relax_section (abfd, sec, link_info, again)
     free (free_relocs);
   if (free_contents != NULL)
     free (free_contents);
+  if (shndx_buf != NULL)
+    free (shndx_buf);
   if (free_extsyms != NULL)
     free (free_extsyms);
   return false;
 }
 \f
+/* Return true if NAME is an unwind table section name.  */
+
+static inline boolean
+is_unwind_section_name (abfd, 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);
+}
+
 /* Handle an IA-64 specific section when reading an object file.  This
    is called when elfcode.h finds a section with an unknown type.  */
 
@@ -929,8 +1016,10 @@ elfNN_ia64_section_from_shdr (abfd, hdr, name)
   switch (hdr->sh_type)
     {
     case SHT_IA_64_UNWIND:
-      if (strcmp (name, ELF_STRING_ia64_unwind) != 0)
-       return false;
+    case SHT_INIT_ARRAY:
+    case SHT_FINI_ARRAY:
+    case SHT_PREINIT_ARRAY:
+    case SHT_IA_64_HP_OPT_ANOT:
       break;
 
     case SHT_IA_64_EXT:
@@ -970,7 +1059,7 @@ elfNN_ia64_section_flags (flags, hdr)
 
 static boolean
 elfNN_ia64_fake_sections (abfd, hdr, sec)
-     bfd *abfd;
+     bfd *abfd ATTRIBUTE_UNUSED;
      ElfNN_Internal_Shdr *hdr;
      asection *sec;
 {
@@ -978,10 +1067,23 @@ elfNN_ia64_fake_sections (abfd, hdr, sec)
 
   name = bfd_get_section_name (abfd, sec);
 
-  if (strcmp (name, ELF_STRING_ia64_unwind) == 0)
-    hdr->sh_type = SHT_IA_64_UNWIND;
+  if (is_unwind_section_name (abfd, name))
+    {
+      /* We don't have the sections numbered at this point, so sh_info
+        is set later, in elfNN_ia64_final_write_processing.  */
+      hdr->sh_type = SHT_IA_64_UNWIND;
+      hdr->sh_flags |= SHF_LINK_ORDER;
+    }
   else if (strcmp (name, ELF_STRING_ia64_archext) == 0)
     hdr->sh_type = SHT_IA_64_EXT;
+  else if (strcmp (name, ".init_array") == 0)
+    hdr->sh_type = SHT_INIT_ARRAY;
+  else if (strcmp (name, ".fini_array") == 0)
+    hdr->sh_type = SHT_FINI_ARRAY;
+  else if (strcmp (name, ".preinit_array") == 0)
+    hdr->sh_type = SHT_PREINIT_ARRAY;
+  else if (strcmp (name, ".HP.opt_annot") == 0)
+    hdr->sh_type = SHT_IA_64_HP_OPT_ANOT;
   else if (strcmp (name, ".reloc") == 0)
     /*
      * This is an ugly, but unfortunately necessary hack that is
@@ -1009,6 +1111,88 @@ elfNN_ia64_fake_sections (abfd, hdr, sec)
   return true;
 }
 
+/* The final processing done just before writing out an IA-64 ELF
+   object file.  */
+
+static void
+elfNN_ia64_final_write_processing (abfd, linker)
+     bfd *abfd;
+     boolean linker ATTRIBUTE_UNUSED;
+{
+  Elf_Internal_Shdr *hdr;
+  const char *sname;
+  asection *text_sect, *s;
+  size_t len;
+
+  for (s = abfd->sections; s; s = s->next)
+    {
+      hdr = &elf_section_data (s)->this_hdr;
+      switch (hdr->sh_type)
+       {
+       case SHT_IA_64_UNWIND:
+         /* See comments in gas/config/tc-ia64.c:dot_endp on why we
+            have to do this.  */
+         sname = bfd_get_section_name (abfd, s);
+         len = sizeof (ELF_STRING_ia64_unwind) - 1;
+         if (sname && strncmp (sname, ELF_STRING_ia64_unwind, len) == 0)
+           {
+             sname += len;
+
+             if (sname[0] == '\0')
+               /* .IA_64.unwind -> .text */
+               text_sect = bfd_get_section_by_name (abfd, ".text");
+             else
+               /* .IA_64.unwindFOO -> FOO */
+               text_sect = bfd_get_section_by_name (abfd, sname);
+           }
+         else if (sname
+                  && (len = sizeof (ELF_STRING_ia64_unwind_once) - 1,
+                      strncmp (sname, ELF_STRING_ia64_unwind_once, len)) == 0)
+           {
+             /* .gnu.linkonce.ia64unw.FOO -> .gnu.linkonce.t.FOO */
+             size_t len2 = sizeof (".gnu.linkonce.t.") - 1;
+             char *once_name = bfd_malloc (len2 + strlen (sname + len) + 1);
+
+             if (once_name != NULL)
+               {
+                 memcpy (once_name, ".gnu.linkonce.t.", len2);
+                 strcpy (once_name + len2, sname + len);
+                 text_sect = bfd_get_section_by_name (abfd, once_name);
+                 free (once_name);
+               }
+             else
+               /* Should only happen if we run out of memory, in
+                  which case we're probably toast anyway.  Try to
+                  cope by finding the section the slow way.  */
+               for (text_sect = abfd->sections;
+                    text_sect != NULL;
+                    text_sect = text_sect->next)
+                 {
+                   if (strncmp (bfd_section_name (abfd, text_sect),
+                                ".gnu.linkonce.t.", len2) == 0
+                       && strcmp (bfd_section_name (abfd, text_sect) + len2,
+                                  sname + len) == 0)
+                     break;
+                 }
+           }
+         else
+           /* last resort: fall back on .text */
+           text_sect = bfd_get_section_by_name (abfd, ".text");
+
+         if (text_sect)
+           {
+             /* The IA-64 processor-specific ABI requires setting
+                sh_link to the unwind section, whereas HP-UX requires
+                sh_info to do so.  For maximum compatibility, we'll
+                set both for now... */
+             hdr->sh_link = elf_section_data (text_sect)->this_idx;
+             hdr->sh_info = elf_section_data (text_sect)->this_idx;
+           }
+         break;
+       }
+    }
+}
+
 /* Hook called by the linker routine which adds symbols from an object
    file.  We use it to put .comm items in .sbss, and not .bss.  */
 
@@ -1017,14 +1201,14 @@ elfNN_ia64_add_symbol_hook (abfd, info, sym, namep, flagsp, secp, valp)
      bfd *abfd;
      struct bfd_link_info *info;
      const Elf_Internal_Sym *sym;
-     const char **namep;
-     flagword *flagsp;
+     const char **namep ATTRIBUTE_UNUSED;
+     flagword *flagsp ATTRIBUTE_UNUSED;
      asection **secp;
      bfd_vma *valp;
 {
   if (sym->st_shndx == SHN_COMMON
       && !info->relocateable
-      && sym->st_size <= bfd_get_gp_size (abfd))
+      && sym->st_size <= elf_gp_size (abfd))
     {
       /* Common symbols less than or equal to -G nn bytes are
         automatically put into .sbss.  */
@@ -1048,6 +1232,112 @@ elfNN_ia64_add_symbol_hook (abfd, info, sym, namep, flagsp, secp, valp)
   return true;
 }
 
+static boolean
+elfNN_ia64_aix_vec (const bfd_target *vec)
+{
+  extern const bfd_target bfd_elfNN_ia64_aix_little_vec;
+  extern const bfd_target bfd_elfNN_ia64_aix_big_vec;
+
+  return (/**/vec == & bfd_elfNN_ia64_aix_little_vec
+         ||  vec == & bfd_elfNN_ia64_aix_big_vec);
+}
+
+/* Hook called by the linker routine which adds symbols from an object
+   file.  We use it to handle OS-specific symbols.  */
+
+static boolean
+elfNN_ia64_aix_add_symbol_hook (abfd, info, sym, namep, flagsp, secp, valp)
+     bfd *abfd;
+     struct bfd_link_info *info;
+     const Elf_Internal_Sym *sym;
+     const char **namep;
+     flagword *flagsp;
+     asection **secp;
+     bfd_vma *valp;
+{
+  if (strcmp (*namep, "__GLOB_DATA_PTR") == 0)
+    {
+      /* Define __GLOB_DATA_PTR when it is encountered.  This is expected to
+        be a linker-defined symbol by the Aix C runtime startup code. IBM sez
+        no one else should use it b/c it is undocumented.  */
+      struct elf_link_hash_entry *h;
+
+      h = elf_link_hash_lookup (elf_hash_table (info), *namep,
+                               false, false, false);
+      if (h == NULL)
+       {
+         struct elf_backend_data *bed;
+         struct elfNN_ia64_link_hash_table *ia64_info;
+
+         bed = get_elf_backend_data (abfd);
+         ia64_info = elfNN_ia64_hash_table (info);
+
+         if (!(_bfd_generic_link_add_one_symbol
+               (info, abfd, *namep, BSF_GLOBAL,
+                bfd_get_section_by_name (abfd, ".bss"),
+                bed->got_symbol_offset, (const char *) NULL, false,
+                bed->collect, (struct bfd_link_hash_entry **) &h)))
+           return false;
+
+         h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR;
+         h->type = STT_OBJECT;
+
+         if (! _bfd_elf_link_record_dynamic_symbol (info, h))
+           return false;
+       }
+
+      return true;
+    }
+  else if (sym->st_shndx == SHN_LOOS)
+    {
+      unsigned int i;
+
+      /* SHN_AIX_SYSCALL: Treat this as any other symbol.  The special symbol
+        is only relevant when compiling code for extended system calls.
+        Replace the "special" section with .text, if possible.
+        Note that these symbols are always assumed to be in .text. */
+      for (i = 1; i < elf_numsections (abfd); i++)
+       {
+         asection * sec = bfd_section_from_elf_index (abfd, i);
+
+         if (sec && strcmp (sec->name, ".text") == 0)
+           {
+             *secp = sec;
+             break;
+           }
+       }
+
+      if (*secp == NULL)
+       *secp = bfd_abs_section_ptr;
+
+      *valp = sym->st_size;
+
+      return true;
+    }
+  else
+    {
+      return elfNN_ia64_add_symbol_hook (abfd, info, sym,
+                                        namep, flagsp, secp, valp);
+    }
+}
+
+boolean
+elfNN_ia64_aix_link_add_symbols (abfd, info)
+     bfd *abfd;
+     struct bfd_link_info *info;
+{
+  /* Make sure dynamic sections are always created.  */
+  if (! elf_hash_table (info)->dynamic_sections_created
+      && abfd->xvec == info->hash->creator)
+    {
+      if (! bfd_elfNN_link_create_dynamic_sections (abfd, info))
+       return false;
+    }
+
+  /* Now do the standard call.  */
+  return bfd_elfNN_bfd_link_add_symbols (abfd, info);
+}
+
 /* Return the number of additional phdrs we will need.  */
 
 static int
@@ -1062,10 +1352,10 @@ elfNN_ia64_additional_program_headers (abfd)
   if (s && (s->flags & SEC_LOAD))
     ++ret;
 
-  /* See if we need a PT_IA_64_UNWIND segment.  */
-  s = bfd_get_section_by_name (abfd, ELF_STRING_ia64_unwind);
-  if (s && (s->flags & SEC_LOAD))
-    ++ret;
+  /* Count how many PT_IA_64_UNWIND segments we need.  */
+  for (s = abfd->sections; s; s = s->next)
+    if (is_unwind_section_name (abfd, s->name) && (s->flags & SEC_LOAD))
+      ++ret;
 
   return ret;
 }
@@ -1075,7 +1365,10 @@ elfNN_ia64_modify_segment_map (abfd)
      bfd *abfd;
 {
   struct elf_segment_map *m, **pm;
+  Elf_Internal_Shdr *hdr;
   asection *s;
+  boolean unwind_found;
+  asection *unwind_sec;
 
   /* If we need a PT_IA_64_ARCHEXT segment, it must come before
      all PT_LOAD segments.  */
@@ -1087,7 +1380,8 @@ elfNN_ia64_modify_segment_map (abfd)
          break;
       if (m == NULL)
        {
-         m = (struct elf_segment_map *) bfd_zalloc (abfd, sizeof *m);
+         m = ((struct elf_segment_map *)
+              bfd_zalloc (abfd, (bfd_size_type) sizeof *m));
          if (m == NULL)
            return false;
 
@@ -1107,29 +1401,53 @@ elfNN_ia64_modify_segment_map (abfd)
        }
     }
 
-  /* Install the PT_IA_64_UNWIND segment, if needed.  */
-  s = bfd_get_section_by_name (abfd, ELF_STRING_ia64_unwind);
-  if (s && (s->flags & SEC_LOAD))
+  /* Install PT_IA_64_UNWIND segments, if needed.  */
+  for (s = abfd->sections; s; s = s->next)
     {
-      for (m = elf_tdata (abfd)->segment_map; m != NULL; m = m->next)
-       if (m->p_type == PT_IA_64_UNWIND)
-         break;
-      if (m == NULL)
+      hdr = &elf_section_data (s)->this_hdr;
+      if (hdr->sh_type != SHT_IA_64_UNWIND)
+       continue;
+
+      if (s && (s->flags & SEC_LOAD))
        {
-         m = (struct elf_segment_map *) bfd_zalloc (abfd, sizeof *m);
+         for (m = elf_tdata (abfd)->segment_map; m != NULL; m = m->next)
+           if (m->p_type == PT_IA_64_UNWIND)
+             {
+               /* Look through all sections in the unwind segment
+                  for a match since there may be multiple sections
+                  to a segment.  */
+
+               unwind_sec = m->sections[0];
+               unwind_found = false;
+               while (unwind_sec != NULL && !unwind_found)
+                 {
+                   if (unwind_sec == s)
+                     unwind_found = true;
+                   else
+                     unwind_sec = unwind_sec -> next;
+                 }
+               if (unwind_found)
+                 break;
+             }
+
          if (m == NULL)
-           return false;
+           {
+             m = ((struct elf_segment_map *)
+                  bfd_zalloc (abfd, (bfd_size_type) sizeof *m));
+             if (m == NULL)
+               return false;
 
-         m->p_type = PT_IA_64_UNWIND;
-         m->count = 1;
-         m->sections[0] = s;
-         m->next = NULL;
+             m->p_type = PT_IA_64_UNWIND;
+             m->count = 1;
+             m->sections[0] = s;
+             m->next = NULL;
 
-         /* We want to put it last.  */
-         pm = &elf_tdata (abfd)->segment_map;
-         while (*pm != NULL)
-           pm = &(*pm)->next;
-         *pm = m;
+             /* We want to put it last.  */
+             pm = &elf_tdata (abfd)->segment_map;
+             while (*pm != NULL)
+               pm = &(*pm)->next;
+             *pm = m;
+           }
        }
     }
 
@@ -1164,13 +1482,12 @@ elfNN_ia64_modify_segment_map (abfd)
   return true;
 }
 
-
 /* According to the Tahoe assembler spec, all labels starting with a
    '.' are local.  */
 
 static boolean
 elfNN_ia64_is_local_label_name (abfd, name)
-     bfd *abfd;
+     bfd *abfd ATTRIBUTE_UNUSED;
      const char *name;
 {
   return name[0] == '.';
@@ -1192,12 +1509,18 @@ elfNN_ia64_dynamic_symbol_p (h, info)
 
   if (h->dynindx == -1)
     return false;
+  switch (ELF_ST_VISIBILITY (h->other))
+    {
+    case STV_INTERNAL:
+    case STV_HIDDEN:
+      return false;
+    }
 
   if (h->root.type == bfd_link_hash_undefweak
       || h->root.type == bfd_link_hash_defweak)
     return true;
 
-  if ((info->shared && !info->symbolic)
+  if ((info->shared && (!info->symbolic || info->allow_shlib_undefined))
       || ((h->elf_link_hash_flags
           & (ELF_LINK_HASH_DEF_DYNAMIC | ELF_LINK_HASH_REF_REGULAR))
          == (ELF_LINK_HASH_DEF_DYNAMIC | ELF_LINK_HASH_REF_REGULAR)))
@@ -1209,10 +1532,10 @@ elfNN_ia64_dynamic_symbol_p (h, info)
 static boolean
 elfNN_ia64_local_hash_table_init (ht, abfd, new)
      struct elfNN_ia64_local_hash_table *ht;
-     bfd *abfd;
+     bfd *abfd ATTRIBUTE_UNUSED;
      new_hash_entry_func new;
 {
-  memset (ht, 0, sizeof(*ht));
+  memset (ht, 0, sizeof (*ht));
   return bfd_hash_table_init (&ht->root, new);
 }
 
@@ -1235,7 +1558,7 @@ elfNN_ia64_new_loc_hash_entry (entry, table, string)
 
   /* Initialize our local data.  All zeros, and definitely easier
      than setting a handful of bit fields.  */
-  memset (ret, 0, sizeof(*ret));
+  memset (ret, 0, sizeof (*ret));
 
   /* Call the allocation method of the superclass.  */
   ret = ((struct elfNN_ia64_local_hash_entry *)
@@ -1263,7 +1586,7 @@ elfNN_ia64_new_elf_hash_entry (entry, table, string)
 
   /* Initialize our local data.  All zeros, and definitely easier
      than setting a handful of bit fields.  */
-  memset (ret, 0, sizeof(*ret));
+  memset (ret, 0, sizeof (*ret));
 
   /* Call the allocation method of the superclass.  */
   ret = ((struct elfNN_ia64_link_hash_entry *)
@@ -1279,10 +1602,10 @@ elfNN_ia64_hash_copy_indirect (xdir, xind)
 {
   struct elfNN_ia64_link_hash_entry *dir, *ind;
 
-  dir = (struct elfNN_ia64_link_hash_entry *)xdir;
-  ind = (struct elfNN_ia64_link_hash_entry *)xind;
+  dir = (struct elfNN_ia64_link_hash_entry *) xdir;
+  ind = (struct elfNN_ia64_link_hash_entry *) xind;
 
-  /* Copy down any references that we may have already seen to the 
+  /* Copy down any references that we may have already seen to the
      symbol which just became indirect.  */
 
   dir->root.elf_link_hash_flags |=
@@ -1291,6 +1614,9 @@ elfNN_ia64_hash_copy_indirect (xdir, xind)
         | ELF_LINK_HASH_REF_REGULAR
         | ELF_LINK_HASH_REF_REGULAR_NONWEAK));
 
+  if (ind->root.root.type != bfd_link_hash_indirect)
+    return;
+
   /* Copy over the got and plt data.  This would have been done
      by check_relocs.  */
 
@@ -1330,7 +1656,8 @@ elfNN_ia64_hash_hide_symbol (info, xh)
   h = (struct elfNN_ia64_link_hash_entry *)xh;
 
   h->root.elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT;
-  h->root.dynindx = -1;
+  if ((h->root.elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) != 0)
+    h->root.dynindx = -1;
 
   for (dyn_i = h->info; dyn_i; dyn_i = dyn_i->next)
     dyn_i->want_plt2 = 0;
@@ -1346,7 +1673,7 @@ elfNN_ia64_hash_table_create (abfd)
 {
   struct elfNN_ia64_link_hash_table *ret;
 
-  ret = bfd_alloc (abfd, sizeof (*ret));
+  ret = bfd_zalloc (abfd, (bfd_size_type) sizeof (*ret));
   if (!ret)
     return 0;
   if (!_bfd_elf_link_hash_table_init (&ret->root, abfd,
@@ -1439,7 +1766,6 @@ elfNN_ia64_create_dynamic_sections (abfd, info)
      struct bfd_link_info *info;
 {
   struct elfNN_ia64_link_hash_table *ia64_info;
-  struct elf_link_hash_entry *h;
   asection *s;
 
   if (! _bfd_elf_create_dynamic_sections (abfd, info))
@@ -1483,6 +1809,37 @@ elfNN_ia64_create_dynamic_sections (abfd, info)
   return true;
 }
 
+/* Find and/or create a hash entry for local symbol.  */
+static struct elfNN_ia64_local_hash_entry *
+get_local_sym_hash (ia64_info, abfd, rel, create)
+     struct elfNN_ia64_link_hash_table *ia64_info;
+     bfd *abfd;
+     const Elf_Internal_Rela *rel;
+     boolean create;
+{
+  char *addr_name;
+  size_t len;
+  struct elfNN_ia64_local_hash_entry *ret;
+
+  /* Construct a string for use in the elfNN_ia64_local_hash_table.
+     name describes what was once anonymous memory.  */
+
+  len = sizeof (void*)*2 + 1 + sizeof (bfd_vma)*4 + 1 + 1;
+  len += 10;   /* %p slop */
+
+  addr_name = bfd_malloc (len);
+  if (addr_name == NULL)
+    return 0;
+  sprintf (addr_name, "%p:%lx",
+          (void *) abfd, (unsigned long) ELFNN_R_SYM (rel->r_info));
+
+  /* Collect the canonical entry data for this address.  */
+  ret = elfNN_ia64_local_hash_lookup (&ia64_info->loc_hash_table,
+                                     addr_name, create, create);
+  free (addr_name);
+  return ret;
+}
+
 /* 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.  */
 
@@ -1497,39 +1854,26 @@ get_dyn_sym_info (ia64_info, h, abfd, rel, create)
   struct elfNN_ia64_dyn_sym_info **pp;
   struct elfNN_ia64_dyn_sym_info *dyn_i;
   bfd_vma addend = rel ? rel->r_addend : 0;
-  
+
   if (h)
     pp = &((struct elfNN_ia64_link_hash_entry *)h)->info;
   else
     {
       struct elfNN_ia64_local_hash_entry *loc_h;
-      char *addr_name;
-      size_t len;
-
-      /* Construct a string for use in the elfNN_ia64_local_hash_table.
-         The name describes what was once anonymous memory.  */
 
-      len = sizeof(void*)*2 + 1 + sizeof(bfd_vma)*4 + 1 + 1;
-      len += 10;       /* %p slop */
-
-      addr_name = alloca (len);
-      sprintf (addr_name, "%p:%lx", abfd, ELFNN_R_SYM (rel->r_info));
-
-      /* Collect the canonical entry data for this address.  */
-      loc_h = elfNN_ia64_local_hash_lookup (&ia64_info->loc_hash_table,
-                                           addr_name, create, create);
+      loc_h = get_local_sym_hash (ia64_info, abfd, rel, create);
       BFD_ASSERT (loc_h);
 
       pp = &loc_h->info;
-    }    
+    }
 
   for (dyn_i = *pp; dyn_i && dyn_i->addend != addend; dyn_i = *pp)
     pp = &dyn_i->next;
 
   if (dyn_i == NULL && create)
     {
-      dyn_i = (struct elfNN_ia64_dyn_sym_info *)
-       bfd_zalloc (abfd, sizeof *dyn_i);
+      dyn_i = ((struct elfNN_ia64_dyn_sym_info *)
+              bfd_zalloc (abfd, (bfd_size_type) sizeof *dyn_i));
       *pp = dyn_i;
       dyn_i->addend = addend;
     }
@@ -1543,7 +1887,7 @@ get_got (abfd, info, ia64_info)
      struct bfd_link_info *info;
      struct elfNN_ia64_link_hash_table *ia64_info;
 {
-  asection *got, *srel;
+  asection *got;
   bfd *dynobj;
 
   got = ia64_info->got_sec;
@@ -1576,7 +1920,7 @@ get_got (abfd, info, ia64_info)
 static asection *
 get_fptr (abfd, info, ia64_info)
      bfd *abfd;
-     struct bfd_link_info *info;
+     struct bfd_link_info *info ATTRIBUTE_UNUSED;
      struct elfNN_ia64_link_hash_table *ia64_info;
 {
   asection *fptr;
@@ -1613,7 +1957,7 @@ get_fptr (abfd, info, ia64_info)
 static asection *
 get_pltoff (abfd, info, ia64_info)
      bfd *abfd;
-     struct bfd_link_info *info;
+     struct bfd_link_info *info ATTRIBUTE_UNUSED;
      struct elfNN_ia64_link_hash_table *ia64_info;
 {
   asection *pltoff;
@@ -1691,6 +2035,9 @@ get_reloc_section (abfd, ia64_info, sec, create)
        return NULL;
     }
 
+  if (sec->flags & SEC_READONLY)
+    ia64_info->reltext = 1;
+
   return srel;
 }
 
@@ -1709,8 +2056,8 @@ count_dyn_reloc (abfd, dyn_i, srel, type)
 
   if (!rent)
     {
-      rent = (struct elfNN_ia64_dyn_reloc_entry *)
-       bfd_alloc (abfd, sizeof (*rent));
+      rent = ((struct elfNN_ia64_dyn_reloc_entry *)
+             bfd_alloc (abfd, (bfd_size_type) sizeof (*rent)));
       if (!rent)
        return false;
 
@@ -1764,7 +2111,7 @@ elfNN_ia64_check_relocs (abfd, info, sec, relocs)
       struct elfNN_ia64_dyn_sym_info *dyn_i;
       int need_entry;
       boolean maybe_dynamic;
-      int dynrel_type;
+      int dynrel_type = R_IA64_NONE;
 
       if (r_symndx >= symtab_hdr->sh_info)
        {
@@ -1784,9 +2131,11 @@ elfNN_ia64_check_relocs (abfd, info, sec, relocs)
         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->shared && ! info->symbolic)
+      if (h && ((info->shared
+                     && (!info->symbolic || info->allow_shlib_undefined))
                || ! (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR)
-               || h->root.type == bfd_link_hash_defweak))
+               || h->root.type == bfd_link_hash_defweak
+               || elfNN_ia64_aix_vec (abfd->xvec)))
        maybe_dynamic = true;
 
       need_entry = 0;
@@ -1800,6 +2149,8 @@ elfNN_ia64_check_relocs (abfd, info, sec, relocs)
 
        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;
@@ -1810,7 +2161,7 @@ elfNN_ia64_check_relocs (abfd, info, sec, relocs)
        case R_IA64_FPTR32LSB:
        case R_IA64_FPTR64MSB:
        case R_IA64_FPTR64LSB:
-         if (info->shared || h)
+         if (info->shared || h || elfNN_ia64_aix_vec (abfd->xvec))
            need_entry = NEED_FPTR | NEED_DYNREL;
          else
            need_entry = NEED_FPTR;
@@ -1837,7 +2188,7 @@ elfNN_ia64_check_relocs (abfd, info, sec, relocs)
            {
              (*info->callbacks->warning)
                (info, _("@pltoff reloc against local symbol"), 0,
-                abfd, 0, 0);
+                abfd, 0, (bfd_vma) 0);
            }
          break;
 
@@ -1859,11 +2210,22 @@ elfNN_ia64_check_relocs (abfd, info, sec, relocs)
        case R_IA64_DIR64MSB:
        case R_IA64_DIR64LSB:
          /* Shared objects will always need at least a REL relocation.  */
-         if (info->shared || maybe_dynamic)
+         if (info->shared || maybe_dynamic
+             || (elfNN_ia64_aix_vec (abfd->xvec)
+                 && (!h || strcmp (h->root.root.string,
+                                   "__GLOB_DATA_PTR") != 0)))
            need_entry = NEED_DYNREL;
          dynrel_type = R_IA64_DIR64LSB;
          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;
+         dynrel_type = R_IA64_IPLTLSB;
+         break;
+
        case R_IA64_PCREL22:
        case R_IA64_PCREL64I:
        case R_IA64_PCREL32MSB:
@@ -1884,7 +2246,7 @@ elfNN_ia64_check_relocs (abfd, info, sec, relocs)
        {
          (*info->callbacks->warning)
            (info, _("non-zero addend in @fptr reloc"), 0,
-            abfd, 0, 0);
+            abfd, 0, (bfd_vma) 0);
        }
 
       dyn_i = get_dyn_sym_info (ia64_info, h, abfd, rel, true);
@@ -1915,10 +2277,12 @@ elfNN_ia64_check_relocs (abfd, info, sec, relocs)
          /* FPTRs for shared libraries are allocated by the dynamic
             linker.  Make sure this local symbol will appear in the
             dynamic symbol table.  */
-         if (!h && info->shared)
+         if (!h && (info->shared
+                    /* AIX also needs one */
+                    || elfNN_ia64_aix_vec (abfd->xvec)))
            {
              if (! (_bfd_elfNN_link_record_local_dynamic_symbol
-                    (info, abfd, r_symndx)))
+                    (info, abfd, (long) r_symndx)))
                return false;
            }
 
@@ -1971,7 +2335,10 @@ allocate_global_data_got (dyn_i, data)
 
   if (dyn_i->want_got
       && ! dyn_i->want_fptr
-      && elfNN_ia64_dynamic_symbol_p (dyn_i->h, x->info))
+      && (elfNN_ia64_dynamic_symbol_p (dyn_i->h, x->info)
+         || (elfNN_ia64_aix_vec (x->info->hash->creator)
+             && (!dyn_i->h || strcmp (dyn_i->h->root.root.string,
+                                      "__GLOB_DATA_PTR") != 0))))
      {
        dyn_i->got_offset = x->ofs;
        x->ofs += 8;
@@ -1990,7 +2357,8 @@ allocate_global_fptr_got (dyn_i, data)
 
   if (dyn_i->want_got
       && dyn_i->want_fptr
-      && elfNN_ia64_dynamic_symbol_p (dyn_i->h, x->info))
+      && (elfNN_ia64_dynamic_symbol_p (dyn_i->h, x->info)
+         || elfNN_ia64_aix_vec (x->info->hash->creator)))
     {
       dyn_i->got_offset = x->ofs;
       x->ofs += 8;
@@ -2008,7 +2376,8 @@ allocate_local_got (dyn_i, data)
   struct elfNN_ia64_allocate_data *x = (struct elfNN_ia64_allocate_data *)data;
 
   if (dyn_i->want_got
-      && ! elfNN_ia64_dynamic_symbol_p (dyn_i->h, x->info))
+      && ! (elfNN_ia64_dynamic_symbol_p (dyn_i->h, x->info)
+           || elfNN_ia64_aix_vec (x->info->hash->creator)))
     {
       dyn_i->got_offset = x->ofs;
       x->ofs += 8;
@@ -2018,7 +2387,7 @@ allocate_local_got (dyn_i, data)
 
 /* Search for the index of a global symbol in it's defining object file.  */
 
-static unsigned long
+static long
 global_sym_index (h)
      struct elf_link_hash_entry *h;
 {
@@ -2048,13 +2417,18 @@ allocate_fptr (dyn_i, data)
   if (dyn_i->want_fptr)
     {
       struct elf_link_hash_entry *h = dyn_i->h;
-      
+
       if (h)
        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;
 
-      if (x->info->shared)
+      if (x->info->shared
+         /* AIX needs an FPTR in this case. */
+         || (elfNN_ia64_aix_vec (x->info->hash->creator)
+             && (!h
+                 || h->root.type == bfd_link_hash_defined
+                 || h->root.type == bfd_link_hash_defweak)))
        {
          if (h && h->dynindx == -1)
            {
@@ -2177,13 +2551,19 @@ allocate_dynrel_entries (dyn_i, data)
   boolean dynamic_symbol, shared;
 
   ia64_info = elfNN_ia64_hash_table (x->info);
-  dynamic_symbol = elfNN_ia64_dynamic_symbol_p (dyn_i->h, x->info);
+  dynamic_symbol = elfNN_ia64_dynamic_symbol_p (dyn_i->h, x->info)
+    || (elfNN_ia64_aix_vec (x->info->hash->creator)
+       /* Don't allocate an entry for __GLOB_DATA_PTR */
+       && (!dyn_i->h || strcmp (dyn_i->h->root.root.string,
+         "__GLOB_DATA_PTR") != 0));
   shared = x->info->shared;
 
   /* Take care of the normal data relocations.  */
 
   for (rent = dyn_i->reloc_entries; rent; rent = rent->next)
     {
+      int count = rent->count;
+
       switch (rent->type)
        {
        case R_IA64_FPTR64LSB:
@@ -2201,8 +2581,18 @@ allocate_dynrel_entries (dyn_i, data)
          if (!dynamic_symbol && !shared)
            continue;
          break;
+       case R_IA64_IPLTLSB:
+         if (!dynamic_symbol && !shared)
+           continue;
+         /* Use two REL relocations for IPLT relocations
+            against local symbols.  */
+         if (!dynamic_symbol)
+           count *= 2;
+         break;
+       default:
+         abort ();
        }
-      rent->srel->_raw_size += sizeof (ElfNN_External_Rela) * rent->count;
+      rent->srel->_raw_size += sizeof (ElfNN_External_Rela) * count;
     }
 
   /* Take care of the GOT and PLT relocations.  */
@@ -2231,7 +2621,7 @@ allocate_dynrel_entries (dyn_i, data)
 
 static boolean
 elfNN_ia64_adjust_dynamic_symbol (info, h)
-     struct bfd_link_info *info;
+     struct bfd_link_info *info ATTRIBUTE_UNUSED;
      struct elf_link_hash_entry *h;
 {
   /* ??? Undefined symbols with PLT entries should be re-defined
@@ -2268,7 +2658,6 @@ elfNN_ia64_size_dynamic_sections (output_bfd, info)
   struct elfNN_ia64_link_hash_table *ia64_info;
   asection *sec;
   bfd *dynobj;
-  boolean reltext = false;
   boolean relplt = false;
 
   dynobj = elf_hash_table(info)->dynobj;
@@ -2282,38 +2671,8 @@ elfNN_ia64_size_dynamic_sections (output_bfd, info)
     {
       sec = bfd_get_section_by_name (dynobj, ".interp");
       BFD_ASSERT (sec != NULL);
-      sec->contents = (bfd_byte *) ELF_DYNAMIC_INTERPRETER;
-      sec->_raw_size = strlen (ELF_DYNAMIC_INTERPRETER) + 1;
-    }
-
-  /* DT_INIT and DT_FINI get function descriptors not raw code addresses.
-     Force their symbols to have pltoff entries so we can use those.  */
-  if (ia64_info->root.dynamic_sections_created)
-    {
-      struct elf_link_hash_entry *h;
-      struct elfNN_ia64_dyn_sym_info *dyn_i;
-      if (info->init_function
-         && (h = elf_link_hash_lookup (elf_hash_table (info), 
-                                       info->init_function, false,
-                                       false, false))
-          && (h->elf_link_hash_flags & (ELF_LINK_HASH_REF_REGULAR
-                                        | ELF_LINK_HASH_DEF_REGULAR)) != 0)
-        {
-         dyn_i = get_dyn_sym_info (ia64_info, h, output_bfd, NULL, true);
-         dyn_i->want_pltoff = 1;
-        }
-
-      if (info->fini_function
-         && (h = elf_link_hash_lookup (elf_hash_table (info), 
-                                       info->fini_function, false,
-                                       false, false))
-          && (h->elf_link_hash_flags & (ELF_LINK_HASH_REF_REGULAR
-                                        | ELF_LINK_HASH_DEF_REGULAR)) != 0)
-        {
-         dyn_i = get_dyn_sym_info (ia64_info, h, output_bfd, NULL, true);
-         dyn_i->want_pltoff = 1;
-        }
+      sec->contents = (bfd_byte *) DYNAMIC_INTERPRETER (output_bfd);
+      sec->_raw_size = strlen (DYNAMIC_INTERPRETER (output_bfd)) + 1;
     }
 
   /* Allocate the GOT entries.  */
@@ -2352,7 +2711,7 @@ elfNN_ia64_size_dynamic_sections (output_bfd, info)
     }
 
   /* Align the pointer for the plt2 entries.  */
-  data.ofs = (data.ofs + 31) & -32;
+  data.ofs = (data.ofs + 31) & (bfd_vma) -32;
 
   elfNN_ia64_dyn_sym_traverse (ia64_info, allocate_plt2_entries, &data);
   if (data.ofs != 0)
@@ -2455,24 +2814,6 @@ elfNN_ia64_size_dynamic_sections (output_bfd, info)
            {
              if (!strip)
                {
-                 const char *outname;
-                 asection *target;
-
-                 /* If this relocation section applies to a read only
-                    section, then we probably need a DT_TEXTREL entry.  */
-                 outname = bfd_get_section_name (output_bfd,
-                                                 sec->output_section);
-                 if (outname[4] == 'a')
-                   outname += 5;
-                 else
-                   outname += 4;
-
-                 target = bfd_get_section_by_name (output_bfd, outname);
-                 if (target != NULL
-                     && (target->flags & SEC_READONLY) != 0
-                     && (target->flags & SEC_ALLOC) != 0)
-                   reltext = true;
-
                  /* We use the reloc_count field as a counter if we need to
                     copy relocs into the output file.  */
                  sec->reloc_count = 0;
@@ -2487,7 +2828,7 @@ elfNN_ia64_size_dynamic_sections (output_bfd, info)
       else
        {
          /* Allocate memory for the section contents.  */
-         sec->contents = (bfd_byte *) bfd_zalloc(dynobj, sec->_raw_size);
+         sec->contents = (bfd_byte *) bfd_zalloc (dynobj, sec->_raw_size);
          if (sec->contents == NULL && sec->_raw_size != 0)
            return false;
        }
@@ -2503,32 +2844,34 @@ elfNN_ia64_size_dynamic_sections (output_bfd, info)
        {
          /* The DT_DEBUG entry is filled in by the dynamic linker and used
             by the debugger.  */
-         if (!bfd_elfNN_add_dynamic_entry (info, DT_DEBUG, 0))
+#define add_dynamic_entry(TAG, VAL) \
+  bfd_elfNN_add_dynamic_entry (info, (bfd_vma) (TAG), (bfd_vma) (VAL))
+
+         if (!add_dynamic_entry (DT_DEBUG, 0))
            return false;
        }
 
-      if (! bfd_elfNN_add_dynamic_entry (info, DT_IA_64_PLT_RESERVE, 0))
+      if (!add_dynamic_entry (DT_IA_64_PLT_RESERVE, 0))
        return false;
-      if (! bfd_elfNN_add_dynamic_entry (info, DT_PLTGOT, 0))
+      if (!add_dynamic_entry (DT_PLTGOT, 0))
        return false;
 
       if (relplt)
        {
-         if (! bfd_elfNN_add_dynamic_entry (info, DT_PLTRELSZ, 0)
-             || ! bfd_elfNN_add_dynamic_entry (info, DT_PLTREL, DT_RELA)
-             || ! bfd_elfNN_add_dynamic_entry (info, DT_JMPREL, 0))
+         if (!add_dynamic_entry (DT_PLTRELSZ, 0)
+             || !add_dynamic_entry (DT_PLTREL, DT_RELA)
+             || !add_dynamic_entry (DT_JMPREL, 0))
            return false;
        }
 
-      if (! bfd_elfNN_add_dynamic_entry (info, DT_RELA, 0)
-         || ! bfd_elfNN_add_dynamic_entry (info, DT_RELASZ, 0)
-         || ! bfd_elfNN_add_dynamic_entry (info, DT_RELAENT,
-                                           sizeof(ElfNN_External_Rela)))
+      if (!add_dynamic_entry (DT_RELA, 0)
+         || !add_dynamic_entry (DT_RELASZ, 0)
+         || !add_dynamic_entry (DT_RELAENT, sizeof (ElfNN_External_Rela)))
        return false;
 
-      if (reltext)
+      if (ia64_info->reltext)
        {
-         if (! bfd_elfNN_add_dynamic_entry (info, DT_TEXTREL, 0))
+         if (!add_dynamic_entry (DT_TEXTREL, 0))
            return false;
          info->flags |= DF_TEXTREL;
        }
@@ -2540,10 +2883,10 @@ elfNN_ia64_size_dynamic_sections (output_bfd, info)
 }
 
 static bfd_reloc_status_type
-elfNN_ia64_install_value (abfd, hit_addr, val, r_type)
+elfNN_ia64_install_value (abfd, hit_addr, v, r_type)
      bfd *abfd;
      bfd_byte *hit_addr;
-     bfd_vma val;
+     bfd_vma v;
      unsigned int r_type;
 {
   const struct ia64_operand *op;
@@ -2552,6 +2895,11 @@ elfNN_ia64_install_value (abfd, hit_addr, val, r_type)
   enum ia64_opnd opnd;
   const char *err;
   size_t size = 8;
+#ifdef BFD_HOST_U_64_BIT
+  BFD_HOST_U_64_BIT val = (BFD_HOST_U_64_BIT) v;
+#else
+  bfd_vma val = v;
+#endif
 
   opnd = IA64_OPND_NIL;
   switch (r_type)
@@ -2560,7 +2908,7 @@ elfNN_ia64_install_value (abfd, hit_addr, val, r_type)
     case R_IA64_LDXMOV:
       return bfd_reloc_ok;
 
-      /* Instruction relocations. */
+      /* Instruction relocations.  */
 
     case R_IA64_IMM14:         opnd = IA64_OPND_IMM14; break;
 
@@ -2598,6 +2946,7 @@ elfNN_ia64_install_value (abfd, hit_addr, val, r_type)
     case R_IA64_GPREL32MSB:
     case R_IA64_FPTR32MSB:
     case R_IA64_PCREL32MSB:
+    case R_IA64_LTOFF_FPTR32MSB:
     case R_IA64_SEGREL32MSB:
     case R_IA64_SECREL32MSB:
     case R_IA64_LTV32MSB:
@@ -2608,6 +2957,7 @@ elfNN_ia64_install_value (abfd, hit_addr, val, r_type)
     case R_IA64_GPREL32LSB:
     case R_IA64_FPTR32LSB:
     case R_IA64_PCREL32LSB:
+    case R_IA64_LTOFF_FPTR32LSB:
     case R_IA64_SEGREL32LSB:
     case R_IA64_SECREL32LSB:
     case R_IA64_LTV32LSB:
@@ -2639,25 +2989,6 @@ elfNN_ia64_install_value (abfd, hit_addr, val, r_type)
       break;
 
       /* Unsupported / Dynamic relocations.  */
-
-    case R_IA64_REL32MSB:
-    case R_IA64_REL32LSB:
-    case R_IA64_REL64MSB:
-    case R_IA64_REL64LSB:
-
-    case R_IA64_IPLTMSB:
-    case R_IA64_IPLTLSB:
-    case R_IA64_EPLTMSB:
-    case R_IA64_EPLTLSB:
-    case R_IA64_COPY:
-
-    case R_IA64_SEGBASE:
-
-    case R_IA64_TPREL22:
-    case R_IA64_TPREL64MSB:
-    case R_IA64_TPREL64LSB:
-    case R_IA64_LTOFF_TP22:
-
     default:
       return bfd_reloc_notsupported;
     }
@@ -2724,13 +3055,13 @@ elfNN_ia64_install_value (abfd, hit_addr, val, r_type)
        case 0: shift =  5; break;
        case 1: shift = 14; hit_addr += 3; break;
        case 2: shift = 23; hit_addr += 6; break;
-       case 3: return bfd_reloc_notsupported; /* shouldn't happen... */
+       case 3: return bfd_reloc_notsupported; /* shouldn't happen...  */
        }
       dword = bfd_get_64 (abfd, hit_addr);
       insn = (dword >> shift) & 0x1ffffffffffLL;
 
       op = elf64_ia64_operands + opnd;
-      err = (*op->insert) (op, val, &insn);
+      err = (*op->insert) (op, val, (ia64_insn *)& insn);
       if (err)
        return bfd_reloc_overflow;
 
@@ -2771,39 +3102,25 @@ elfNN_ia64_install_dyn_reloc (abfd, info, sec, srel, offset, type,
 {
   Elf_Internal_Rela outrel;
 
-  outrel.r_offset = (sec->output_section->vma
-                    + sec->output_offset
-                    + offset);
+  offset += sec->output_section->vma + sec->output_offset;
 
   BFD_ASSERT (dynindx != -1);
   outrel.r_info = ELFNN_R_INFO (dynindx, type);
   outrel.r_addend = addend;
-
-  if (elf_section_data (sec)->stab_info != NULL)
+  outrel.r_offset = _bfd_elf_section_offset (abfd, info, sec, offset);
+  if (outrel.r_offset == (bfd_vma) -1)
     {
-      /* This may be NULL for linker-generated relocations, as it is
-        inconvenient to pass all the bits around.  And this shouldn't
-        happen.  */
-      BFD_ASSERT (info != NULL);
-
-      offset = (_bfd_stab_section_offset
-               (abfd, &elf_hash_table (info)->stab_info, sec,
-                &elf_section_data (sec)->stab_info, offset));
-      if (offset == (bfd_vma) -1)
-       {
-         /* Run for the hills.  We shouldn't be outputting a relocation
-            for this.  So do what everyone else does and output a no-op.  */
-         outrel.r_info = ELFNN_R_INFO (0, R_IA64_NONE);
-         outrel.r_addend = 0;
-         offset = 0;
-       }
-      outrel.r_offset = offset;
+      /* Run for the hills.  We shouldn't be outputting a relocation
+        for this.  So do what everyone else does and output a no-op.  */
+      outrel.r_info = ELFNN_R_INFO (0, R_IA64_NONE);
+      outrel.r_addend = 0;
+      outrel.r_offset = 0;
     }
 
   bfd_elfNN_swap_reloca_out (abfd, &outrel,
                             ((ElfNN_External_Rela *) srel->contents
                              + srel->reloc_count++));
-  BFD_ASSERT (sizeof(ElfNN_External_Rela) * srel->reloc_count
+  BFD_ASSERT (sizeof (ElfNN_External_Rela) * srel->reloc_count
              <= srel->_cooked_size);
 }
 
@@ -2838,6 +3155,7 @@ set_got_entry (abfd, info, dyn_i, dynindx, addend, value, dyn_r_type)
       /* Install a dynamic relocation if needed.  */
       if (info->shared
           || elfNN_ia64_dynamic_symbol_p (dyn_i->h, info)
+         || elfNN_ia64_aix_vec (abfd->xvec)
          || (dynindx != -1 && dyn_r_type == R_IA64_FPTR64LSB))
        {
          if (dynindx == -1)
@@ -2937,10 +3255,11 @@ set_pltoff_entry (abfd, info, dyn_i, value, is_plt)
   if ((! dyn_i->want_plt || is_plt)
       && !dyn_i->pltoff_done)
     {
+      bfd_vma gp = _bfd_get_gp_value (abfd);
+
       /* Fill in the function descriptor.  */
       bfd_put_64 (abfd, value, pltoff_sec->contents + dyn_i->pltoff_offset);
-      bfd_put_64 (abfd, _bfd_get_gp_value (abfd),
-                 pltoff_sec->contents + dyn_i->pltoff_offset + 8);
+      bfd_put_64 (abfd, gp, pltoff_sec->contents + dyn_i->pltoff_offset + 8);
 
       /* Install dynamic relocations if needed.  */
       if (!is_plt && info->shared)
@@ -2955,11 +3274,11 @@ set_pltoff_entry (abfd, info, dyn_i, value, is_plt)
          elfNN_ia64_install_dyn_reloc (abfd, NULL, pltoff_sec,
                                        ia64_info->rel_pltoff_sec,
                                        dyn_i->pltoff_offset,
-                                       dyn_r_type, 0, 0);
+                                       dyn_r_type, 0, value);
          elfNN_ia64_install_dyn_reloc (abfd, NULL, pltoff_sec,
                                        ia64_info->rel_pltoff_sec,
                                        dyn_i->pltoff_offset + 8,
-                                       dyn_r_type, 0, 0);
+                                       dyn_r_type, 0, gp);
        }
 
       dyn_i->pltoff_done = 1;
@@ -2981,8 +3300,8 @@ static bfd *elfNN_ia64_unwind_entry_compare_bfd;
 
 static int
 elfNN_ia64_unwind_entry_compare (a, b)
-     PTR a;
-     PTR b;
+     const PTR a;
+     const PTR b;
 {
   bfd_vma av, bv;
 
@@ -2998,6 +3317,8 @@ elfNN_ia64_final_link (abfd, info)
      struct bfd_link_info *info;
 {
   struct elfNN_ia64_link_hash_table *ia64_info;
+  asection *unwind_output_sec;
+
   ia64_info = elfNN_ia64_hash_table (info);
 
   /* Make sure we've got ourselves a nice fat __gp value.  */
@@ -3092,7 +3413,7 @@ elfNN_ia64_final_link (abfd, info)
              (*_bfd_error_handler)
                (_("%s: short data segment overflowed (0x%lx >= 0x400000)"),
                 bfd_get_filename (abfd),
-                (unsigned long)(max_short_vma - min_short_vma));
+                (unsigned long) (max_short_vma - min_short_vma));
              return false;
            }
          else if ((gp_val > min_short_vma
@@ -3108,77 +3429,48 @@ elfNN_ia64_final_link (abfd, info)
        }
 
       _bfd_set_gp_value (abfd, gp_val);
-    }
 
-  /* Tricky bits.  DT_INIT and DT_FINI use a pltoff entry, which is
-     normally initialized in finish_dynamic_sections.  Except that
-     we need all non-plt pltoff entries to be initialized before
-     finish_dynamic_symbols.  This because the array of relocations
-     used for plt entries (aka DT_JMPREL) begins after all the 
-     non-plt pltoff relocations.  If the order gets confused, we
-     munge either the array or the array base.  */
-  if (ia64_info->root.dynamic_sections_created)
-    {
-      struct elf_link_hash_entry *h;
-      struct elfNN_ia64_dyn_sym_info *dyn_i;
-      bfd_vma addr;
-      if (info->init_function
-         && (h = elf_link_hash_lookup (elf_hash_table (info), 
-                                       info->init_function, false,
-                                       false, false))
-          && (h->elf_link_hash_flags & (ELF_LINK_HASH_REF_REGULAR
-                                        | ELF_LINK_HASH_DEF_REGULAR)) != 0)
-        {
-         dyn_i = get_dyn_sym_info (ia64_info, h, NULL, NULL, false);
-         addr = (h->root.u.def.section->output_section->vma
-                 + h->root.u.def.section->output_offset
-                 + h->root.u.def.value);
-         (void) set_pltoff_entry (abfd, info, dyn_i, addr, false);
-        }
-
-      if (info->fini_function
-         && (h = elf_link_hash_lookup (elf_hash_table (info), 
-                                       info->fini_function, false,
-                                       false, false))
-          && (h->elf_link_hash_flags & (ELF_LINK_HASH_REF_REGULAR
-                                        | ELF_LINK_HASH_DEF_REGULAR)) != 0)
-        {
-         dyn_i = get_dyn_sym_info (ia64_info, h, NULL, NULL, false);
-         addr = (h->root.u.def.section->output_section->vma
-                 + h->root.u.def.section->output_offset
-                 + h->root.u.def.value);
-         (void) set_pltoff_entry (abfd, info, dyn_i, addr, false);
-        }
+      if (gp)
+       {
+         gp->root.type = bfd_link_hash_defined;
+         gp->root.u.def.value = gp_val;
+         gp->root.u.def.section = bfd_abs_section_ptr;
+       }
     }
 
-  /* Invoke the regular ELF backend linker to do all the work.  */
-  if (!bfd_elfNN_bfd_final_link (abfd, info))
-    return false;
-
   /* If we're producing a final executable, we need to sort the contents
-     of the .IA_64.unwind section.  */
+     of the .IA_64.unwind section.  Force this section to be relocated
+     into memory rather than written immediately to the output file.  */
+  unwind_output_sec = NULL;
   if (!info->relocateable)
     {
       asection *s = bfd_get_section_by_name (abfd, ELF_STRING_ia64_unwind);
       if (s)
        {
-         bfd_size_type size = s->output_section->_raw_size;
-         char *contents = bfd_malloc (size);
-
-         if (contents == NULL)
-           return false;
-         if (! bfd_get_section_contents (abfd, s->output_section,
-                                         contents, (file_ptr) 0, size))
+         unwind_output_sec = s->output_section;
+         unwind_output_sec->contents
+           = bfd_malloc (unwind_output_sec->_raw_size);
+         if (unwind_output_sec->contents == NULL)
            return false;
+       }
+    }
 
-         elfNN_ia64_unwind_entry_compare_bfd = abfd;
-         qsort (contents, size / 24, 24, elfNN_ia64_unwind_entry_compare);
+  /* Invoke the regular ELF backend linker to do all the work.  */
+  if (!bfd_elfNN_bfd_final_link (abfd, info))
+    return false;
 
-         if (! bfd_set_section_contents (abfd, s->output_section,
-                                         contents, (file_ptr) 0, size))
-           return false;
-       }
+  if (unwind_output_sec)
+    {
+      elfNN_ia64_unwind_entry_compare_bfd = abfd;
+      qsort (unwind_output_sec->contents,
+            (size_t) (unwind_output_sec->_raw_size / 24),
+            24,
+            elfNN_ia64_unwind_entry_compare);
+
+      if (! bfd_set_section_contents (abfd, unwind_output_sec,
+                                     unwind_output_sec->contents, (bfd_vma) 0,
+                                     unwind_output_sec->_raw_size))
+       return false;
     }
 
   return true;
@@ -3244,7 +3536,7 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section,
        {
          (*_bfd_error_handler)
            (_("%s: unknown relocation type %d"),
-            bfd_get_filename (input_bfd), (int)r_type);
+            bfd_archive_filename (input_bfd), (int)r_type);
          bfd_set_error (bfd_error_bad_value);
          ret_val = false;
          continue;
@@ -3282,9 +3574,39 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section,
          /* Reloc against local symbol.  */
          sym = local_syms + r_symndx;
          sym_sec = local_sections[r_symndx];
-         value  = (sym_sec->output_section->vma
-                   + sym_sec->output_offset
-                   + sym->st_value);
+         value = _bfd_elf_rela_local_sym (output_bfd, sym, sym_sec, rel);
+         if ((sym_sec->flags & SEC_MERGE)
+             && ELF_ST_TYPE (sym->st_info) == STT_SECTION
+             && (elf_section_data (sym_sec)->sec_info_type
+                 == ELF_INFO_TYPE_MERGE))
+           {
+             struct elfNN_ia64_local_hash_entry *loc_h;
+      
+             loc_h = get_local_sym_hash (ia64_info, input_bfd, rel, false);
+             if (loc_h && ! loc_h->sec_merge_done)
+               {
+                 struct elfNN_ia64_dyn_sym_info *dynent;
+                 asection *msec;
+
+                 for (dynent = loc_h->info; dynent; dynent = dynent->next)
+                   {
+                     msec = sym_sec;
+                     dynent->addend =
+                       _bfd_merged_section_offset (output_bfd, &msec,
+                                                   elf_section_data (msec)->
+                                                   sec_info,
+                                                   sym->st_value
+                                                   + dynent->addend,
+                                                   (bfd_vma) 0);
+                     dynent->addend -= sym->st_value;
+                     dynent->addend += msec->output_section->vma
+                                       + msec->output_offset
+                                       - sym_sec->output_section->vma
+                                       - sym_sec->output_offset;
+                   }
+                 loc_h->sec_merge_done = 1;
+               }
+           }
        }
       else
        {
@@ -3320,7 +3642,8 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section,
            }
          else if (h->root.type == bfd_link_hash_undefweak)
            undef_weak_ref = true;
-         else if (info->shared && !info->symbolic
+         else if (info->shared
+                  && (!info->symbolic || info->allow_shlib_undefined)
                   && !info->no_undefined
                   && ELF_ST_VISIBILITY (h->other) == STV_DEFAULT)
            ;
@@ -3355,11 +3678,17 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section,
        case R_IA64_DIR64MSB:
        case R_IA64_DIR64LSB:
          /* Install a dynamic relocation for this reloc.  */
-         if ((dynamic_symbol_p || info->shared)
+         if ((dynamic_symbol_p || info->shared
+              || (elfNN_ia64_aix_vec (info->hash->creator)
+                  /* Don't emit relocs for __GLOB_DATA_PTR on AIX. */
+                  && (!h || strcmp (h->root.root.string,
+                                    "__GLOB_DATA_PTR") != 0)))
+             && r_symndx != 0
              && (input_section->flags & SEC_ALLOC) != 0)
            {
              unsigned int dyn_r_type;
              long dynindx;
+             bfd_vma addend;
 
              BFD_ASSERT (srel != NULL);
 
@@ -3367,7 +3696,11 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section,
                 matching RELATIVE relocation.  */
              dyn_r_type = r_type;
              if (dynamic_symbol_p)
-               dynindx = h->dynindx;
+               {
+                 dynindx = h->dynindx;
+                 addend = rel->r_addend;
+                 value = 0;
+               }
              else
                {
                  switch (r_type)
@@ -3394,16 +3727,19 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section,
                         shared libraries.  Hork.  */
                      (*_bfd_error_handler)
                        (_("%s: linking non-pic code in a shared library"),
-                        bfd_get_filename (input_bfd));
+                        bfd_archive_filename (input_bfd));
                      ret_val = false;
                      continue;
                    }
                  dynindx = 0;
+                 addend = value;
                }
 
+             if (elfNN_ia64_aix_vec (info->hash->creator))
+               rel->r_addend = value;
              elfNN_ia64_install_dyn_reloc (output_bfd, info, input_section,
                                            srel, rel->r_offset, dyn_r_type,
-                                           dynindx, rel->r_addend);
+                                           dynindx, addend);
            }
          /* FALLTHRU */
 
@@ -3424,7 +3760,7 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section,
            {
              (*_bfd_error_handler)
                (_("%s: @gprel relocation against dynamic symbol %s"),
-                bfd_get_filename (input_bfd), h->root.root.string);
+                bfd_archive_filename (input_bfd), h->root.root.string);
              ret_val = false;
              continue;
            }
@@ -3482,7 +3818,7 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section,
              else
                {
                  dynindx = (_bfd_elf_link_lookup_local_dynindx
-                            (info, input_bfd, r_symndx));
+                            (info, input_bfd, (long) r_symndx));
                }
 
              elfNN_ia64_install_dyn_reloc (output_bfd, info, input_section,
@@ -3496,6 +3832,8 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section,
 
        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:
          {
@@ -3524,7 +3862,7 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section,
                  }
                else
                  dynindx = (_bfd_elf_link_lookup_local_dynindx
-                            (info, input_bfd, r_symndx));
+                            (info, input_bfd, (long) r_symndx));
                value = 0;
              }
 
@@ -3540,7 +3878,9 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section,
        case R_IA64_PCREL64MSB:
        case R_IA64_PCREL64LSB:
          /* Install a dynamic relocation for this reloc.  */
-         if (dynamic_symbol_p)
+         if ((dynamic_symbol_p
+              || elfNN_ia64_aix_vec (info->hash->creator))
+             && r_symndx != 0)
            {
              BFD_ASSERT (srel != NULL);
 
@@ -3559,7 +3899,7 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section,
            {
              (*_bfd_error_handler)
                (_("%s: dynamic relocation against speculation fixup"),
-                bfd_get_filename (input_bfd));
+                bfd_archive_filename (input_bfd));
              ret_val = false;
              continue;
            }
@@ -3567,7 +3907,7 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section,
            {
              (*_bfd_error_handler)
                (_("%s: speculation fixup against undefined weak symbol"),
-                bfd_get_filename (input_bfd));
+                bfd_archive_filename (input_bfd));
              ret_val = false;
              continue;
            }
@@ -3618,47 +3958,48 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section,
        case R_IA64_SEGREL32LSB:
        case R_IA64_SEGREL64MSB:
        case R_IA64_SEGREL64LSB:
-         {
-           struct elf_segment_map *m;
-           Elf_Internal_Phdr *p;
-
-           /* Find the segment that contains the output_section.  */
-           for (m = elf_tdata (output_bfd)->segment_map,
-                  p = elf_tdata (output_bfd)->phdr;
-                m != NULL;
-                m = m->next, p++)
-             {
-               int i;
-               for (i = m->count - 1; i >= 0; i--)
-                 if (m->sections[i] == sym_sec->output_section)
+         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;
+
+             /* Find the segment that contains the output_section.  */
+             for (m = elf_tdata (output_bfd)->segment_map,
+                    p = elf_tdata (output_bfd)->phdr;
+                  m != NULL;
+                  m = m->next, p++)
+               {
+                 int i;
+                 for (i = m->count - 1; i >= 0; i--)
+                   if (m->sections[i] == sym_sec->output_section)
+                     break;
+                 if (i >= 0)
                    break;
-               if (i >= 0)
-                 break;
-             }
-
-           if (m == NULL)
-             {
-               /* If the input section was discarded from the output, then
-                  do nothing.  */
+               }
 
-               if (bfd_is_abs_section (sym_sec->output_section))
-                 r = bfd_reloc_ok;
-               else
+             if (m == NULL)
+               {
                  r = bfd_reloc_notsupported;
-             }
-           else
-             {
-               /* The VMA of the segment is the vaddr of the associated
-                  program header.  */
-               if (value > p->p_vaddr)
-                 value -= p->p_vaddr;
-               else
-                 value = 0;
-               r = elfNN_ia64_install_value (output_bfd, hit_addr, value,
-                                             r_type);
-             }
-           break;
-         }
+               }
+             else
+               {
+                 /* The VMA of the segment is the vaddr of the associated
+                    program header.  */
+                 if (value > p->p_vaddr)
+                   value -= p->p_vaddr;
+                 else
+                   value = 0;
+                 r = elfNN_ia64_install_value (output_bfd, hit_addr, value,
+                                               r_type);
+               }
+             break;
+           }
 
        case R_IA64_SECREL32MSB:
        case R_IA64_SECREL32LSB:
@@ -3672,23 +4013,49 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section,
          r = elfNN_ia64_install_value (output_bfd, hit_addr, value, r_type);
          break;
 
-       case R_IA64_SEGBASE:
-
-       case R_IA64_REL32MSB:
-       case R_IA64_REL32LSB:
-       case R_IA64_REL64MSB:
-       case R_IA64_REL64LSB:
-
        case R_IA64_IPLTMSB:
        case R_IA64_IPLTLSB:
-       case R_IA64_EPLTMSB:
-       case R_IA64_EPLTLSB:
-       case R_IA64_COPY:
+         /* Install a dynamic relocation for this reloc.  */
+         if ((dynamic_symbol_p || info->shared)
+             && (input_section->flags & SEC_ALLOC) != 0)
+           {
+             BFD_ASSERT (srel != NULL);
+
+             /* If we don't need dynamic symbol lookup, install two
+                RELATIVE relocations.  */
+             if (! dynamic_symbol_p)
+               {
+                 unsigned int dyn_r_type;
+
+                 if (r_type == R_IA64_IPLTMSB)
+                   dyn_r_type = R_IA64_REL64MSB;
+                 else
+                   dyn_r_type = R_IA64_REL64LSB;
+
+                 elfNN_ia64_install_dyn_reloc (output_bfd, info,
+                                               input_section,
+                                               srel, rel->r_offset,
+                                               dyn_r_type, 0, value);
+                 elfNN_ia64_install_dyn_reloc (output_bfd, info,
+                                               input_section,
+                                               srel, rel->r_offset + 8,
+                                               dyn_r_type, 0, gp_val);
+               }
+             else
+               elfNN_ia64_install_dyn_reloc (output_bfd, info, input_section,
+                                             srel, rel->r_offset, r_type,
+                                             h->dynindx, rel->r_addend);
+           }
+
+         if (r_type == R_IA64_IPLTMSB)
+           r_type = R_IA64_DIR64MSB;
+         else
+           r_type = R_IA64_DIR64LSB;
+         elfNN_ia64_install_value (output_bfd, hit_addr, value, r_type);
+         r = elfNN_ia64_install_value (output_bfd, hit_addr + 8, gp_val,
+                                       r_type);
+         break;
 
-       case R_IA64_TPREL22:
-       case R_IA64_TPREL64MSB:
-       case R_IA64_TPREL64LSB:
-       case R_IA64_LTOFF_TP22:
        default:
          r = bfd_reloc_notsupported;
          break;
@@ -3751,7 +4118,8 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section,
                  name = bfd_section_name (input_bfd, input_section);
              }
            if (!(*info->callbacks->reloc_overflow) (info, name,
-                                                    howto->name, 0,
+                                                    howto->name,
+                                                    (bfd_vma) 0,
                                                     input_bfd,
                                                     input_section,
                                                     rel->r_offset))
@@ -3885,8 +4253,6 @@ elfNN_ia64_finish_dynamic_sections (abfd, info)
       for (; dyncon < dynconend; dyncon++)
        {
          Elf_Internal_Dyn dyn;
-         const char *name;
-         asection *s;
 
          bfd_elfNN_swap_dyn_in (dynobj, dyncon, &dyn);
 
@@ -3916,29 +4282,10 @@ elfNN_ia64_finish_dynamic_sections (abfd, info)
 
            case DT_RELASZ:
              /* Do not have RELASZ include JMPREL.  This makes things
-                easier on ld.so.  This is not what the rest of BFD set up. */
+                easier on ld.so.  This is not what the rest of BFD set up.  */
              dyn.d_un.d_val -= (ia64_info->minplt_entries
                                 * sizeof (ElfNN_External_Rela));
              break;
-
-           case DT_INIT:
-           case DT_FINI:
-             {
-               struct elf_link_hash_entry *h;
-               struct elfNN_ia64_dyn_sym_info *dyn_i;
-               const char *which;
-               if (dyn.d_tag == DT_INIT)
-                 which = info->init_function;
-               else
-                 which = info->fini_function;
-
-               h = elf_link_hash_lookup (elf_hash_table (info), which,
-                                         false, false, false);
-               dyn_i = get_dyn_sym_info (ia64_info, h, NULL, NULL, false);
-               dyn.d_un.d_ptr = set_pltoff_entry (abfd, info, dyn_i,
-                                                  dyn.d_un.d_ptr, 0);
-             }
            }
 
          bfd_elfNN_swap_dyn_out (abfd, &dyn, dyncon);
@@ -3965,7 +4312,7 @@ elfNN_ia64_finish_dynamic_sections (abfd, info)
 \f
 /* ELF file flag handling: */
 
-/* Function to keep IA-64 specific file flags. */
+/* Function to keep IA-64 specific file flags.  */
 static boolean
 elfNN_ia64_set_private_flags (abfd, flags)
      bfd *abfd;
@@ -3979,24 +4326,6 @@ elfNN_ia64_set_private_flags (abfd, flags)
   return true;
 }
 
-/* Copy backend specific data from one object module to another */
-static boolean
-elfNN_ia64_copy_private_bfd_data (ibfd, obfd)
-     bfd *ibfd, *obfd;
-{
-  if (   bfd_get_flavour (ibfd) != bfd_target_elf_flavour
-      || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
-    return true;
-
-  BFD_ASSERT (!elf_flags_init (obfd)
-             || (elf_elfheader (obfd)->e_flags
-                 == elf_elfheader (ibfd)->e_flags));
-
-  elf_elfheader (obfd)->e_flags = elf_elfheader (ibfd)->e_flags;
-  elf_flags_init (obfd) = true;
-  return true;
-}
-
 /* Merge backend specific data from an object file to the output
    object file when linking.  */
 static boolean
@@ -4042,7 +4371,7 @@ elfNN_ia64_merge_private_bfd_data (ibfd, obfd)
     {
       (*_bfd_error_handler)
        (_("%s: linking trap-on-NULL-dereference with non-trapping files"),
-        bfd_get_filename (ibfd));
+        bfd_archive_filename (ibfd));
 
       bfd_set_error (bfd_error_bad_value);
       ok = false;
@@ -4051,7 +4380,7 @@ elfNN_ia64_merge_private_bfd_data (ibfd, obfd)
     {
       (*_bfd_error_handler)
        (_("%s: linking big-endian files with little-endian files"),
-        bfd_get_filename (ibfd));
+        bfd_archive_filename (ibfd));
 
       bfd_set_error (bfd_error_bad_value);
       ok = false;
@@ -4060,7 +4389,7 @@ elfNN_ia64_merge_private_bfd_data (ibfd, obfd)
     {
       (*_bfd_error_handler)
        (_("%s: linking 64-bit files with 32-bit files"),
-        bfd_get_filename (ibfd));
+        bfd_archive_filename (ibfd));
 
       bfd_set_error (bfd_error_bad_value);
       ok = false;
@@ -4069,7 +4398,7 @@ elfNN_ia64_merge_private_bfd_data (ibfd, obfd)
     {
       (*_bfd_error_handler)
        (_("%s: linking constant-gp files with non-constant-gp files"),
-        bfd_get_filename (ibfd));
+        bfd_archive_filename (ibfd));
 
       bfd_set_error (bfd_error_bad_value);
       ok = false;
@@ -4079,7 +4408,7 @@ elfNN_ia64_merge_private_bfd_data (ibfd, obfd)
     {
       (*_bfd_error_handler)
        (_("%s: linking auto-pic files with non-auto-pic files"),
-        bfd_get_filename (ibfd));
+        bfd_archive_filename (ibfd));
 
       bfd_set_error (bfd_error_bad_value);
       ok = false;
@@ -4107,10 +4436,63 @@ elfNN_ia64_print_private_bfd_data (abfd, ptr)
           (flags & EF_IA_64_NOFUNCDESC_CONS_GP) ? "NOFUNCDESC_CONS_GP, " : "",
           (flags & EF_IA_64_ABSOLUTE) ? "ABSOLUTE, " : "",
           (flags & EF_IA_64_ABI64) ? "ABI64" : "ABI32");
-  
+
   _bfd_elf_print_private_bfd_data (abfd, ptr);
   return true;
 }
+
+static enum elf_reloc_type_class
+elfNN_ia64_reloc_type_class (rela)
+     const Elf_Internal_Rela *rela;
+{
+  switch ((int) ELFNN_R_TYPE (rela->r_info))
+    {
+    case R_IA64_REL32MSB:
+    case R_IA64_REL32LSB:
+    case R_IA64_REL64MSB:
+    case R_IA64_REL64LSB:
+      return reloc_class_relative;
+    case R_IA64_IPLTMSB:
+    case R_IA64_IPLTLSB:
+      return reloc_class_plt;
+    case R_IA64_COPY:
+      return reloc_class_copy;
+    default:
+      return reloc_class_normal;
+    }
+}
+
+static boolean
+elfNN_ia64_hpux_vec (const bfd_target *vec)
+{
+  extern const bfd_target bfd_elfNN_ia64_hpux_big_vec;
+  return (vec == & bfd_elfNN_ia64_hpux_big_vec);
+}
+
+static void
+elfNN_hpux_post_process_headers (abfd, info)
+       bfd *abfd;
+       struct bfd_link_info *info ATTRIBUTE_UNUSED;
+{
+  Elf_Internal_Ehdr *i_ehdrp = elf_elfheader (abfd);
+
+  i_ehdrp->e_ident[EI_OSABI] = ELFOSABI_HPUX;
+  i_ehdrp->e_ident[EI_ABIVERSION] = 1;
+}
+
+boolean
+elfNN_hpux_backend_section_from_bfd_section (abfd, sec, retval)
+       bfd *abfd ATTRIBUTE_UNUSED;
+       asection *sec;
+       int *retval;
+{
+  if (bfd_is_com_section (sec))
+    {
+      *retval = SHN_IA_64_ANSI_COMMON;
+      return true;
+    }
+  return false;
+}
 \f
 #define TARGET_LITTLE_SYM              bfd_elfNN_ia64_little_vec
 #define TARGET_LITTLE_NAME             "elfNN-ia64-little"
@@ -4128,6 +4510,8 @@ elfNN_ia64_print_private_bfd_data (abfd, ptr)
        elfNN_ia64_section_flags
 #define elf_backend_fake_sections \
        elfNN_ia64_fake_sections
+#define elf_backend_final_write_processing \
+       elfNN_ia64_final_write_processing
 #define elf_backend_add_symbol_hook \
        elfNN_ia64_add_symbol_hook
 #define elf_backend_additional_program_headers \
@@ -4164,8 +4548,6 @@ elfNN_ia64_print_private_bfd_data (abfd, ptr)
 #define bfd_elfNN_bfd_final_link \
        elfNN_ia64_final_link
 
-#define bfd_elfNN_bfd_copy_private_bfd_data \
-       elfNN_ia64_copy_private_bfd_data
 #define bfd_elfNN_bfd_merge_private_bfd_data \
        elfNN_ia64_merge_private_bfd_data
 #define bfd_elfNN_bfd_set_private_flags \
@@ -4185,5 +4567,50 @@ elfNN_ia64_print_private_bfd_data (abfd, ptr)
 #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_reloc_type_class   elfNN_ia64_reloc_type_class
+
+#include "elfNN-target.h"
+
+/* AIX-specific vectors.  */
+
+#undef  TARGET_LITTLE_SYM
+#define TARGET_LITTLE_SYM              bfd_elfNN_ia64_aix_little_vec
+#undef  TARGET_LITTLE_NAME
+#define TARGET_LITTLE_NAME             "elfNN-ia64-aix-little"
+#undef  TARGET_BIG_SYM
+#define TARGET_BIG_SYM                 bfd_elfNN_ia64_aix_big_vec
+#undef  TARGET_BIG_NAME
+#define TARGET_BIG_NAME                        "elfNN-ia64-aix-big"
+
+#undef  elf_backend_add_symbol_hook
+#define elf_backend_add_symbol_hook    elfNN_ia64_aix_add_symbol_hook
+
+#undef  bfd_elfNN_bfd_link_add_symbols
+#define bfd_elfNN_bfd_link_add_symbols         elfNN_ia64_aix_link_add_symbols
+
+#define elfNN_bed elfNN_ia64_aix_bed
+
+#include "elfNN-target.h"
+
+/* HPUX-specific vectors.  */
+
+#undef  TARGET_LITTLE_SYM
+#undef  TARGET_LITTLE_NAME
+#undef  TARGET_BIG_SYM
+#define TARGET_BIG_SYM                  bfd_elfNN_ia64_hpux_big_vec
+#undef  TARGET_BIG_NAME
+#define TARGET_BIG_NAME                 "elfNN-ia64-hpux-big"
+
+#undef  elf_backend_post_process_headers
+#define elf_backend_post_process_headers elfNN_hpux_post_process_headers
+
+#undef  elf_backend_section_from_bfd_section
+#define elf_backend_section_from_bfd_section elfNN_hpux_backend_section_from_bfd_section
+
+#undef  ELF_MAXPAGESIZE
+#define ELF_MAXPAGESIZE                 0x1000  /* 1K */
+
+#undef  elfNN_bed
+#define elfNN_bed elfNN_ia64_hpux_bed
 
 #include "elfNN-target.h"