* elf32-sh.c (sh_elf_relocate_section): Don't complain about
[deliverable/binutils-gdb.git] / bfd / elfxx-ia64.c
index 8f43563c43852987d08ee946c3d0cff69ca9daab..ddd86fbfda52aa86234560903888dbc237851a5a 100644 (file)
@@ -1,22 +1,22 @@
 /* IA-64 support for 64-bit ELF
-   Copyright 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+   Copyright 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
    Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
 
-This file is part of BFD, the Binary File Descriptor library.
+   This file is part of BFD, the Binary File Descriptor library.
 
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
-(at your option) any later version.
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
 
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
 
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
 #include "bfd.h"
 #include "sysdep.h"
@@ -25,37 +25,33 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 #include "opcode/ia64.h"
 #include "elf/ia64.h"
 
-/*
- * THE RULES for all the stuff the linker creates --
- *
- * GOT         Entries created in response to LTOFF or LTOFF_FPTR
- *             relocations.  Dynamic relocs created for dynamic
- *             symbols in an application; REL relocs for locals
- *             in a shared library.
- *
- * FPTR                The canonical function descriptor.  Created for local
- *             symbols in applications.  Descriptors for dynamic symbols
- *             and local symbols in shared libraries are created by
- *             ld.so.  Thus there are no dynamic relocs against these
- *             objects.  The FPTR relocs for such _are_ passed through
- *             to the dynamic relocation tables.
- *
- * FULL_PLT    Created for a PCREL21B relocation against a dynamic symbol.
- *             Requires the creation of a PLTOFF entry.  This does not
- *             require any dynamic relocations.
- *
- * PLTOFF      Created by PLTOFF relocations.  For local symbols, this
- *             is an alternate function descriptor, and in shared libraries
- *             requires two REL relocations.  Note that this cannot be
- *             transformed into an FPTR relocation, since it must be in
- *             range of the GP.  For dynamic symbols, this is a function
- *             descriptor for a MIN_PLT entry, and requires one IPLT reloc.
- *
- * MIN_PLT     Created by PLTOFF entries against dynamic symbols.  This
- *             does not reqire dynamic relocations.
- */
-
-#define USE_RELA               /* we want RELA relocs, not REL */
+/* THE RULES for all the stuff the linker creates --
+  GOT          Entries created in response to LTOFF or LTOFF_FPTR
+               relocations.  Dynamic relocs created for dynamic
+               symbols in an application; REL relocs for locals
+               in a shared library.
+  FPTR         The canonical function descriptor.  Created for local
+               symbols in applications.  Descriptors for dynamic symbols
+               and local symbols in shared libraries are created by
+               ld.so.  Thus there are no dynamic relocs against these
+               objects.  The FPTR relocs for such _are_ passed through
+               to the dynamic relocation tables.
+  FULL_PLT     Created for a PCREL21B relocation against a dynamic symbol.
+               Requires the creation of a PLTOFF entry.  This does not
+               require any dynamic relocations.
+  PLTOFF       Created by PLTOFF relocations.  For local symbols, this
+               is an alternate function descriptor, and in shared libraries
+               requires two REL relocations.  Note that this cannot be
+               transformed into an FPTR relocation, since it must be in
+               range of the GP.  For dynamic symbols, this is a function
+               descriptor for a MIN_PLT entry, and requires one IPLT reloc.
+  MIN_PLT      Created by PLTOFF entries against dynamic symbols.  This
+               does not reqire dynamic relocations.  */
 
 #define NELEMS(a)      ((int) (sizeof (a) / sizeof ((a)[0])))
 
@@ -79,6 +75,9 @@ struct elfNN_ia64_dyn_sym_info
   bfd_vma pltoff_offset;
   bfd_vma plt_offset;
   bfd_vma plt2_offset;
+  bfd_vma tprel_offset;
+  bfd_vma dtpmod_offset;
+  bfd_vma dtprel_offset;
 
   /* The symbol table entry, if any, that this was derrived from.  */
   struct elf_link_hash_entry *h;
@@ -97,6 +96,9 @@ struct elfNN_ia64_dyn_sym_info
   unsigned got_done : 1;
   unsigned fptr_done : 1;
   unsigned pltoff_done : 1;
+  unsigned tprel_done : 1;
+  unsigned dtpmod_done : 1;
+  unsigned dtprel_done : 1;
 
   /* True for the different kinds of linker data we want created.  */
   unsigned want_got : 1;
@@ -105,6 +107,9 @@ struct elfNN_ia64_dyn_sym_info
   unsigned want_plt : 1;
   unsigned want_plt2 : 1;
   unsigned want_pltoff : 1;
+  unsigned want_tprel : 1;
+  unsigned want_dtpmod : 1;
+  unsigned want_dtprel : 1;
 };
 
 struct elfNN_ia64_local_hash_entry
@@ -131,7 +136,7 @@ struct elfNN_ia64_link_hash_entry
 
 struct elfNN_ia64_link_hash_table
 {
-  /* The main hash table */
+  /* The main hash table */
   struct elf_link_hash_table root;
 
   asection *got_sec;           /* the linkage table section (or NULL) */
@@ -163,9 +168,9 @@ static boolean elfNN_ia64_relax_section
   PARAMS((bfd *abfd, asection *sec, struct bfd_link_info *link_info,
          boolean *again));
 static boolean is_unwind_section_name
-  PARAMS ((const char *));
+  PARAMS ((bfd *abfd, const char *));
 static boolean elfNN_ia64_section_from_shdr
-  PARAMS ((bfd *, ElfNN_Internal_Shdr *, char *));
+  PARAMS ((bfd *, ElfNN_Internal_Shdr *, const char *));
 static boolean elfNN_ia64_section_flags
   PARAMS ((flagword *, ElfNN_Internal_Shdr *));
 static boolean elfNN_ia64_fake_sections
@@ -202,9 +207,10 @@ static struct bfd_hash_entry *elfNN_ia64_new_elf_hash_entry
   PARAMS ((struct bfd_hash_entry *entry, struct bfd_hash_table *table,
           const char *string));
 static void elfNN_ia64_hash_copy_indirect
-  PARAMS ((struct elf_link_hash_entry *, struct elf_link_hash_entry *));
+  PARAMS ((struct elf_backend_data *, struct elf_link_hash_entry *,
+          struct elf_link_hash_entry *));
 static void elfNN_ia64_hash_hide_symbol
-  PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *));
+  PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *, boolean));
 static struct bfd_link_hash_table *elfNN_ia64_hash_table_create
   PARAMS ((bfd *abfd));
 static struct elfNN_ia64_local_hash_entry *elfNN_ia64_local_hash_lookup
@@ -285,6 +291,10 @@ static bfd_vma set_pltoff_entry
   PARAMS ((bfd *abfd, struct bfd_link_info *info,
           struct elfNN_ia64_dyn_sym_info *dyn_i,
           bfd_vma value, boolean));
+static bfd_vma elfNN_ia64_tprel_base
+  PARAMS ((struct bfd_link_info *info));
+static bfd_vma elfNN_ia64_dtprel_base
+  PARAMS ((struct bfd_link_info *info));
 static int elfNN_ia64_unwind_entry_compare
   PARAMS ((const PTR, const PTR));
 static boolean elfNN_ia64_final_link
