include/elf/ChangeLog
[deliverable/binutils-gdb.git] / bfd / elfxx-ia64.c
index 8d80e6e27dfc9725510e9043e51e60705f591fda..9a6f65c4049eebab711893e5aad9d74accb385d1 100644 (file)
@@ -1,22 +1,22 @@
 /* IA-64 support for 64-bit ELF
-   Copyright 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+   Copyright 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
    Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
 
-This file is part of BFD, the Binary File Descriptor library.
+   This file is part of BFD, the Binary File Descriptor library.
 
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
-(at your option) any later version.
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
 
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
 
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
 #include "bfd.h"
 #include "sysdep.h"
@@ -25,37 +25,33 @@ 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 --
- *
- * GOT         Entries created in response to LTOFF or LTOFF_FPTR
- *             relocations.  Dynamic relocs created for dynamic
- *             symbols in an application; REL relocs for locals
- *             in a shared library.
- *
- * FPTR                The canonical function descriptor.  Created for local
- *             symbols in applications.  Descriptors for dynamic symbols
- *             and local symbols in shared libraries are created by
- *             ld.so.  Thus there are no dynamic relocs against these
- *             objects.  The FPTR relocs for such _are_ passed through
- *             to the dynamic relocation tables.
- *
- * FULL_PLT    Created for a PCREL21B relocation against a dynamic symbol.
- *             Requires the creation of a PLTOFF entry.  This does not
- *             require any dynamic relocations.
- *
- * PLTOFF      Created by PLTOFF relocations.  For local symbols, this
- *             is an alternate function descriptor, and in shared libraries
- *             requires two REL relocations.  Note that this cannot be
- *             transformed into an FPTR relocation, since it must be in
- *             range of the GP.  For dynamic symbols, this is a function
- *             descriptor for a MIN_PLT entry, and requires one IPLT reloc.
- *
- * MIN_PLT     Created by PLTOFF entries against dynamic symbols.  This
- *             does not reqire dynamic relocations.
- */
-
-#define USE_RELA               /* we want RELA relocs, not REL */
+/* THE RULES for all the stuff the linker creates --
+  GOT          Entries created in response to LTOFF or LTOFF_FPTR
+               relocations.  Dynamic relocs created for dynamic
+               symbols in an application; REL relocs for locals
+               in a shared library.
+  FPTR         The canonical function descriptor.  Created for local
+               symbols in applications.  Descriptors for dynamic symbols
+               and local symbols in shared libraries are created by
+               ld.so.  Thus there are no dynamic relocs against these
+               objects.  The FPTR relocs for such _are_ passed through
+               to the dynamic relocation tables.
+  FULL_PLT     Created for a PCREL21B relocation against a dynamic symbol.
+               Requires the creation of a PLTOFF entry.  This does not
+               require any dynamic relocations.
+  PLTOFF       Created by PLTOFF relocations.  For local symbols, this
+               is an alternate function descriptor, and in shared libraries
+               requires two REL relocations.  Note that this cannot be
+               transformed into an FPTR relocation, since it must be in
+               range of the GP.  For dynamic symbols, this is a function
+               descriptor for a MIN_PLT entry, and requires one IPLT reloc.
+  MIN_PLT      Created by PLTOFF entries against dynamic symbols.  This
+               does not reqire dynamic relocations.  */
 
 #define NELEMS(a)      ((int) (sizeof (a) / sizeof ((a)[0])))
 
@@ -79,6 +75,9 @@ struct elfNN_ia64_dyn_sym_info
   bfd_vma pltoff_offset;
   bfd_vma plt_offset;
   bfd_vma plt2_offset;
+  bfd_vma tprel_offset;
+  bfd_vma dtpmod_offset;
+  bfd_vma dtprel_offset;
 
   /* The symbol table entry, if any, that this was derrived from.  */
   struct elf_link_hash_entry *h;
@@ -97,6 +96,9 @@ struct elfNN_ia64_dyn_sym_info
   unsigned got_done : 1;
   unsigned fptr_done : 1;
   unsigned pltoff_done : 1;
+  unsigned tprel_done : 1;
+  unsigned dtpmod_done : 1;
+  unsigned dtprel_done : 1;
 
   /* True for the different kinds of linker data we want created.  */
   unsigned want_got : 1;
@@ -105,12 +107,19 @@ struct elfNN_ia64_dyn_sym_info
   unsigned want_plt : 1;
   unsigned want_plt2 : 1;
   unsigned want_pltoff : 1;
+  unsigned want_tprel : 1;
+  unsigned want_dtpmod : 1;
+  unsigned want_dtprel : 1;
 };
 
 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
@@ -127,7 +136,7 @@ struct elfNN_ia64_link_hash_entry
 
 struct elfNN_ia64_link_hash_table
 {
-  /* The main hash table */
+  /* The main hash table */
   struct elf_link_hash_table root;
 
   asection *got_sec;           /* the linkage table section (or NULL) */
@@ -138,6 +147,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;
 };
@@ -153,23 +163,25 @@ static reloc_howto_type * lookup_howto
 static reloc_howto_type *elfNN_ia64_reloc_type_lookup
   PARAMS ((bfd *abfd, bfd_reloc_code_real_type bfd_code));
 static void elfNN_ia64_info_to_howto
-  PARAMS ((bfd *abfd, arelent *bfd_reloc, ElfNN_Internal_Rela *elf_reloc));
+  PARAMS ((bfd *abfd, arelent *bfd_reloc, Elf_Internal_Rela *elf_reloc));
 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 ((const char *));
+  PARAMS ((bfd *abfd, const char *));
 static boolean elfNN_ia64_section_from_shdr
-  PARAMS ((bfd *, ElfNN_Internal_Shdr *, char *));
+  PARAMS ((bfd *, Elf_Internal_Shdr *, const char *));
+static boolean elfNN_ia64_section_flags
+  PARAMS ((flagword *, Elf_Internal_Shdr *));
 static boolean elfNN_ia64_fake_sections
-  PARAMS ((bfd *abfd, ElfNN_Internal_Shdr *hdr, asection *sec));
+  PARAMS ((bfd *abfd, Elf_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 
+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,
@@ -179,6 +191,8 @@ 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
@@ -192,17 +206,29 @@ 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_backend_data *, 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 *, boolean));
 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),
           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,
@@ -227,7 +253,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));
@@ -265,6 +291,12 @@ 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 bfd_vma elfNN_ia64_tprel_base
+  PARAMS ((struct bfd_link_info *info));
+static bfd_vma elfNN_ia64_dtprel_base
+  PARAMS ((struct bfd_link_info *info));
+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
@@ -279,14 +311,20 @@ 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 */
+/* ia64-specific relocation */
 
 /* Perform a relocation.  Not much to do here as all the hard work is
    done in elfNN_ia64_final_link_relocate.  */
@@ -360,6 +398,8 @@ 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),
 
@@ -393,17 +433,32 @@ static reloc_howto_type ia64_howto_table[] =
     IA64_HOWTO (R_IA64_LTOFF22X,    "LTOFF22X",           0, false, true),
     IA64_HOWTO (R_IA64_LDXMOV,     "LDXMOV",      0, false, true),
 
