* elf-bfd.h (elf_backend_data <elf_backend_section_from_bfd_section>):
[binutils-gdb.git] / bfd / elfxx-ia64.c
index 6abd6909dd7cb60fd87f12b6ceab7cd6defdc4ad..ee49f5a9c17fed24f8e7cdad53707b353737d01e 100644 (file)
@@ -163,7 +163,7 @@ 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 *));
 static boolean elfNN_ia64_section_flags
@@ -301,14 +301,18 @@ static boolean elfNN_ia64_finish_dynamic_sections
   PARAMS ((bfd *abfd, struct bfd_link_info *info));
 static boolean elfNN_ia64_set_private_flags
   PARAMS ((bfd *abfd, flagword flags));
-static boolean elfNN_ia64_copy_private_bfd_data
-  PARAMS ((bfd *ibfd, bfd *obfd));
 static boolean elfNN_ia64_merge_private_bfd_data
   PARAMS ((bfd *ibfd, bfd *obfd));
 static boolean elfNN_ia64_print_private_bfd_data
   PARAMS ((bfd *abfd, PTR ptr));
 static enum elf_reloc_type_class elfNN_ia64_reloc_type_class
   PARAMS ((const Elf_Internal_Rela *));
+static boolean elfNN_ia64_hpux_vec
+  PARAMS ((const bfd_target *vec));
+static void elfNN_hpux_post_process_headers
+  PARAMS ((bfd *abfd, struct bfd_link_info *info));
+boolean elfNN_hpux_backend_section_from_bfd_section
+  PARAMS ((bfd *abfd, asection *sec, int *retval));
 \f
 /* ia64-specific relocation */
 
@@ -644,6 +648,7 @@ 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;
@@ -651,6 +656,7 @@ elfNN_ia64_relax_section (abfd, sec, link_info, again)
   bfd_byte *free_contents = NULL;
   ElfNN_External_Sym *extsyms;
   ElfNN_External_Sym *free_extsyms = NULL;
+  Elf_External_Sym_Shndx *shndx_buf = NULL;
   struct elfNN_ia64_link_hash_table *ia64_info;
   struct one_fixup *fixups = NULL;
   boolean changed_contents = false;
@@ -712,18 +718,34 @@ elfNN_ia64_relax_section (abfd, sec, link_info, again)
        goto error_return;
     }
 
-  /* Read this BFD's symbols.  */
+  /* Read this BFD's local symbols.  */
   if (symtab_hdr->contents != NULL)
     extsyms = (ElfNN_External_Sym *) symtab_hdr->contents;
   else
     {
-      extsyms = (ElfNN_External_Sym *) bfd_malloc (symtab_hdr->sh_size);
+      bfd_size_type amt;
+
+      amt = symtab_hdr->sh_info * sizeof (ElfNN_External_Sym);
+      extsyms = (ElfNN_External_Sym *) bfd_malloc (amt);
       if (extsyms == NULL)
        goto error_return;
       free_extsyms = extsyms;
       if (bfd_seek (abfd, symtab_hdr->sh_offset, SEEK_SET) != 0
-         || (bfd_bread (extsyms, symtab_hdr->sh_size, abfd)
-             != symtab_hdr->sh_size))
+         || bfd_bread (extsyms, amt, abfd) != amt)
+       goto error_return;
+    }
+
+  shndx_hdr = &elf_tdata (abfd)->symtab_shndx_hdr;
+  if (shndx_hdr->sh_size != 0)
+    {
+      bfd_size_type amt;
+
+      amt = symtab_hdr->sh_info * sizeof (Elf_External_Sym_Shndx);
+      shndx_buf = (Elf_External_Sym_Shndx *) bfd_malloc (amt);
+      if (shndx_buf == NULL)
+       goto error_return;
+      if (bfd_seek (abfd, shndx_hdr->sh_offset, SEEK_SET) != 0
+         || bfd_bread (shndx_buf, amt, abfd) != amt)
        goto error_return;
     }
 
@@ -741,20 +763,23 @@ elfNN_ia64_relax_section (abfd, sec, link_info, again)
       /* Get the value of the symbol referred to by the reloc.  */
       if (ELFNN_R_SYM (irel->r_info) < symtab_hdr->sh_info)
        {
+         ElfNN_External_Sym *esym;
+         Elf_External_Sym_Shndx *shndx;
+
          /* A local symbol.  */
-         bfd_elfNN_swap_symbol_in (abfd,
-                                   extsyms + ELFNN_R_SYM (irel->r_info),
-                                   &isym);
+         esym = extsyms + ELFNN_R_SYM (irel->r_info);
+         shndx = shndx_buf + (shndx_buf ? ELFNN_R_SYM (irel->r_info) : 0);
+         bfd_elfNN_swap_symbol_in (abfd, esym, shndx, &isym);
          if (isym.st_shndx == SHN_UNDEF)
            continue;   /* We can't do anthing with undefined symbols.  */
          else if (isym.st_shndx == SHN_ABS)
            tsec = bfd_abs_section_ptr;
          else if (isym.st_shndx == SHN_COMMON)
            tsec = bfd_com_section_ptr;
-         else if (isym.st_shndx > 0 && isym.st_shndx < SHN_LORESERVE)
-           tsec = bfd_section_from_elf_index (abfd, isym.st_shndx);
+         else if (isym.st_shndx == SHN_IA_64_ANSI_COMMON)
+           tsec = bfd_com_section_ptr;
          else
-           continue;   /* who knows.  */
+           tsec = bfd_section_from_elf_index (abfd, isym.st_shndx);
 
          toff = isym.st_value;
        }