@@ -301,16 +311,20 @@ static boolean elfNN_ia64_finish_dynamic_sections
   PARAMS ((bfd *abfd, struct bfd_link_info *info));
 static boolean elfNN_ia64_set_private_flags
   PARAMS ((bfd *abfd, flagword flags));
-static boolean elfNN_ia64_copy_private_bfd_data
-  PARAMS ((bfd *ibfd, bfd *obfd));
 static boolean elfNN_ia64_merge_private_bfd_data
   PARAMS ((bfd *ibfd, bfd *obfd));
 static boolean elfNN_ia64_print_private_bfd_data
   PARAMS ((bfd *abfd, PTR ptr));
 static enum elf_reloc_type_class elfNN_ia64_reloc_type_class
   PARAMS ((const Elf_Internal_Rela *));
+static boolean elfNN_ia64_hpux_vec
+  PARAMS ((const bfd_target *vec));
+static void elfNN_hpux_post_process_headers
+  PARAMS ((bfd *abfd, struct bfd_link_info *info));
+boolean elfNN_hpux_backend_section_from_bfd_section
+  PARAMS ((bfd *abfd, asection *sec, int *retval));
 \f
-/* ia64-specific relocation */
+/* ia64-specific relocation */
 
 /* Perform a relocation.  Not much to do here as all the hard work is
    done in elfNN_ia64_final_link_relocate.  */
@@ -419,17 +433,32 @@ static reloc_howto_type ia64_howto_table[] =
     IA64_HOWTO (R_IA64_LTOFF22X,    "LTOFF22X",           0, false, true),
     IA64_HOWTO (R_IA64_LDXMOV,     "LDXMOV",      0, false, true),
 
+    IA64_HOWTO (R_IA64_TPREL14,            "TPREL14",     0, false, false),
     IA64_HOWTO (R_IA64_TPREL22,            "TPREL22",     0, false, false),
+    IA64_HOWTO (R_IA64_TPREL64I,    "TPREL64I",           0, false, false),
     IA64_HOWTO (R_IA64_TPREL64MSB,  "TPREL64MSB",  8, false, false),
     IA64_HOWTO (R_IA64_TPREL64LSB,  "TPREL64LSB",  8, false, false),
-    IA64_HOWTO (R_IA64_LTOFF_TP22,  "LTOFF_TP22",  0, false, false),
+    IA64_HOWTO (R_IA64_LTOFF_TPREL22, "LTOFF_TPREL22",  0, false, false),
+
+    IA64_HOWTO (R_IA64_DTPMOD64MSB, "TPREL64MSB",  8, false, false),
+    IA64_HOWTO (R_IA64_DTPMOD64LSB, "TPREL64LSB",  8, false, false),
+    IA64_HOWTO (R_IA64_LTOFF_DTPMOD22, "LTOFF_DTPMOD22", 0, false, false),
+
+    IA64_HOWTO (R_IA64_DTPREL14,    "DTPREL14",           0, false, false),
+    IA64_HOWTO (R_IA64_DTPREL22,    "DTPREL22",           0, false, false),
+    IA64_HOWTO (R_IA64_DTPREL64I,   "DTPREL64I",   0, false, false),
+    IA64_HOWTO (R_IA64_DTPREL32MSB, "DTPREL32MSB", 4, false, false),
+    IA64_HOWTO (R_IA64_DTPREL32LSB, "DTPREL32LSB", 4, false, false),
+    IA64_HOWTO (R_IA64_DTPREL64MSB, "DTPREL64MSB", 8, false, false),
+    IA64_HOWTO (R_IA64_DTPREL64LSB, "DTPREL64LSB", 8, false, false),
+    IA64_HOWTO (R_IA64_LTOFF_DTPREL22, "LTOFF_DTPREL22", 0, false, false),
   };
 
 static unsigned char elf_code_to_howto_index[R_IA64_MAX_RELOC_CODE + 1];
 
 /* Given a BFD reloc type, return the matching HOWTO structure.  */
 
-static reloc_howto_type*
+static reloc_howto_type *
 lookup_howto (rtype)
      unsigned int rtype;
 {
@@ -537,10 +566,25 @@ elfNN_ia64_reloc_type_lookup (abfd, bfd_code)
     case BFD_RELOC_IA64_LTOFF22X:      rtype = R_IA64_LTOFF22X; break;
     case BFD_RELOC_IA64_LDXMOV:                rtype = R_IA64_LDXMOV; break;
 
+    case BFD_RELOC_IA64_TPREL14:       rtype = R_IA64_TPREL14; break;
     case BFD_RELOC_IA64_TPREL22:       rtype = R_IA64_TPREL22; break;
+    case BFD_RELOC_IA64_TPREL64I:      rtype = R_IA64_TPREL64I; break;
     case BFD_RELOC_IA64_TPREL64MSB:    rtype = R_IA64_TPREL64MSB; break;
     case BFD_RELOC_IA64_TPREL64LSB:    rtype = R_IA64_TPREL64LSB; break;
-    case BFD_RELOC_IA64_LTOFF_TP22:    rtype = R_IA64_LTOFF_TP22; break;
+    case BFD_RELOC_IA64_LTOFF_TPREL22: rtype = R_IA64_LTOFF_TPREL22; break;
+
+    case BFD_RELOC_IA64_DTPMOD64MSB:   rtype = R_IA64_DTPMOD64MSB; break;
+    case BFD_RELOC_IA64_DTPMOD64LSB:   rtype = R_IA64_DTPMOD64LSB; break;
+    case BFD_RELOC_IA64_LTOFF_DTPMOD22:        rtype = R_IA64_LTOFF_DTPMOD22; break;
+
+    case BFD_RELOC_IA64_DTPREL14:      rtype = R_IA64_DTPREL14; break;
+    case BFD_RELOC_IA64_DTPREL22:      rtype = R_IA64_DTPREL22; break;
+    case BFD_RELOC_IA64_DTPREL64I:     rtype = R_IA64_DTPREL64I; break;
+    case BFD_RELOC_IA64_DTPREL32MSB:   rtype = R_IA64_DTPREL32MSB; break;
+    case BFD_RELOC_IA64_DTPREL32LSB:   rtype = R_IA64_DTPREL32LSB; break;
+    case BFD_RELOC_IA64_DTPREL64MSB:   rtype = R_IA64_DTPREL64MSB; break;
+    case BFD_RELOC_IA64_DTPREL64LSB:   rtype = R_IA64_DTPREL64LSB; break;
+    case BFD_RELOC_IA64_LTOFF_DTPREL22:        rtype = R_IA64_LTOFF_DTPREL22; break;
 
     default: return 0;
     }
@@ -603,13 +647,14 @@ static const bfd_byte plt_full_entry[PLT_FULL_ENTRY_SIZE] =
    not support brl, and so it gets emulated by the kernel.  */
 #undef USE_BRL
 
+#ifdef USE_BRL
 static const bfd_byte oor_brl[16] =
 {
   0x05, 0x00, 0x00, 0x00, 0x01, 0x00,  /*  [MLX]        nop.m 0            */
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /*               brl.sptk.few tgt;; */
   0x00, 0x00, 0x00, 0xc0
 };
