bfd/
[deliverable/binutils-gdb.git] / bfd / elfxx-ia64.c
index 93741bdc72e00dee233b654ac0c66bd64a7a10d0..917e2c3bbf7f770200e02e7543461f0475cbf2ed 100644 (file)
@@ -1,5 +1,6 @@
 /* IA-64 support for 64-bit ELF
-   Copyright 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+   Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004
+   Free Software Foundation, Inc.
    Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
 
    This file is part of BFD, the Binary File Descriptor library.
@@ -24,6 +25,8 @@
 #include "elf-bfd.h"
 #include "opcode/ia64.h"
 #include "elf/ia64.h"
+#include "objalloc.h"
+#include "hashtab.h"
 
 /* THE RULES for all the stuff the linker creates --
 
@@ -51,7 +54,7 @@
                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.  */
+               does not require dynamic relocations.  */
 
 #define NELEMS(a)      ((int) (sizeof (a) / sizeof ((a)[0])))
 
@@ -79,7 +82,7 @@ struct elfNN_ia64_dyn_sym_info
   bfd_vma dtpmod_offset;
   bfd_vma dtprel_offset;
 
-  /* The symbol table entry, if any, that this was derrived from.  */
+  /* The symbol table entry, if any, that this was derived from.  */
   struct elf_link_hash_entry *h;
 
   /* Used to count non-got, non-plt relocations for delayed sizing
@@ -90,6 +93,9 @@ struct elfNN_ia64_dyn_sym_info
     asection *srel;
     int type;
     int count;
+
+    /* Is this reloc against readonly section? */
+    bfd_boolean reltext;
   } *reloc_entries;
 
   /* TRUE when the section contents have been updated.  */
@@ -102,6 +108,7 @@ struct elfNN_ia64_dyn_sym_info
 
   /* TRUE for the different kinds of linker data we want created.  */
   unsigned want_got : 1;
+  unsigned want_gotx : 1;
   unsigned want_fptr : 1;
   unsigned want_ltoff_fptr : 1;
   unsigned want_plt : 1;
@@ -114,7 +121,8 @@ struct elfNN_ia64_dyn_sym_info
 
 struct elfNN_ia64_local_hash_entry
 {
-  struct bfd_hash_entry root;
+  int id;
+  unsigned int r_sym;
   struct elfNN_ia64_dyn_sym_info *info;
 
   /* TRUE if this hash entry's addends was translated for
@@ -122,12 +130,6 @@ struct elfNN_ia64_local_hash_entry
   unsigned sec_merge_done : 1;
 };
 
-struct elfNN_ia64_local_hash_table
-{
-  struct bfd_hash_table root;
-  /* No additional fields for now.  */
-};
-
 struct elfNN_ia64_link_hash_entry
 {
   struct elf_link_hash_entry root;
@@ -142,14 +144,24 @@ struct elfNN_ia64_link_hash_table
   asection *got_sec;           /* the linkage table section (or NULL) */
   asection *rel_got_sec;       /* dynamic relocation section for same */
   asection *fptr_sec;          /* function descriptor table (or NULL) */
+  asection *rel_fptr_sec;      /* dynamic relocation section for same */
   asection *plt_sec;           /* the primary plt section (or NULL) */
   asection *pltoff_sec;                /* private descriptors for plt (or NULL) */
   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? */
+  unsigned self_dtpmod_done : 1;/* has self DTPMOD entry been finished? */
+  bfd_vma self_dtpmod_offset;  /* .got offset to self DTPMOD entry */
 
-  struct elfNN_ia64_local_hash_table loc_hash_table;
+  htab_t loc_hash_table;
+  void *loc_hash_memory;
+};
+
+struct elfNN_ia64_allocate_data
+{
+  struct bfd_link_info *info;
+  bfd_size_type ofs;
 };
 
 #define elfNN_ia64_hash_table(p) \
@@ -167,59 +179,49 @@ static void elfNN_ia64_info_to_howto
 static bfd_boolean elfNN_ia64_relax_section
   PARAMS((bfd *abfd, asection *sec, struct bfd_link_info *link_info,
          bfd_boolean *again));
+static void elfNN_ia64_relax_ldxmov
+  PARAMS((bfd_byte *contents, bfd_vma off));
 static bfd_boolean is_unwind_section_name
   PARAMS ((bfd *abfd, const char *));
 static bfd_boolean elfNN_ia64_section_from_shdr
   PARAMS ((bfd *, Elf_Internal_Shdr *, const char *));
 static bfd_boolean elfNN_ia64_section_flags
-  PARAMS ((flagword *, Elf_Internal_Shdr *));
+  PARAMS ((flagword *, const Elf_Internal_Shdr *));
 static bfd_boolean elfNN_ia64_fake_sections
   PARAMS ((bfd *abfd, Elf_Internal_Shdr *hdr, asection *sec));
 static void elfNN_ia64_final_write_processing
   PARAMS ((bfd *abfd, bfd_boolean linker));
 static bfd_boolean elfNN_ia64_add_symbol_hook
-  PARAMS ((bfd *abfd, struct bfd_link_info *info, const Elf_Internal_Sym *sym,
+  PARAMS ((bfd *abfd, struct bfd_link_info *info, Elf_Internal_Sym *sym,
           const char **namep, flagword *flagsp, asection **secp,
           bfd_vma *valp));
-static bfd_boolean elfNN_ia64_aix_vec
-  PARAMS ((const bfd_target *vec));
-static bfd_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 bfd_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 bfd_boolean elfNN_ia64_modify_segment_map
-  PARAMS ((bfd *));
+  PARAMS ((bfd *, struct bfd_link_info *));
 static bfd_boolean elfNN_ia64_is_local_label_name
   PARAMS ((bfd *abfd, const char *name));
 static bfd_boolean elfNN_ia64_dynamic_symbol_p
-  PARAMS ((struct elf_link_hash_entry *h, struct bfd_link_info *info));
-static bfd_boolean elfNN_ia64_local_hash_table_init
-  PARAMS ((struct elfNN_ia64_local_hash_table *ht, bfd *abfd,
-          new_hash_entry_func new));
-static struct bfd_hash_entry *elfNN_ia64_new_loc_hash_entry
-  PARAMS ((struct bfd_hash_entry *entry, struct bfd_hash_table *table,
-          const char *string));
+  PARAMS ((struct elf_link_hash_entry *h, struct bfd_link_info *info, int));
 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 *,
+  PARAMS ((const 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 *, bfd_boolean));
+static hashval_t elfNN_ia64_local_htab_hash PARAMS ((const void *));
+static int elfNN_ia64_local_htab_eq PARAMS ((const void *ptr1,
+                                            const void *ptr2));
 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,
-          bfd_boolean create, bfd_boolean copy));
+static void elfNN_ia64_hash_table_free
+  PARAMS ((struct bfd_link_hash_table *hash));
 static bfd_boolean elfNN_ia64_global_dyn_sym_thunk
   PARAMS ((struct bfd_hash_entry *, PTR));
-static bfd_boolean elfNN_ia64_local_dyn_sym_thunk
-  PARAMS ((struct bfd_hash_entry *, PTR));
+static int elfNN_ia64_local_dyn_sym_thunk
+  PARAMS ((void **, PTR));
 static void elfNN_ia64_dyn_sym_traverse
   PARAMS ((struct elfNN_ia64_link_hash_table *ia64_info,
           bfd_boolean (*func) (struct elfNN_ia64_dyn_sym_info *, PTR),
@@ -245,9 +247,6 @@ static asection *get_pltoff
 static asection *get_reloc_section
   PARAMS ((bfd *abfd, struct elfNN_ia64_link_hash_table *ia64_info,
           asection *sec, bfd_boolean create));
-static bfd_boolean count_dyn_reloc
-  PARAMS ((bfd *abfd, struct elfNN_ia64_dyn_sym_info *dyn_i,
-          asection *srel, int type));
 static bfd_boolean elfNN_ia64_check_relocs
   PARAMS ((bfd *abfd, struct bfd_link_info *info, asection *sec,
           const Elf_Internal_Rela *relocs));
@@ -274,7 +273,7 @@ static bfd_boolean allocate_dynrel_entries
 static bfd_boolean elfNN_ia64_size_dynamic_sections
   PARAMS ((bfd *output_bfd, struct bfd_link_info *info));
 static bfd_reloc_status_type elfNN_ia64_install_value
-  PARAMS ((bfd *abfd, bfd_byte *hit_addr, bfd_vma val, unsigned int r_type));
+  PARAMS ((bfd_byte *hit_addr, bfd_vma val, unsigned int r_type));
 static void elfNN_ia64_install_dyn_reloc
   PARAMS ((bfd *abfd, struct bfd_link_info *info, asection *sec,
           asection *srel, bfd_vma offset, unsigned int type,
@@ -297,6 +296,8 @@ 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 bfd_boolean elfNN_ia64_choose_gp
+  PARAMS ((bfd *abfd, struct bfd_link_info *info));
 static bfd_boolean elfNN_ia64_final_link
   PARAMS ((bfd *abfd, struct bfd_link_info *info));
 static bfd_boolean elfNN_ia64_relocate_section
@@ -344,13 +345,17 @@ elfNN_ia64_reloc (abfd, reloc, sym, data, input_section,
       reloc->address += input_section->output_offset;
       return bfd_reloc_ok;
     }
+
+  if (input_section->flags & SEC_DEBUGGING)
+    return bfd_reloc_continue;
+
   *error_message = "Unsupported call to elfNN_ia64_reloc";
   return bfd_reloc_notsupported;
 }
 
 #define IA64_HOWTO(TYPE, NAME, SIZE, PCREL, IN)                        \
   HOWTO (TYPE, 0, SIZE, 0, PCREL, 0, complain_overflow_signed, \
-        elfNN_ia64_reloc, NAME, FALSE, 0, 0, IN)
+        elfNN_ia64_reloc, NAME, FALSE, 0, -1, IN)
 
 /* This table has to be sorted according to increasing number of the
    TYPE field.  */
@@ -436,21 +441,21 @@ static reloc_howto_type ia64_howto_table[] =
     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_TPREL64MSB,  "TPREL64MSB",  4, FALSE, FALSE),
+    IA64_HOWTO (R_IA64_TPREL64LSB,  "TPREL64LSB",  4, 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_DTPMOD64MSB, "TPREL64MSB",  4, FALSE, FALSE),
+    IA64_HOWTO (R_IA64_DTPMOD64LSB, "TPREL64LSB",  4, 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_DTPREL32MSB, "DTPREL32MSB", 2, FALSE, FALSE),
+    IA64_HOWTO (R_IA64_DTPREL32LSB, "DTPREL32LSB", 2, FALSE, FALSE),
+    IA64_HOWTO (R_IA64_DTPREL64MSB, "DTPREL64MSB", 4, FALSE, FALSE),
+    IA64_HOWTO (R_IA64_DTPREL64LSB, "DTPREL64LSB", 4, FALSE, FALSE),
     IA64_HOWTO (R_IA64_LTOFF_DTPREL22, "LTOFF_DTPREL22", 0, FALSE, FALSE),
   };
 
@@ -631,7 +636,7 @@ static const bfd_byte plt_min_entry[PLT_MIN_ENTRY_SIZE] =
 static const bfd_byte plt_full_entry[PLT_FULL_ENTRY_SIZE] =
 {
   0x0b, 0x78, 0x00, 0x02, 0x00, 0x24,  /*   [MMI]       addl r15=0,r1;;    */
-  0x00, 0x41, 0x3c, 0x30, 0x28, 0xc0,  /*               ld8 r16=[r15],8    */
+  0x00, 0x41, 0x3c, 0x70, 0x29, 0xc0,  /*               ld8.acq r16=[r15],8*/
   0x01, 0x08, 0x00, 0x84,              /*               mov r14=r1;;       */
   0x11, 0x08, 0x00, 0x1e, 0x18, 0x10,  /*   [MIB]       ld8 r1=[r15]       */
   0x60, 0x80, 0x04, 0x80, 0x03, 0x00,  /*               mov b6=r16         */
@@ -639,22 +644,14 @@ 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.  */
-#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            */
@@ -667,12 +664,47 @@ 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.
 
-   This is primarily to support branches to targets out of range;
-   relaxation of R_IA64_LTOFF22X and R_IA64_LDXMOV not yet supported.  */
+static size_t oor_branch_size = sizeof (oor_brl);
+
+void
+bfd_elfNN_ia64_after_parse (int itanium)
+{
+  oor_branch_size = itanium ? sizeof (oor_ip) : sizeof (oor_brl);
+}
+
+static void
+elfNN_ia64_relax_brl (bfd_byte *contents, bfd_vma off)
+{
+  int template;
+  bfd_byte *hit_addr;
+  bfd_vma t0, t1, i0, i1, i2;
+
+  hit_addr = (bfd_byte *) (contents + off);
+  hit_addr -= (long) hit_addr & 0x3;
+  t0 = bfd_getl64 (hit_addr);
+  t1 = bfd_getl64 (hit_addr + 8);
+
+  /* Keep the instruction in slot 0. */
+  i0 = (t0 >> 5) & 0x1ffffffffffLL;
+  /* Use nop.b for slot 1. */
+  i1 = 0x4000000000LL;
+  /* For slot 2, turn brl into br by masking out bit 40.  */
+  i2 = (t1 >> 23) & 0x0ffffffffffLL;
+
+  /* Turn a MLX bundle into a MBB bundle with the same stop-bit
+     variety.  */
+  template = 0x12;
+  if ((t0 & 0x1fLL) == 5)
+    template += 1;
+  t0 = (i1 << 46) | (i0 << 5) | template;
+  t1 = (i2 << 23) | (i1 >> 18);
+
+  bfd_putl64 (t0, hit_addr);
+  bfd_putl64 (t1, hit_addr + 8);
+}
+\f
+/* These functions do relaxation for IA-64 ELF.  */
 
 static bfd_boolean
 elfNN_ia64_relax_section (abfd, sec, link_info, again)
@@ -698,25 +730,29 @@ elfNN_ia64_relax_section (abfd, sec, link_info, again)
   struct one_fixup *fixups = NULL;
   bfd_boolean changed_contents = FALSE;
   bfd_boolean changed_relocs = FALSE;
+  bfd_boolean changed_got = FALSE;
+  bfd_vma gp = 0;
 
   /* Assume we're not going to change any sizes, and we'll only need
      one pass.  */
   *again = FALSE;
 
-  /* Nothing to do if there are no relocations.  */
+  /* Don't even try to relax for non-ELF outputs.  */
+  if (!is_elf_hash_table (link_info->hash))
+    return FALSE;
+
+  /* Nothing to do if there are no relocations or there is no need for
+     the relax finalize pass.  */
   if ((sec->flags & SEC_RELOC) == 0
-      || sec->reloc_count == 0)
+      || sec->reloc_count == 0
+      || (!link_info->need_relax_finalize
+         && sec->need_finalize_relax == 0))
     return TRUE;
 