+    IA64_HOWTO (R_IA64_TPREL14,            "TPREL14",     0, false, false),
     IA64_HOWTO (R_IA64_TPREL22,            "TPREL22",     0, false, false),
+    IA64_HOWTO (R_IA64_TPREL64I,    "TPREL64I",           0, false, false),
     IA64_HOWTO (R_IA64_TPREL64MSB,  "TPREL64MSB",  8, false, false),
     IA64_HOWTO (R_IA64_TPREL64LSB,  "TPREL64LSB",  8, false, false),
-    IA64_HOWTO (R_IA64_LTOFF_TP22,  "LTOFF_TP22",  0, false, false),
+    IA64_HOWTO (R_IA64_LTOFF_TPREL22, "LTOFF_TPREL22",  0, false, false),
+
+    IA64_HOWTO (R_IA64_DTPMOD64MSB, "TPREL64MSB",  8, false, false),
+    IA64_HOWTO (R_IA64_DTPMOD64LSB, "TPREL64LSB",  8, false, false),
+    IA64_HOWTO (R_IA64_LTOFF_DTPMOD22, "LTOFF_DTPMOD22", 0, false, false),
+
+    IA64_HOWTO (R_IA64_DTPREL14,    "DTPREL14",           0, false, false),
+    IA64_HOWTO (R_IA64_DTPREL22,    "DTPREL22",           0, false, false),
+    IA64_HOWTO (R_IA64_DTPREL64I,   "DTPREL64I",   0, false, false),
+    IA64_HOWTO (R_IA64_DTPREL32MSB, "DTPREL32MSB", 4, false, false),
+    IA64_HOWTO (R_IA64_DTPREL32LSB, "DTPREL32LSB", 4, false, false),
+    IA64_HOWTO (R_IA64_DTPREL64MSB, "DTPREL64MSB", 8, false, false),
+    IA64_HOWTO (R_IA64_DTPREL64LSB, "DTPREL64LSB", 8, false, false),
+    IA64_HOWTO (R_IA64_LTOFF_DTPREL22, "LTOFF_DTPREL22", 0, false, false),
   };
 
 static unsigned char elf_code_to_howto_index[R_IA64_MAX_RELOC_CODE + 1];
 
 /* Given a BFD reloc type, return the matching HOWTO structure.  */
 
-static reloc_howto_type*
+static reloc_howto_type *
 lookup_howto (rtype)
      unsigned int rtype;
 {
@@ -480,6 +535,8 @@ 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;
 
@@ -509,10 +566,25 @@ elfNN_ia64_reloc_type_lookup (abfd, bfd_code)
     case BFD_RELOC_IA64_LTOFF22X:      rtype = R_IA64_LTOFF22X; break;
     case BFD_RELOC_IA64_LDXMOV:                rtype = R_IA64_LDXMOV; break;
 
+    case BFD_RELOC_IA64_TPREL14:       rtype = R_IA64_TPREL14; break;
     case BFD_RELOC_IA64_TPREL22:       rtype = R_IA64_TPREL22; break;
+    case BFD_RELOC_IA64_TPREL64I:      rtype = R_IA64_TPREL64I; break;
     case BFD_RELOC_IA64_TPREL64MSB:    rtype = R_IA64_TPREL64MSB; break;
     case BFD_RELOC_IA64_TPREL64LSB:    rtype = R_IA64_TPREL64LSB; break;
-    case BFD_RELOC_IA64_LTOFF_TP22:    rtype = R_IA64_LTOFF_TP22; break;
+    case BFD_RELOC_IA64_LTOFF_TPREL22: rtype = R_IA64_LTOFF_TPREL22; break;
+
+    case BFD_RELOC_IA64_DTPMOD64MSB:   rtype = R_IA64_DTPMOD64MSB; break;
+    case BFD_RELOC_IA64_DTPMOD64LSB:   rtype = R_IA64_DTPMOD64LSB; break;
+    case BFD_RELOC_IA64_LTOFF_DTPMOD22:        rtype = R_IA64_LTOFF_DTPMOD22; break;
+
+    case BFD_RELOC_IA64_DTPREL14:      rtype = R_IA64_DTPREL14; break;
+    case BFD_RELOC_IA64_DTPREL22:      rtype = R_IA64_DTPREL22; break;
+    case BFD_RELOC_IA64_DTPREL64I:     rtype = R_IA64_DTPREL64I; break;
+    case BFD_RELOC_IA64_DTPREL32MSB:   rtype = R_IA64_DTPREL32MSB; break;
+    case BFD_RELOC_IA64_DTPREL32LSB:   rtype = R_IA64_DTPREL32LSB; break;
+    case BFD_RELOC_IA64_DTPREL64MSB:   rtype = R_IA64_DTPREL64MSB; break;
+    case BFD_RELOC_IA64_DTPREL64LSB:   rtype = R_IA64_DTPREL64LSB; break;
+    case BFD_RELOC_IA64_LTOFF_DTPREL22:        rtype = R_IA64_LTOFF_DTPREL22; break;
 
     default: return 0;
     }
@@ -525,9 +597,10 @@ static void
 elfNN_ia64_info_to_howto (abfd, bfd_reloc, elf_reloc)
      bfd *abfd ATTRIBUTE_UNUSED;
      arelent *bfd_reloc;
-     ElfNN_Internal_Rela *elf_reloc;
+     Elf_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)
@@ -574,13 +647,14 @@ static const bfd_byte plt_full_entry[PLT_FULL_ENTRY_SIZE] =
    not support brl, and so it gets emulated by the kernel.  */
 #undef USE_BRL
 
+#ifdef USE_BRL
 static const bfd_byte oor_brl[16] =
 {
   0x05, 0x00, 0x00, 0x00, 0x01, 0x00,  /*  [MLX]        nop.m 0            */
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /*               brl.sptk.few tgt;; */
   0x00, 0x00, 0x00, 0xc0
 };
-
+#else
 static const bfd_byte oor_ip[48] =
 {
   0x04, 0x00, 0x00, 0x00, 0x01, 0x00,  /*  [MLX]        nop.m 0            */
@@ -593,6 +667,7 @@ static const bfd_byte oor_ip[48] =
   0x60, 0x80, 0x04, 0x80, 0x03, 0x00,  /*               mov b6=r16         */
   0x60, 0x00, 0x80, 0x00               /*               br b6;;            */
 };