-
+#else
 static const bfd_byte oor_ip[48] =
 {
   0x04, 0x00, 0x00, 0x00, 0x01, 0x00,  /*  [MLX]        nop.m 0            */
@@ -622,6 +667,7 @@ static const bfd_byte oor_ip[48] =
   0x60, 0x80, 0x04, 0x80, 0x03, 0x00,  /*               mov b6=r16         */
   0x60, 0x00, 0x80, 0x00               /*               br b6;;            */
 };
+#endif
 \f
 /* These functions do relaxation for IA-64 ELF.
 
@@ -644,15 +690,10 @@ elfNN_ia64_relax_section (abfd, sec, link_info, again)
     };
 
   Elf_Internal_Shdr *symtab_hdr;
-  Elf_Internal_Shdr *shndx_hdr;
   Elf_Internal_Rela *internal_relocs;
-  Elf_Internal_Rela *free_relocs = NULL;
   Elf_Internal_Rela *irel, *irelend;
   bfd_byte *contents;
-  bfd_byte *free_contents = NULL;
-  ElfNN_External_Sym *extsyms;
-  ElfNN_External_Sym *free_extsyms = NULL;
-  Elf_External_Sym_Shndx *shndx_buf = NULL;
+  Elf_Internal_Sym *isymbuf = NULL;
   struct elfNN_ia64_link_hash_table *ia64_info;
   struct one_fixup *fixups = NULL;
   boolean changed_contents = false;
@@ -679,23 +720,22 @@ elfNN_ia64_relax_section (abfd, sec, link_info, again)
                     (abfd, sec, (PTR) NULL, (Elf_Internal_Rela *) NULL,
                      link_info->keep_memory));
   if (internal_relocs == NULL)
-    goto error_return;
-
-  if (! link_info->keep_memory)
-    free_relocs = internal_relocs;
+    return false;
 
   ia64_info = elfNN_ia64_hash_table (link_info);
   irelend = internal_relocs + sec->reloc_count;
 
   for (irel = internal_relocs; irel < irelend; irel++)
-    if (ELFNN_R_TYPE (irel->r_info) == (int) R_IA64_PCREL21B)
+    if (ELFNN_R_TYPE (irel->r_info) == (int) R_IA64_PCREL21B
+       || ELFNN_R_TYPE (irel->r_info) == (int) R_IA64_PCREL21M
+       || ELFNN_R_TYPE (irel->r_info) == (int) R_IA64_PCREL21F)
       break;
 
   /* No branch-type relocations.  */
   if (irel == irelend)
     {
-      if (free_relocs != NULL)
-       free (free_relocs);
+      if (elf_section_data (sec)->relocs != internal_relocs)
+       free (internal_relocs);
       return true;
     }
 
@@ -707,75 +747,55 @@ elfNN_ia64_relax_section (abfd, sec, link_info, again)
       contents = (bfd_byte *) bfd_malloc (sec->_raw_size);
       if (contents == NULL)
        goto error_return;
-      free_contents = contents;
 
       if (! bfd_get_section_contents (abfd, sec, contents,
                                      (file_ptr) 0, sec->_raw_size))
        goto error_return;
     }
 
-  /* Read this BFD's local symbols.  */
-  if (symtab_hdr->contents != NULL)
-    extsyms = (ElfNN_External_Sym *) symtab_hdr->contents;
-  else
-    {
-      bfd_size_type amt;
-
-      amt = symtab_hdr->sh_info * sizeof (ElfNN_External_Sym);
-      extsyms = (ElfNN_External_Sym *) bfd_malloc (amt);
-      if (extsyms == NULL)
-       goto error_return;
-      free_extsyms = extsyms;
-      if (bfd_seek (abfd, symtab_hdr->sh_offset, SEEK_SET) != 0
-         || bfd_bread (extsyms, amt, abfd) != amt)
-       goto error_return;
-    }
-
-  shndx_hdr = &elf_tdata (abfd)->symtab_shndx_hdr;
-  if (shndx_hdr->sh_size != 0)
-    {
-      bfd_size_type amt;
-
-      amt = symtab_hdr->sh_info * sizeof (Elf_External_Sym_Shndx);
-      shndx_buf = (Elf_External_Sym_Shndx *) bfd_malloc (amt);
-      if (shndx_buf == NULL)
-       goto error_return;
-      if (bfd_seek (abfd, shndx_hdr->sh_offset, SEEK_SET) != 0
-         || bfd_bread (shndx_buf, amt, abfd) != amt)
-       goto error_return;
-    }
-
   for (; irel < irelend; irel++)
     {
       bfd_vma symaddr, reladdr, trampoff, toff, roff;
-      Elf_Internal_Sym isym;
       asection *tsec;
       struct one_fixup *f;
       bfd_size_type amt;
 
-      if (ELFNN_R_TYPE (irel->r_info) != (int) R_IA64_PCREL21B)
+      if (ELFNN_R_TYPE (irel->r_info) != (int) R_IA64_PCREL21B
+         && ELFNN_R_TYPE (irel->r_info) != (int) R_IA64_PCREL21M
+         && ELFNN_R_TYPE (irel->r_info) != (int) R_IA64_PCREL21F)
        continue;
 
       /* Get the value of the symbol referred to by the reloc.  */
       if (ELFNN_R_SYM (irel->r_info) < symtab_hdr->sh_info)
        {
-         ElfNN_External_Sym *esym;
-         Elf_External_Sym_Shndx *shndx;
-
          /* A local symbol.  */
-         esym = extsyms + ELFNN_R_SYM (irel->r_info);
-         shndx = shndx_buf + (shndx_buf ? ELFNN_R_SYM (irel->r_info) : 0);
-         bfd_elfNN_swap_symbol_in (abfd, esym, shndx, &isym);
-         if (isym.st_shndx == SHN_UNDEF)
+         Elf_Internal_Sym *isym;
+
+         /* Read this BFD's local symbols.  */
+         if (isymbuf == NULL)
+           {
+             isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
+             if (isymbuf == NULL)
+               isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr,
+                                               symtab_hdr->sh_info, 0,
+                                               NULL, NULL, NULL);
+             if (isymbuf == 0)
+               goto error_return;
+           }
+
+         isym = isymbuf + ELF64_R_SYM (irel->r_info);
+         if (isym->st_shndx == SHN_UNDEF)
            continue;   /* We can't do anthing with undefined symbols.  */
-         else if (isym.st_shndx == SHN_ABS)
+         else if (isym->st_shndx == SHN_ABS)
            tsec = bfd_abs_section_ptr;
-         else if (isym.st_shndx == SHN_COMMON)
+         else if (isym->st_shndx == SHN_COMMON)
+           tsec = bfd_com_section_ptr;
+         else if (isym->st_shndx == SHN_IA_64_ANSI_COMMON)
            tsec = bfd_com_section_ptr;
          else
-           tsec = bfd_section_from_elf_index (abfd, isym.st_shndx);
+           tsec = bfd_section_from_elf_index (abfd, isym->st_shndx);
 
-         toff = isym.st_value;
+         toff = isym->st_value;
        }
       else
        {
@@ -923,61 +943,66 @@ elfNN_ia64_relax_section (abfd, sec, link_info, again)
       free (f);
     }
 