-  /* If this is the first time we have been called for this section,
-     initialize the cooked size.  */
-  if (sec->_cooked_size == 0)
-    sec->_cooked_size = sec->_raw_size;
-
   symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
 
   /* Load the relocations for this section.  */
-  internal_relocs = (_bfd_elfNN_link_read_relocs
+  internal_relocs = (_bfd_elf_link_read_relocs
                     (abfd, sec, (PTR) NULL, (Elf_Internal_Rela *) NULL,
                      link_info->keep_memory));
   if (internal_relocs == NULL)
@@ -725,45 +761,67 @@ elfNN_ia64_relax_section (abfd, sec, link_info, again)
   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
-       || 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 (elf_section_data (sec)->relocs != internal_relocs)
-       free (internal_relocs);
-      return TRUE;
-    }
-
   /* Get the section contents.  */
   if (elf_section_data (sec)->this_hdr.contents != NULL)
     contents = elf_section_data (sec)->this_hdr.contents;
   else
     {
-      contents = (bfd_byte *) bfd_malloc (sec->_raw_size);
-      if (contents == NULL)
-       goto error_return;
-
-      if (! bfd_get_section_contents (abfd, sec, contents,
-                                     (file_ptr) 0, sec->_raw_size))
+      if (!bfd_malloc_and_get_section (abfd, sec, &contents))
        goto error_return;
     }
 
-  for (; irel < irelend; irel++)
+  for (irel = internal_relocs; irel < irelend; irel++)
     {
+      unsigned long r_type = ELFNN_R_TYPE (irel->r_info);
       bfd_vma symaddr, reladdr, trampoff, toff, roff;
       asection *tsec;
       struct one_fixup *f;
       bfd_size_type amt;
+      bfd_boolean is_branch;
+      struct elfNN_ia64_dyn_sym_info *dyn_i;
+      char symtype;
 
-      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;
+      switch (r_type)
+       {
+       case R_IA64_PCREL21B:
+       case R_IA64_PCREL21BI:
+       case R_IA64_PCREL21M:
+       case R_IA64_PCREL21F:
+         /* In the finalize pass, all br relaxations are done. We can
+            skip it. */
+         if (!link_info->need_relax_finalize)
+           continue;
+         is_branch = TRUE;
+         break;
+
+       case R_IA64_PCREL60B:
+         /* We can't optimize brl to br before the finalize pass since
+            br relaxations will increase the code size. Defer it to
+            the finalize pass.  */
+         if (link_info->need_relax_finalize)
+           {
+             sec->need_finalize_relax = 1;
+             continue;
+           }
+         is_branch = TRUE;
+         break;
+
+       case R_IA64_LTOFF22X:
+       case R_IA64_LDXMOV:
+         /* We can't relax ldx/mov before the finalize pass since
+            br relaxations will increase the code size. Defer it to
+            the finalize pass.  */
+         if (link_info->need_relax_finalize)
+           {
+             sec->need_finalize_relax = 1;
+             continue;
+           }
+         is_branch = FALSE;
+         break;
+
+       default:
+         continue;
+       }
 
       /* Get the value of the symbol referred to by the reloc.  */
       if (ELFNN_R_SYM (irel->r_info) < symtab_hdr->sh_info)
@@ -783,9 +841,9 @@ elfNN_ia64_relax_section (abfd, sec, link_info, again)
                goto error_return;
            }
 
-         isym = isymbuf + ELF64_R_SYM (irel->r_info);
+         isym = isymbuf + ELFNN_R_SYM (irel->r_info);
          if (isym->st_shndx == SHN_UNDEF)
-           continue;   /* We can't do anthing with undefined symbols.  */
+           continue;   /* We can't do anything with undefined symbols.  */
          else if (isym->st_shndx == SHN_ABS)
            tsec = bfd_abs_section_ptr;
          else if (isym->st_shndx == SHN_COMMON)
@@ -796,12 +854,13 @@ elfNN_ia64_relax_section (abfd, sec, link_info, again)
            tsec = bfd_section_from_elf_index (abfd, isym->st_shndx);
 
          toff = isym->st_value;
+         dyn_i = get_dyn_sym_info (ia64_info, NULL, abfd, irel, FALSE);
+         symtype = ELF_ST_TYPE (isym->st_info);
        }
       else
        {
          unsigned long indx;
          struct elf_link_hash_entry *h;
-          struct elfNN_ia64_dyn_sym_info *dyn_i;
 
          indx = ELFNN_R_SYM (irel->r_info) - symtab_hdr->sh_info;
          h = elf_sym_hashes (abfd)[indx];
@@ -815,14 +874,25 @@ elfNN_ia64_relax_section (abfd, sec, link_info, again)
 
          /* For branches to dynamic symbols, we're interested instead
             in a branch to the PLT entry.  */
-         if (dyn_i && dyn_i->want_plt2)
+         if (is_branch && dyn_i && dyn_i->want_plt2)
            {
+             /* Internal branches shouldn't be sent to the PLT.
+                Leave this for now and we'll give an error later.  */
+             if (r_type != R_IA64_PCREL21B)
+               continue;
+
              tsec = ia64_info->plt_sec;
              toff = dyn_i->plt2_offset;
+             BFD_ASSERT (irel->r_addend == 0);
            }
+
+         /* Can't do anything else with dynamic symbols.  */
+         else if (elfNN_ia64_dynamic_symbol_p (h, link_info, r_type))
+           continue;
+
          else
            {
-             /* We can't do anthing with undefined symbols.  */
+             /* We can't do anything with undefined symbols.  */
              if (h->root.type == bfd_link_hash_undefined
                  || h->root.type == bfd_link_hash_undefweak)
                continue;
@@ -830,111 +900,232 @@ elfNN_ia64_relax_section (abfd, sec, link_info, again)
              tsec = h->root.u.def.section;
              toff = h->root.u.def.value;
            }
+
+         symtype = h->type;
        }
 
-      symaddr = (tsec->output_section->vma
-                + tsec->output_offset
-                + toff
-                + irel->r_addend);
+      if (tsec->sec_info_type == ELF_INFO_TYPE_MERGE)
+       {
+         /* At this stage in linking, no SEC_MERGE symbol has been
+            adjusted, so all references to such symbols need to be
+            passed through _bfd_merged_section_offset.  (Later, in
+            relocate_section, all SEC_MERGE symbols *except* for
+            section symbols have been adjusted.)
+
+            gas may reduce relocations against symbols in SEC_MERGE
+            sections to a relocation against the section symbol when
+            the original addend was zero.  When the reloc is against
+            a section symbol we should include the addend in the
+            offset passed to _bfd_merged_section_offset, since the
+            location of interest is the original symbol.  On the
+            other hand, an access to "sym+addend" where "sym" is not
+            a section symbol should not include the addend;  Such an
+            access is presumed to be an offset from "sym";  The
+            location of interest is just "sym".  */
+          if (symtype == STT_SECTION)
+            toff += irel->r_addend;
+
+          toff = _bfd_merged_section_offset (abfd, &tsec,
+                                             elf_section_data (tsec)->sec_info,
+                                             toff);
+
+          if (symtype != STT_SECTION)
+            toff += irel->r_addend;
+       }
+      else
+       toff += irel->r_addend;
+
+      symaddr = tsec->output_section->vma + tsec->output_offset + toff;
 
       roff = irel->r_offset;
-      reladdr = (sec->output_section->vma
-                + sec->output_offset
-                + roff) & (bfd_vma) -4;
 
-      /* If the branch is in range, no need to do anything.  */
-      if ((bfd_signed_vma) (symaddr - reladdr) >= -0x1000000
-         && (bfd_signed_vma) (symaddr - reladdr) <= 0x0FFFFF0)
-       continue;
+      if (is_branch)
+       {
+         bfd_signed_vma offset;
 
-      /* If the branch and target are in the same section, you've
-        got one honking big section and we can't help you.  You'll
-        get an error message later.  */
-      if (tsec == sec)
-       continue;
+         reladdr = (sec->output_section->vma
+                    + sec->output_offset
+                    + roff) & (bfd_vma) -4;
 
-      /* Look for an existing fixup to this address.  */
-      for (f = fixups; f ; f = f->next)
-       if (f->tsec == tsec && f->toff == toff)
-         break;
+         /* If the branch is in range, no need to do anything.  */
+         if ((bfd_signed_vma) (symaddr - reladdr) >= -0x1000000
+             && (bfd_signed_vma) (symaddr - reladdr) <= 0x0FFFFF0)
+           {
+             /* If the 60-bit branch is in 21-bit range, optimize it. */
+             if (r_type == R_IA64_PCREL60B)
+               {
+                 elfNN_ia64_relax_brl (contents, roff);
 
-      if (f == NULL)
-       {
-         /* Two alternatives: If it's a branch to a PLT entry, we can
-            make a copy of the FULL_PLT entry.  Otherwise, we'll have
-            to use a `brl' insn to get where we're going.  */
+                 irel->r_info
+                   = ELF64_R_INFO (ELF64_R_SYM (irel->r_info),
+                                   R_IA64_PCREL21B);
 
-         size_t size;
+                 /* If the original relocation offset points to slot
+                    1, change it to slot 2.  */
+                 if ((irel->r_offset & 3) == 1)
+                   irel->r_offset += 1;
+               }
 
-         if (tsec == ia64_info->plt_sec)
-           size = sizeof (plt_full_entry);
-         else
+             continue;
+           }
+         else if (r_type == R_IA64_PCREL60B)
+           continue;
+
+         /* We can't put a trampoline in a .init/.fini section. Issue
+            an error.  */
+         if (strcmp (sec->output_section->name, ".init") == 0
+             || strcmp (sec->output_section->name, ".fini") == 0)
            {
-#ifdef USE_BRL
-             size = sizeof (oor_brl);
-#else
-             size = sizeof (oor_ip);
-#endif
+             (*_bfd_error_handler)
+               (_("%B: Can't relax br at 0x%lx in section `%A'. Please use brl or indirect branch."),
+                sec->owner, sec, (unsigned long) roff);
+             bfd_set_error (bfd_error_bad_value);
+             goto error_return;
            }
 
-         /* Resize the current section to make room for the new branch.  */
-         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 = amt;
+         /* If the branch and target are in the same section, you've
+            got one honking big section and we can't help you.  You'll
+            get an error message later.  */
+         if (tsec == sec)
+           continue;
 
-         if (tsec == ia64_info->plt_sec)
+         /* Look for an existing fixup to this address.  */
+         for (f = fixups; f ; f = f->next)
+           if (f->tsec == tsec && f->toff == toff)
+             break;
+
+         if (f == NULL)
            {
-             memcpy (contents + trampoff, plt_full_entry, size);
+             /* Two alternatives: If it's a branch to a PLT entry, we can
+                make a copy of the FULL_PLT entry.  Otherwise, we'll have
+                to use a `brl' insn to get where we're going.  */
 
-             /* Hijack the old relocation for use as the PLTOFF reloc.  */
-             irel->r_info = ELFNN_R_INFO (ELFNN_R_SYM (irel->r_info),
-                                          R_IA64_PLTOFF22);
-             irel->r_offset = trampoff;
+             size_t size;
+
+             if (tsec == ia64_info->plt_sec)
+               size = sizeof (plt_full_entry);
+             else
+               size = oor_branch_size;
+
+             /* Resize the current section to make room for the new branch. */
+             trampoff = (sec->size + 15) & (bfd_vma) -16;
+
+             /* If trampoline is out of range, there is nothing we
+                can do.  */
+             offset = trampoff - (roff & (bfd_vma) -4);
+             if (offset < -0x1000000 || offset > 0x0FFFFF0)
+               continue;
+
+             amt = trampoff + size;
+             contents = (bfd_byte *) bfd_realloc (contents, amt);
+             if (contents == NULL)
+               goto error_return;
+             sec->size = amt;
+
+             if (tsec == ia64_info->plt_sec)
+               {
+                 memcpy (contents + trampoff, plt_full_entry, size);
+
+                 /* Hijack the old relocation for use as the PLTOFF reloc.  */
+                 irel->r_info = ELFNN_R_INFO (ELFNN_R_SYM (irel->r_info),
+                                              R_IA64_PLTOFF22);
+                 irel->r_offset = trampoff;
+               }
+             else
+               {
+                 if (size == sizeof (oor_ip))
+                   {
+                     memcpy (contents + trampoff, oor_ip, size);
+                     irel->r_info = ELFNN_R_INFO (ELFNN_R_SYM (irel->r_info),
+                                                  R_IA64_PCREL64I);
+                     irel->r_addend -= 16;
+                     irel->r_offset = trampoff + 2;
+                   }
+                 else
+                   {
+                     memcpy (contents + trampoff, oor_brl, size);
+                     irel->r_info = ELFNN_R_INFO (ELFNN_R_SYM (irel->r_info),
+                                                  R_IA64_PCREL60B);
+                     irel->r_offset = trampoff + 2;
+                   }
+
+               }
+
+             /* Record the fixup so we don't do it again this section.  */
+             f = (struct one_fixup *)
+               bfd_malloc ((bfd_size_type) sizeof (*f));
+             f->next = fixups;
+             f->tsec = tsec;
+             f->toff = toff;
+             f->trampoff = trampoff;
+             fixups = f;
            }
          else
            {
-#ifdef USE_BRL
-             memcpy (contents + trampoff, oor_brl, size);
-             irel->r_info = ELFNN_R_INFO (ELFNN_R_SYM (irel->r_info),
-                                          R_IA64_PCREL60B);
-             irel->r_offset = trampoff + 2;
-#else
-             memcpy (contents + trampoff, oor_ip, size);
-             irel->r_info = ELFNN_R_INFO (ELFNN_R_SYM (irel->r_info),
-                                          R_IA64_PCREL64I);
-             irel->r_addend -= 16;
-             irel->r_offset = trampoff + 2;
-#endif
+             /* If trampoline is out of range, there is nothing we
+                can do.  */
+             offset = f->trampoff - (roff & (bfd_vma) -4);
+             if (offset < -0x1000000 || offset > 0x0FFFFF0)
+               continue;
+
+             /* Nop out the reloc, since we're finalizing things here.  */
+             irel->r_info = ELFNN_R_INFO (0, R_IA64_NONE);
            }
 
-         /* Record the fixup so we don't do it again this section.  */
-         f = (struct one_fixup *) bfd_malloc ((bfd_size_type) sizeof (*f));
-         f->next = fixups;
-         f->tsec = tsec;
-         f->toff = toff;
-         f->trampoff = trampoff;
-         fixups = f;
+         /* Fix up the existing branch to hit the trampoline.  */
+         if (elfNN_ia64_install_value (contents + roff, offset, r_type)
+             != bfd_reloc_ok)
+           goto error_return;
+
+         changed_contents = TRUE;
+         changed_relocs = TRUE;
        }
       else
        {
-         /* Nop out the reloc, since we're finalizing things here.  */
-         irel->r_info = ELFNN_R_INFO (0, R_IA64_NONE);
-       }
+         /* Fetch the gp.  */
+         if (gp == 0)
+           {
+             bfd *obfd = sec->output_section->owner;
+             gp = _bfd_get_gp_value (obfd);
+             if (gp == 0)
+               {
+                 if (!elfNN_ia64_choose_gp (obfd, link_info))
+                   goto error_return;
+                 gp = _bfd_get_gp_value (obfd);
+               }
+           }
 
-      /* 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 & (bfd_vma) -4),
-                                   R_IA64_PCREL21B) != bfd_reloc_ok)
-       goto error_return;
+         /* If the data is out of range, do nothing.  */
+         if ((bfd_signed_vma) (symaddr - gp) >= 0x200000
+             ||(bfd_signed_vma) (symaddr - gp) < -0x200000)
+           continue;
 
-      changed_contents = TRUE;
-      changed_relocs = TRUE;
+         if (r_type == R_IA64_LTOFF22X)
+           {
+             irel->r_info = ELFNN_R_INFO (ELFNN_R_SYM (irel->r_info),
+                                          R_IA64_GPREL22);
+             changed_relocs = TRUE;
+             if (dyn_i->want_gotx)
+               {
+                 dyn_i->want_gotx = 0;
+                 changed_got |= !dyn_i->want_got;
+               }
+           }
+         else
+           {
+             elfNN_ia64_relax_ldxmov (contents, roff);
+             irel->r_info = ELFNN_R_INFO (0, R_IA64_NONE);
+             changed_contents = TRUE;
+             changed_relocs = TRUE;
+           }
+       }
     }
 