+#endif
 \f
 /* These functions do relaxation for IA-64 ELF.
 
@@ -616,12 +691,9 @@ elfNN_ia64_relax_section (abfd, sec, link_info, again)
 
   Elf_Internal_Shdr *symtab_hdr;
   Elf_Internal_Rela *internal_relocs;
-  Elf_Internal_Rela *free_relocs = NULL;
   Elf_Internal_Rela *irel, *irelend;
   bfd_byte *contents;
-  bfd_byte *free_contents = NULL;
-  ElfNN_External_Sym *extsyms;
-  ElfNN_External_Sym *free_extsyms = NULL;
+  Elf_Internal_Sym *isymbuf = NULL;
   struct elfNN_ia64_link_hash_table *ia64_info;
   struct one_fixup *fixups = NULL;
   boolean changed_contents = false;
@@ -648,23 +720,22 @@ elfNN_ia64_relax_section (abfd, sec, link_info, again)
                     (abfd, sec, (PTR) NULL, (Elf_Internal_Rela *) NULL,
                      link_info->keep_memory));
   if (internal_relocs == NULL)
-    goto error_return;
-
-  if (! link_info->keep_memory)
-    free_relocs = internal_relocs;
+    return false;
 
   ia64_info = elfNN_ia64_hash_table (link_info);
   irelend = internal_relocs + sec->reloc_count;
 
   for (irel = internal_relocs; irel < irelend; irel++)
-    if (ELFNN_R_TYPE (irel->r_info) == (int) R_IA64_PCREL21B)
+    if (ELFNN_R_TYPE (irel->r_info) == (int) R_IA64_PCREL21B
+       || ELFNN_R_TYPE (irel->r_info) == (int) R_IA64_PCREL21M
+       || ELFNN_R_TYPE (irel->r_info) == (int) R_IA64_PCREL21F)
       break;
 
   /* No branch-type relocations.  */
   if (irel == irelend)
     {
-      if (free_relocs != NULL)
-       free (free_relocs);
+      if (elf_section_data (sec)->relocs != internal_relocs)
+       free (internal_relocs);
       return true;
     }
 
@@ -676,57 +747,55 @@ elfNN_ia64_relax_section (abfd, sec, link_info, again)
       contents = (bfd_byte *) bfd_malloc (sec->_raw_size);
       if (contents == NULL)
        goto error_return;
-      free_contents = contents;
 
       if (! bfd_get_section_contents (abfd, sec, contents,
                                      (file_ptr) 0, sec->_raw_size))
        goto error_return;
     }
 
-  /* Read this BFD's symbols.  */
-  if (symtab_hdr->contents != NULL)
-    extsyms = (ElfNN_External_Sym *) symtab_hdr->contents;
-  else
-    {
-      extsyms = (ElfNN_External_Sym *) bfd_malloc (symtab_hdr->sh_size);
-      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))
-       goto error_return;
-    }
-
   for (; irel < irelend; irel++)
     {
       bfd_vma symaddr, reladdr, trampoff, toff, roff;
-      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)
+      if (ELFNN_R_TYPE (irel->r_info) != (int) R_IA64_PCREL21B
+         && ELFNN_R_TYPE (irel->r_info) != (int) R_IA64_PCREL21M
+         && ELFNN_R_TYPE (irel->r_info) != (int) R_IA64_PCREL21F)
        continue;
 
       /* Get the value of the symbol referred to by the reloc.  */
       if (ELFNN_R_SYM (irel->r_info) < symtab_hdr->sh_info)
        {
          /* A local symbol.  */
-         bfd_elfNN_swap_symbol_in (abfd,
-                                   extsyms + ELFNN_R_SYM (irel->r_info),
-                                   &isym);
-         if (isym.st_shndx == SHN_UNDEF)
+         Elf_Internal_Sym *isym;
+
+         /* Read this BFD's local symbols.  */
+         if (isymbuf == NULL)
+           {
+             isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
+             if (isymbuf == NULL)
+               isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr,
+                                               symtab_hdr->sh_info, 0,
+                                               NULL, NULL, NULL);
+             if (isymbuf == 0)
+               goto error_return;
+           }
+
+         isym = isymbuf + ELF64_R_SYM (irel->r_info);
+         if (isym->st_shndx == SHN_UNDEF)
            continue;   /* We can't do anthing with undefined symbols.  */
-         else if (isym.st_shndx == SHN_ABS)
+         else if (isym->st_shndx == SHN_ABS)
            tsec = bfd_abs_section_ptr;
-         else if (isym.st_shndx == SHN_COMMON)
+         else if (isym->st_shndx == SHN_COMMON)
+           tsec = bfd_com_section_ptr;
+         else if (isym->st_shndx == SHN_IA_64_ANSI_COMMON)
            tsec = bfd_com_section_ptr;
-         else if (isym.st_shndx > 0 && isym.st_shndx < SHN_LORESERVE)
-           tsec = bfd_section_from_elf_index (abfd, isym.st_shndx);
          else
-           continue;   /* who knows.  */
+           tsec = bfd_section_from_elf_index (abfd, isym->st_shndx);
 
-         toff = isym.st_value;
+         toff = isym->st_value;
        }
       else
        {
@@ -771,7 +840,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
@@ -795,7 +864,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);
@@ -809,11 +878,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)
            {
@@ -841,7 +911,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;
@@ -857,7 +927,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;
 
@@ -873,60 +943,72 @@ elfNN_ia64_relax_section (abfd, sec, link_info, again)
       free (f);
     }
 
-  if (changed_relocs)
-    elf_section_data (sec)->relocs = internal_relocs;
-  else if (free_relocs != NULL)
-    free (free_relocs);
-
-  if (changed_contents)
-    elf_section_data (sec)->this_hdr.contents = contents;
-  else if (free_contents != NULL)
+  if (isymbuf != NULL
+      && symtab_hdr->contents != (unsigned char *) isymbuf)
     {
       if (! link_info->keep_memory)
-       free (free_contents);
+       free (isymbuf);
       else
        {
-         /* Cache the section contents for elf_link_input_bfd.  */
-         elf_section_data (sec)->this_hdr.contents = contents;
+         /* Cache the symbols for elf_link_input_bfd.  */
+         symtab_hdr->contents = (unsigned char *) isymbuf;
        }
     }
 
-  if (free_extsyms != NULL)
+  if (contents != NULL
+      && elf_section_data (sec)->this_hdr.contents != contents)
     {
-      if (! link_info->keep_memory)
-       free (free_extsyms);
+      if (!changed_contents && !link_info->keep_memory)
+       free (contents);
       else
        {
-         /* Cache the symbols for elf_link_input_bfd.  */
-         symtab_hdr->contents = extsyms;
+         /* Cache the section contents for elf_link_input_bfd.  */
+         elf_section_data (sec)->this_hdr.contents = contents;
        }
     }
 
+  if (elf_section_data (sec)->relocs != internal_relocs)
+    {
+      if (!changed_relocs)
+       free (internal_relocs);
+      else
+       elf_section_data (sec)->relocs = internal_relocs;
+    }
+
   *again = changed_contents || changed_relocs;
   return true;
 
  error_return:
-  if (free_relocs != NULL)
-    free (free_relocs);
-  if (free_contents != NULL)
-    free (free_contents);
-  if (free_extsyms != NULL)
-    free (free_extsyms);
+  if (isymbuf != NULL && (unsigned char *) isymbuf != symtab_hdr->contents)
+    free (isymbuf);
+  if (contents != NULL
+      && elf_section_data (sec)->this_hdr.contents != contents)
+    free (contents);
+  if (internal_relocs != NULL
+      && elf_section_data (sec)->relocs != internal_relocs)
+    free (internal_relocs);
   return false;
 }
 \f
 /* Return true if NAME is an unwind table section name.  */
 
 static inline boolean