-  if (changed_relocs)
-    elf_section_data (sec)->relocs = internal_relocs;
-  else if (free_relocs != NULL)
-    free (free_relocs);
-
-  if (changed_contents)
-    elf_section_data (sec)->this_hdr.contents = contents;
-  else if (free_contents != NULL)
+  if (isymbuf != NULL
+      && symtab_hdr->contents != (unsigned char *) isymbuf)
     {
       if (! link_info->keep_memory)
-       free (free_contents);
+       free (isymbuf);
       else
        {
-         /* Cache the section contents for elf_link_input_bfd.  */
-         elf_section_data (sec)->this_hdr.contents = contents;
+         /* Cache the symbols for elf_link_input_bfd.  */
+         symtab_hdr->contents = (unsigned char *) isymbuf;
        }
     }
 
-  if (shndx_buf != NULL)
-    free (shndx_buf);
-
-  if (free_extsyms != NULL)
+  if (contents != NULL
+      && elf_section_data (sec)->this_hdr.contents != contents)
     {
-      if (! link_info->keep_memory)
-       free (free_extsyms);
+      if (!changed_contents && !link_info->keep_memory)
+       free (contents);
       else
        {
-         /* Cache the symbols for elf_link_input_bfd.  */
-         symtab_hdr->contents = (unsigned char *) extsyms;
+         /* Cache the section contents for elf_link_input_bfd.  */
+         elf_section_data (sec)->this_hdr.contents = contents;
        }
     }
 
+  if (elf_section_data (sec)->relocs != internal_relocs)
+    {
+      if (!changed_relocs)
+       free (internal_relocs);
+      else
+       elf_section_data (sec)->relocs = internal_relocs;
+    }
+
   *again = changed_contents || changed_relocs;
   return true;
 
  error_return:
-  if (free_relocs != NULL)
-    free (free_relocs);
-  if (free_contents != NULL)
-    free (free_contents);
-  if (shndx_buf != NULL)
-    free (shndx_buf);
-  if (free_extsyms != NULL)
-    free (free_extsyms);
+  if (isymbuf != NULL && (unsigned char *) isymbuf != symtab_hdr->contents)
+    free (isymbuf);
+  if (contents != NULL
+      && elf_section_data (sec)->this_hdr.contents != contents)
+    free (contents);
+  if (internal_relocs != NULL
+      && elf_section_data (sec)->relocs != internal_relocs)
+    free (internal_relocs);
   return false;
 }
 \f
 /* Return true if NAME is an unwind table section name.  */
 
 static inline boolean
