* elf-bfd.h (struct elf_size_info): Add swap_symbol_in field.
[deliverable/binutils-gdb.git] / bfd / elfxx-ia64.c
index bfb7d7498a0911d7f99b0aa99de2daf5eb790f3a..0e3d0db84fb375d0ea194b2ddcce03905dcf2119 100644 (file)
@@ -1,5 +1,5 @@
 /* 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.
@@ -79,6 +79,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 +100,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 +111,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
@@ -163,9 +172,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
@@ -204,7 +213,7 @@ static struct bfd_hash_entry *elfNN_ia64_new_elf_hash_entry
 static void elfNN_ia64_hash_copy_indirect
   PARAMS ((struct elf_link_hash_entry *, struct elf_link_hash_entry *));
 static void elfNN_ia64_hash_hide_symbol
-  PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *));
+  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 +294,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
@@ -307,6 +320,12 @@ 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 */
 
@@ -417,10 +436,25 @@ 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];
@@ -535,10 +569,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;
     }
@@ -763,13 +812,16 @@ elfNN_ia64_relax_section (abfd, sec, link_info, again)
          /* 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);
+         bfd_elfNN_swap_symbol_in (abfd, (const PTR *) esym,
+                                   (const PTR *) shndx, &isym);
          if (isym.st_shndx == SHN_UNDEF)
            continue;   /* We can't do anthing with undefined symbols.  */
          else if (isym.st_shndx == SHN_ABS)
            tsec = bfd_abs_section_ptr;
          else if (isym.st_shndx == SHN_COMMON)
            tsec = bfd_com_section_ptr;
+         else if (isym.st_shndx == SHN_IA_64_ANSI_COMMON)
+           tsec = bfd_com_section_ptr;
          else
            tsec = bfd_section_from_elf_index (abfd, isym.st_shndx);
 
@@ -971,11 +1023,16 @@ elfNN_ia64_relax_section (abfd, sec, link_info, again)
 /* 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;
@@ -991,7 +1048,7 @@ static boolean
 elfNN_ia64_section_from_shdr (abfd, hdr, name)
      bfd *abfd;
      ElfNN_Internal_Shdr *hdr;
-     char *name;
+     const char *name;
 {
   asection *newsect;
 
@@ -1003,6 +1060,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:
@@ -1050,7 +1108,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.  */
@@ -1059,6 +1117,8 @@ 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
@@ -1126,11 +1186,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 */
@@ -1311,7 +1389,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;
@@ -1324,6 +1402,8 @@ elfNN_ia64_modify_segment_map (abfd)
   struct elf_segment_map *m, **pm;
   Elf_Internal_Shdr *hdr;
   asection *s;
+  boolean unwind_found;
+  asection *unwind_sec;
 
   /* If we need a PT_IA_64_ARCHEXT segment, it must come before
      all PT_LOAD segments.  */
@@ -1366,8 +1446,24 @@ 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)
+             {
+               /* Look through all sections in the unwind segment
+                  for a match since there may be multiple sections
+                  to a segment.  */
+
+               unwind_sec = m->sections[0];
+               unwind_found = false;
+               while (unwind_sec != NULL && !unwind_found)
+                 {
+                   if (unwind_sec == s)
+                     unwind_found = true;
+                   else
+                     unwind_sec = unwind_sec -> next;
+                 }
+               if (unwind_found)
+                 break;
+             }
 
          if (m == NULL)
            {
@@ -1585,18 +1681,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;
@@ -1659,6 +1754,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;
@@ -1758,6 +1856,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.  */
@@ -1765,13 +1864,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
@@ -2038,6 +2141,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;
@@ -2075,11 +2181,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:
@@ -2189,7 +2326,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)
            {
@@ -2197,7 +2334,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)
        {
@@ -2277,6 +2421,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;
 }
 
@@ -2523,6 +2682,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 ();
        }
@@ -2534,6 +2697,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)
     {
@@ -2844,7 +3013,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;
@@ -2861,6 +3034,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;
 
@@ -2871,6 +3049,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;
 
@@ -2884,6 +3064,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;
 
@@ -2895,6 +3076,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;
 
@@ -2907,6 +3089,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;
 
@@ -2919,6 +3104,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;
 
@@ -3042,7 +3230,7 @@ elfNN_ia64_install_dyn_reloc (abfd, info, sec, srel, offset, type,
   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 | 1) == (bfd_vma) -1)
     {
       /* Run for the hills.  We shouldn't be outputting a relocation
         for this.  So do what everyone else does and output a no-op.  */
@@ -3073,26 +3261,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;
@@ -3112,6 +3327,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;
@@ -3120,7 +3344,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);
        }
     }
@@ -3128,7 +3352,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;
 }
@@ -3226,6 +3450,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.  */
@@ -3443,6 +3696,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);
@@ -3475,29 +3729,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;
@@ -3990,6 +4224,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;
@@ -4395,6 +4678,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,6 +4785,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"
 
@@ -4493,3 +4809,36 @@ 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_MAXPAGESIZE
+#define ELF_MAXPAGESIZE                 0x1000  /* 1K */
+
+#undef  elfNN_bed
+#define elfNN_bed elfNN_ia64_hpux_bed
+
+#include "elfNN-target.h"
This page took 0.032911 seconds and 4 git commands to generate.