-is_unwind_section_name (name)
+is_unwind_section_name (abfd, name)
+       bfd *abfd;
        const char *name;
 {
-  size_t len1, len2;
+  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;
-  return (strncmp (name, ELF_STRING_ia64_unwind, len1) == 0
-         && strncmp (name, ELF_STRING_ia64_unwind_info, len2) != 0);
+  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
@@ -935,8 +1017,8 @@ is_unwind_section_name (name)
 static boolean
 elfNN_ia64_section_from_shdr (abfd, hdr, name)
      bfd *abfd;
-     ElfNN_Internal_Shdr *hdr;
-     char *name;
+     Elf_Internal_Shdr *hdr;
+     const char *name;
 {
   asection *newsect;
 
@@ -948,6 +1030,7 @@ elfNN_ia64_section_from_shdr (abfd, hdr, name)
   switch (hdr->sh_type)
     {
     case SHT_IA_64_UNWIND:
+    case SHT_IA_64_HP_OPT_ANOT:
       break;
 
     case SHT_IA_64_EXT:
@@ -974,7 +1057,7 @@ elfNN_ia64_section_from_shdr (abfd, hdr, name)
 static boolean
 elfNN_ia64_section_flags (flags, hdr)
      flagword *flags;
-     ElfNN_Internal_Shdr *hdr;
+     Elf_Internal_Shdr *hdr;
 {
   if (hdr->sh_flags & SHF_IA_64_SHORT)
     *flags |= SEC_SMALL_DATA;
@@ -988,14 +1071,14 @@ elfNN_ia64_section_flags (flags, hdr)
 static boolean
 elfNN_ia64_fake_sections (abfd, hdr, sec)
      bfd *abfd ATTRIBUTE_UNUSED;
-     ElfNN_Internal_Shdr *hdr;
+     Elf_Internal_Shdr *hdr;
      asection *sec;
 {
   register const char *name;
 
   name = bfd_get_section_name (abfd, sec);
 
-  if (is_unwind_section_name (name))
+  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.  */
@@ -1004,25 +1087,25 @@ elfNN_ia64_fake_sections (abfd, hdr, sec)
     }
   else if (strcmp (name, ELF_STRING_ia64_archext) == 0)
     hdr->sh_type = SHT_IA_64_EXT;
+  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
-     * needed when producing EFI binaries on IA-64. It tells
-     * elf.c:elf_fake_sections() not to consider ".reloc" as a section
-     * containing ELF relocation info.  We need this hack in order to
-     * be able to generate ELF binaries that can be translated into
-     * EFI applications (which are essentially COFF objects).  Those
-     * files contain a COFF ".reloc" section inside an ELFNN object,
-     * which would normally cause BFD to segfault because it would
-     * attempt to interpret this section as containing relocation
-     * entries for section "oc".  With this hack enabled, ".reloc"
-     * will be treated as a normal data section, which will avoid the
-     * segfault.  However, you won't be able to create an ELFNN binary
-     * with a section named "oc" that needs relocations, but that's
-     * the kind of ugly side-effects you get when detecting section
-     * types based on their names...  In practice, this limitation is
-     * unlikely to bite.
-     */
+    /* This is an ugly, but unfortunately necessary hack that is
+       needed when producing EFI binaries on IA-64. It tells
+       elf.c:elf_fake_sections() not to consider ".reloc" as a section
+       containing ELF relocation info.  We need this hack in order to
+       be able to generate ELF binaries that can be translated into
+       EFI applications (which are essentially COFF objects).  Those
+       files contain a COFF ".reloc" section inside an ELFNN object,
+       which would normally cause BFD to segfault because it would
+       attempt to interpret this section as containing relocation
+       entries for section "oc".  With this hack enabled, ".reloc"
+       will be treated as a normal data section, which will avoid the
+       segfault.  However, you won't be able to create an ELFNN binary
+       with a section named "oc" that needs relocations, but that's
+       the kind of ugly side-effects you get when detecting section
+       types based on their names...  In practice, this limitation is
+       unlikely to bite.  */
     hdr->sh_type = SHT_PROGBITS;
 
   if (sec->flags & SEC_SMALL_DATA)
@@ -1065,6 +1148,36 @@ elfNN_ia64_final_write_processing (abfd, linker)
                /* .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");
@@ -1081,6 +1194,19 @@ elfNN_ia64_final_write_processing (abfd, linker)
          break;
        }
     }
+
+  if (! elf_flags_init (abfd))
+    {
+      unsigned long flags = 0;
+
+      if (abfd->xvec->byteorder == BFD_ENDIAN_BIG)
+       flags |= EF_IA_64_BE;
+      if (bfd_get_mach (abfd) == bfd_mach_ia64_elf64)
+       flags |= EF_IA_64_ABI64;
+
+      elf_elfheader(abfd)->e_flags = flags;
+      elf_flags_init (abfd) = true;
+    }
 }
 
 /* Hook called by the linker routine which adds symbols from an object
@@ -1098,7 +1224,7 @@ elfNN_ia64_add_symbol_hook (abfd, info, sym, namep, flagsp, secp, valp)
 {
   if (sym->st_shndx == SHN_COMMON
       && !info->relocateable
-      && sym->st_size <= (unsigned) 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.  */
@@ -1128,7 +1254,7 @@ 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 
+  return (/**/vec == & bfd_elfNN_ia64_aix_little_vec
          ||  vec == & bfd_elfNN_ia64_aix_big_vec);
 }
 
@@ -1147,32 +1273,34 @@ elfNN_ia64_aix_add_symbol_hook (abfd, info, sym, namep, flagsp, secp, valp)
 {
   if (strcmp (*namep, "__GLOB_DATA_PTR") == 0)
     {
-      /* Define __GLOB_DATA_PTR.  This is expected to be a linker-defined
-        symbol by the Aix C runtime startup code.  Define the symbol
-        when it is encountered.  IBM sez no one else should use it b/c it is
-        undocumented.  */
+      /* 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 = (struct elf_link_hash_entry *) bfd_link_hash_lookup (info->hash, *namep, false, false, false);
-      if (h == NULL) 
+      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;
+         struct bfd_link_hash_entry *bh = NULL;
 
          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, ia64_info->got_sec,
+               (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)))
+                bed->collect, &bh)))
            return false;
-         
+
+         h = (struct elf_link_hash_entry *) bh;
          h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR;
          h->type = STT_OBJECT;
-         
-         if (info->shared
-             && ! _bfd_elf_link_record_dynamic_symbol (info, h))
+
+         if (! _bfd_elf_link_record_dynamic_symbol (info, h))
            return false;
        }
 
@@ -1180,17 +1308,16 @@ elfNN_ia64_aix_add_symbol_hook (abfd, info, sym, namep, flagsp, secp, valp)
     }
   else if (sym->st_shndx == SHN_LOOS)
     {
-      int i;
-      
+      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. */
-      /* FIXME need to determine the proper section instead of defaulting to
-        .text.  */
-      for (i = 1; i < elf_elfheader (abfd)->e_shnum; i++)
+        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;
@@ -1200,14 +1327,14 @@ elfNN_ia64_aix_add_symbol_hook (abfd, info, sym, namep, flagsp, secp, valp)
 
       if (*secp == NULL)
        *secp = bfd_abs_section_ptr;
-      
+
       *valp = sym->st_size;
-      
+
       return true;
     }
-  else 
+  else
     {
-      return elfNN_ia64_add_symbol_hook (abfd, info, sym, 
+      return elfNN_ia64_add_symbol_hook (abfd, info, sym,
                                         namep, flagsp, secp, valp);
     }
 }
@@ -1245,7 +1372,7 @@ elfNN_ia64_additional_program_headers (abfd)
 
   /* Count how many PT_IA_64_UNWIND segments we need.  */
   for (s = abfd->sections; s; s = s->next)
-    if (is_unwind_section_name(s->name) && (s->flags & SEC_LOAD))
+    if (is_unwind_section_name (abfd, s->name) && (s->flags & SEC_LOAD))
       ++ret;
 
   return ret;
@@ -1269,7 +1396,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;
 
@@ -1299,12 +1427,25 @@ elfNN_ia64_modify_segment_map (abfd)
       if (s && (s->flags & SEC_LOAD))
        {
          for (m = elf_tdata (abfd)->segment_map; m != NULL; m = m->next)
-           if (m->p_type == PT_IA_64_UNWIND && m->sections[0] == s)
-             break;
+           if (m->p_type == PT_IA_64_UNWIND)
+             {
+               int i;
+
+               /* Look through all sections in the unwind segment
+                  for a match since there may be multiple sections
+                  to a segment.  */
+               for (i = m->count - 1; i >= 0; --i)
+                 if (m->sections[i] == s)
+                   break;
+
+               if (i >= 0)
+                 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;
 
@@ -1385,13 +1526,15 @@ elfNN_ia64_dynamic_symbol_p (h, info)
     case STV_INTERNAL:
     case STV_HIDDEN:
       return false;
+    default:
+      break;
     }
 
   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)))
@@ -1468,13 +1611,14 @@ elfNN_ia64_new_elf_hash_entry (entry, table, string)
 }
 
 static void
-elfNN_ia64_hash_copy_indirect (xdir, xind)
+elfNN_ia64_hash_copy_indirect (bed, xdir, xind)
+     struct elf_backend_data *bed ATTRIBUTE_UNUSED;
      struct elf_link_hash_entry *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
      symbol which just became indirect.  */
@@ -1485,6 +1629,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.  */
 
@@ -1514,18 +1661,17 @@ elfNN_ia64_hash_copy_indirect (xdir, xind)
 }
 
 static void