+  /* ??? If we created fixups, this may push the code segment large
+     enough that the data segment moves, which will change the GP.
+     Reset the GP so that we re-calculate next round.  We need to
+     do this at the _beginning_ of the next round; now will not do.  */
+
   /* Clean up and go home.  */
   while (fixups)
     {
@@ -975,6 +1166,24 @@ elfNN_ia64_relax_section (abfd, sec, link_info, again)
        elf_section_data (sec)->relocs = internal_relocs;
     }
 
+  if (changed_got)
+    {
+      struct elfNN_ia64_allocate_data data;
+      data.info = link_info;
+      data.ofs = 0;
+      ia64_info->self_dtpmod_offset = (bfd_vma) -1;
+
+      elfNN_ia64_dyn_sym_traverse (ia64_info, allocate_global_data_got, &data);
+      elfNN_ia64_dyn_sym_traverse (ia64_info, allocate_global_fptr_got, &data);
+      elfNN_ia64_dyn_sym_traverse (ia64_info, allocate_local_got, &data);
+      ia64_info->got_sec->size = data.ofs;
+
+      /* ??? Resize .rela.got too.  */
+    }
+
+  if (!link_info->need_relax_finalize)
+    sec->need_finalize_relax = 0;
+
   *again = changed_contents || changed_relocs;
   return TRUE;
 
@@ -989,6 +1198,38 @@ elfNN_ia64_relax_section (abfd, sec, link_info, again)
     free (internal_relocs);
   return FALSE;
 }
+
+static void
+elfNN_ia64_relax_ldxmov (contents, off)
+     bfd_byte *contents;
+     bfd_vma off;
+{
+  int shift, r1, r3;
+  bfd_vma dword, insn;
+
+  switch ((int)off & 0x3)
+    {
+    case 0: shift =  5; break;
+    case 1: shift = 14; off += 3; break;
+    case 2: shift = 23; off += 6; break;
+    default:
+      abort ();
+    }
+
+  dword = bfd_getl64 (contents + off);
+  insn = (dword >> shift) & 0x1ffffffffffLL;
+
+  r1 = (insn >> 6) & 127;
+  r3 = (insn >> 20) & 127;
+  if (r1 == r3)
+    insn = 0x8000000;                             /* nop */
+  else
+    insn = (insn & 0x7f01fff) | 0x10800000000LL;   /* (qp) mov r1 = r3 */
+
+  dword &= ~(0x1ffffffffffLL << shift);
+  dword |= (insn << shift);
+  bfd_putl64 (dword, contents + off);
+}
 \f
 /* Return TRUE if NAME is an unwind table section name.  */
 
@@ -1057,7 +1298,7 @@ elfNN_ia64_section_from_shdr (abfd, hdr, name)
 static bfd_boolean
 elfNN_ia64_section_flags (flags, hdr)
      flagword *flags;
-     Elf_Internal_Shdr *hdr;
+     const Elf_Internal_Shdr *hdr;
 {
   if (hdr->sh_flags & SHF_IA_64_SHORT)
     *flags |= SEC_SMALL_DATA;
@@ -1123,9 +1364,7 @@ elfNN_ia64_final_write_processing (abfd, linker)
      bfd_boolean linker ATTRIBUTE_UNUSED;
 {
   Elf_Internal_Shdr *hdr;
-  const char *sname;
-  asection *text_sect, *s;
-  size_t len;
+  asection *s;
 
   for (s = abfd->sections; s; s = s->next)
     {
@@ -1133,64 +1372,11 @@ elfNN_ia64_final_write_processing (abfd, linker)
       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;
-           }
+         /* 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_info = hdr->sh_link;
          break;
        }
     }
@@ -1216,14 +1402,14 @@ static bfd_boolean
 elfNN_ia64_add_symbol_hook (abfd, info, sym, namep, flagsp, secp, valp)
      bfd *abfd;
      struct bfd_link_info *info;
-     const Elf_Internal_Sym *sym;
+     Elf_Internal_Sym *sym;
      const char **namep ATTRIBUTE_UNUSED;
      flagword *flagsp ATTRIBUTE_UNUSED;
      asection **secp;
      bfd_vma *valp;
 {
   if (sym->st_shndx == SHN_COMMON
-      && !info->relocateable
+      && !info->relocatable
       && sym->st_size <= elf_gp_size (abfd))
     {
       /* Common symbols less than or equal to -G nn bytes are
@@ -1248,114 +1434,6 @@ elfNN_ia64_add_symbol_hook (abfd, info, sym, namep, flagsp, secp, valp)
   return TRUE;
 }
 
-static bfd_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 bfd_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;
-         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,
-                bfd_get_section_by_name (abfd, ".bss"),
-                bed->got_symbol_offset, (const char *) NULL, FALSE,
-                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 (! _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);
-    }
-}
-
-bfd_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
@@ -1379,8 +1457,9 @@ elfNN_ia64_additional_program_headers (abfd)
 }
 
 static bfd_boolean
-elfNN_ia64_modify_segment_map (abfd)
+elfNN_ia64_modify_segment_map (abfd, info)
      bfd *abfd;
+     struct bfd_link_info *info ATTRIBUTE_UNUSED;
 {
   struct elf_segment_map *m, **pm;
   Elf_Internal_Shdr *hdr;
@@ -1508,79 +1587,18 @@ elfNN_ia64_is_local_label_name (abfd, name)
 /* Should we do dynamic things to this symbol?  */
 
 static bfd_boolean
-elfNN_ia64_dynamic_symbol_p (h, info)
+elfNN_ia64_dynamic_symbol_p (h, info, r_type)
      struct elf_link_hash_entry *h;
      struct bfd_link_info *info;
+     int r_type;
 {
-  if (h == NULL)
-    return FALSE;
-
-  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;
+  bfd_boolean ignore_protected
+    = ((r_type & 0xf8) == 0x40         /* FPTR relocs */
+       || (r_type & 0xf8) == 0x50);    /* LTOFF_FPTR relocs */
 
-  if (h->dynindx == -1)
-    return FALSE;
-  switch (ELF_ST_VISIBILITY (h->other))
-    {
-    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 || 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)))
-    return TRUE;
-
-  return FALSE;
+  return _bfd_elf_dynamic_symbol_p (h, info, ignore_protected);
 }
 \f
-static bfd_boolean
-elfNN_ia64_local_hash_table_init (ht, abfd, new)
-     struct elfNN_ia64_local_hash_table *ht;
-     bfd *abfd ATTRIBUTE_UNUSED;
-     new_hash_entry_func new;
-{
-  memset (ht, 0, sizeof (*ht));
-  return bfd_hash_table_init (&ht->root, new);
-}
-
-static struct bfd_hash_entry*
-elfNN_ia64_new_loc_hash_entry (entry, table, string)
-     struct bfd_hash_entry *entry;
-     struct bfd_hash_table *table;
-     const char *string;
-{
-  struct elfNN_ia64_local_hash_entry *ret;
-  ret = (struct elfNN_ia64_local_hash_entry *) entry;
-
-  /* Allocate the structure if it has not already been allocated by a
-     subclass.  */
-  if (!ret)
-    ret = bfd_hash_allocate (table, sizeof (*ret));
-
-  if (!ret)
-    return 0;
-
-  /* Initialize our local data.  All zeros, and definitely easier
-     than setting a handful of bit fields.  */
-  memset (ret, 0, sizeof (*ret));
-
-  /* Call the allocation method of the superclass.  */
-  ret = ((struct elfNN_ia64_local_hash_entry *)
-        bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string));
-
-  return (struct bfd_hash_entry *) ret;
-}
-
 static struct bfd_hash_entry*
 elfNN_ia64_new_elf_hash_entry (entry, table, string)
      struct bfd_hash_entry *entry;
@@ -1612,7 +1630,7 @@ elfNN_ia64_new_elf_hash_entry (entry, table, string)
 
 static void
 elfNN_ia64_hash_copy_indirect (bed, xdir, xind)
-     struct elf_backend_data *bed ATTRIBUTE_UNUSED;
+     const struct elf_backend_data *bed ATTRIBUTE_UNUSED;
      struct elf_link_hash_entry *xdir, *xind;
 {
   struct elfNN_ia64_link_hash_entry *dir, *ind;
@@ -1623,11 +1641,10 @@ elfNN_ia64_hash_copy_indirect (bed, xdir, xind)
   /* Copy down any references that we may have already seen to the
      symbol which just became indirect.  */
 
-  dir->root.elf_link_hash_flags |=
-    (ind->root.elf_link_hash_flags
-     & (ELF_LINK_HASH_REF_DYNAMIC
-        | ELF_LINK_HASH_REF_REGULAR
-        | ELF_LINK_HASH_REF_REGULAR_NONWEAK));
+  dir->root.ref_dynamic |= ind->root.ref_dynamic;
+  dir->root.ref_regular |= ind->root.ref_regular;
+  dir->root.ref_regular_nonweak |= ind->root.ref_regular_nonweak;
+  dir->root.needs_plt |= ind->root.needs_plt;
 
   if (ind->root.root.type != bfd_link_hash_indirect)
     return;
@@ -1674,7 +1691,37 @@ elfNN_ia64_hash_hide_symbol (info, xh, force_local)
   _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;
+    {
+      dyn_i->want_plt2 = 0;
+      dyn_i->want_plt = 0;
+    }
+}
+
+/* Compute a hash of a local hash entry.  */
+
+static hashval_t
+elfNN_ia64_local_htab_hash (ptr)
+     const void *ptr;
+{
+  struct elfNN_ia64_local_hash_entry *entry
+    = (struct elfNN_ia64_local_hash_entry *) ptr;
+
+  return (((entry->id & 0xff) << 24) | ((entry->id & 0xff00) << 8))
+         ^ entry->r_sym ^ (entry->id >> 16);
+}
+
+/* Compare local hash entries.  */
+
+static int
+elfNN_ia64_local_htab_eq (ptr1, ptr2)
+     const void *ptr1, *ptr2;
+{
+  struct elfNN_ia64_local_hash_entry *entry1
+    = (struct elfNN_ia64_local_hash_entry *) ptr1;
+  struct elfNN_ia64_local_hash_entry *entry2
+    = (struct elfNN_ia64_local_hash_entry *) ptr2;
+
+  return entry1->id == entry2->id && entry1->r_sym == entry2->r_sym;
 }
 
 /* Create the derived linker hash table.  The IA-64 ELF port uses this
@@ -1687,32 +1734,42 @@ elfNN_ia64_hash_table_create (abfd)
 {
   struct elfNN_ia64_link_hash_table *ret;
 
-  ret = bfd_zalloc (abfd, (bfd_size_type) sizeof (*ret));
+  ret = bfd_zmalloc ((bfd_size_type) sizeof (*ret));
   if (!ret)
     return 0;
+
   if (!_bfd_elf_link_hash_table_init (&ret->root, abfd,
                                      elfNN_ia64_new_elf_hash_entry))
     {
-      bfd_release (abfd, ret);
+      free (ret);
+      return 0;
+    }
+
+  ret->loc_hash_table = htab_try_create (1024, elfNN_ia64_local_htab_hash,
+                                        elfNN_ia64_local_htab_eq, NULL);
+  ret->loc_hash_memory = objalloc_create ();
+  if (!ret->loc_hash_table || !ret->loc_hash_memory)
+    {
+      free (ret);
       return 0;
     }
 
-  if (!elfNN_ia64_local_hash_table_init (&ret->loc_hash_table, abfd,
-                                        elfNN_ia64_new_loc_hash_entry))
-    return 0;
   return &ret->root.root;
 }
 
-/* Look up an entry in a Alpha ELF linker hash table.  */
+/* Destroy IA-64 linker hash table.  */
 
-static INLINE struct elfNN_ia64_local_hash_entry *
-elfNN_ia64_local_hash_lookup(table, string, create, copy)
-     struct elfNN_ia64_local_hash_table *table;
-     const char *string;
-     bfd_boolean create, copy;
+static void
+elfNN_ia64_hash_table_free (hash)
+     struct bfd_link_hash_table *hash;
 {
-  return ((struct elfNN_ia64_local_hash_entry *)
-         bfd_hash_lookup (&table->root, string, create, copy));
+  struct elfNN_ia64_link_hash_table *ia64_info
+    = (struct elfNN_ia64_link_hash_table *) hash;
+  if (ia64_info->loc_hash_table)
+    htab_delete (ia64_info->loc_hash_table);
+  if (ia64_info->loc_hash_memory)
+    objalloc_free ((struct objalloc *) ia64_info->loc_hash_memory);
+  _bfd_generic_link_hash_table_free (hash);
 }
 
 /* Traverse both local and global hash tables.  */
@@ -1744,20 +1801,20 @@ elfNN_ia64_global_dyn_sym_thunk (xentry, xdata)
 }
 
 static bfd_boolean
-elfNN_ia64_local_dyn_sym_thunk (xentry, xdata)
-     struct bfd_hash_entry *xentry;
+elfNN_ia64_local_dyn_sym_thunk (slot, xdata)
+     void **slot;
      PTR xdata;
 {
   struct elfNN_ia64_local_hash_entry *entry
-    = (struct elfNN_ia64_local_hash_entry *) xentry;
+    = (struct elfNN_ia64_local_hash_entry *) *slot;
   struct elfNN_ia64_dyn_sym_traverse_data *data
     = (struct elfNN_ia64_dyn_sym_traverse_data *) xdata;
   struct elfNN_ia64_dyn_sym_info *dyn_i;
 
   for (dyn_i = entry->info; dyn_i; dyn_i = dyn_i->next)
     if (! (*data->func) (dyn_i, data->data))
-      return FALSE;
-  return TRUE;
+      return 0;
+  return 1;
 }
 
 static void