-is_unwind_section_name (name)
+is_unwind_section_name (abfd, name)
+       bfd *abfd;
        const char *name;
 {
   size_t len1, len2, len3;
 
+  if (elfNN_ia64_hpux_vec (abfd->xvec)
+      && !strcmp (name, ELF_STRING_ia64_unwind_hdr))
+    return false;
+
   len1 = sizeof (ELF_STRING_ia64_unwind) - 1;
   len2 = sizeof (ELF_STRING_ia64_unwind_info) - 1;
   len3 = sizeof (ELF_STRING_ia64_unwind_once) - 1;
@@ -993,7 +1018,7 @@ static boolean
 elfNN_ia64_section_from_shdr (abfd, hdr, name)
      bfd *abfd;
      ElfNN_Internal_Shdr *hdr;
-     char *name;
+     const char *name;
 {
   asection *newsect;
 
@@ -1005,6 +1030,7 @@ elfNN_ia64_section_from_shdr (abfd, hdr, name)
   switch (hdr->sh_type)
     {
     case SHT_IA_64_UNWIND:
+    case SHT_IA_64_HP_OPT_ANOT:
       break;
 
     case SHT_IA_64_EXT:
@@ -1052,7 +1078,7 @@ elfNN_ia64_fake_sections (abfd, hdr, sec)
 
   name = bfd_get_section_name (abfd, sec);
 
-  if (is_unwind_section_name (name))
+  if (is_unwind_section_name (abfd, name))
     {
       /* We don't have the sections numbered at this point, so sh_info
         is set later, in elfNN_ia64_final_write_processing.  */
@@ -1061,25 +1087,25 @@ elfNN_ia64_fake_sections (abfd, hdr, sec)
     }
   else if (strcmp (name, ELF_STRING_ia64_archext) == 0)
     hdr->sh_type = SHT_IA_64_EXT;
+  else if (strcmp (name, ".HP.opt_annot") == 0)
+    hdr->sh_type = SHT_IA_64_HP_OPT_ANOT;
   else if (strcmp (name, ".reloc") == 0)
-    /*
-     * This is an ugly, but unfortunately necessary hack that is
-     * needed when producing EFI binaries on IA-64. It tells
-     * elf.c:elf_fake_sections() not to consider ".reloc" as a section
-     * containing ELF relocation info.  We need this hack in order to
-     * be able to generate ELF binaries that can be translated into
-     * EFI applications (which are essentially COFF objects).  Those
-     * files contain a COFF ".reloc" section inside an ELFNN object,
-     * which would normally cause BFD to segfault because it would
-     * attempt to interpret this section as containing relocation
-     * entries for section "oc".  With this hack enabled, ".reloc"
-     * will be treated as a normal data section, which will avoid the
-     * segfault.  However, you won't be able to create an ELFNN binary
-     * with a section named "oc" that needs relocations, but that's
-     * the kind of ugly side-effects you get when detecting section
-     * types based on their names...  In practice, this limitation is
-     * unlikely to bite.
-     */
+    /* This is an ugly, but unfortunately necessary hack that is
+       needed when producing EFI binaries on IA-64. It tells
+       elf.c:elf_fake_sections() not to consider ".reloc" as a section
+       containing ELF relocation info.  We need this hack in order to
+       be able to generate ELF binaries that can be translated into
+       EFI applications (which are essentially COFF objects).  Those
+       files contain a COFF ".reloc" section inside an ELFNN object,
+       which would normally cause BFD to segfault because it would
+       attempt to interpret this section as containing relocation
+       entries for section "oc".  With this hack enabled, ".reloc"
+       will be treated as a normal data section, which will avoid the
+       segfault.  However, you won't be able to create an ELFNN binary
+       with a section named "oc" that needs relocations, but that's
+       the kind of ugly side-effects you get when detecting section
+       types based on their names...  In practice, this limitation is
+       unlikely to bite.  */
     hdr->sh_type = SHT_PROGBITS;
 
   if (sec->flags & SEC_SMALL_DATA)
@@ -1128,11 +1154,29 @@ elfNN_ia64_final_write_processing (abfd, linker)
            {
              /* .gnu.linkonce.ia64unw.FOO -> .gnu.linkonce.t.FOO */
              size_t len2 = sizeof (".gnu.linkonce.t.") - 1;
-             char *once_name = alloca (len2 + strlen (sname) - len + 1);
+             char *once_name = bfd_malloc (len2 + strlen (sname + len) + 1);
 
-             memcpy (once_name, ".gnu.linkonce.t.", len2);
-             strcpy (once_name + len2, sname + len);
-             text_sect = bfd_get_section_by_name (abfd, once_name);
+             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 */
@@ -1150,6 +1194,19 @@ elfNN_ia64_final_write_processing (abfd, linker)
          break;
        }
     }
+
+  if (! elf_flags_init (abfd))
+    {
+      unsigned long flags = 0;
+
+      if (abfd->xvec->byteorder == BFD_ENDIAN_BIG)
+       flags |= EF_IA_64_BE;
+      if (bfd_get_mach (abfd) == bfd_mach_ia64_elf64)
+       flags |= EF_IA_64_ABI64;
+
+      elf_elfheader(abfd)->e_flags = flags;
+      elf_flags_init (abfd) = true;
+    }
 }
 
 /* Hook called by the linker routine which adds symbols from an object
@@ -1227,6 +1284,7 @@ elfNN_ia64_aix_add_symbol_hook (abfd, info, sym, namep, flagsp, secp, valp)
        {
          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);
@@ -1235,9 +1293,10 @@ elfNN_ia64_aix_add_symbol_hook (abfd, info, sym, namep, flagsp, secp, valp)
                (info, abfd, *namep, BSF_GLOBAL,
                 bfd_get_section_by_name (abfd, ".bss"),
                 bed->got_symbol_offset, (const char *) NULL, false,
-                bed->collect, (struct bfd_link_hash_entry **) &h)))
+                bed->collect, &bh)))
            return false;
 
+         h = (struct elf_link_hash_entry *) bh;
          h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR;
          h->type = STT_OBJECT;
 
@@ -1313,7 +1372,7 @@ elfNN_ia64_additional_program_headers (abfd)
 
   /* Count how many PT_IA_64_UNWIND segments we need.  */
   for (s = abfd->sections; s; s = s->next)
-    if (is_unwind_section_name(s->name) && (s->flags & SEC_LOAD))
+    if (is_unwind_section_name (abfd, s->name) && (s->flags & SEC_LOAD))
       ++ret;
 
   return ret;
@@ -1368,8 +1427,20 @@ elfNN_ia64_modify_segment_map (abfd)
       if (s && (s->flags & SEC_LOAD))
        {
          for (m = elf_tdata (abfd)->segment_map; m != NULL; m = m->next)
-           if (m->p_type == PT_IA_64_UNWIND && m->sections[0] == s)
-             break;
+           if (m->p_type == PT_IA_64_UNWIND)
+             {
+               int i;
+
+               /* Look through all sections in the unwind segment
+                  for a match since there may be multiple sections
+                  to a segment.  */
+               for (i = m->count - 1; i >= 0; --i)
+                 if (m->sections[i] == s)
+                   break;
+
+               if (i >= 0)
+                 break;
+             }
 
          if (m == NULL)
            {
@@ -1455,6 +1526,8 @@ elfNN_ia64_dynamic_symbol_p (h, info)
     case STV_INTERNAL:
     case STV_HIDDEN:
       return false;
+    default:
+      break;
     }
 
   if (h->root.type == bfd_link_hash_undefweak
@@ -1538,7 +1611,8 @@ elfNN_ia64_new_elf_hash_entry (entry, table, string)
 }
 
 static void
-elfNN_ia64_hash_copy_indirect (xdir, xind)
+elfNN_ia64_hash_copy_indirect (bed, xdir, xind)
+     struct elf_backend_data *bed ATTRIBUTE_UNUSED;
      struct elf_link_hash_entry *xdir, *xind;
 {
   struct elfNN_ia64_link_hash_entry *dir, *ind;
@@ -1587,18 +1661,17 @@ elfNN_ia64_hash_copy_indirect (xdir, xind)
 }
 
 static void
-elfNN_ia64_hash_hide_symbol (info, xh)
-     struct bfd_link_info *info ATTRIBUTE_UNUSED;
+elfNN_ia64_hash_hide_symbol (info, xh, force_local)
+     struct bfd_link_info *info;
      struct elf_link_hash_entry *xh;
+     boolean force_local;
 {
   struct elfNN_ia64_link_hash_entry *h;
   struct elfNN_ia64_dyn_sym_info *dyn_i;
 
   h = (struct elfNN_ia64_link_hash_entry *)xh;
 
-  h->root.elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT;
-  if ((h->root.elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) != 0)
-    h->root.dynindx = -1;
+  _bfd_elf_link_hash_hide_symbol (info, &h->root, force_local);
 
   for (dyn_i = h->info; dyn_i; dyn_i = dyn_i->next)
     dyn_i->want_plt2 = 0;
@@ -1661,6 +1734,9 @@ elfNN_ia64_global_dyn_sym_thunk (xentry, xdata)
     = (struct elfNN_ia64_dyn_sym_traverse_data *) xdata;
   struct elfNN_ia64_dyn_sym_info *dyn_i;
 
+  if (entry->root.root.type == bfd_link_hash_warning)
+    entry = (struct elfNN_ia64_link_hash_entry *) entry->root.root.u.i.link;
+
   for (dyn_i = entry->info; dyn_i; dyn_i = dyn_i->next)
     if (! (*data->func) (dyn_i, data->data))
       return false;
@@ -1760,6 +1836,7 @@ get_local_sym_hash (ia64_info, abfd, rel, 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.  */
@@ -1767,13 +1844,17 @@ get_local_sym_hash (ia64_info, abfd, rel, create)
   len = sizeof (void*)*2 + 1 + sizeof (bfd_vma)*4 + 1 + 1;
   len += 10;   /* %p slop */
 
-  addr_name = alloca (len);
+  addr_name = bfd_malloc (len);
+  if (addr_name == NULL)
+    return 0;
   sprintf (addr_name, "%p:%lx",
           (void *) abfd, (unsigned long) ELFNN_R_SYM (rel->r_info));
 
   /* Collect the canonical entry data for this address.  */
-  return elfNN_ia64_local_hash_lookup (&ia64_info->loc_hash_table,
-                                      addr_name, create, create);
+  ret = elfNN_ia64_local_hash_lookup (&ia64_info->loc_hash_table,
+                                     addr_name, create, create);
+  free (addr_name);
+  return ret;
 }
 
 /* Find and/or create a descriptor for dynamic symbol info.  This will
@@ -2040,6 +2121,9 @@ elfNN_ia64_check_relocs (abfd, info, sec, relocs)
        NEED_FULL_PLT = 16,
        NEED_DYNREL = 32,
        NEED_LTOFF_FPTR = 64,
+       NEED_TPREL = 128,
+       NEED_DTPMOD = 256,
+       NEED_DTPREL = 512
       };
 
       struct elf_link_hash_entry *h = NULL;
@@ -2077,11 +2161,42 @@ elfNN_ia64_check_relocs (abfd, info, sec, relocs)
       need_entry = 0;
       switch (ELFNN_R_TYPE (rel->r_info))
        {
-       case R_IA64_TPREL22:
        case R_IA64_TPREL64MSB:
        case R_IA64_TPREL64LSB:
-       case R_IA64_LTOFF_TP22:
-         return false;
+         if (info->shared || maybe_dynamic)
+           need_entry = NEED_DYNREL;
+         dynrel_type = R_IA64_TPREL64LSB;
+         if (info->shared)
+           info->flags |= DF_STATIC_TLS;
+         break;
+
+       case R_IA64_LTOFF_TPREL22:
+         need_entry = NEED_TPREL;
+         if (info->shared)
+           info->flags |= DF_STATIC_TLS;
+         break;
+
+       case R_IA64_DTPREL64MSB:
+       case R_IA64_DTPREL64LSB:
+         if (info->shared || maybe_dynamic)
+           need_entry = NEED_DYNREL;
+         dynrel_type = R_IA64_DTPREL64LSB;
+         break;
+
+       case R_IA64_LTOFF_DTPREL22:
+         need_entry = NEED_DTPREL;
+         break;
+
+       case R_IA64_DTPMOD64MSB:
+       case R_IA64_DTPMOD64LSB:
+         if (info->shared || maybe_dynamic)
+           need_entry = NEED_DYNREL;
+         dynrel_type = R_IA64_DTPMOD64LSB;
+         break;
+
+       case R_IA64_LTOFF_DTPMOD22:
+         need_entry = NEED_DTPMOD;
+         break;
 
        case R_IA64_LTOFF_FPTR22:
        case R_IA64_LTOFF_FPTR64I:
@@ -2191,7 +2306,7 @@ elfNN_ia64_check_relocs (abfd, info, sec, relocs)
       dyn_i->h = h;
 
       /* Create what's needed.  */
-      if (need_entry & NEED_GOT)
+      if (need_entry & (NEED_GOT | NEED_TPREL | NEED_DTPMOD | NEED_DTPREL))
        {
          if (!got)
            {
@@ -2199,7 +2314,14 @@ elfNN_ia64_check_relocs (abfd, info, sec, relocs)
              if (!got)
                return false;
            }
-         dyn_i->want_got = 1;
+         if (need_entry & NEED_GOT)
+           dyn_i->want_got = 1;
+         if (need_entry & NEED_TPREL)
+           dyn_i->want_tprel = 1;
+         if (need_entry & NEED_DTPMOD)
+           dyn_i->want_dtpmod = 1;
+         if (need_entry & NEED_DTPREL)
+           dyn_i->want_dtprel = 1;
        }
       if (need_entry & NEED_FPTR)
        {
@@ -2279,6 +2401,21 @@ allocate_global_data_got (dyn_i, data)
        dyn_i->got_offset = x->ofs;
        x->ofs += 8;
      }
+  if (dyn_i->want_tprel)
+    {
+      dyn_i->tprel_offset = x->ofs;
+      x->ofs += 8;
+    }
+  if (dyn_i->want_dtpmod)
+    {
+      dyn_i->dtpmod_offset = x->ofs;
+      x->ofs += 8;
+    }
+  if (dyn_i->want_dtprel)
+    {
+      dyn_i->dtprel_offset = x->ofs;
+      x->ofs += 8;
+    }
   return true;
 }
 
@@ -2525,6 +2662,10 @@ allocate_dynrel_entries (dyn_i, data)
          if (!dynamic_symbol)
            count *= 2;
          break;
+       case R_IA64_TPREL64LSB:
+       case R_IA64_DTPREL64LSB:
+       case R_IA64_DTPMOD64LSB:
+         break;
        default:
          abort ();
        }
@@ -2536,6 +2677,12 @@ allocate_dynrel_entries (dyn_i, data)
   if (((dynamic_symbol || shared) && dyn_i->want_got)
       || (dyn_i->want_ltoff_fptr && dyn_i->h && dyn_i->h->dynindx != -1))
     ia64_info->rel_got_sec->_raw_size += sizeof (ElfNN_External_Rela);
+  if ((dynamic_symbol || shared) && dyn_i->want_tprel)
+    ia64_info->rel_got_sec->_raw_size += sizeof (ElfNN_External_Rela);
+  if ((dynamic_symbol || shared) && dyn_i->want_dtpmod)
+    ia64_info->rel_got_sec->_raw_size += sizeof (ElfNN_External_Rela);
+  if (dynamic_symbol && dyn_i->want_dtprel)
+    ia64_info->rel_got_sec->_raw_size += sizeof (ElfNN_External_Rela);
 
   if (dyn_i->want_pltoff)
     {
@@ -2846,7 +2993,11 @@ elfNN_ia64_install_value (abfd, hit_addr, v, r_type)
 
       /* Instruction relocations.  */
 
-    case R_IA64_IMM14:         opnd = IA64_OPND_IMM14; break;
+    case R_IA64_IMM14:
+    case R_IA64_TPREL14:
+    case R_IA64_DTPREL14:
+      opnd = IA64_OPND_IMM14;
+      break;
 
     case R_IA64_PCREL21F:      opnd = IA64_OPND_TGT25; break;
     case R_IA64_PCREL21M:      opnd = IA64_OPND_TGT25b; break;
@@ -2863,6 +3014,11 @@ elfNN_ia64_install_value (abfd, hit_addr, v, r_type)
     case R_IA64_PLTOFF22:
     case R_IA64_PCREL22:
     case R_IA64_LTOFF_FPTR22:
+    case R_IA64_TPREL22:
+    case R_IA64_DTPREL22:
+    case R_IA64_LTOFF_TPREL22:
+    case R_IA64_LTOFF_DTPMOD22:
+    case R_IA64_LTOFF_DTPREL22:
       opnd = IA64_OPND_IMM22;
       break;
 
@@ -2873,6 +3029,8 @@ elfNN_ia64_install_value (abfd, hit_addr, v, r_type)
     case R_IA64_PCREL64I:
     case R_IA64_FPTR64I:
     case R_IA64_LTOFF_FPTR64I:
+    case R_IA64_TPREL64I:
+    case R_IA64_DTPREL64I:
       opnd = IA64_OPND_IMMU64;
       break;
 
@@ -2886,6 +3044,7 @@ elfNN_ia64_install_value (abfd, hit_addr, v, r_type)
     case R_IA64_SEGREL32MSB:
     case R_IA64_SECREL32MSB:
     case R_IA64_LTV32MSB:
+    case R_IA64_DTPREL32MSB:
       size = 4; bigendian = 1;
       break;
 
@@ -2897,6 +3056,7 @@ elfNN_ia64_install_value (abfd, hit_addr, v, r_type)
     case R_IA64_SEGREL32LSB:
     case R_IA64_SECREL32LSB:
     case R_IA64_LTV32LSB:
+    case R_IA64_DTPREL32LSB:
       size = 4; bigendian = 0;
       break;
 
@@ -2909,6 +3069,9 @@ elfNN_ia64_install_value (abfd, hit_addr, v, r_type)
     case R_IA64_SEGREL64MSB:
     case R_IA64_SECREL64MSB:
     case R_IA64_LTV64MSB:
+    case R_IA64_TPREL64MSB:
+    case R_IA64_DTPMOD64MSB:
+    case R_IA64_DTPREL64MSB:
       size = 8; bigendian = 1;
       break;
 
@@ -2921,6 +3084,9 @@ elfNN_ia64_install_value (abfd, hit_addr, v, r_type)
     case R_IA64_SEGREL64LSB:
     case R_IA64_SECREL64LSB:
     case R_IA64_LTV64LSB:
+    case R_IA64_TPREL64LSB:
+    case R_IA64_DTPMOD64LSB:
+    case R_IA64_DTPREL64LSB:
       size = 8; bigendian = 0;
       break;
 
@@ -3038,13 +3204,11 @@ elfNN_ia64_install_dyn_reloc (abfd, info, sec, srel, offset, type,
 {
   Elf_Internal_Rela outrel;
 
-  offset += sec->output_section->vma + sec->output_offset;
-
   BFD_ASSERT (dynindx != -1);
   outrel.r_info = ELFNN_R_INFO (dynindx, type);
   outrel.r_addend = addend;
   outrel.r_offset = _bfd_elf_section_offset (abfd, info, sec, offset);
-  if (outrel.r_offset == (bfd_vma) -1)
+  if (outrel.r_offset >= (bfd_vma) -2)
     {
       /* Run for the hills.  We shouldn't be outputting a relocation
         for this.  So do what everyone else does and output a no-op.  */
@@ -3052,6 +3216,8 @@ elfNN_ia64_install_dyn_reloc (abfd, info, sec, srel, offset, type,
       outrel.r_addend = 0;
       outrel.r_offset = 0;
     }
+  else
+    outrel.r_offset += sec->output_section->vma + sec->output_offset;
 
   bfd_elfNN_swap_reloca_out (abfd, &outrel,
                             ((ElfNN_External_Rela *) srel->contents
@@ -3075,26 +3241,53 @@ set_got_entry (abfd, info, dyn_i, dynindx, addend, value, dyn_r_type)
 {
   struct elfNN_ia64_link_hash_table *ia64_info;
   asection *got_sec;
+  boolean done;
+  bfd_vma got_offset;
 
   ia64_info = elfNN_ia64_hash_table (info);
   got_sec = ia64_info->got_sec;
 
-  BFD_ASSERT ((dyn_i->got_offset & 7) == 0);
-
-  if (! dyn_i->got_done)
+  switch (dyn_r_type)
     {
+    case R_IA64_TPREL64LSB:
+      done = dyn_i->tprel_done;
+      dyn_i->tprel_done = true;
+      got_offset = dyn_i->tprel_offset;
+      break;
+    case R_IA64_DTPMOD64LSB:
+      done = dyn_i->dtpmod_done;
+      dyn_i->dtpmod_done = true;
+      got_offset = dyn_i->dtpmod_offset;
+      break;
+    case R_IA64_DTPREL64LSB:
+      done = dyn_i->dtprel_done;
+      dyn_i->dtprel_done = true;
+      got_offset = dyn_i->dtprel_offset;
+      break;
+    default:
+      done = dyn_i->got_done;
       dyn_i->got_done = true;
+      got_offset = dyn_i->got_offset;
+      break;
+    }
+
+  BFD_ASSERT ((got_offset & 7) == 0);
 
+  if (! done)
+    {
       /* Store the target address in the linkage table entry.  */
-      bfd_put_64 (abfd, value, got_sec->contents + dyn_i->got_offset);
+      bfd_put_64 (abfd, value, got_sec->contents + got_offset);
 
       /* Install a dynamic relocation if needed.  */
-      if (info->shared
+      if ((info->shared && dyn_r_type != R_IA64_DTPREL64LSB)
           || elfNN_ia64_dynamic_symbol_p (dyn_i->h, info)
          || elfNN_ia64_aix_vec (abfd->xvec)
          || (dynindx != -1 && dyn_r_type == R_IA64_FPTR64LSB))
        {
-         if (dynindx == -1)
+         if (dynindx == -1
+             && dyn_r_type != R_IA64_TPREL64LSB
+             && dyn_r_type != R_IA64_DTPMOD64LSB
+             && dyn_r_type != R_IA64_DTPREL64LSB)
            {
              dyn_r_type = R_IA64_REL64LSB;
              dynindx = 0;
@@ -3114,6 +3307,15 @@ set_got_entry (abfd, info, dyn_i, dynindx, addend, value, dyn_r_type)
                case R_IA64_FPTR64LSB:
                  dyn_r_type = R_IA64_FPTR64MSB;
                  break;
+               case R_IA64_TPREL64LSB:
+                 dyn_r_type = R_IA64_TPREL64MSB;
+                 break;
+               case R_IA64_DTPMOD64LSB:
+                 dyn_r_type = R_IA64_DTPMOD64MSB;
+                 break;
+               case R_IA64_DTPREL64LSB:
+                 dyn_r_type = R_IA64_DTPREL64MSB;
+                 break;
                default:
                  BFD_ASSERT (false);
                  break;
@@ -3122,7 +3324,7 @@ set_got_entry (abfd, info, dyn_i, dynindx, addend, value, dyn_r_type)
 
          elfNN_ia64_install_dyn_reloc (abfd, NULL, got_sec,
                                        ia64_info->rel_got_sec,
-                                       dyn_i->got_offset, dyn_r_type,
+                                       got_offset, dyn_r_type,
                                        dynindx, addend);
        }
     }
@@ -3130,7 +3332,7 @@ set_got_entry (abfd, info, dyn_i, dynindx, addend, value, dyn_r_type)
   /* Return the address of the linkage table entry.  */
   value = (got_sec->output_section->vma
           + got_sec->output_offset
-          + dyn_i->got_offset);
+          + got_offset);
 
   return value;
 }
@@ -3228,6 +3430,35 @@ set_pltoff_entry (abfd, info, dyn_i, value, is_plt)
   return value;
 }
 
+/* Return the base VMA address which should be subtracted from real addresses
+   when resolving @tprel() relocation.
+   Main program TLS (whose template starts at PT_TLS p_vaddr)
+   is assigned offset round(16, PT_TLS p_align).  */
+
+static bfd_vma
+elfNN_ia64_tprel_base (info)
+     struct bfd_link_info *info;
+{
+  struct elf_link_tls_segment *tls_segment
+    = elf_hash_table (info)->tls_segment;
+
+  BFD_ASSERT (tls_segment != NULL);
+  return (tls_segment->start
+         - align_power ((bfd_vma) 16, tls_segment->align));
+}
+
+/* Return the base VMA address which should be subtracted from real addresses
+   when resolving @dtprel() relocation.
+   This is PT_TLS segment p_vaddr.  */
+
+static bfd_vma
+elfNN_ia64_dtprel_base (info)
+     struct bfd_link_info *info;
+{
+  BFD_ASSERT (elf_hash_table (info)->tls_segment != NULL);
+  return elf_hash_table (info)->tls_segment->start;
+}
+
 /* Called through qsort to sort the .IA_64.unwind section during a
    non-relocatable link.  Set elfNN_ia64_unwind_entry_compare_bfd
    to the output bfd so we can do proper endianness frobbing.  */
@@ -3445,6 +3676,7 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section,
 
       elf_section_data(input_section->output_section)
        ->this_hdr.sh_flags |= flags;
+      return true;
     }
 
   gp_val = _bfd_get_gp_value (output_bfd);
@@ -3477,29 +3709,9 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section,
          ret_val = false;
          continue;
        }
+
       howto = lookup_howto (r_type);
       r_symndx = ELFNN_R_SYM (rel->r_info);
-
-      if (info->relocateable)
-       {
-         /* This is a relocateable link.  We don't have to change
-            anything, unless the reloc is against a section symbol,
-            in which case we have to adjust according to where the
-            section symbol winds up in the output section.  */
-         if (r_symndx < symtab_hdr->sh_info)
-           {
-             sym = local_syms + r_symndx;
-             if (ELF_ST_TYPE (sym->st_info) == STT_SECTION)
-               {
-                 sym_sec = local_sections[r_symndx];
-                 rel->r_addend += sym_sec->output_offset;
-               }
-           }
-         continue;
-       }
-
-      /* This is a final link.  */
-
       h = NULL;
       sym = NULL;
       sym_sec = NULL;
@@ -3992,6 +4204,55 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section,
                                        r_type);
          break;
 
+       case R_IA64_TPREL14:
+       case R_IA64_TPREL22:
+       case R_IA64_TPREL64I:
+         value -= elfNN_ia64_tprel_base (info);
+         r = elfNN_ia64_install_value (output_bfd, hit_addr, value, r_type);
+         break;
+
+       case R_IA64_DTPREL14:
+       case R_IA64_DTPREL22:
+       case R_IA64_DTPREL64I:
+         value -= elfNN_ia64_dtprel_base (info);
+         r = elfNN_ia64_install_value (output_bfd, hit_addr, value, r_type);
+         break;
+
+       case R_IA64_LTOFF_TPREL22:
+       case R_IA64_LTOFF_DTPMOD22:
+       case R_IA64_LTOFF_DTPREL22:
+         {
+           int got_r_type;
+
+           switch (r_type)
+             {
+             default:
+             case R_IA64_LTOFF_TPREL22:
+               if (!dynamic_symbol_p && !info->shared)
+                 value -= elfNN_ia64_tprel_base (info);
+               got_r_type = R_IA64_TPREL64LSB;
+               break;
+             case R_IA64_LTOFF_DTPMOD22:
+               if (!dynamic_symbol_p && !info->shared)
+                 value = 1;
+               got_r_type = R_IA64_DTPMOD64LSB;
+               break;
+             case R_IA64_LTOFF_DTPREL22:
+               if (!dynamic_symbol_p)
+                 value -= elfNN_ia64_dtprel_base (info);
+               got_r_type = R_IA64_DTPREL64LSB;
+               break;
+             }
+           dyn_i = get_dyn_sym_info (ia64_info, h, input_bfd, rel, false);
+           value = set_got_entry (input_bfd, info, dyn_i,
+                                  (h ? h->dynindx : -1), rel->r_addend,
+                                  value, got_r_type);
+           value -= gp_val;
+           r = elfNN_ia64_install_value (output_bfd, hit_addr, value,
+                                         r_type);
+         }
+         break;
+
        default:
          r = bfd_reloc_notsupported;
          break;
@@ -4262,24 +4523,6 @@ elfNN_ia64_set_private_flags (abfd, flags)
   return true;
 }
 
-/* Copy backend specific data from one object module to another */
-static boolean
-elfNN_ia64_copy_private_bfd_data (ibfd, obfd)
-     bfd *ibfd, *obfd;
-{
-  if (   bfd_get_flavour (ibfd) != bfd_target_elf_flavour
-      || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
-    return true;
-
-  BFD_ASSERT (!elf_flags_init (obfd)
-             || (elf_elfheader (obfd)->e_flags
-                 == elf_elfheader (ibfd)->e_flags));
-
-  elf_elfheader (obfd)->e_flags = elf_elfheader (ibfd)->e_flags;
-  elf_flags_init (obfd) = true;
-  return true;
-}
-
 /* Merge backend specific data from an object file to the output
    object file when linking.  */
 static boolean
@@ -4415,6 +4658,38 @@ elfNN_ia64_reloc_type_class (rela)
       return reloc_class_normal;
     }
 }
+
+static boolean
+elfNN_ia64_hpux_vec (const bfd_target *vec)
+{
+  extern const bfd_target bfd_elfNN_ia64_hpux_big_vec;
+  return (vec == & bfd_elfNN_ia64_hpux_big_vec);
+}
+
+static void
+elfNN_hpux_post_process_headers (abfd, info)
+       bfd *abfd;
+       struct bfd_link_info *info ATTRIBUTE_UNUSED;
+{
+  Elf_Internal_Ehdr *i_ehdrp = elf_elfheader (abfd);
+
+  i_ehdrp->e_ident[EI_OSABI] = ELFOSABI_HPUX;
+  i_ehdrp->e_ident[EI_ABIVERSION] = 1;
+}
+
+boolean
+elfNN_hpux_backend_section_from_bfd_section (abfd, sec, retval)
+       bfd *abfd ATTRIBUTE_UNUSED;
+       asection *sec;
+       int *retval;
+{
+  if (bfd_is_com_section (sec))
+    {
+      *retval = SHN_IA_64_ANSI_COMMON;
+      return true;
+    }
+  return false;
+}
 \f
 #define TARGET_LITTLE_SYM              bfd_elfNN_ia64_little_vec
 #define TARGET_LITTLE_NAME             "elfNN-ia64-little"
@@ -4470,8 +4745,6 @@ elfNN_ia64_reloc_type_class (rela)
 #define bfd_elfNN_bfd_final_link \
        elfNN_ia64_final_link
 
-#define bfd_elfNN_bfd_copy_private_bfd_data \
-       elfNN_ia64_copy_private_bfd_data
 #define bfd_elfNN_bfd_merge_private_bfd_data \
        elfNN_ia64_merge_private_bfd_data
 #define bfd_elfNN_bfd_set_private_flags \
@@ -4492,6 +4765,7 @@ elfNN_ia64_reloc_type_class (rela)
 #define elf_backend_copy_indirect_symbol elfNN_ia64_hash_copy_indirect
 #define elf_backend_hide_symbol                elfNN_ia64_hash_hide_symbol
 #define elf_backend_reloc_type_class   elfNN_ia64_reloc_type_class
+#define elf_backend_rela_normal                1
 
 #include "elfNN-target.h"
 
@@ -4515,3 +4789,41 @@ elfNN_ia64_reloc_type_class (rela)
 #define elfNN_bed elfNN_ia64_aix_bed
 
 #include "elfNN-target.h"
+
+/* HPUX-specific vectors.  */
+
+#undef  TARGET_LITTLE_SYM
+#undef  TARGET_LITTLE_NAME
+#undef  TARGET_BIG_SYM
+#define TARGET_BIG_SYM                  bfd_elfNN_ia64_hpux_big_vec
+#undef  TARGET_BIG_NAME
+#define TARGET_BIG_NAME                 "elfNN-ia64-hpux-big"
+
+/* We need to undo the AIX specific functions.  */
+
+#undef  elf_backend_add_symbol_hook
+#define elf_backend_add_symbol_hook    elfNN_ia64_add_symbol_hook
+
+#undef  bfd_elfNN_bfd_link_add_symbols
+#define bfd_elfNN_bfd_link_add_symbols _bfd_generic_link_add_symbols
+
+/* These are HP-UX specific functions.  */
+
+#undef  elf_backend_post_process_headers
+#define elf_backend_post_process_headers elfNN_hpux_post_process_headers
+
+#undef  elf_backend_section_from_bfd_section
+#define elf_backend_section_from_bfd_section elfNN_hpux_backend_section_from_bfd_section
+
+#undef  elf_backend_want_p_paddr_set_to_zero
+#define elf_backend_want_p_paddr_set_to_zero 1
+
+#undef  ELF_MAXPAGESIZE
+#define ELF_MAXPAGESIZE                 0x1000  /* 1K */
+
+#undef  elfNN_bed
+#define elfNN_bed elfNN_ia64_hpux_bed
+
+#include "elfNN-target.h"
+
+#undef  elf_backend_want_p_paddr_set_to_zero
This page took 0.038283 seconds and 4 git commands to generate.