-elfNN_ia64_hash_hide_symbol (info, xh)
-     struct bfd_link_info *info ATTRIBUTE_UNUSED;
+elfNN_ia64_hash_hide_symbol (info, xh, force_local)
+     struct bfd_link_info *info;
      struct elf_link_hash_entry *xh;
+     boolean force_local;
 {
   struct elfNN_ia64_link_hash_entry *h;
   struct elfNN_ia64_dyn_sym_info *dyn_i;
 
   h = (struct elfNN_ia64_link_hash_entry *)xh;
 
-  h->root.elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT;
-  if ((h->root.elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) != 0)
-    h->root.dynindx = -1;
+  _bfd_elf_link_hash_hide_symbol (info, &h->root, force_local);
 
   for (dyn_i = h->info; dyn_i; dyn_i = dyn_i->next)
     dyn_i->want_plt2 = 0;
@@ -1541,7 +1687,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,
@@ -1588,6 +1734,9 @@ elfNN_ia64_global_dyn_sym_thunk (xentry, xdata)
     = (struct elfNN_ia64_dyn_sym_traverse_data *) xdata;
   struct elfNN_ia64_dyn_sym_info *dyn_i;
 
+  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)
     if (! (*data->func) (dyn_i, data->data))
       return false;
@@ -1677,6 +1826,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.  */
 
@@ -1697,21 +1877,8 @@ get_dyn_sym_info (ia64_info, h, abfd, rel, create)
   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", (void *) 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;
@@ -1722,8 +1889,8 @@ get_dyn_sym_info (ia64_info, h, abfd, rel, create)
 
   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;
     }
@@ -1885,6 +2052,9 @@ get_reloc_section (abfd, ia64_info, sec, create)
        return NULL;
     }
 
+  if (sec->flags & SEC_READONLY)
+    ia64_info->reltext = 1;
+
   return srel;
 }
 
@@ -1903,8 +2073,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;
 
@@ -1951,6 +2121,9 @@ elfNN_ia64_check_relocs (abfd, info, sec, relocs)
        NEED_FULL_PLT = 16,
        NEED_DYNREL = 32,
        NEED_LTOFF_FPTR = 64,
+       NEED_TPREL = 128,
+       NEED_DTPMOD = 256,
+       NEED_DTPREL = 512
       };
 
       struct elf_link_hash_entry *h = NULL;
@@ -1978,7 +2151,8 @@ 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
                || elfNN_ia64_aix_vec (abfd->xvec)))
@@ -1987,14 +2161,47 @@ elfNN_ia64_check_relocs (abfd, info, sec, relocs)
       need_entry = 0;
       switch (ELFNN_R_TYPE (rel->r_info))
        {
-       case R_IA64_TPREL22:
        case R_IA64_TPREL64MSB:
        case R_IA64_TPREL64LSB:
-       case R_IA64_LTOFF_TP22:
-         return false;
+         if (info->shared || maybe_dynamic)
+           need_entry = NEED_DYNREL;
+         dynrel_type = R_IA64_TPREL64LSB;
+         if (info->shared)
+           info->flags |= DF_STATIC_TLS;
+         break;
+
+       case R_IA64_LTOFF_TPREL22:
+         need_entry = NEED_TPREL;
+         if (info->shared)
+           info->flags |= DF_STATIC_TLS;
+         break;
+
+       case R_IA64_DTPREL64MSB:
+       case R_IA64_DTPREL64LSB:
+         if (info->shared || maybe_dynamic)
+           need_entry = NEED_DYNREL;
+         dynrel_type = R_IA64_DTPREL64LSB;
+         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;
+         dynrel_type = R_IA64_DTPMOD64LSB;
+         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;
@@ -2005,9 +2212,7 @@ elfNN_ia64_check_relocs (abfd, info, sec, relocs)
        case R_IA64_FPTR32LSB:
        case R_IA64_FPTR64MSB:
        case R_IA64_FPTR64LSB:
-         if (elfNN_ia64_aix_vec (abfd->xvec))
-           need_entry = NEED_FPTR | NEED_DYNREL;
-         else 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;
@@ -2034,7 +2239,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;
 
@@ -2057,10 +2262,8 @@ elfNN_ia64_check_relocs (abfd, info, sec, relocs)
        case R_IA64_DIR64LSB:
          /* Shared objects will always need at least a REL relocation.  */
          if (info->shared || maybe_dynamic
-             /* On AIX, we always need a relocation, but make sure
-                __GLOB_DATA_PTR doesn't get an entry.  */ 
              || (elfNN_ia64_aix_vec (abfd->xvec)
-                 && (!h || strcmp (h->root.root.string, 
+                 && (!h || strcmp (h->root.root.string,
                                    "__GLOB_DATA_PTR") != 0)))
            need_entry = NEED_DYNREL;
          dynrel_type = R_IA64_DIR64LSB;
@@ -2094,7 +2297,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);
@@ -2103,7 +2306,7 @@ elfNN_ia64_check_relocs (abfd, info, sec, relocs)
       dyn_i->h = h;
 
       /* Create what's needed.  */
-      if (need_entry & NEED_GOT)
+      if (need_entry & (NEED_GOT | NEED_TPREL | NEED_DTPMOD | NEED_DTPREL))
        {
          if (!got)
            {
@@ -2111,7 +2314,14 @@ elfNN_ia64_check_relocs (abfd, info, sec, relocs)
              if (!got)
                return false;
            }
-         dyn_i->want_got = 1;
+         if (need_entry & NEED_GOT)
+           dyn_i->want_got = 1;
+         if (need_entry & NEED_TPREL)
+           dyn_i->want_tprel = 1;
+         if (need_entry & NEED_DTPMOD)
+           dyn_i->want_dtpmod = 1;
+         if (need_entry & NEED_DTPREL)
+           dyn_i->want_dtprel = 1;
        }
       if (need_entry & NEED_FPTR)
        {
@@ -2130,7 +2340,7 @@ elfNN_ia64_check_relocs (abfd, info, sec, relocs)
                     || 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;
            }
 
@@ -2184,11 +2394,28 @@ 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_aix_vec (x->info->hash->creator)))
+         || (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;
      }