@@ -1773,8 +1830,8 @@ elfNN_ia64_dyn_sym_traverse (ia64_info, func, data)
 
   elf_link_hash_traverse (&ia64_info->root,
                          elfNN_ia64_global_dyn_sym_thunk, &xdata);
-  bfd_hash_traverse (&ia64_info->loc_hash_table.root,
-                    elfNN_ia64_local_dyn_sym_thunk, &xdata);
+  htab_traverse (ia64_info->loc_hash_table,
+                elfNN_ia64_local_dyn_sym_thunk, &xdata);
 }
 \f
 static bfd_boolean
@@ -1796,6 +1853,8 @@ elfNN_ia64_create_dynamic_sections (abfd, info)
   {
     flagword flags = bfd_get_section_flags (abfd, ia64_info->got_sec);
     bfd_set_section_flags (abfd, ia64_info->got_sec, SEC_SMALL_DATA | flags);
+    /* The .got section is always aligned at 8 bytes.  */
+    bfd_set_section_alignment (abfd, ia64_info->got_sec, 3);
   }
 
   if (!get_pltoff (abfd, info, ia64_info))
@@ -1834,26 +1893,33 @@ get_local_sym_hash (ia64_info, abfd, rel, create)
      const Elf_Internal_Rela *rel;
      bfd_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 */
+  struct elfNN_ia64_local_hash_entry e, *ret;
+  asection *sec = abfd->sections;
+  hashval_t h = (((sec->id & 0xff) << 24) | ((sec->id & 0xff00) << 8))
+               ^ ELFNN_R_SYM (rel->r_info) ^ (sec->id >> 16);
+  void **slot;
+
+  e.id = sec->id;
+  e.r_sym = ELFNN_R_SYM (rel->r_info);
+  slot = htab_find_slot_with_hash (ia64_info->loc_hash_table, &e, h,
+                                  create ? INSERT : NO_INSERT);
+
+  if (!slot)
+    return NULL;
 
-  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));
+  if (*slot)
+    return (struct elfNN_ia64_local_hash_entry *) *slot;
 
-  /* 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);
+  ret = (struct elfNN_ia64_local_hash_entry *)
+       objalloc_alloc ((struct objalloc *) ia64_info->loc_hash_memory,
+                       sizeof (struct elfNN_ia64_local_hash_entry));
+  if (ret)
+    {
+      memset (ret, 0, sizeof (*ret));
+      ret->id = sec->id;
+      ret->r_sym = ELFNN_R_SYM (rel->r_info);
+      *slot = ret;
+    }
   return ret;
 }
 
@@ -1879,7 +1945,11 @@ get_dyn_sym_info (ia64_info, h, abfd, rel, create)
       struct elfNN_ia64_local_hash_entry *loc_h;
 
       loc_h = get_local_sym_hash (ia64_info, abfd, rel, create);
-      BFD_ASSERT (loc_h);
+      if (!loc_h)
+       {
+         BFD_ASSERT (!create);
+         return NULL;
+       }
 
       pp = &loc_h->info;
     }
@@ -1922,6 +1992,10 @@ get_got (abfd, info, ia64_info)
       BFD_ASSERT (got);
       ia64_info->got_sec = got;
 
+      /* The .got section is always aligned at 8 bytes.  */
+      if (!bfd_set_section_alignment (abfd, got, 3))
+       return 0;
+
       flags = bfd_get_section_flags (abfd, got);
       bfd_set_section_flags (abfd, got, SEC_SMALL_DATA | flags);
     }
@@ -1930,14 +2004,14 @@ get_got (abfd, info, ia64_info)
 }
 
 /* Create function descriptor section (.opd).  This section is called .opd
-   because it contains "official prodecure descriptors".  The "official"
+   because it contains "official procedure descriptors".  The "official"
    refers to the fact that these descriptors are used when taking the address
    of a procedure, thus ensuring a unique address for each procedure.  */
 
 static asection *
 get_fptr (abfd, info, ia64_info)
      bfd *abfd;
-     struct bfd_link_info *info ATTRIBUTE_UNUSED;
+     struct bfd_link_info *info;
      struct elfNN_ia64_link_hash_table *ia64_info;
 {
   asection *fptr;
@@ -1957,7 +2031,7 @@ get_fptr (abfd, info, ia64_info)
                                      | SEC_LOAD
                                      | SEC_HAS_CONTENTS
                                      | SEC_IN_MEMORY
-                                     | SEC_READONLY
+                                     | (info->pie ? 0 : SEC_READONLY)
                                      | SEC_LINKER_CREATED))
          || !bfd_set_section_alignment (abfd, fptr, 4))
        {
@@ -1966,6 +2040,26 @@ get_fptr (abfd, info, ia64_info)
        }
 
       ia64_info->fptr_sec = fptr;
+
+      if (info->pie)
+       {
+         asection *fptr_rel;
+         fptr_rel = bfd_make_section(dynobj, ".rela.opd");
+         if (fptr_rel == NULL
+             || !bfd_set_section_flags (dynobj, fptr_rel,
+                                        (SEC_ALLOC | SEC_LOAD
+                                         | SEC_HAS_CONTENTS
+                                         | SEC_IN_MEMORY
+                                         | SEC_LINKER_CREATED
+                                         | SEC_READONLY))
+             || !bfd_set_section_alignment (abfd, fptr_rel, 3))
+           {
+             BFD_ASSERT (0);
+             return NULL;
+           }
+
+         ia64_info->rel_fptr_sec = fptr_rel;
+       }
     }
 
   return fptr;
@@ -2052,18 +2146,12 @@ get_reloc_section (abfd, ia64_info, sec, create)
        return NULL;
     }
 
-  if (sec->flags & SEC_READONLY)
-    ia64_info->reltext = 1;
-
   return srel;
 }
 
 static bfd_boolean
-count_dyn_reloc (abfd, dyn_i, srel, type)
-     bfd *abfd;
-     struct elfNN_ia64_dyn_sym_info *dyn_i;
-     asection *srel;
-     int type;
+count_dyn_reloc (bfd *abfd, struct elfNN_ia64_dyn_sym_info *dyn_i,
+                asection *srel, int type, bfd_boolean reltext)
 {
   struct elfNN_ia64_dyn_reloc_entry *rent;
 
@@ -2084,6 +2172,7 @@ count_dyn_reloc (abfd, dyn_i, srel, type)
       rent->count = 0;
       dyn_i->reloc_entries = rent;
     }
+  rent->reltext = reltext;
   rent->count++;
 
   return TRUE;
@@ -2100,30 +2189,31 @@ elfNN_ia64_check_relocs (abfd, info, sec, relocs)
   const Elf_Internal_Rela *relend;
   Elf_Internal_Shdr *symtab_hdr;
   const Elf_Internal_Rela *rel;
-  asection *got, *fptr, *srel;
+  asection *got, *fptr, *srel, *pltoff;
 
-  if (info->relocateable)
+  if (info->relocatable)
     return TRUE;
 
   symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
   ia64_info = elfNN_ia64_hash_table (info);
 
-  got = fptr = srel = NULL;
+  got = fptr = srel = pltoff = NULL;
 
   relend = relocs + sec->reloc_count;
   for (rel = relocs; rel < relend; ++rel)
     {
       enum {
        NEED_GOT = 1,
-       NEED_FPTR = 2,
-       NEED_PLTOFF = 4,
-       NEED_MIN_PLT = 8,
-       NEED_FULL_PLT = 16,
-       NEED_DYNREL = 32,
-       NEED_LTOFF_FPTR = 64,
-       NEED_TPREL = 128,
-       NEED_DTPMOD = 256,
-       NEED_DTPREL = 512
+       NEED_GOTX = 2,
+       NEED_FPTR = 4,
+       NEED_PLTOFF = 8,
+       NEED_MIN_PLT = 16,
+       NEED_FULL_PLT = 32,
+       NEED_DYNREL = 64,
+       NEED_LTOFF_FPTR = 128,
+       NEED_TPREL = 256,
+       NEED_DTPMOD = 512,
+       NEED_DTPREL = 1024
       };
 
       struct elf_link_hash_entry *h = NULL;
@@ -2143,7 +2233,7 @@ elfNN_ia64_check_relocs (abfd, info, sec, relocs)
                 || h->root.type == bfd_link_hash_warning)
            h = (struct elf_link_hash_entry *) h->root.u.i.link;
 
-         h->elf_link_hash_flags |= ELF_LINK_HASH_REF_REGULAR;
+         h->ref_regular = 1;
        }
 
       /* We can only get preliminary data on whether a symbol is
@@ -2151,11 +2241,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 || 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)))
+      if (h && ((!info->executable
+                && (!info->symbolic
+                    || info->unresolved_syms_in_shared_libs == RM_IGNORE))
+               || !h->def_regular
+               || h->root.type == bfd_link_hash_defweak))
        maybe_dynamic = TRUE;
 
       need_entry = 0;
@@ -2212,7 +2302,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 || elfNN_ia64_aix_vec (abfd->xvec))
+         if (info->shared || h)
            need_entry = NEED_FPTR | NEED_DYNREL;
          else
            need_entry = NEED_FPTR;
@@ -2220,11 +2310,14 @@ elfNN_ia64_check_relocs (abfd, info, sec, relocs)
          break;
 
        case R_IA64_LTOFF22:
-       case R_IA64_LTOFF22X:
        case R_IA64_LTOFF64I:
          need_entry = NEED_GOT;
          break;
 
+       case R_IA64_LTOFF22X:
+         need_entry = NEED_GOTX;
+         break;
+
        case R_IA64_PLTOFF22:
        case R_IA64_PLTOFF64I:
        case R_IA64_PLTOFF64MSB:
@@ -2261,10 +2354,7 @@ 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
-             || (elfNN_ia64_aix_vec (abfd->xvec)
-                 && (!h || strcmp (h->root.root.string,
-                                   "__GLOB_DATA_PTR") != 0)))
+         if (info->shared || maybe_dynamic)
            need_entry = NEED_DYNREL;
          dynrel_type = R_IA64_DIR64LSB;
          break;
@@ -2306,7 +2396,8 @@ elfNN_ia64_check_relocs (abfd, info, sec, relocs)
       dyn_i->h = h;
 
       /* Create what's needed.  */
-      if (need_entry & (NEED_GOT | NEED_TPREL | NEED_DTPMOD | NEED_DTPREL))
+      if (need_entry & (NEED_GOT | NEED_GOTX | NEED_TPREL
+                       | NEED_DTPMOD | NEED_DTPREL))
        {
          if (!got)
            {
@@ -2316,6 +2407,8 @@ elfNN_ia64_check_relocs (abfd, info, sec, relocs)
            }
          if (need_entry & NEED_GOT)
            dyn_i->want_got = 1;
+         if (need_entry & NEED_GOTX)
+           dyn_i->want_gotx = 1;
          if (need_entry & NEED_TPREL)
            dyn_i->want_tprel = 1;
          if (need_entry & NEED_DTPMOD)
@@ -2335,11 +2428,9 @@ 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
-                    /* AIX also needs one */
-                    || elfNN_ia64_aix_vec (abfd->xvec)))
+         if (!h && info->shared)
            {
-             if (! (_bfd_elfNN_link_record_local_dynamic_symbol
+             if (! (bfd_elf_link_record_local_dynamic_symbol
                     (info, abfd, (long) r_symndx)))
                return FALSE;
            }
@@ -2352,13 +2443,24 @@ elfNN_ia64_check_relocs (abfd, info, sec, relocs)
        {
           if (!ia64_info->root.dynobj)
            ia64_info->root.dynobj = abfd;
-         h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT;
+         h->needs_plt = 1;
          dyn_i->want_plt = 1;
        }
       if (need_entry & NEED_FULL_PLT)
        dyn_i->want_plt2 = 1;
       if (need_entry & NEED_PLTOFF)
-       dyn_i->want_pltoff = 1;
+       {
+         /* This is needed here, in case @pltoff is used in a non-shared
+            link.  */
+         if (!pltoff)
+           {
+             pltoff = get_pltoff (abfd, info, ia64_info);
+             if (!pltoff)
+               return FALSE;
+           }
+
+         dyn_i->want_pltoff = 1;
+       }
       if ((need_entry & NEED_DYNREL) && (sec->flags & SEC_ALLOC))
        {
          if (!srel)
@@ -2367,7 +2469,8 @@ elfNN_ia64_check_relocs (abfd, info, sec, relocs)
              if (!srel)
                return FALSE;
            }
-         if (!count_dyn_reloc (abfd, dyn_i, srel, dynrel_type))
+         if (!count_dyn_reloc (abfd, dyn_i, srel, dynrel_type,
+                               (sec->flags & SEC_READONLY) != 0))
            return FALSE;
        }
     }
@@ -2375,12 +2478,6 @@ elfNN_ia64_check_relocs (abfd, info, sec, relocs)
   return TRUE;
 }
 
-struct elfNN_ia64_allocate_data
-{
-  struct bfd_link_info *info;
-  bfd_size_type ofs;
-};
-
 /* For cleanliness, and potentially faster dynamic loading, allocate
    external GOT entries first.  */
 
@@ -2391,12 +2488,9 @@ allocate_global_data_got (dyn_i, data)
 {
   struct elfNN_ia64_allocate_data *x = (struct elfNN_ia64_allocate_data *)data;
 
-  if (dyn_i->want_got
+  if ((dyn_i->want_got || dyn_i->want_gotx)
       && ! dyn_i->want_fptr
-      && (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))))
+      && elfNN_ia64_dynamic_symbol_p (dyn_i->h, x->info, 0))
      {
        dyn_i->got_offset = x->ofs;
        x->ofs += 8;
@@ -2408,8 +2502,23 @@ allocate_global_data_got (dyn_i, data)
     }
   if (dyn_i->want_dtpmod)
     {
-      dyn_i->dtpmod_offset = x->ofs;
-      x->ofs += 8;
+      if (elfNN_ia64_dynamic_symbol_p (dyn_i->h, x->info, 0))
+       {
+         dyn_i->dtpmod_offset = x->ofs;
+         x->ofs += 8;
+       }
+      else
+       {
+         struct elfNN_ia64_link_hash_table *ia64_info;
+
+         ia64_info = elfNN_ia64_hash_table (x->info);
+         if (ia64_info->self_dtpmod_offset == (bfd_vma) -1)
+           {
+             ia64_info->self_dtpmod_offset = x->ofs;
+             x->ofs += 8;
+           }
+         dyn_i->dtpmod_offset = ia64_info->self_dtpmod_offset;
+       }
     }
   if (dyn_i->want_dtprel)
     {
@@ -2430,8 +2539,7 @@ 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_aix_vec (x->info->hash->creator)))
+      && elfNN_ia64_dynamic_symbol_p (dyn_i->h, x->info, R_IA64_FPTR64LSB))
     {
       dyn_i->got_offset = x->ofs;
       x->ofs += 8;
@@ -2448,9 +2556,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_aix_vec (x->info->hash->creator)))
+  if ((dyn_i->want_got || dyn_i->want_gotx)
+      && !elfNN_ia64_dynamic_symbol_p (dyn_i->h, x->info, 0))
     {
       dyn_i->got_offset = x->ofs;
       x->ofs += 8;
@@ -2496,19 +2603,17 @@ allocate_fptr (dyn_i, data)
               || h->root.type == bfd_link_hash_warning)
          h = (struct elf_link_hash_entry *) h->root.u.i.link;
 