@@ -922,6 +947,9 @@ elfNN_ia64_relax_section (abfd, sec, link_info, again)
        }
     }
 
+  if (shndx_buf != NULL)
+    free (shndx_buf);
+
   if (free_extsyms != NULL)
     {
       if (! link_info->keep_memory)
@@ -941,6 +969,8 @@ elfNN_ia64_relax_section (abfd, sec, link_info, again)
     free (free_relocs);
   if (free_contents != NULL)
     free (free_contents);
+  if (shndx_buf != NULL)
+    free (shndx_buf);
   if (free_extsyms != NULL)
     free (free_extsyms);
   return false;
@@ -949,11 +979,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;
@@ -981,6 +1016,10 @@ elfNN_ia64_section_from_shdr (abfd, hdr, name)
   switch (hdr->sh_type)
     {
     case SHT_IA_64_UNWIND:
+    case SHT_INIT_ARRAY:
+    case SHT_FINI_ARRAY:
+    case SHT_PREINIT_ARRAY:
+    case SHT_IA_64_HP_OPT_ANOT:
       break;
 
     case SHT_IA_64_EXT:
@@ -1028,7 +1067,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.  */
@@ -1037,6 +1076,14 @@ 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, ".init_array") == 0)
+    hdr->sh_type = SHT_INIT_ARRAY;
+  else if (strcmp (name, ".fini_array") == 0)
+    hdr->sh_type = SHT_FINI_ARRAY;
+  else if (strcmp (name, ".preinit_array") == 0)
+    hdr->sh_type = SHT_PREINIT_ARRAY;
+  else if (strcmp (name, ".HP.opt_annot") == 0)
+    hdr->sh_type = SHT_IA_64_HP_OPT_ANOT;
   else if (strcmp (name, ".reloc") == 0)
     /*
      * This is an ugly, but unfortunately necessary hack that is
@@ -1104,11 +1151,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 */
@@ -1225,15 +1290,15 @@ elfNN_ia64_aix_add_symbol_hook (abfd, info, sym, namep, flagsp, secp, valp)
     }
   else if (sym->st_shndx == SHN_LOOS)
     {
-      int i;
+      unsigned int i;
 
       /* SHN_AIX_SYSCALL: Treat this as any other symbol.  The special symbol
         is only relevant when compiling code for extended system calls.
         Replace the "special" section with .text, if possible.
         Note that these symbols are always assumed to be in .text. */
-      for (i = 1; i < elf_elfheader (abfd)->e_shnum; i++)
+      for (i = 1; i < elf_numsections (abfd); i++)
        {
-         asection * sec = bfd_section_from_elf_index (abfd, (unsigned) i);
+         asection * sec = bfd_section_from_elf_index (abfd, i);
 
          if (sec && strcmp (sec->name, ".text") == 0)
            {
@@ -1289,7 +1354,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;
@@ -1302,6 +1367,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.  */
@@ -1344,8 +1411,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)
            {
@@ -1736,6 +1819,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.  */
@@ -1743,13 +1827,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
@@ -4238,24 +4326,6 @@ elfNN_ia64_set_private_flags (abfd, flags)
   return true;
 }
 
-/* Copy backend specific data from one object module to another */
-static boolean
-elfNN_ia64_copy_private_bfd_data (ibfd, obfd)
-     bfd *ibfd, *obfd;
-{
-  if (   bfd_get_flavour (ibfd) != bfd_target_elf_flavour
-      || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
-    return true;
-
-  BFD_ASSERT (!elf_flags_init (obfd)
-             || (elf_elfheader (obfd)->e_flags
-                 == elf_elfheader (ibfd)->e_flags));
-
-  elf_elfheader (obfd)->e_flags = elf_elfheader (ibfd)->e_flags;
-  elf_flags_init (obfd) = true;
-  return true;
-}
-
 /* Merge backend specific data from an object file to the output
    object file when linking.  */
 static boolean
@@ -4391,6 +4461,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"
@@ -4446,8 +4548,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 \
@@ -4491,3 +4591,26 @@ 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"
+
+#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"