+  if (dyn_i->want_tprel)
+    {
+      dyn_i->tprel_offset = x->ofs;
+      x->ofs += 8;
+    }
+  if (dyn_i->want_dtpmod)
+    {
+      dyn_i->dtpmod_offset = x->ofs;
+      x->ofs += 8;
+    }
+  if (dyn_i->want_dtprel)
+    {
+      dyn_i->dtprel_offset = x->ofs;
+      x->ofs += 8;
+    }
   return true;
 }
 
@@ -2233,7 +2460,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;
 {
@@ -2398,7 +2625,10 @@ allocate_dynrel_entries (dyn_i, data)
 
   ia64_info = elfNN_ia64_hash_table (x->info);
   dynamic_symbol = elfNN_ia64_dynamic_symbol_p (dyn_i->h, x->info)
-    || elfNN_ia64_aix_vec (x->info->hash->creator);
+    || (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.  */
@@ -2432,6 +2662,10 @@ allocate_dynrel_entries (dyn_i, data)
          if (!dynamic_symbol)
            count *= 2;
          break;
+       case R_IA64_TPREL64LSB:
+       case R_IA64_DTPREL64LSB:
+       case R_IA64_DTPMOD64LSB:
+         break;
        default:
          abort ();
        }
@@ -2443,6 +2677,12 @@ allocate_dynrel_entries (dyn_i, data)
   if (((dynamic_symbol || shared) && dyn_i->want_got)
       || (dyn_i->want_ltoff_fptr && dyn_i->h && dyn_i->h->dynindx != -1))
     ia64_info->rel_got_sec->_raw_size += sizeof (ElfNN_External_Rela);
+  if ((dynamic_symbol || shared) && dyn_i->want_tprel)
+    ia64_info->rel_got_sec->_raw_size += sizeof (ElfNN_External_Rela);
+  if ((dynamic_symbol || shared) && dyn_i->want_dtpmod)
+    ia64_info->rel_got_sec->_raw_size += sizeof (ElfNN_External_Rela);
+  if (dynamic_symbol && dyn_i->want_dtprel)
+    ia64_info->rel_got_sec->_raw_size += sizeof (ElfNN_External_Rela);
 
   if (dyn_i->want_pltoff)
     {
@@ -2501,7 +2741,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;
@@ -2555,7 +2794,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)
@@ -2658,24 +2897,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;
@@ -2690,7 +2911,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;
        }
@@ -2706,32 +2927,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;
        }
@@ -2743,10 +2966,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;
@@ -2755,6 +2978,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)
@@ -2765,7 +2993,11 @@ elfNN_ia64_install_value (abfd, hit_addr, val, r_type)
 
       /* Instruction relocations.  */
 
-    case R_IA64_IMM14:         opnd = IA64_OPND_IMM14; break;
+    case R_IA64_IMM14:
+    case R_IA64_TPREL14:
+    case R_IA64_DTPREL14:
+      opnd = IA64_OPND_IMM14;
+      break;
 
     case R_IA64_PCREL21F:      opnd = IA64_OPND_TGT25; break;
     case R_IA64_PCREL21M:      opnd = IA64_OPND_TGT25b; break;
@@ -2782,6 +3014,11 @@ elfNN_ia64_install_value (abfd, hit_addr, val, r_type)
     case R_IA64_PLTOFF22:
     case R_IA64_PCREL22:
     case R_IA64_LTOFF_FPTR22:
+    case R_IA64_TPREL22:
+    case R_IA64_DTPREL22:
+    case R_IA64_LTOFF_TPREL22:
+    case R_IA64_LTOFF_DTPMOD22:
+    case R_IA64_LTOFF_DTPREL22:
       opnd = IA64_OPND_IMM22;
       break;
 
@@ -2792,6 +3029,8 @@ elfNN_ia64_install_value (abfd, hit_addr, val, r_type)
     case R_IA64_PCREL64I:
     case R_IA64_FPTR64I:
     case R_IA64_LTOFF_FPTR64I:
+    case R_IA64_TPREL64I:
+    case R_IA64_DTPREL64I:
       opnd = IA64_OPND_IMMU64;
       break;
 
@@ -2801,9 +3040,11 @@ 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:
+    case R_IA64_DTPREL32MSB:
       size = 4; bigendian = 1;
       break;
 
@@ -2811,9 +3052,11 @@ 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:
+    case R_IA64_DTPREL32LSB:
       size = 4; bigendian = 0;
       break;
 
@@ -2826,6 +3069,9 @@ elfNN_ia64_install_value (abfd, hit_addr, val, r_type)
     case R_IA64_SEGREL64MSB:
     case R_IA64_SECREL64MSB:
     case R_IA64_LTV64MSB:
+    case R_IA64_TPREL64MSB:
+    case R_IA64_DTPMOD64MSB:
+    case R_IA64_DTPREL64MSB:
       size = 8; bigendian = 1;
       break;
 
@@ -2838,6 +3084,9 @@ elfNN_ia64_install_value (abfd, hit_addr, val, r_type)
     case R_IA64_SEGREL64LSB:
     case R_IA64_SECREL64LSB:
     case R_IA64_LTV64LSB:
+    case R_IA64_TPREL64LSB:
+    case R_IA64_DTPMOD64LSB:
+    case R_IA64_DTPREL64LSB:
       size = 8; bigendian = 0;
       break;
 