-      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 (!x->info->executable
+         && (!h
+             || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
+             || h->root.type != bfd_link_hash_undefweak))
        {
          if (h && h->dynindx == -1)
            {
              BFD_ASSERT ((h->root.type == bfd_link_hash_defined)
                          || (h->root.type == bfd_link_hash_defweak));
 
-             if (!_bfd_elfNN_link_record_local_dynamic_symbol
+             if (!bfd_elf_link_record_local_dynamic_symbol
                    (x->info, h->root.u.def.section->owner,
                     global_sym_index (h)))
                return FALSE;
@@ -2545,8 +2650,8 @@ allocate_plt_entries (dyn_i, data)
               || h->root.type == bfd_link_hash_warning)
          h = (struct elf_link_hash_entry *) h->root.u.i.link;
 
-      /* ??? Versioned symbols seem to lose ELF_LINK_HASH_NEEDS_PLT.  */
-      if (elfNN_ia64_dynamic_symbol_p (h, x->info))
+      /* ??? Versioned symbols seem to lose NEEDS_PLT.  */
+      if (elfNN_ia64_dynamic_symbol_p (h, x->info, 0))
        {
          bfd_size_type offset = x->ofs;
          if (offset == 0)
@@ -2621,15 +2726,17 @@ allocate_dynrel_entries (dyn_i, data)
   struct elfNN_ia64_allocate_data *x = (struct elfNN_ia64_allocate_data *)data;
   struct elfNN_ia64_link_hash_table *ia64_info;
   struct elfNN_ia64_dyn_reloc_entry *rent;
-  bfd_boolean dynamic_symbol, shared;
+  bfd_boolean dynamic_symbol, shared, resolved_zero;
 
   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)
-       /* Don't allocate an entry for __GLOB_DATA_PTR */
-       && (!dyn_i->h || strcmp (dyn_i->h->root.root.string,
-         "__GLOB_DATA_PTR") != 0));
+
+  /* Note that this can't be used in relation to FPTR relocs below.  */
+  dynamic_symbol = elfNN_ia64_dynamic_symbol_p (dyn_i->h, x->info, 0);
+
   shared = x->info->shared;
+  resolved_zero = (dyn_i->h
+                  && ELF_ST_VISIBILITY (dyn_i->h->other)
+                  && dyn_i->h->root.type == bfd_link_hash_undefweak);
 
   /* Take care of the normal data relocations.  */
 
@@ -2640,10 +2747,11 @@ allocate_dynrel_entries (dyn_i, data)
       switch (rent->type)
        {
        case R_IA64_FPTR64LSB:
-         /* Allocate one iff !want_fptr, which by this point will
-            be true only if we're actually allocating one statically
-            in the main executable.  */
-         if (dyn_i->want_fptr)
+         /* Allocate one iff !want_fptr and not PIE, which by this point
+            will be true only if we're actually allocating one statically
+            in the main executable.  Position independent executables
+            need a relative reloc.  */
+         if (dyn_i->want_fptr && !x->info->pie)
            continue;
          break;
        case R_IA64_PCREL64LSB:
@@ -2669,22 +2777,39 @@ allocate_dynrel_entries (dyn_i, data)
        default:
          abort ();
        }
-      rent->srel->_raw_size += sizeof (ElfNN_External_Rela) * count;
+      if (rent->reltext)
+       ia64_info->reltext = 1;
+      rent->srel->size += sizeof (ElfNN_External_Rela) * count;
     }
 
   /* Take care of the GOT and PLT relocations.  */
 
-  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 ((!resolved_zero
+       && (dynamic_symbol || shared)
+       && (dyn_i->want_got || dyn_i->want_gotx))
+      || (dyn_i->want_ltoff_fptr
+         && dyn_i->h
+         && dyn_i->h->dynindx != -1))
+    {
+      if (!dyn_i->want_ltoff_fptr
+         || !x->info->pie
+         || dyn_i->h == NULL
+         || dyn_i->h->root.type != bfd_link_hash_undefweak)
+       ia64_info->rel_got_sec->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);
+    ia64_info->rel_got_sec->size += sizeof (ElfNN_External_Rela);
+  if (dynamic_symbol && dyn_i->want_dtpmod)
+    ia64_info->rel_got_sec->size += sizeof (ElfNN_External_Rela);
   if (dynamic_symbol && dyn_i->want_dtprel)
-    ia64_info->rel_got_sec->_raw_size += sizeof (ElfNN_External_Rela);
+    ia64_info->rel_got_sec->size += sizeof (ElfNN_External_Rela);
+  if (ia64_info->rel_fptr_sec && dyn_i->want_fptr)
+    {
+      if (dyn_i->h == NULL || dyn_i->h->root.type != bfd_link_hash_undefweak)
+       ia64_info->rel_fptr_sec->size += sizeof (ElfNN_External_Rela);
+    }
 
-  if (dyn_i->want_pltoff)
+  if (!resolved_zero && dyn_i->want_pltoff)
     {
       bfd_size_type t = 0;
 
@@ -2696,7 +2821,7 @@ allocate_dynrel_entries (dyn_i, data)
       else if (shared)
        t = 2 * sizeof (ElfNN_External_Rela);
 
-      ia64_info->rel_pltoff_sec->_raw_size += t;
+      ia64_info->rel_pltoff_sec->size += t;
     }
 
   return TRUE;
@@ -2713,12 +2838,12 @@ elfNN_ia64_adjust_dynamic_symbol (info, h)
   /* If this is a weak symbol, and there is a real definition, the
      processor independent code will have arranged for us to see the
      real definition first, and we can just use the same value.  */
-  if (h->weakdef != NULL)
+  if (h->u.weakdef != NULL)
     {
-      BFD_ASSERT (h->weakdef->root.type == bfd_link_hash_defined
-                  || h->weakdef->root.type == bfd_link_hash_defweak);
-      h->root.u.def.section = h->weakdef->root.u.def.section;
-      h->root.u.def.value = h->weakdef->root.u.def.value;
+      BFD_ASSERT (h->u.weakdef->root.type == bfd_link_hash_defined
+                  || h->u.weakdef->root.type == bfd_link_hash_defweak);
+      h->root.u.def.section = h->u.weakdef->root.u.def.section;
+      h->root.u.def.value = h->u.weakdef->root.u.def.value;
       return TRUE;
     }
 
@@ -2734,7 +2859,7 @@ elfNN_ia64_adjust_dynamic_symbol (info, h)
 
 static bfd_boolean
 elfNN_ia64_size_dynamic_sections (output_bfd, info)
-     bfd *output_bfd;
+     bfd *output_bfd ATTRIBUTE_UNUSED;
      struct bfd_link_info *info;
 {
   struct elfNN_ia64_allocate_data data;
@@ -2745,17 +2870,18 @@ elfNN_ia64_size_dynamic_sections (output_bfd, info)
 
   dynobj = elf_hash_table(info)->dynobj;
   ia64_info = elfNN_ia64_hash_table (info);
+  ia64_info->self_dtpmod_offset = (bfd_vma) -1;
   BFD_ASSERT(dynobj != NULL);
   data.info = info;
 
   /* Set the contents of the .interp section to the interpreter.  */
   if (ia64_info->root.dynamic_sections_created
-      && !info->shared)
+      && info->executable)
     {
       sec = bfd_get_section_by_name (dynobj, ".interp");
       BFD_ASSERT (sec != NULL);
-      sec->contents = (bfd_byte *) DYNAMIC_INTERPRETER (output_bfd);
-      sec->_raw_size = strlen (DYNAMIC_INTERPRETER (output_bfd)) + 1;
+      sec->contents = (bfd_byte *) ELF_DYNAMIC_INTERPRETER;
+      sec->size = strlen (ELF_DYNAMIC_INTERPRETER) + 1;
     }
 
   /* Allocate the GOT entries.  */
@@ -2766,7 +2892,7 @@ elfNN_ia64_size_dynamic_sections (output_bfd, info)
       elfNN_ia64_dyn_sym_traverse (ia64_info, allocate_global_data_got, &data);
       elfNN_ia64_dyn_sym_traverse (ia64_info, allocate_global_fptr_got, &data);
       elfNN_ia64_dyn_sym_traverse (ia64_info, allocate_local_got, &data);
-      ia64_info->got_sec->_raw_size = data.ofs;
+      ia64_info->got_sec->size = data.ofs;
     }
 
   /* Allocate the FPTR entries.  */
@@ -2775,7 +2901,7 @@ elfNN_ia64_size_dynamic_sections (output_bfd, info)
     {
       data.ofs = 0;
       elfNN_ia64_dyn_sym_traverse (ia64_info, allocate_fptr, &data);
-      ia64_info->fptr_sec->_raw_size = data.ofs;
+      ia64_info->fptr_sec->size = data.ofs;
     }
 
   /* Now that we've seen all of the input files, we can decide which
@@ -2797,16 +2923,20 @@ elfNN_ia64_size_dynamic_sections (output_bfd, info)
   data.ofs = (data.ofs + 31) & (bfd_vma) -32;
 
   elfNN_ia64_dyn_sym_traverse (ia64_info, allocate_plt2_entries, &data);
-  if (data.ofs != 0)
+  if (data.ofs != 0 || ia64_info->root.dynamic_sections_created)
     {
+      /* FIXME: we always reserve the memory for dynamic linker even if
+        there are no PLT entries since dynamic linker may assume the
+        reserved memory always exists.  */
+
       BFD_ASSERT (ia64_info->root.dynamic_sections_created);
 
-      ia64_info->plt_sec->_raw_size = data.ofs;
+      ia64_info->plt_sec->size = data.ofs;
 
       /* If we've got a .plt, we need some extra memory for the dynamic
         linker.  We stuff these in .got.plt.  */
       sec = bfd_get_section_by_name (dynobj, ".got.plt");
-      sec->_raw_size = 8 * PLT_RESERVED_WORDS;
+      sec->size = 8 * PLT_RESERVED_WORDS;
     }
 
   /* Allocate the PLTOFF entries.  */
@@ -2815,7 +2945,7 @@ elfNN_ia64_size_dynamic_sections (output_bfd, info)
     {
       data.ofs = 0;
       elfNN_ia64_dyn_sym_traverse (ia64_info, allocate_pltoff_entries, &data);
-      ia64_info->pltoff_sec->_raw_size = data.ofs;
+      ia64_info->pltoff_sec->size = data.ofs;
     }
 
   if (ia64_info->root.dynamic_sections_created)
@@ -2823,6 +2953,8 @@ elfNN_ia64_size_dynamic_sections (output_bfd, info)
       /* Allocate space for the dynamic relocations that turned out to be
         required.  */
 
+      if (info->shared && ia64_info->self_dtpmod_offset != (bfd_vma) -1)
+       ia64_info->rel_got_sec->size += sizeof (ElfNN_External_Rela);
       elfNN_ia64_dyn_sym_traverse (ia64_info, allocate_dynrel_entries, &data);
     }
 
@@ -2843,7 +2975,7 @@ elfNN_ia64_size_dynamic_sections (output_bfd, info)
         function which decides whether anything needs to go into
         these sections.  */
 
-      strip = (sec->_raw_size == 0);
+      strip = (sec->size == 0);
 
       if (sec == ia64_info->got_sec)
        strip = FALSE;
@@ -2861,6 +2993,15 @@ elfNN_ia64_size_dynamic_sections (output_bfd, info)
          if (strip)
            ia64_info->fptr_sec = NULL;
        }
+      else if (sec == ia64_info->rel_fptr_sec)
+       {
+         if (strip)
+           ia64_info->rel_fptr_sec = NULL;
+         else
+           /* We use the reloc_count field as a counter if we need to
+              copy relocs into the output file.  */
+           sec->reloc_count = 0;
+       }
       else if (sec == ia64_info->plt_sec)
        {
          if (strip)
@@ -2911,8 +3052,8 @@ 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);
-         if (sec->contents == NULL && sec->_raw_size != 0)
+         sec->contents = (bfd_byte *) bfd_zalloc (dynobj, sec->size);
+         if (sec->contents == NULL && sec->size != 0)
            return FALSE;
        }
     }
@@ -2923,12 +3064,12 @@ elfNN_ia64_size_dynamic_sections (output_bfd, info)
         later (in finish_dynamic_sections) but we must add the entries now
         so that we get the correct size for the .dynamic section.  */
 
-      if (!info->shared)
+      if (info->executable)
        {
          /* The DT_DEBUG entry is filled in by the dynamic linker and used
             by the debugger.  */
 #define add_dynamic_entry(TAG, VAL) \
-  bfd_elfNN_add_dynamic_entry (info, (bfd_vma) (TAG), (bfd_vma) (VAL))
+  _bfd_elf_add_dynamic_entry (info, TAG, VAL)
 
          if (!add_dynamic_entry (DT_DEBUG, 0))
            return FALSE;
@@ -2966,8 +3107,7 @@ elfNN_ia64_size_dynamic_sections (output_bfd, info)
 }
 
 static bfd_reloc_status_type
-elfNN_ia64_install_value (abfd, hit_addr, v, r_type)
-     bfd *abfd;
+elfNN_ia64_install_value (hit_addr, v, r_type)
      bfd_byte *hit_addr;
      bfd_vma v;
      unsigned int r_type;
@@ -3099,8 +3239,8 @@ elfNN_ia64_install_value (abfd, hit_addr, v, r_type)
     {
     case IA64_OPND_IMMU64:
       hit_addr -= (long) hit_addr & 0x3;
-      t0 = bfd_get_64 (abfd, hit_addr);
-      t1 = bfd_get_64 (abfd, hit_addr + 8);
+      t0 = bfd_getl64 (hit_addr);
+      t1 = bfd_getl64 (hit_addr + 8);
 
       /* tmpl/s: bits  0.. 5 in t0
         slot 0: bits  5..45 in t0
@@ -3122,14 +3262,14 @@ elfNN_ia64_install_value (abfd, hit_addr, v, r_type)
               | (((val >> 21) & 0x001) << 21)          /* ic */
               | (((val >> 63) & 0x001) << 36)) << 23;  /* i */
 