@@ -2914,7 +3163,7 @@ elfNN_ia64_install_value (abfd, hit_addr, val, r_type)
       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;
 
@@ -2954,39 +3203,26 @@ elfNN_ia64_install_dyn_reloc (abfd, info, sec, srel, offset, type,
      bfd_vma addend;
 {
   Elf_Internal_Rela outrel;
-
-  outrel.r_offset = (sec->output_section->vma
-                    + sec->output_offset
-                    + offset);
+  bfd_byte *loc;
 
   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) -2)
     {
-      /* 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;
     }
+  else
+    outrel.r_offset += sec->output_section->vma + sec->output_offset;
 
-  bfd_elfNN_swap_reloca_out (abfd, &outrel,
-                            ((ElfNN_External_Rela *) srel->contents
-                             + srel->reloc_count++));
+  loc = srel->contents;
+  loc += srel->reloc_count++ * sizeof (ElfNN_External_Rela);
+  bfd_elfNN_swap_reloca_out (abfd, &outrel, loc);
   BFD_ASSERT (sizeof (ElfNN_External_Rela) * srel->reloc_count
              <= srel->_cooked_size);
 }
@@ -3006,26 +3242,53 @@ set_got_entry (abfd, info, dyn_i, dynindx, addend, value, dyn_r_type)
 {
   struct elfNN_ia64_link_hash_table *ia64_info;
   asection *got_sec;
+  boolean done;
+  bfd_vma got_offset;
 
   ia64_info = elfNN_ia64_hash_table (info);
   got_sec = ia64_info->got_sec;
 
-  BFD_ASSERT ((dyn_i->got_offset & 7) == 0);
-
-  if (! dyn_i->got_done)
+  switch (dyn_r_type)
     {
+    case R_IA64_TPREL64LSB:
+      done = dyn_i->tprel_done;
+      dyn_i->tprel_done = true;
+      got_offset = dyn_i->tprel_offset;
+      break;
+    case R_IA64_DTPMOD64LSB:
+      done = dyn_i->dtpmod_done;
+      dyn_i->dtpmod_done = true;
+      got_offset = dyn_i->dtpmod_offset;
+      break;
+    case R_IA64_DTPREL64LSB:
+      done = dyn_i->dtprel_done;
+      dyn_i->dtprel_done = true;
+      got_offset = dyn_i->dtprel_offset;
+      break;
+    default:
+      done = dyn_i->got_done;
       dyn_i->got_done = true;
+      got_offset = dyn_i->got_offset;
+      break;
+    }
+
+  BFD_ASSERT ((got_offset & 7) == 0);
 
+  if (! done)
+    {
       /* Store the target address in the linkage table entry.  */
-      bfd_put_64 (abfd, value, got_sec->contents + dyn_i->got_offset);
+      bfd_put_64 (abfd, value, got_sec->contents + got_offset);
 
       /* Install a dynamic relocation if needed.  */
-      if (info->shared
+      if ((info->shared && dyn_r_type != R_IA64_DTPREL64LSB)
           || 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)
+         if (dynindx == -1
+             && dyn_r_type != R_IA64_TPREL64LSB
+             && dyn_r_type != R_IA64_DTPMOD64LSB
+             && dyn_r_type != R_IA64_DTPREL64LSB)
            {
              dyn_r_type = R_IA64_REL64LSB;
              dynindx = 0;
@@ -3045,6 +3308,15 @@ set_got_entry (abfd, info, dyn_i, dynindx, addend, value, dyn_r_type)
                case R_IA64_FPTR64LSB:
                  dyn_r_type = R_IA64_FPTR64MSB;
                  break;
+               case R_IA64_TPREL64LSB:
+                 dyn_r_type = R_IA64_TPREL64MSB;
+                 break;
+               case R_IA64_DTPMOD64LSB:
+                 dyn_r_type = R_IA64_DTPMOD64MSB;
+                 break;
+               case R_IA64_DTPREL64LSB:
+                 dyn_r_type = R_IA64_DTPREL64MSB;
+                 break;
                default:
                  BFD_ASSERT (false);
                  break;
@@ -3053,7 +3325,7 @@ set_got_entry (abfd, info, dyn_i, dynindx, addend, value, dyn_r_type)
 
          elfNN_ia64_install_dyn_reloc (abfd, NULL, got_sec,
                                        ia64_info->rel_got_sec,
-                                       dyn_i->got_offset, dyn_r_type,
+                                       got_offset, dyn_r_type,
                                        dynindx, addend);
        }
     }
@@ -3061,7 +3333,7 @@ set_got_entry (abfd, info, dyn_i, dynindx, addend, value, dyn_r_type)
   /* Return the address of the linkage table entry.  */
   value = (got_sec->output_section->vma
           + got_sec->output_offset
-          + dyn_i->got_offset);
+          + got_offset);
 
   return value;
 }
@@ -3159,6 +3431,35 @@ set_pltoff_entry (abfd, info, dyn_i, value, is_plt)
   return value;
 }
 
+/* Return the base VMA address which should be subtracted from real addresses
+   when resolving @tprel() relocation.
+   Main program TLS (whose template starts at PT_TLS p_vaddr)
+   is assigned offset round(16, PT_TLS p_align).  */
+
+static bfd_vma
+elfNN_ia64_tprel_base (info)
+     struct bfd_link_info *info;
+{
+  struct elf_link_tls_segment *tls_segment
+    = elf_hash_table (info)->tls_segment;
+
+  BFD_ASSERT (tls_segment != NULL);
+  return (tls_segment->start
+         - align_power ((bfd_vma) 16, tls_segment->align));
+}
+
+/* Return the base VMA address which should be subtracted from real addresses
+   when resolving @dtprel() relocation.
+   This is PT_TLS segment p_vaddr.  */
+
+static bfd_vma
+elfNN_ia64_dtprel_base (info)
+     struct bfd_link_info *info;
+{
+  BFD_ASSERT (elf_hash_table (info)->tls_segment != NULL);
+  return elf_hash_table (info)->tls_segment->start;
+}
+
 /* Called through qsort to sort the .IA_64.unwind section during a
    non-relocatable link.  Set elfNN_ia64_unwind_entry_compare_bfd
    to the output bfd so we can do proper endianness frobbing.  */
@@ -3167,8 +3468,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;
 
@@ -3329,11 +3630,13 @@ elfNN_ia64_final_link (abfd, info)
   if (unwind_output_sec)
     {
       elfNN_ia64_unwind_entry_compare_bfd = abfd;
-      qsort (unwind_output_sec->contents, unwind_output_sec->_raw_size / 24,
-            24, elfNN_ia64_unwind_entry_compare);
+      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, 0,
+                                     unwind_output_sec->contents, (bfd_vma) 0,
                                      unwind_output_sec->_raw_size))
        return false;
     }
@@ -3374,6 +3677,7 @@ 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);
@@ -3401,34 +3705,14 @@ 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;
        }
+
       howto = lookup_howto (r_type);
       r_symndx = ELFNN_R_SYM (rel->r_info);
-
-      if (info->relocateable)
-       {
-         /* This is a relocateable link.  We don't have to change
-            anything, unless the reloc is against a section symbol,
-            in which case we have to adjust according to where the
-            section symbol winds up in the output section.  */
-         if (r_symndx < symtab_hdr->sh_info)
-           {
-             sym = local_syms + r_symndx;
-             if (ELF_ST_TYPE (sym->st_info) == STT_SECTION)
-               {
-                 sym_sec = local_sections[r_symndx];
-                 rel->r_addend += sym_sec->output_offset;
-               }
-           }
-         continue;
-       }
-
-      /* This is a final link.  */
-
       h = NULL;
       sym = NULL;
       sym_sec = NULL;
@@ -3439,9 +3723,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
        {
@@ -3477,7 +3791,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)
            ;
@@ -3514,11 +3829,10 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section,
          /* Install a dynamic relocation for this reloc.  */
          if ((dynamic_symbol_p || info->shared
               || (elfNN_ia64_aix_vec (info->hash->creator)
-                  /* We want REL relocation for _GLOB_DATA_PTR, which would
-                     otherwise be an IMM64, which isn't handled below.  The
-                     symbol comes from the C runtime.  */
-                  && (!h || 
-                      strcmp (h->root.root.string, "__GLOB_DATA_PTR") != 0)))
+                  /* 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;
@@ -3562,7 +3876,7 @@ 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;
                    }
@@ -3595,7 +3909,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;
            }
@@ -3653,7 +3967,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,
@@ -3667,6 +3981,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:
          {
@@ -3695,7 +4011,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;
              }
 
@@ -3711,8 +4027,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
-             || elfNN_ia64_aix_vec (info->hash->creator))
+         if ((dynamic_symbol_p
+              || elfNN_ia64_aix_vec (info->hash->creator))
+             && r_symndx != 0)
            {
              BFD_ASSERT (srel != NULL);
 
@@ -3731,7 +4048,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;
            }
@@ -3739,7 +4056,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;
            }
@@ -3790,47 +4107,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:
@@ -3887,6 +4205,55 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section,
                                        r_type);
          break;
 
+       case R_IA64_TPREL14:
+       case R_IA64_TPREL22:
+       case R_IA64_TPREL64I:
+         value -= elfNN_ia64_tprel_base (info);
+         r = elfNN_ia64_install_value (output_bfd, hit_addr, value, r_type);
+         break;
+
+       case R_IA64_DTPREL14:
+       case R_IA64_DTPREL22:
+       case R_IA64_DTPREL64I:
+         value -= elfNN_ia64_dtprel_base (info);
+         r = elfNN_ia64_install_value (output_bfd, hit_addr, value, r_type);
+         break;
+
+       case R_IA64_LTOFF_TPREL22:
+       case R_IA64_LTOFF_DTPMOD22:
+       case R_IA64_LTOFF_DTPREL22:
+         {
+           int got_r_type;
+
+           switch (r_type)
+             {
+             default:
+             case R_IA64_LTOFF_TPREL22:
+               if (!dynamic_symbol_p && !info->shared)
+                 value -= elfNN_ia64_tprel_base (info);
+               got_r_type = R_IA64_TPREL64LSB;
+               break;
+             case R_IA64_LTOFF_DTPMOD22:
+               if (!dynamic_symbol_p && !info->shared)
+                 value = 1;
+               got_r_type = R_IA64_DTPMOD64LSB;
+               break;
+             case R_IA64_LTOFF_DTPREL22:
+               if (!dynamic_symbol_p)
+                 value -= elfNN_ia64_dtprel_base (info);
+               got_r_type = R_IA64_DTPREL64LSB;
+               break;
+             }
+           dyn_i = get_dyn_sym_info (ia64_info, h, input_bfd, rel, false);
+           value = set_got_entry (input_bfd, info, dyn_i,
+                                  (h ? h->dynindx : -1), rel->r_addend,
+                                  value, got_r_type);
+           value -= gp_val;
+           r = elfNN_ia64_install_value (output_bfd, hit_addr, value,
+                                         r_type);
+         }
+         break;
+
        default:
          r = bfd_reloc_notsupported;
          break;
@@ -3949,7 +4316,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))
@@ -3983,7 +4351,6 @@ elfNN_ia64_finish_dynamic_symbol (output_bfd, info, h, sym)
       bfd_byte *loc;
       asection *plt_sec;
       bfd_vma plt_addr, pltoff_addr, gp_val, index;
-      ElfNN_External_Rela *rel;
 
       gp_val = _bfd_get_gp_value (output_bfd);
 
@@ -4040,10 +4407,10 @@ elfNN_ia64_finish_dynamic_symbol (output_bfd, info, h, sym)
         existing sec->reloc_count to be the base of the array of
         PLT relocations.  */
 
-      rel = (ElfNN_External_Rela *)ia64_info->rel_pltoff_sec->contents;
-      rel += ia64_info->rel_pltoff_sec->reloc_count;
-
-      bfd_elfNN_swap_reloca_out (output_bfd, &outrel, rel + index);
+      loc = ia64_info->rel_pltoff_sec->contents;
+      loc += ((ia64_info->rel_pltoff_sec->reloc_count + index)
+             * sizeof (Elf64_External_Rela));
+      bfd_elfNN_swap_reloca_out (output_bfd, &outrel, loc);
     }
 
   /* Mark some specially defined symbols as absolute.  */
@@ -4156,24 +4523,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
@@ -4219,7 +4568,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;
@@ -4228,7 +4577,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;
@@ -4237,7 +4586,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;
@@ -4246,7 +4595,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;
@@ -4256,7 +4605,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;
@@ -4288,6 +4637,59 @@ elfNN_ia64_print_private_bfd_data (abfd, ptr)
   _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"
@@ -4343,8 +4745,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 \
@@ -4364,6 +4764,8 @@ 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
+#define elf_backend_rela_normal                1
 
 #include "elfNN-target.h"
 
@@ -4387,3 +4789,41 @@ elfNN_ia64_print_private_bfd_data (abfd, ptr)
 #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"
+
+/* We need to undo the AIX specific functions.  */
+
+#undef  elf_backend_add_symbol_hook
+#define elf_backend_add_symbol_hook    elfNN_ia64_add_symbol_hook
+
+#undef  bfd_elfNN_bfd_link_add_symbols
+#define bfd_elfNN_bfd_link_add_symbols _bfd_generic_link_add_symbols
+
+/* These are HP-UX specific functions.  */
+
+#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_backend_want_p_paddr_set_to_zero
+#define elf_backend_want_p_paddr_set_to_zero 1
+
+#undef  ELF_MAXPAGESIZE
+#define ELF_MAXPAGESIZE                 0x1000  /* 1K */
+
+#undef  elfNN_bed
+#define elfNN_bed elfNN_ia64_hpux_bed
+
+#include "elfNN-target.h"
+
+#undef  elf_backend_want_p_paddr_set_to_zero
This page took 0.061553 seconds and 4 git commands to generate.