-      bfd_put_64 (abfd, t0, hit_addr);
-      bfd_put_64 (abfd, t1, hit_addr + 8);
+      bfd_putl64 (t0, hit_addr);
+      bfd_putl64 (t1, hit_addr + 8);
       break;
 
     case IA64_OPND_TGT64:
       hit_addr -= (long) hit_addr & 0x3;
-      t0 = bfd_get_64 (abfd, hit_addr);
-      t1 = bfd_get_64 (abfd, hit_addr + 8);
+      t0 = bfd_getl64 (hit_addr);
+      t1 = bfd_getl64 (hit_addr + 8);
 
       /* tmpl/s: bits  0.. 5 in t0
         slot 0: bits  5..45 in t0
@@ -3147,8 +3287,8 @@ elfNN_ia64_install_value (abfd, hit_addr, v, r_type)
       t1 |= ((((val >> 0) & 0xfffffLL) << 13)          /* imm20b */
              | (((val >> 59) & 0x1LL) << 36)) << 23;   /* i */
 
-      bfd_put_64 (abfd, t0, hit_addr);
-      bfd_put_64 (abfd, t1, hit_addr + 8);
+      bfd_putl64 (t0, hit_addr);
+      bfd_putl64 (t1, hit_addr + 8);
       break;
 
     default:
@@ -3159,7 +3299,7 @@ elfNN_ia64_install_value (abfd, hit_addr, v, r_type)
        case 2: shift = 23; hit_addr += 6; break;
        case 3: return bfd_reloc_notsupported; /* shouldn't happen...  */
        }
-      dword = bfd_get_64 (abfd, hit_addr);
+      dword = bfd_getl64 (hit_addr);
       insn = (dword >> shift) & 0x1ffffffffffLL;
 
       op = elf64_ia64_operands + opnd;
@@ -3169,7 +3309,7 @@ elfNN_ia64_install_value (abfd, hit_addr, v, r_type)
 
       dword &= ~(0x1ffffffffffLL << shift);
       dword |= (insn << shift);
-      bfd_put_64 (abfd, dword, hit_addr);
+      bfd_putl64 (dword, hit_addr);
       break;
 
     case IA64_OPND_NIL:
@@ -3223,8 +3363,7 @@ elfNN_ia64_install_dyn_reloc (abfd, info, sec, srel, offset, type,
   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);
+  BFD_ASSERT (sizeof (ElfNN_External_Rela) * srel->reloc_count <= srel->size);
 }
 
 /* Store an entry for target address TARGET_ADDR in the linkage table
@@ -3256,8 +3395,17 @@ set_got_entry (abfd, info, dyn_i, dynindx, addend, value, dyn_r_type)
       got_offset = dyn_i->tprel_offset;
       break;
     case R_IA64_DTPMOD64LSB:
-      done = dyn_i->dtpmod_done;
-      dyn_i->dtpmod_done = TRUE;
+      if (dyn_i->dtpmod_offset != ia64_info->self_dtpmod_offset)
+       {
+         done = dyn_i->dtpmod_done;
+         dyn_i->dtpmod_done = TRUE;
+       }
+      else
+       {
+         done = ia64_info->self_dtpmod_done;
+         ia64_info->self_dtpmod_done = TRUE;
+         dynindx = 0;
+       }
       got_offset = dyn_i->dtpmod_offset;
       break;
     case R_IA64_DTPREL64LSB:
@@ -3280,10 +3428,17 @@ set_got_entry (abfd, info, dyn_i, dynindx, addend, value, dyn_r_type)
       bfd_put_64 (abfd, value, got_sec->contents + got_offset);
 
       /* Install a dynamic relocation if needed.  */
-      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 (((info->shared
+           && (!dyn_i->h
+               || ELF_ST_VISIBILITY (dyn_i->h->other) == STV_DEFAULT
+               || dyn_i->h->root.type != bfd_link_hash_undefweak)
+           && dyn_r_type != R_IA64_DTPREL64LSB)
+           || elfNN_ia64_dynamic_symbol_p (dyn_i->h, info, dyn_r_type)
+          || (dynindx != -1 && dyn_r_type == R_IA64_FPTR64LSB))
+         && (!dyn_i->want_ltoff_fptr
+             || !info->pie
+             || !dyn_i->h
+             || dyn_i->h->root.type != bfd_link_hash_undefweak))
        {
          if (dynindx == -1
              && dyn_r_type != R_IA64_TPREL64LSB
@@ -3362,6 +3517,24 @@ set_fptr_entry (abfd, info, dyn_i, value)
       bfd_put_64 (abfd, value, fptr_sec->contents + dyn_i->fptr_offset);
       bfd_put_64 (abfd, _bfd_get_gp_value (abfd),
                  fptr_sec->contents + dyn_i->fptr_offset + 8);
+      if (ia64_info->rel_fptr_sec)
+       {
+         Elf_Internal_Rela outrel;
+         bfd_byte *loc;
+
+         if (bfd_little_endian (abfd))
+           outrel.r_info = ELFNN_R_INFO (0, R_IA64_IPLTLSB);
+         else
+           outrel.r_info = ELFNN_R_INFO (0, R_IA64_IPLTMSB);
+         outrel.r_addend = value;
+         outrel.r_offset = (fptr_sec->output_section->vma
+                            + fptr_sec->output_offset
+                            + dyn_i->fptr_offset);
+         loc = ia64_info->rel_fptr_sec->contents;
+         loc += ia64_info->rel_fptr_sec->reloc_count++
+                * sizeof (ElfNN_External_Rela);
+         bfd_elfNN_swap_reloca_out (abfd, &outrel, loc);
+       }
     }
 
   /* Return the descriptor's address.  */
@@ -3401,7 +3574,11 @@ set_pltoff_entry (abfd, info, dyn_i, value, is_plt)
       bfd_put_64 (abfd, gp, pltoff_sec->contents + dyn_i->pltoff_offset + 8);
 
       /* Install dynamic relocations if needed.  */
-      if (!is_plt && info->shared)
+      if (!is_plt
+         && info->shared
+         && (!dyn_i->h
+             || ELF_ST_VISIBILITY (dyn_i->h->other) == STV_DEFAULT
+             || dyn_i->h->root.type != bfd_link_hash_undefweak))
        {
          unsigned int dyn_r_type;
 
@@ -3440,12 +3617,10 @@ 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;
+  asection *tls_sec = elf_hash_table (info)->tls_sec;
 
-  BFD_ASSERT (tls_segment != NULL);
-  return (tls_segment->start
-         - align_power ((bfd_vma) 16, tls_segment->align));
+  BFD_ASSERT (tls_sec != NULL);
+  return tls_sec->vma - align_power ((bfd_vma) 16, tls_sec->alignment_power);
 }
 
 /* Return the base VMA address which should be subtracted from real addresses
@@ -3456,8 +3631,8 @@ 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;
+  BFD_ASSERT (elf_hash_table (info)->tls_sec != NULL);
+  return elf_hash_table (info)->tls_sec->vma;
 }
 
 /* Called through qsort to sort the .IA_64.unwind section during a
@@ -3479,125 +3654,148 @@ elfNN_ia64_unwind_entry_compare (a, b)
   return (av < bv ? -1 : av > bv ? 1 : 0);
 }
 
+/* Make sure we've got ourselves a nice fat __gp value.  */
 static bfd_boolean
-elfNN_ia64_final_link (abfd, info)
+elfNN_ia64_choose_gp (abfd, info)
      bfd *abfd;
      struct bfd_link_info *info;
 {
+  bfd_vma min_vma = (bfd_vma) -1, max_vma = 0;
+  bfd_vma min_short_vma = min_vma, max_short_vma = 0;
+  struct elf_link_hash_entry *gp;
+  bfd_vma gp_val;
+  asection *os;
   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.  */
-  if (!info->relocateable)
+  /* Find the min and max vma of all sections marked short.  Also collect
+     min and max vma of any type, for use in selecting a nice gp.  */
+  for (os = abfd->sections; os ; os = os->next)
     {
-      bfd_vma min_vma = (bfd_vma) -1, max_vma = 0;
-      bfd_vma min_short_vma = min_vma, max_short_vma = 0;
-      struct elf_link_hash_entry *gp;
-      bfd_vma gp_val;
-      asection *os;
+      bfd_vma lo, hi;
+
+      if ((os->flags & SEC_ALLOC) == 0)
+       continue;
 
-      /* Find the min and max vma of all sections marked short.  Also
-        collect min and max vma of any type, for use in selecting a
-        nice gp.  */
-      for (os = abfd->sections; os ; os = os->next)
+      lo = os->vma;
+      hi = os->vma + os->size;
+      if (hi < lo)
+       hi = (bfd_vma) -1;
+
+      if (min_vma > lo)
+       min_vma = lo;
+      if (max_vma < hi)
+       max_vma = hi;
+      if (os->flags & SEC_SMALL_DATA)
        {
-         bfd_vma lo, hi;
+         if (min_short_vma > lo)
+           min_short_vma = lo;
+         if (max_short_vma < hi)
+           max_short_vma = hi;
+       }
+    }
 
-         if ((os->flags & SEC_ALLOC) == 0)
-           continue;
+  /* See if the user wants to force a value.  */
+  gp = elf_link_hash_lookup (elf_hash_table (info), "__gp", FALSE,
+                            FALSE, FALSE);
 
-         lo = os->vma;
-         hi = os->vma + os->_raw_size;
-         if (hi < lo)
-           hi = (bfd_vma) -1;
+  if (gp
+      && (gp->root.type == bfd_link_hash_defined
+         || gp->root.type == bfd_link_hash_defweak))
+    {
+      asection *gp_sec = gp->root.u.def.section;
+      gp_val = (gp->root.u.def.value
+               + gp_sec->output_section->vma
+               + gp_sec->output_offset);
+    }
+  else
+    {
+      /* Pick a sensible value.  */
 
-         if (min_vma > lo)
-           min_vma = lo;
-         if (max_vma < hi)
-           max_vma = hi;
-         if (os->flags & SEC_SMALL_DATA)
-           {
-             if (min_short_vma > lo)
-               min_short_vma = lo;
-             if (max_short_vma < hi)
-               max_short_vma = hi;
-           }
+      asection *got_sec = ia64_info->got_sec;
+
+      /* Start with just the address of the .got.  */
+      if (got_sec)
+       gp_val = got_sec->output_section->vma;
+      else if (max_short_vma != 0)
+       gp_val = min_short_vma;
+      else
+       gp_val = min_vma;
+
+      /* If it is possible to address the entire image, but we
+        don't with the choice above, adjust.  */
+      if (max_vma - min_vma < 0x400000
+         && max_vma - gp_val <= 0x200000
+         && gp_val - min_vma > 0x200000)
+       gp_val = min_vma + 0x200000;
+      else if (max_short_vma != 0)
+       {
+         /* If we don't cover all the short data, adjust.  */
+         if (max_short_vma - gp_val >= 0x200000)
+           gp_val = min_short_vma + 0x200000;
+
+         /* If we're addressing stuff past the end, adjust back.  */
+         if (gp_val > max_vma)
+           gp_val = max_vma - 0x200000 + 8;
        }
+    }
 
-      /* See if the user wants to force a value.  */
-      gp = elf_link_hash_lookup (elf_hash_table (info), "__gp", FALSE,
-                                FALSE, FALSE);
+  /* Validate whether all SHF_IA_64_SHORT sections are within
+     range of the chosen GP.  */
 
-      if (gp
-         && (gp->root.type == bfd_link_hash_defined
-             || gp->root.type == bfd_link_hash_defweak))
+  if (max_short_vma != 0)
+    {
+      if (max_short_vma - min_short_vma >= 0x400000)
        {
-         asection *gp_sec = gp->root.u.def.section;
-         gp_val = (gp->root.u.def.value
-                   + gp_sec->output_section->vma
-                   + gp_sec->output_offset);
+         (*_bfd_error_handler)
+           (_("%s: short data segment overflowed (0x%lx >= 0x400000)"),
+            bfd_get_filename (abfd),
+            (unsigned long) (max_short_vma - min_short_vma));
+         return FALSE;
        }
-      else
+      else if ((gp_val > min_short_vma
+               && gp_val - min_short_vma > 0x200000)
+              || (gp_val < max_short_vma
+                  && max_short_vma - gp_val >= 0x200000))
        {
-         /* Pick a sensible value.  */
+         (*_bfd_error_handler)
+           (_("%s: __gp does not cover short data segment"),
+            bfd_get_filename (abfd));
+         return FALSE;
+       }
+    }
 
-         asection *got_sec = ia64_info->got_sec;
+  _bfd_set_gp_value (abfd, gp_val);
 
-         /* Start with just the address of the .got.  */
-         if (got_sec)
-           gp_val = got_sec->output_section->vma;
-         else if (max_short_vma != 0)
-           gp_val = min_short_vma;
-         else
-           gp_val = min_vma;
-
-         /* If it is possible to address the entire image, but we
-            don't with the choice above, adjust.  */
-         if (max_vma - min_vma < 0x400000
-             && max_vma - gp_val <= 0x200000
-             && gp_val - min_vma > 0x200000)
-           gp_val = min_vma + 0x200000;
-         else if (max_short_vma != 0)
-           {
-             /* If we don't cover all the short data, adjust.  */
-             if (max_short_vma - gp_val >= 0x200000)
-               gp_val = min_short_vma + 0x200000;
+  return TRUE;
+}
 
-             /* If we're addressing stuff past the end, adjust back.  */
-             if (gp_val > max_vma)
-               gp_val = max_vma - 0x200000 + 8;
-           }
-       }
+static bfd_boolean
+elfNN_ia64_final_link (abfd, info)
+     bfd *abfd;
+     struct bfd_link_info *info;
+{
+  struct elfNN_ia64_link_hash_table *ia64_info;
+  asection *unwind_output_sec;
+
+  ia64_info = elfNN_ia64_hash_table (info);
 
-      /* Validate whether all SHF_IA_64_SHORT sections are within
-        range of the chosen GP.  */
+  /* Make sure we've got ourselves a nice fat __gp value.  */
+  if (!info->relocatable)
+    {
+      bfd_vma gp_val = _bfd_get_gp_value (abfd);
+      struct elf_link_hash_entry *gp;
 
-      if (max_short_vma != 0)
+      if (gp_val == 0)
        {
-         if (max_short_vma - min_short_vma >= 0x400000)
-           {
-             (*_bfd_error_handler)
-               (_("%s: short data segment overflowed (0x%lx >= 0x400000)"),
-                bfd_get_filename (abfd),
-                (unsigned long) (max_short_vma - min_short_vma));
-             return FALSE;
-           }
-         else if ((gp_val > min_short_vma
-                   && gp_val - min_short_vma > 0x200000)
-                  || (gp_val < max_short_vma
-                      && max_short_vma - gp_val >= 0x200000))
-           {
-             (*_bfd_error_handler)
-               (_("%s: __gp does not cover short data segment"),
-                bfd_get_filename (abfd));
-             return FALSE;
-           }
+         if (! elfNN_ia64_choose_gp (abfd, info))
+           return FALSE;
+         gp_val = _bfd_get_gp_value (abfd);
        }
 
-      _bfd_set_gp_value (abfd, gp_val);
-
+      gp = elf_link_hash_lookup (elf_hash_table (info), "__gp", FALSE,
+                                FALSE, FALSE);
       if (gp)
        {
          gp->root.type = bfd_link_hash_defined;
@@ -3610,34 +3808,34 @@ elfNN_ia64_final_link (abfd, info)
      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)
+  if (!info->relocatable)
     {
       asection *s = bfd_get_section_by_name (abfd, ELF_STRING_ia64_unwind);
       if (s)
        {
          unwind_output_sec = s->output_section;
          unwind_output_sec->contents
-           = bfd_malloc (unwind_output_sec->_raw_size);
+           = bfd_malloc (unwind_output_sec->size);
          if (unwind_output_sec->contents == NULL)
            return FALSE;
        }
     }
 
   /* Invoke the regular ELF backend linker to do all the work.  */
-  if (!bfd_elfNN_bfd_final_link (abfd, info))
+  if (!bfd_elf_final_link (abfd, info))
     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),
+            (size_t) (unwind_output_sec->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))
+                                     unwind_output_sec->size))
        return FALSE;
     }
 
@@ -3668,7 +3866,7 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section,
   ia64_info = elfNN_ia64_hash_table (info);
 
   /* Infect various flags from the input section to the output section.  */
-  if (info->relocateable)
+  if (info->relocatable)
     {
       bfd_vma flags;
 
@@ -3704,8 +3902,8 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section,
       if (r_type > R_IA64_MAX_RELOC_CODE)
        {
          (*_bfd_error_handler)
-           (_("%s: unknown relocation type %d"),
-            bfd_archive_filename (input_bfd), (int)r_type);
+           (_("%B: unknown relocation type %d"),
+            input_bfd, (int) r_type);
          bfd_set_error (bfd_error_bad_value);
          ret_val = FALSE;
          continue;
@@ -3721,13 +3919,14 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section,
       if (r_symndx < symtab_hdr->sh_info)
        {
          /* Reloc against local symbol.  */
+         asection *msec;
          sym = local_syms + r_symndx;
          sym_sec = local_sections[r_symndx];
-         value = _bfd_elf_rela_local_sym (output_bfd, sym, sym_sec, rel);
+         msec = sym_sec;
+         value = _bfd_elf_rela_local_sym (output_bfd, sym, &msec, 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))
+             && sym_sec->sec_info_type == ELF_INFO_TYPE_MERGE)
            {
              struct elfNN_ia64_local_hash_entry *loc_h;
 
@@ -3735,7 +3934,6 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section,
              if (loc_h && ! loc_h->sec_merge_done)
                {
                  struct elfNN_ia64_dyn_sym_info *dynent;
-                 asection *msec;
 
                  for (dynent = loc_h->info; dynent; dynent = dynent->next)
                    {
@@ -3745,8 +3943,7 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section,
                                                    elf_section_data (msec)->
                                                    sec_info,
                                                    sym->st_value
-                                                   + dynent->addend,
-                                                   (bfd_vma) 0);
+                                                   + dynent->addend);
                      dynent->addend -= sym->st_value;
                      dynent->addend += msec->output_section->vma
                                        + msec->output_offset
@@ -3759,59 +3956,24 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section,
        }
       else
        {
-         long indx;
-
-         /* Reloc against global symbol.  */
-         indx = r_symndx - symtab_hdr->sh_info;
-         h = elf_sym_hashes (input_bfd)[indx];
-         while (h->root.type == bfd_link_hash_indirect
-                || h->root.type == bfd_link_hash_warning)
-           h = (struct elf_link_hash_entry *) h->root.u.i.link;
-
-         value = 0;
-         if (h->root.type == bfd_link_hash_defined
-             || h->root.type == bfd_link_hash_defweak)
-           {
-             sym_sec = h->root.u.def.section;
+         bfd_boolean unresolved_reloc;
+         bfd_boolean warned;
+         struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (input_bfd);
 
-             /* Detect the cases that sym_sec->output_section is
-                expected to be NULL -- all cases in which the symbol
-                is defined in another shared module.  This includes
-                PLT relocs for which we've created a PLT entry and
-                other relocs for which we're prepared to create
-                dynamic relocations.  */
-             /* ??? Just accept it NULL and continue.  */
+         RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
+                                  r_symndx, symtab_hdr, sym_hashes,
+                                  h, sym_sec, value,
+                                  unresolved_reloc, warned);
 
-             if (sym_sec->output_section != NULL)
-               {
-                 value = (h->root.u.def.value
-                          + sym_sec->output_section->vma
-                          + sym_sec->output_offset);
-               }
-           }
-         else if (h->root.type == bfd_link_hash_undefweak)
+         if (h->root.type == bfd_link_hash_undefweak)
            undef_weak_ref = TRUE;
-         else if (info->shared
-                  && (!info->symbolic || info->allow_shlib_undefined)
-                  && !info->no_undefined
-                  && ELF_ST_VISIBILITY (h->other) == STV_DEFAULT)
-           ;
-         else
-           {
-             if (! ((*info->callbacks->undefined_symbol)
-                    (info, h->root.root.string, input_bfd,
-                     input_section, rel->r_offset,
-                     (!info->shared || info->no_undefined
-                      || ELF_ST_VISIBILITY (h->other)))))
-               return FALSE;
-             ret_val = FALSE;
-             continue;
-           }
+         else if (warned)
+           continue;
        }
 
       hit_addr = contents + rel->r_offset;
       value += rel->r_addend;
-      dynamic_symbol_p = elfNN_ia64_dynamic_symbol_p (h, info);
+      dynamic_symbol_p = elfNN_ia64_dynamic_symbol_p (h, info, r_type);
 
       switch (r_type)
        {
@@ -3827,11 +3989,7 @@ 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
-              || (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)))
+         if ((dynamic_symbol_p || info->shared)
              && r_symndx != 0
              && (input_section->flags & SEC_ALLOC) != 0)
            {
@@ -3841,6 +3999,24 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section,
 
              BFD_ASSERT (srel != NULL);
 
+             switch (r_type)
+               {
+               case R_IA64_IMM14:
+               case R_IA64_IMM22:
+               case R_IA64_IMM64:
+                 /* ??? People shouldn't be doing non-pic code in
+                    shared libraries nor dynamic executables.  */
+                 (*_bfd_error_handler)
+                   (_("%B: non-pic code with imm relocation against dynamic symbol `%s'"),
+                    input_bfd,
+                    h->root.root.string);
+                 ret_val = FALSE;
+                 continue;
+
+               default:
+                 break;
+               }
+
              /* If we don't need dynamic symbol lookup, find a
                 matching RELATIVE relocation.  */
              dyn_r_type = r_type;
@@ -3868,35 +4044,23 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section,
                      break;
 
                    default:
-                     /* We can't represent this without a dynamic symbol.
-                        Adjust the relocation to be against an output
-                        section symbol, which are always present in the
-                        dynamic symbol table.  */
-                     /* ??? People shouldn't be doing non-pic code in
-                        shared libraries.  Hork.  */
-                     (*_bfd_error_handler)
-                       (_("%s: linking non-pic code in a shared library"),
-                        bfd_archive_filename (input_bfd));
-                     ret_val = FALSE;
-                     continue;
+                     break;
                    }
                  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, addend);
            }
-         /* FALLTHRU */
+         /* Fall through.  */
 
        case R_IA64_LTV32MSB:
        case R_IA64_LTV32LSB:
        case R_IA64_LTV64MSB:
        case R_IA64_LTV64LSB:
-         r = elfNN_ia64_install_value (output_bfd, hit_addr, value, r_type);
+         r = elfNN_ia64_install_value (hit_addr, value, r_type);
          break;
 
        case R_IA64_GPREL22:
@@ -3908,13 +4072,13 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section,
          if (dynamic_symbol_p)
            {
              (*_bfd_error_handler)
-               (_("%s: @gprel relocation against dynamic symbol %s"),
-                bfd_archive_filename (input_bfd), h->root.root.string);
+               (_("%B: @gprel relocation against dynamic symbol %s"),
+                input_bfd, h->root.root.string);
              ret_val = FALSE;
              continue;
            }
          value -= gp_val;
-         r = elfNN_ia64_install_value (output_bfd, hit_addr, value, r_type);
+         r = elfNN_ia64_install_value (hit_addr, value, r_type);
          break;
 
        case R_IA64_LTOFF22:
@@ -3924,7 +4088,7 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section,
          value = set_got_entry (input_bfd, info, dyn_i, (h ? h->dynindx : -1),
                                 rel->r_addend, value, R_IA64_DIR64LSB);
          value -= gp_val;
-         r = elfNN_ia64_install_value (output_bfd, hit_addr, value, r_type);
+         r = elfNN_ia64_install_value (hit_addr, value, r_type);
          break;
 
        case R_IA64_PLTOFF22:
@@ -3934,7 +4098,7 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section,
           dyn_i = get_dyn_sym_info (ia64_info, h, input_bfd, rel, FALSE);
          value = set_pltoff_entry (output_bfd, info, dyn_i, value, FALSE);
          value -= gp_val;
-         r = elfNN_ia64_install_value (output_bfd, hit_addr, value, r_type);
+         r = elfNN_ia64_install_value (hit_addr, value, r_type);
          break;
 
        case R_IA64_FPTR64I:
@@ -3948,14 +4112,36 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section,
              if (!undef_weak_ref)
                value = set_fptr_entry (output_bfd, info, dyn_i, value);
            }
-         else
+         if (!dyn_i->want_fptr || info->pie)
            {
              long dynindx;
+             unsigned int dyn_r_type = r_type;
+             bfd_vma addend = rel->r_addend;
 
              /* Otherwise, we expect the dynamic linker to create
                 the entry.  */
 
-             if (h)
+             if (dyn_i->want_fptr)
+               {
+                 if (r_type == R_IA64_FPTR64I)
+                   {
+                     /* We can't represent this without a dynamic symbol.
+                        Adjust the relocation to be against an output
+                        section symbol, which are always present in the
+                        dynamic symbol table.  */
+                     /* ??? People shouldn't be doing non-pic code in
+                        shared libraries.  Hork.  */
+                     (*_bfd_error_handler)
+                       (_("%B: linking non-pic code in a position independent executable"),
+                        input_bfd);
+                     ret_val = FALSE;
+                     continue;
+                   }
+                 dynindx = 0;
+                 addend = value;
+                 dyn_r_type = r_type + R_IA64_REL64LSB - R_IA64_FPTR64LSB;
+               }
+             else if (h)
                {
                  if (h->dynindx != -1)
                    dynindx = h->dynindx;
@@ -3963,20 +4149,21 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section,
                    dynindx = (_bfd_elf_link_lookup_local_dynindx
                               (info, h->root.u.def.section->owner,
                                global_sym_index (h)));
+                 value = 0;
                }
              else
                {
                  dynindx = (_bfd_elf_link_lookup_local_dynindx
                             (info, input_bfd, (long) r_symndx));
+                 value = 0;
                }
 
              elfNN_ia64_install_dyn_reloc (output_bfd, info, input_section,
-                                           srel, rel->r_offset, r_type,
-                                           dynindx, rel->r_addend);
-             value = 0;
+                                           srel, rel->r_offset, dyn_r_type,
+                                           dynindx, addend);
            }
 
-         r = elfNN_ia64_install_value (output_bfd, hit_addr, value, r_type);
+         r = elfNN_ia64_install_value (hit_addr, value, r_type);
          break;
 
        case R_IA64_LTOFF_FPTR22:
@@ -3991,7 +4178,7 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section,
            dyn_i = get_dyn_sym_info (ia64_info, h, input_bfd, rel, FALSE);
            if (dyn_i->want_fptr)
              {
-               BFD_ASSERT (h == NULL || h->dynindx == -1)
+               BFD_ASSERT (h == NULL || h->dynindx == -1);
                if (!undef_weak_ref)
                  value = set_fptr_entry (output_bfd, info, dyn_i, value);
                dynindx = -1;
@@ -4018,7 +4205,7 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section,
            value = set_got_entry (output_bfd, info, dyn_i, dynindx,
                                   rel->r_addend, value, R_IA64_FPTR64LSB);
            value -= gp_val;
-           r = elfNN_ia64_install_value (output_bfd, hit_addr, value, r_type);
+           r = elfNN_ia64_install_value (hit_addr, value, r_type);
          }
          break;
 
@@ -4027,9 +4214,7 @@ 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))
-             && r_symndx != 0)
+         if (dynamic_symbol_p && r_symndx != 0)
            {
              BFD_ASSERT (srel != NULL);
 
@@ -4039,29 +4224,6 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section,
            }
          goto finish_pcrel;
 
-       case R_IA64_PCREL21BI:
-       case R_IA64_PCREL21F:
-       case R_IA64_PCREL21M:
-         /* ??? These two are only used for speculation fixup code.
-            They should never be dynamic.  */
-         if (dynamic_symbol_p)
-           {
-             (*_bfd_error_handler)
-               (_("%s: dynamic relocation against speculation fixup"),
-                bfd_archive_filename (input_bfd));
-             ret_val = FALSE;
-             continue;
-           }
-         if (undef_weak_ref)
-           {
-             (*_bfd_error_handler)
-               (_("%s: speculation fixup against undefined weak symbol"),
-                bfd_archive_filename (input_bfd));
-             ret_val = FALSE;
-             continue;
-           }
-         goto finish_pcrel;
-
        case R_IA64_PCREL21B:
        case R_IA64_PCREL60B:
          /* We should have created a PLT entry for any dynamic symbol.  */
@@ -4093,14 +4255,37 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section,
            }
          goto finish_pcrel;
 
+       case R_IA64_PCREL21BI:
+       case R_IA64_PCREL21F:
+       case R_IA64_PCREL21M:
        case R_IA64_PCREL22:
        case R_IA64_PCREL64I:
+         /* The PCREL21BI reloc is specifically not intended for use with
+            dynamic relocs.  PCREL21F and PCREL21M are used for speculation
+            fixup code, and thus probably ought not be dynamic.  The
+            PCREL22 and PCREL64I relocs aren't emitted as dynamic relocs.  */
+         if (dynamic_symbol_p)
+           {
+             const char *msg;
+
+             if (r_type == R_IA64_PCREL21BI)
+               msg = _("%B: @internal branch to dynamic symbol %s");
+             else if (r_type == R_IA64_PCREL21F || r_type == R_IA64_PCREL21M)
+               msg = _("%B: speculation fixup to dynamic symbol %s");
+             else
+               msg = _("%B: @pcrel relocation against dynamic symbol %s");
+             (*_bfd_error_handler) (msg, input_bfd, h->root.root.string);
+             ret_val = FALSE;
+             continue;
+           }
+         goto finish_pcrel;
+
        finish_pcrel:
          /* Make pc-relative.  */
          value -= (input_section->output_section->vma
                    + input_section->output_offset
                    + rel->r_offset) & ~ (bfd_vma) 0x3;
-         r = elfNN_ia64_install_value (output_bfd, hit_addr, value, r_type);
+         r = elfNN_ia64_install_value (hit_addr, value, r_type);
          break;
 
        case R_IA64_SEGREL32MSB:
@@ -4126,7 +4311,7 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section,
                {
                  int i;
                  for (i = m->count - 1; i >= 0; i--)
-                   if (m->sections[i] == sym_sec->output_section)
+                   if (m->sections[i] == input_section->output_section)
                      break;
                  if (i >= 0)
                    break;
@@ -4144,8 +4329,7 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section,
                    value -= p->p_vaddr;
                  else
                    value = 0;
-                 r = elfNN_ia64_install_value (output_bfd, hit_addr, value,
-                                               r_type);
+                 r = elfNN_ia64_install_value (hit_addr, value, r_type);
                }
              break;
            }
@@ -4159,7 +4343,7 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section,
            value -= input_section->output_section->vma;
          else
            value = 0;
-         r = elfNN_ia64_install_value (output_bfd, hit_addr, value, r_type);
+         r = elfNN_ia64_install_value (hit_addr, value, r_type);
          break;
 
        case R_IA64_IPLTMSB:
@@ -4172,7 +4356,7 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section,
 
              /* If we don't need dynamic symbol lookup, install two
                 RELATIVE relocations.  */
-             if (! dynamic_symbol_p)
+             if (!dynamic_symbol_p)
                {
                  unsigned int dyn_r_type;
 
@@ -4200,23 +4384,24 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section,
            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);
+         elfNN_ia64_install_value (hit_addr, value, r_type);
+         r = elfNN_ia64_install_value (hit_addr + 8, gp_val, 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);
+         r = elfNN_ia64_install_value (hit_addr, value, r_type);
          break;
 
        case R_IA64_DTPREL14:
        case R_IA64_DTPREL22:
        case R_IA64_DTPREL64I:
+       case R_IA64_DTPREL64LSB:
+       case R_IA64_DTPREL64MSB:
          value -= elfNN_ia64_dtprel_base (info);
-         r = elfNN_ia64_install_value (output_bfd, hit_addr, value, r_type);
+         r = elfNN_ia64_install_value (hit_addr, value, r_type);
          break;
 
        case R_IA64_LTOFF_TPREL22:
@@ -4224,13 +4409,23 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section,
        case R_IA64_LTOFF_DTPREL22:
          {
            int got_r_type;
+           long dynindx = h ? h->dynindx : -1;
+           bfd_vma r_addend = rel->r_addend;
 
            switch (r_type)
              {
              default:
              case R_IA64_LTOFF_TPREL22:
-               if (!dynamic_symbol_p && !info->shared)
-                 value -= elfNN_ia64_tprel_base (info);
+               if (!dynamic_symbol_p)
+                 {
+                   if (!info->shared)
+                     value -= elfNN_ia64_tprel_base (info);
+                   else
+                     {
+                       r_addend += value - elfNN_ia64_dtprel_base (info);
+                       dynindx = 0;
+                     }
+                 }
                got_r_type = R_IA64_TPREL64LSB;
                break;
              case R_IA64_LTOFF_DTPMOD22:
@@ -4245,12 +4440,10 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section,
                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 = set_got_entry (input_bfd, info, dyn_i, dynindx, r_addend,
                                   value, got_r_type);
            value -= gp_val;
-           r = elfNN_ia64_install_value (output_bfd, hit_addr, value,
-                                         r_type);
+           r = elfNN_ia64_install_value (hit_addr, value, r_type);
          }
          break;
 
@@ -4304,7 +4497,7 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section,
            const char *name;
 
            if (h)
-             name = h->root.root.string;
+             name = NULL;
            else
              {
                name = bfd_elf_string_from_elf_section (input_bfd,
@@ -4313,10 +4506,10 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section,
                if (name == NULL)
                  return FALSE;
                if (*name == '\0')
-                 name = bfd_section_name (input_bfd, input_section);
+                 name = bfd_section_name (input_bfd, sym_sec);
              }
-           if (!(*info->callbacks->reloc_overflow) (info, name,
-                                                    howto->name,
+           if (!(*info->callbacks->reloc_overflow) (info, &h->root,
+                                                    name, howto->name,
                                                     (bfd_vma) 0,
                                                     input_bfd,
                                                     input_section,
@@ -4361,9 +4554,8 @@ elfNN_ia64_finish_dynamic_symbol (output_bfd, info, h, sym)
       loc = plt_sec->contents + dyn_i->plt_offset;
 
       memcpy (loc, plt_min_entry, PLT_MIN_ENTRY_SIZE);
-      elfNN_ia64_install_value (output_bfd, loc, index, R_IA64_IMM22);
-      elfNN_ia64_install_value (output_bfd, loc+2, -dyn_i->plt_offset,
-                               R_IA64_PCREL21B);
+      elfNN_ia64_install_value (loc, index, R_IA64_IMM22);
+      elfNN_ia64_install_value (loc+2, -dyn_i->plt_offset, R_IA64_PCREL21B);
 
       plt_addr = (plt_sec->output_section->vma
                  + plt_sec->output_offset
@@ -4376,14 +4568,13 @@ elfNN_ia64_finish_dynamic_symbol (output_bfd, info, h, sym)
          loc = plt_sec->contents + dyn_i->plt2_offset;
 
          memcpy (loc, plt_full_entry, PLT_FULL_ENTRY_SIZE);
-         elfNN_ia64_install_value (output_bfd, loc, pltoff_addr - gp_val,
-                                   R_IA64_IMM22);
+         elfNN_ia64_install_value (loc, pltoff_addr - gp_val, R_IA64_IMM22);
 
          /* Mark the symbol as undefined, rather than as defined in the
             plt section.  Leave the value alone.  */
          /* ??? We didn't redefine it in adjust_dynamic_symbol in the
-            first place.  But perhaps elflink.h did some for us.  */
-         if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
+            first place.  But perhaps elflink.c did some for us.  */
+         if (!h->def_regular)
            sym->st_shndx = SHN_UNDEF;
        }
 
@@ -4409,7 +4600,7 @@ elfNN_ia64_finish_dynamic_symbol (output_bfd, info, h, sym)
 
       loc = ia64_info->rel_pltoff_sec->contents;
       loc += ((ia64_info->rel_pltoff_sec->reloc_count + index)
-             * sizeof (Elf64_External_Rela));
+             * sizeof (ElfNN_External_Rela));
       bfd_elfNN_swap_reloca_out (output_bfd, &outrel, loc);
     }
 
@@ -4443,7 +4634,7 @@ elfNN_ia64_finish_dynamic_sections (abfd, info)
       sgotplt = bfd_get_section_by_name (dynobj, ".got.plt");
       BFD_ASSERT (sdyn != NULL);
       dyncon = (ElfNN_External_Dyn *) sdyn->contents;
-      dynconend = (ElfNN_External_Dyn *) (sdyn->contents + sdyn->_raw_size);
+      dynconend = (ElfNN_External_Dyn *) (sdyn->contents + sdyn->size);
 
       gp_val = _bfd_get_gp_value (abfd);
 
@@ -4488,7 +4679,7 @@ elfNN_ia64_finish_dynamic_sections (abfd, info)
          bfd_elfNN_swap_dyn_out (abfd, &dyn, dyncon);
        }
 
-      /* Initialize the PLT0 entry */
+      /* Initialize the PLT0 entry */
       if (ia64_info->plt_sec)
        {
          bfd_byte *loc = ia64_info->plt_sec->contents;
@@ -4500,14 +4691,14 @@ elfNN_ia64_finish_dynamic_sections (abfd, info)
                    + sgotplt->output_offset
                    - gp_val);
 
-         elfNN_ia64_install_value (abfd, loc+1, pltres, R_IA64_GPREL22);
+         elfNN_ia64_install_value (loc+1, pltres, R_IA64_GPREL22);
        }
     }
 
   return TRUE;
 }
 \f
-/* ELF file flag handling: */
+/* ELF file flag handling:  */
 
 /* Function to keep IA-64 specific file flags.  */
 static bfd_boolean
@@ -4567,8 +4758,8 @@ elfNN_ia64_merge_private_bfd_data (ibfd, obfd)
   if ((in_flags & EF_IA_64_TRAPNIL) != (out_flags & EF_IA_64_TRAPNIL))
     {
       (*_bfd_error_handler)
-       (_("%s: linking trap-on-NULL-dereference with non-trapping files"),
-        bfd_archive_filename (ibfd));
+       (_("%B: linking trap-on-NULL-dereference with non-trapping files"),
+        ibfd);
 
       bfd_set_error (bfd_error_bad_value);
       ok = FALSE;
@@ -4576,8 +4767,8 @@ elfNN_ia64_merge_private_bfd_data (ibfd, obfd)
   if ((in_flags & EF_IA_64_BE) != (out_flags & EF_IA_64_BE))
     {
       (*_bfd_error_handler)
-       (_("%s: linking big-endian files with little-endian files"),
-        bfd_archive_filename (ibfd));
+       (_("%B: linking big-endian files with little-endian files"),
+        ibfd);
 
       bfd_set_error (bfd_error_bad_value);
       ok = FALSE;
@@ -4585,8 +4776,8 @@ elfNN_ia64_merge_private_bfd_data (ibfd, obfd)
   if ((in_flags & EF_IA_64_ABI64) != (out_flags & EF_IA_64_ABI64))
     {
       (*_bfd_error_handler)
-       (_("%s: linking 64-bit files with 32-bit files"),
-        bfd_archive_filename (ibfd));
+       (_("%B: linking 64-bit files with 32-bit files"),
+        ibfd);
 
       bfd_set_error (bfd_error_bad_value);
       ok = FALSE;
@@ -4594,8 +4785,8 @@ elfNN_ia64_merge_private_bfd_data (ibfd, obfd)
   if ((in_flags & EF_IA_64_CONS_GP) != (out_flags & EF_IA_64_CONS_GP))
     {
       (*_bfd_error_handler)
-       (_("%s: linking constant-gp files with non-constant-gp files"),
-        bfd_archive_filename (ibfd));
+       (_("%B: linking constant-gp files with non-constant-gp files"),
+        ibfd);
 
       bfd_set_error (bfd_error_bad_value);
       ok = FALSE;
@@ -4604,8 +4795,8 @@ elfNN_ia64_merge_private_bfd_data (ibfd, obfd)
       != (out_flags & EF_IA_64_NOFUNCDESC_CONS_GP))
     {
       (*_bfd_error_handler)
-       (_("%s: linking auto-pic files with non-auto-pic files"),
-        bfd_archive_filename (ibfd));
+       (_("%B: linking auto-pic files with non-auto-pic files"),
+        ibfd);
 
       bfd_set_error (bfd_error_bad_value);
       ok = FALSE;
@@ -4659,6 +4850,13 @@ elfNN_ia64_reloc_type_class (rela)
     }
 }
 
+static struct bfd_elf_special_section const elfNN_ia64_special_sections[]=
+{
+  { ".sbss",  5, -1, SHT_NOBITS,   SHF_ALLOC + SHF_WRITE + SHF_IA_64_SHORT },
+  { ".sdata", 6, -1, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE + SHF_IA_64_SHORT },
+  { NULL,     0,  0, 0,            0 }
+};
+
 static bfd_boolean
 elfNN_ia64_hpux_vec (const bfd_target *vec)
 {
@@ -4690,6 +4888,23 @@ elfNN_hpux_backend_section_from_bfd_section (abfd, sec, retval)
     }
   return FALSE;
 }
+
+static void
+elfNN_hpux_backend_symbol_processing (bfd *abfd ATTRIBUTE_UNUSED,
+                                     asymbol *asym)
+{
+  elf_symbol_type *elfsym = (elf_symbol_type *) asym;;
+
+  switch (elfsym->internal_elf_sym.st_shndx)
+    {
+    case SHN_IA_64_ANSI_COMMON:
+      asym->section = bfd_com_section_ptr;
+      asym->value = elfsym->internal_elf_sym.st_size;
+      asym->flags &= ~BSF_GLOBAL;
+      break;
+    }
+}
+
 \f
 #define TARGET_LITTLE_SYM              bfd_elfNN_ia64_little_vec
 #define TARGET_LITTLE_NAME             "elfNN-ia64-little"
@@ -4728,6 +4943,8 @@ elfNN_hpux_backend_section_from_bfd_section (abfd, sec, retval)
 /* Stuff for the BFD linker: */
 #define bfd_elfNN_bfd_link_hash_table_create \
        elfNN_ia64_hash_table_create
+#define bfd_elfNN_bfd_link_hash_table_free \
+       elfNN_ia64_hash_table_free
 #define elf_backend_create_dynamic_sections \
        elfNN_ia64_create_dynamic_sections
 #define elf_backend_check_relocs \
@@ -4756,7 +4973,6 @@ elfNN_hpux_backend_section_from_bfd_section (abfd, sec, retval)
 #define elf_backend_want_plt_sym       0
 #define elf_backend_plt_alignment      5
 #define elf_backend_got_header_size    0
-#define elf_backend_plt_header_size    PLT_HEADER_SIZE
 #define elf_backend_want_got_plt       1
 #define elf_backend_may_use_rel_p      1
 #define elf_backend_may_use_rela_p     1
@@ -4766,27 +4982,14 @@ elfNN_hpux_backend_section_from_bfd_section (abfd, sec, retval)
 #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
+#define elf_backend_special_sections   elfNN_ia64_special_sections
 
-#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
+/* FIXME: PR 290: The Intel C compiler generates SHT_IA_64_UNWIND with
+   SHF_LINK_ORDER. But it doesn't set theh sh_link or sh_info fields.
+   We don't want to flood users with so many error messages. We turn
+   off the warning for now. It will be turned on later when the Intel
+   compiler is fixed.   */
+#define elf_backend_link_order_error_handler NULL
 
 #include "elfNN-target.h"
 
@@ -4799,14 +5002,6 @@ elfNN_hpux_backend_section_from_bfd_section (abfd, sec, retval)
 #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
@@ -4815,6 +5010,9 @@ elfNN_hpux_backend_section_from_bfd_section (abfd, sec, retval)
 #undef  elf_backend_section_from_bfd_section
 #define elf_backend_section_from_bfd_section elfNN_hpux_backend_section_from_bfd_section
 
+#undef elf_backend_symbol_processing
+#define elf_backend_symbol_processing elfNN_hpux_backend_symbol_processing
+
 #undef  elf_backend_want_p_paddr_set_to_zero
 #define elf_backend_want_p_paddr_set_to_zero 1
 
This page took 0.079703 seconds and 4 git commands to generate.