2010-05-14 Tristan Gingold <gingold@adacore.com>
[deliverable/binutils-gdb.git] / bfd / elf64-alpha.c
index ac7ada245346c6e1e7171956f9667c0d5b045768..649d370874902067cff798cf8dc7a96c42d81393 100644 (file)
@@ -1,13 +1,13 @@
 /* Alpha specific support for 64-bit ELF
-   Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
-   Free Software Foundation, Inc.
+   Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
+   2006, 2007, 2008, 2009, 2010  Free Software Foundation, Inc.
    Contributed by Richard Henderson <rth@tamu.edu>.
 
    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
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
 
    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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
+   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+   MA 02110-1301, USA.  */
+
 
 /* We need a published ABI spec for this.  Until one comes out, don't
    assume this'll remain unchanged forever.  */
 
-#include "bfd.h"
 #include "sysdep.h"
+#include "bfd.h"
 #include "libbfd.h"
 #include "elf-bfd.h"
 
@@ -101,6 +103,57 @@ bfd_boolean elf64_alpha_use_secureplt = FALSE;
 
 #define ELF_DYNAMIC_INTERPRETER "/usr/lib/ld.so"
 \f
+
+/* Used to implement multiple .got subsections.  */
+struct alpha_elf_got_entry
+{
+  struct alpha_elf_got_entry *next;
+
+  /* Which .got subsection?  */
+  bfd *gotobj;
+
+  /* The addend in effect for this entry.  */
+  bfd_vma addend;
+
+  /* The .got offset for this entry.  */
+  int got_offset;
+
+  /* The .plt offset for this entry.  */
+  int plt_offset;
+
+  /* How many references to this entry?  */
+  int use_count;
+
+  /* The relocation type of this entry.  */
+  unsigned char reloc_type;
+
+  /* How a LITERAL is used.  */
+  unsigned char flags;
+
+  /* Have we initialized the dynamic relocation for this entry?  */
+  unsigned char reloc_done;
+
+  /* Have we adjusted this entry for SEC_MERGE?  */
+  unsigned char reloc_xlated;
+};
+
+struct alpha_elf_reloc_entry
+{
+  struct alpha_elf_reloc_entry *next;
+
+  /* Which .reloc section? */
+  asection *srel;
+
+  /* What kind of relocation? */
+  unsigned int rtype;
+
+  /* Is this against read-only section? */
+  unsigned int reltext : 1;
+
+  /* How many did we find?  */
+  unsigned long count;
+};
+
 struct alpha_elf_link_hash_entry
 {
   struct elf_link_hash_entry root;
@@ -123,56 +176,11 @@ struct alpha_elf_link_hash_entry
 #define ALPHA_ELF_LINK_HASH_TLS_IE      0x80
 
   /* Used to implement multiple .got subsections.  */
-  struct alpha_elf_got_entry
-  {
-    struct alpha_elf_got_entry *next;
-
-    /* Which .got subsection?  */
-    bfd *gotobj;
-
-    /* The addend in effect for this entry.  */
-    bfd_vma addend;
-
-    /* The .got offset for this entry.  */
-    int got_offset;
-
-    /* The .plt offset for this entry.  */
-    int plt_offset;
-
-    /* How many references to this entry?  */
-    int use_count;
-
-    /* The relocation type of this entry.  */
-    unsigned char reloc_type;
-
-    /* How a LITERAL is used.  */
-    unsigned char flags;
-
-    /* Have we initialized the dynamic relocation for this entry?  */
-    unsigned char reloc_done;
-
-    /* Have we adjusted this entry for SEC_MERGE?  */
-    unsigned char reloc_xlated;
-  } *got_entries;
+  struct alpha_elf_got_entry *got_entries;
 
   /* Used to count non-got, non-plt relocations for delayed sizing
      of relocation sections.  */
-  struct alpha_elf_reloc_entry
-  {
-    struct alpha_elf_reloc_entry *next;
-
-    /* Which .reloc section? */
-    asection *srel;
-
-    /* What kind of relocation? */
-    unsigned int rtype;
-
-    /* Is this against read-only section? */
-    unsigned int reltext : 1;
-
-    /* How many did we find?  */
-    unsigned long count;
-  } *reloc_entries;
+  struct alpha_elf_reloc_entry *reloc_entries;
 };
 
 /* Alpha ELF linker hash table.  */
@@ -184,6 +192,10 @@ struct alpha_elf_link_hash_table
   /* The head of a list of .got subsections linked through
      alpha_elf_tdata(abfd)->got_link_next.  */
   bfd *got_list;
+
+  /* The most recent relax pass that we've seen.  The GOTs
+     should be regenerated if this doesn't match.  */
+  int relax_trip;
 };
 
 /* Look up an entry in a Alpha ELF linker hash table.  */
@@ -204,7 +216,8 @@ struct alpha_elf_link_hash_table
 /* Get the Alpha ELF linker hash table from a link_info structure.  */
 
 #define alpha_elf_hash_table(p) \
-  ((struct alpha_elf_link_hash_table *) ((p)->hash))
+  (elf_hash_table_id ((struct elf_link_hash_table *) ((p)->hash)) \
+  == ALPHA_ELF_DATA ? ((struct alpha_elf_link_hash_table *) ((p)->hash)) : NULL)
 
 /* Get the object's symbols as our own entry type.  */
 
@@ -273,8 +286,10 @@ elf64_alpha_bfd_link_hash_table_create (bfd *abfd)
   if (ret == (struct alpha_elf_link_hash_table *) NULL)
     return NULL;
 
-  if (! _bfd_elf_link_hash_table_init (&ret->root, abfd,
-                                      elf64_alpha_link_hash_newfunc))
+  if (!_bfd_elf_link_hash_table_init (&ret->root, abfd,
+                                     elf64_alpha_link_hash_newfunc,
+                                     sizeof (struct alpha_elf_link_hash_entry),
+                                     ALPHA_ELF_DATA))
     {
       free (ret);
       return NULL;
@@ -317,14 +332,16 @@ struct alpha_elf_obj_tdata
 #define alpha_elf_tdata(abfd) \
   ((struct alpha_elf_obj_tdata *) (abfd)->tdata.any)
 
+#define is_alpha_elf(bfd) \
+  (bfd_get_flavour (bfd) == bfd_target_elf_flavour \
+   && elf_tdata (bfd) != NULL \
+   && elf_object_id (bfd) == ALPHA_ELF_DATA)
+
 static bfd_boolean
 elf64_alpha_mkobject (bfd *abfd)
 {
-  bfd_size_type amt = sizeof (struct alpha_elf_obj_tdata);
-  abfd->tdata.any = bfd_zalloc (abfd, amt);
-  if (abfd->tdata.any == NULL)
-    return FALSE;
-  return TRUE;
+  return bfd_elf_allocate_object (abfd, sizeof (struct alpha_elf_obj_tdata),
+                                 ALPHA_ELF_DATA);
 }
 
 static bfd_boolean
@@ -449,8 +466,9 @@ elf64_alpha_reloc_gpdisp (bfd *abfd, arelent *reloc_entry,
    from smaller values.  Start with zero, widen, *then* decrement.  */
 #define MINUS_ONE      (((bfd_vma)0) - 1)
 
+
 #define SKIP_HOWTO(N) \
-  HOWTO(N, 0, 0, 0, 0, 0, 0, elf64_alpha_reloc_bad, 0, 0, 0, 0, 0)
+  HOWTO(N, 0, 0, 0, 0, 0, complain_overflow_dont, elf64_alpha_reloc_bad, 0, 0, 0, 0, 0)
 
 static reloc_howto_type elf64_alpha_howto_table[] =
 {
@@ -1051,6 +1069,23 @@ elf64_alpha_bfd_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
   return 0;
 }
 
+static reloc_howto_type *
+elf64_alpha_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
+                                  const char *r_name)
+{
+  unsigned int i;
+
+  for (i = 0;
+       i < (sizeof (elf64_alpha_howto_table)
+           / sizeof (elf64_alpha_howto_table[0]));
+       i++)
+    if (elf64_alpha_howto_table[i].name != NULL
+       && strcasecmp (elf64_alpha_howto_table[i].name, r_name) == 0)
+      return &elf64_alpha_howto_table[i];
+
+  return NULL;
+}
+
 /* Given an Alpha ELF reloc type, fill in an arelent structure.  */
 
 static void
@@ -1207,6 +1242,9 @@ elf64_alpha_create_got_section (bfd *abfd,
   flagword flags;
   asection *s;
 
+  if (! is_alpha_elf (abfd))
+    return FALSE;
+
   flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
           | SEC_LINKER_CREATED);
   s = bfd_make_section_anyway_with_flags (abfd, ".got", flags);
@@ -1232,7 +1270,9 @@ elf64_alpha_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
   asection *s;
   flagword flags;
   struct elf_link_hash_entry *h;
-  struct bfd_link_hash_entry *bh;
+
+  if (! is_alpha_elf (abfd))
+    return FALSE;
 
   /* We need to create .plt, .rela.plt, .got, and .rela.got sections.  */
 
@@ -1245,17 +1285,10 @@ elf64_alpha_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
 
   /* Define the symbol _PROCEDURE_LINKAGE_TABLE_ at the start of the
      .plt section.  */
-  bh = NULL;
-  if (! (_bfd_generic_link_add_one_symbol
-        (info, abfd, "_PROCEDURE_LINKAGE_TABLE_", BSF_GLOBAL, s,
-         (bfd_vma) 0, (const char *) NULL, FALSE,
-         get_elf_backend_data (abfd)->collect, &bh)))
-    return FALSE;
-  h = (struct elf_link_hash_entry *) bh;
-  h->def_regular = 1;
-  h->type = STT_OBJECT;
-
-  if (info->shared && ! bfd_elf_link_record_dynamic_symbol (info, h))
+  h = _bfd_elf_define_linkage_sym (abfd, info, s,
+                                  "_PROCEDURE_LINKAGE_TABLE_");
+  elf_hash_table (info)->hplt = h;
+  if (h == NULL)
     return FALSE;
 
   flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
@@ -1292,21 +1325,11 @@ elf64_alpha_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
      dynobj's .got section.  We don't do this in the linker script
      because we don't want to define the symbol if we are not creating
      a global offset table.  */
-  bh = NULL;
-  if (!(_bfd_generic_link_add_one_symbol
-       (info, abfd, "_GLOBAL_OFFSET_TABLE_", BSF_GLOBAL,
-        alpha_elf_tdata(abfd)->got, (bfd_vma) 0, (const char *) NULL,
-        FALSE, get_elf_backend_data (abfd)->collect, &bh)))
-    return FALSE;
-  h = (struct elf_link_hash_entry *) bh;
-  h->def_regular = 1;
-  h->type = STT_OBJECT;
-
-  if (info->shared
-      && ! bfd_elf_link_record_dynamic_symbol (info, h))
-    return FALSE;
-
+  h = _bfd_elf_define_linkage_sym (abfd, info, alpha_elf_tdata(abfd)->got,
+                                  "_GLOBAL_OFFSET_TABLE_");
   elf_hash_table (info)->hgot = h;
+  if (h == NULL)
+    return FALSE;
 
   return TRUE;
 }
@@ -1734,7 +1757,6 @@ elf64_alpha_check_relocs (bfd *abfd, struct bfd_link_info *info,
 {
   bfd *dynobj;
   asection *sreloc;
-  const char *rel_sec_name;
   Elf_Internal_Shdr *symtab_hdr;
   struct alpha_elf_link_hash_entry **sym_hashes;
   const Elf_Internal_Rela *rel, *relend;
@@ -1752,14 +1774,15 @@ elf64_alpha_check_relocs (bfd *abfd, struct bfd_link_info *info,
   if ((sec->flags & SEC_ALLOC) == 0)
     return TRUE;
 
-  dynobj = elf_hash_table(info)->dynobj;
+  BFD_ASSERT (is_alpha_elf (abfd));
+
+  dynobj = elf_hash_table (info)->dynobj;
   if (dynobj == NULL)
-    elf_hash_table(info)->dynobj = dynobj = abfd;
+    elf_hash_table (info)->dynobj = dynobj = abfd;
 
   sreloc = NULL;
-  rel_sec_name = NULL;
-  symtab_hdr = &elf_tdata(abfd)->symtab_hdr;
-  sym_hashes = alpha_elf_sym_hashes(abfd);
+  symtab_hdr = &elf_symtab_hdr (abfd);
+  sym_hashes = alpha_elf_sym_hashes (abfd);
 
   relend = relocs + sec->reloc_count;
   for (rel = relocs; rel < relend; ++rel)
@@ -1907,41 +1930,16 @@ elf64_alpha_check_relocs (bfd *abfd, struct bfd_link_info *info,
 
       if (need & NEED_DYNREL)
        {
-         if (rel_sec_name == NULL)
-           {
-             rel_sec_name = (bfd_elf_string_from_elf_section
-                             (abfd, elf_elfheader(abfd)->e_shstrndx,
-                              elf_section_data(sec)->rel_hdr.sh_name));
-             if (rel_sec_name == NULL)
-               return FALSE;
-
-             BFD_ASSERT (strncmp (rel_sec_name, ".rela", 5) == 0
-                         && strcmp (bfd_get_section_name (abfd, sec),
-                                    rel_sec_name+5) == 0);
-           }
-
          /* We need to create the section here now whether we eventually
             use it or not so that it gets mapped to an output section by
-            the linker.  If not used, we'll kill it in
-            size_dynamic_sections.  */
+            the linker.  If not used, we'll kill it in size_dynamic_sections.  */
          if (sreloc == NULL)
            {
-             sreloc = bfd_get_section_by_name (dynobj, rel_sec_name);
+             sreloc = _bfd_elf_make_dynamic_reloc_section
+               (sec, dynobj, 3, abfd, /*rela?*/ TRUE);
+
              if (sreloc == NULL)
-               {
-                 flagword flags;
-
-                 flags = (SEC_HAS_CONTENTS | SEC_IN_MEMORY
-                          | SEC_LINKER_CREATED | SEC_READONLY);
-                 if (sec->flags & SEC_ALLOC)
-                   flags |= SEC_ALLOC | SEC_LOAD;
-                 sreloc = bfd_make_section_with_flags (dynobj,
-                                                       rel_sec_name,
-                                                       flags);
-                 if (sreloc == NULL
-                     || !bfd_set_section_alignment (dynobj, sreloc, 3))
-                   return FALSE;
-               }
+               return FALSE;
            }
 
          if (h)
@@ -2049,6 +2047,19 @@ elf64_alpha_adjust_dynamic_symbol (struct bfd_link_info *info,
   return TRUE;
 }
 
+/* Record STO_ALPHA_NOPV and STO_ALPHA_STD_GPLOAD.  */
+
+static void
+elf64_alpha_merge_symbol_attribute (struct elf_link_hash_entry *h,
+                                   const Elf_Internal_Sym *isym,
+                                   bfd_boolean definition,
+                                   bfd_boolean dynamic)
+{
+  if (!dynamic && definition)
+    h->other = ((h->other & ELF_ST_VISIBILITY (-1))
+               | (isym->st_other & ~ELF_ST_VISIBILITY (-1)));
+}
+
 /* Symbol versioning can create new symbols, and make our old symbols
    indirect to the new ones.  Consolidate the got and reloc information
    in these situations.  */
@@ -2313,7 +2324,13 @@ elf64_alpha_calc_got_offsets_for_symbol (struct alpha_elf_link_hash_entry *h,
 static void
 elf64_alpha_calc_got_offsets (struct bfd_link_info *info)
 {
-  bfd *i, *got_list = alpha_elf_hash_table(info)->got_list;
+  bfd *i, *got_list;
+  struct alpha_elf_link_hash_table * htab;
+
+  htab = alpha_elf_hash_table (info);
+  if (htab == NULL)
+    return;
+  got_list = htab->got_list;
 
   /* First, zero out the .got sizes, as we may be recalculating the
      .got after optimizing it.  */
@@ -2321,7 +2338,7 @@ elf64_alpha_calc_got_offsets (struct bfd_link_info *info)
     alpha_elf_tdata(i)->got->size = 0;
 
   /* Next, fill in the offsets for all the global entries.  */
-  alpha_elf_link_hash_traverse (alpha_elf_hash_table (info),
+  alpha_elf_link_hash_traverse (htab,
                                elf64_alpha_calc_got_offsets_for_symbol,
                                NULL);
 
@@ -2359,9 +2376,12 @@ static bfd_boolean
 elf64_alpha_size_got_sections (struct bfd_link_info *info)
 {
   bfd *i, *got_list, *cur_got_obj = NULL;
-  int something_changed = 0;
+  struct alpha_elf_link_hash_table * htab;
 
-  got_list = alpha_elf_hash_table (info)->got_list;
+  htab = alpha_elf_hash_table (info);
+  if (htab == NULL)
+    return FALSE;
+  got_list = htab->got_list;
 
   /* On the first time through, pretend we have an existing got list
      consisting of all of the input files.  */
@@ -2369,7 +2389,12 @@ elf64_alpha_size_got_sections (struct bfd_link_info *info)
     {
       for (i = info->input_bfds; i ; i = i->link_next)
        {
-         bfd *this_got = alpha_elf_tdata (i)->gotobj;
+         bfd *this_got;
+
+         if (! is_alpha_elf (i))
+           continue;
+
+         this_got = alpha_elf_tdata (i)->gotobj;
          if (this_got == NULL)
            continue;
 
@@ -2396,13 +2421,13 @@ elf64_alpha_size_got_sections (struct bfd_link_info *info)
       if (got_list == NULL)
        return TRUE;
 
-      alpha_elf_hash_table (info)->got_list = got_list;
-
-      /* Force got offsets to be recalculated.  */
-      something_changed = 1;
+      htab->got_list = got_list;
     }
 
   cur_got_obj = got_list;
+  if (cur_got_obj == NULL)
+    return FALSE;
+
   i = alpha_elf_tdata(cur_got_obj)->got_link_next;
   while (i != NULL)
     {
@@ -2413,8 +2438,6 @@ elf64_alpha_size_got_sections (struct bfd_link_info *info)
          alpha_elf_tdata(i)->got->size = 0;
          i = alpha_elf_tdata(i)->got_link_next;
          alpha_elf_tdata(cur_got_obj)->got_link_next = i;
-         
-         something_changed = 1;
        }
       else
        {
@@ -2425,8 +2448,7 @@ elf64_alpha_size_got_sections (struct bfd_link_info *info)
 
   /* Once the gots have been merged, fill in the got offsets for
      everything therein.  */
-  if (1 || something_changed)
-    elf64_alpha_calc_got_offsets (info);
+  elf64_alpha_calc_got_offsets (info);
 
   return TRUE;
 }
@@ -2461,28 +2483,34 @@ elf64_alpha_size_plt_section_1 (struct alpha_elf_link_hash_entry *h, PTR data)
   return TRUE;
 }
 
-/* Called from relax_section to rebuild the PLT in light of
-   potential changes in the function's status.  */
+/* Called from relax_section to rebuild the PLT in light of potential changes
+   in the function's status.  */
 
-static bfd_boolean
+static void
 elf64_alpha_size_plt_section (struct bfd_link_info *info)
 {
   asection *splt, *spltrel, *sgotplt;
   unsigned long entries;
   bfd *dynobj;
+  struct alpha_elf_link_hash_table * htab;
+
+  htab = alpha_elf_hash_table (info);
+  if (htab == NULL)
+    return;
 
   dynobj = elf_hash_table(info)->dynobj;
   splt = bfd_get_section_by_name (dynobj, ".plt");
   if (splt == NULL)
-    return TRUE;
+    return;
 
   splt->size = 0;
 
-  alpha_elf_link_hash_traverse (alpha_elf_hash_table (info),
+  alpha_elf_link_hash_traverse (htab,
                                elf64_alpha_size_plt_section_1, splt);
 
   /* Every plt entry requires a JMP_SLOT relocation.  */
   spltrel = bfd_get_section_by_name (dynobj, ".rela.plt");
+  entries = 0;
   if (splt->size)
     {
       if (elf64_alpha_use_secureplt)
@@ -2490,8 +2518,6 @@ elf64_alpha_size_plt_section (struct bfd_link_info *info)
       else
        entries = (splt->size - OLD_PLT_HEADER_SIZE) / OLD_PLT_ENTRY_SIZE;
     }
-  else
-    entries = 0;
   spltrel->size = entries * sizeof (Elf64_External_Rela);
 
   /* When using the secureplt, we need two words somewhere in the data
@@ -2502,8 +2528,6 @@ elf64_alpha_size_plt_section (struct bfd_link_info *info)
       sgotplt = bfd_get_section_by_name (dynobj, ".got.plt");
       sgotplt->size = entries ? 16 : 0;
     }
-
-  return TRUE;
 }
 
 static bfd_boolean
@@ -2511,20 +2535,24 @@ elf64_alpha_always_size_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
                                  struct bfd_link_info *info)
 {
   bfd *i;
+  struct alpha_elf_link_hash_table * htab;
 
   if (info->relocatable)
     return TRUE;
 
+  htab = alpha_elf_hash_table (info);
+  if (htab == NULL)
+    return FALSE;
+
   /* First, take care of the indirect symbols created by versioning.  */
-  alpha_elf_link_hash_traverse (alpha_elf_hash_table (info),
-                               elf64_alpha_merge_ind_symbols,
+  alpha_elf_link_hash_traverse (htab, elf64_alpha_merge_ind_symbols,
                                NULL);
 
   if (!elf64_alpha_size_got_sections (info))
     return FALSE;
 
   /* Allocate space for all of the .got subsections.  */
-  i = alpha_elf_hash_table (info)->got_list;
+  i = htab->got_list;
   for ( ; i ; i = alpha_elf_tdata(i)->got_link_next)
     {
       asection *s = alpha_elf_tdata(i)->got;
@@ -2674,18 +2702,23 @@ elf64_alpha_size_rela_got_1 (struct alpha_elf_link_hash_entry *h,
 
 /* Set the sizes of the dynamic relocation sections.  */
 
-static bfd_boolean
+static void
 elf64_alpha_size_rela_got_section (struct bfd_link_info *info)
 {
   unsigned long entries;
   bfd *i, *dynobj;
   asection *srel;
+  struct alpha_elf_link_hash_table * htab;
+
+  htab = alpha_elf_hash_table (info);
+  if (htab == NULL)
+    return;
 
   /* Shared libraries often require RELATIVE relocs, and some relocs
      require attention for the main application as well.  */
 
   entries = 0;
-  for (i = alpha_elf_hash_table(info)->got_list;
+  for (i = htab->got_list;
        i ; i = alpha_elf_tdata(i)->got_link_next)
     {
       bfd *j;
@@ -2713,15 +2746,13 @@ elf64_alpha_size_rela_got_section (struct bfd_link_info *info)
   if (!srel)
     {
       BFD_ASSERT (entries == 0);
-      return TRUE;
+      return;
     }
   srel->size = sizeof (Elf64_External_Rela) * entries;
 
   /* Now do the non-local symbols.  */
-  alpha_elf_link_hash_traverse (alpha_elf_hash_table (info),
+  alpha_elf_link_hash_traverse (htab,
                                elf64_alpha_size_rela_got_1, info);
-
-  return TRUE;
 }
 
 /* Set the sizes of the dynamic sections.  */
@@ -2733,6 +2764,11 @@ elf64_alpha_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
   bfd *dynobj;
   asection *s;
   bfd_boolean relplt;
+  struct alpha_elf_link_hash_table * htab;
+
+  htab = alpha_elf_hash_table (info);
+  if (htab == NULL)
+    return FALSE;
 
   dynobj = elf_hash_table(info)->dynobj;
   BFD_ASSERT(dynobj != NULL);
@@ -2752,7 +2788,7 @@ elf64_alpha_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
         symbols need dynamic relocation entries and which don't.  We've
         collected information in check_relocs that we can now apply to
         size the dynamic relocation sections.  */
-      alpha_elf_link_hash_traverse (alpha_elf_hash_table (info),
+      alpha_elf_link_hash_traverse (htab,
                                    elf64_alpha_calc_dynrel_sizes, info);
 
       elf64_alpha_size_rela_got_section (info);
@@ -2767,7 +2803,6 @@ elf64_alpha_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
   for (s = dynobj->sections; s != NULL; s = s->next)
     {
       const char *name;
-      bfd_boolean strip;
 
       if (!(s->flags & SEC_LINKER_CREATED))
        continue;
@@ -2776,23 +2811,11 @@ elf64_alpha_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
         of the dynobj section names depend upon the input files.  */
       name = bfd_get_section_name (dynobj, s);
 
-      /* If we don't need this section, strip it from the output file.
-        This is to handle .rela.bss and .rela.plt.  We must create it
-        in create_dynamic_sections, because it must be created before
-        the linker maps input sections to output sections.  The
-        linker does that before adjust_dynamic_symbol is called, and
-        it is that function which decides whether anything needs to
-        go into these sections.  */
-
-      strip = FALSE;
-
-      if (strncmp (name, ".rela", 5) == 0)
+      if (CONST_STRNEQ (name, ".rela"))
        {
-         strip = (s->size == 0);
-
-         if (!strip)
+         if (s->size != 0)
            {
-             if (strcmp(name, ".rela.plt") == 0)
+             if (strcmp (name, ".rela.plt") == 0)
                relplt = TRUE;
 
              /* We use the reloc_count field as a counter if we need
@@ -2800,19 +2823,30 @@ elf64_alpha_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
              s->reloc_count = 0;
            }
        }
-      else if (strcmp (name, ".plt") != 0)
+      else if (! CONST_STRNEQ (name, ".got")
+              && strcmp (name, ".plt") != 0
+              && strcmp (name, ".dynbss") != 0)
        {
          /* It's not one of our dynamic sections, so don't allocate space.  */
          continue;
        }
 
-      if (strip)
-       s->flags |= SEC_EXCLUDE;
-      else
+      if (s->size == 0)
+       {
+         /* If we don't need this section, strip it from the output file.
+            This is to handle .rela.bss and .rela.plt.  We must create it
+            in create_dynamic_sections, because it must be created before
+            the linker maps input sections to output sections.  The
+            linker does that before adjust_dynamic_symbol is called, and
+            it is that function which decides whether anything needs to
+            go into these sections.  */
+         s->flags |= SEC_EXCLUDE;
+       }
+      else if ((s->flags & SEC_HAS_CONTENTS) != 0)
        {
          /* Allocate memory for the section contents.  */
          s->contents = (bfd_byte *) bfd_zalloc (dynobj, s->size);
-         if (s->contents == NULL && s->size != 0)
+         if (s->contents == NULL)
            return FALSE;
        }
     }
@@ -3081,7 +3115,7 @@ elf64_alpha_relax_opt_call (struct alpha_relax_info *info, bfd_vma symval)
 
   /* We've now determined that we can skip an initial gp load.  Verify
      that the call and the target use the same gp.   */
-  if (info->link_info->hash->creator != info->tsec->owner->xvec
+  if (info->link_info->output_bfd->xvec != info->tsec->owner->xvec
       || info->gotobj != alpha_elf_tdata (info->tsec->owner)->gotobj)
     return 0;
 
@@ -3594,8 +3628,13 @@ elf64_alpha_relax_section (bfd *abfd, asection *sec,
   Elf_Internal_Sym *isymbuf = NULL;
   struct alpha_elf_got_entry **local_got_entries;
   struct alpha_relax_info info;
+  struct alpha_elf_link_hash_table * htab;
 
-  /* We are not currently changing any sizes, so only one pass.  */
+  htab = alpha_elf_hash_table (link_info);
+  if (htab == NULL)
+    return FALSE;
+
+  /* There's nothing to change, yet.  */
   *again = FALSE;
 
   if (link_info->relocatable
@@ -3604,7 +3643,25 @@ elf64_alpha_relax_section (bfd *abfd, asection *sec,
       || sec->reloc_count == 0)
     return TRUE;
 
-  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+  BFD_ASSERT (is_alpha_elf (abfd));
+
+  /* Make sure our GOT and PLT tables are up-to-date.  */
+  if (htab->relax_trip != link_info->relax_trip)
+    {
+      htab->relax_trip = link_info->relax_trip;
+
+      /* This should never fail after the initial round, since the only
+        error is GOT overflow, and relaxation only shrinks the table.  */
+      if (!elf64_alpha_size_got_sections (link_info))
+       abort ();
+      if (elf_hash_table (link_info)->dynamic_sections_created)
+       {
+         elf64_alpha_size_plt_section (link_info);
+         elf64_alpha_size_rela_got_section (link_info);
+       }
+    }
+
+  symtab_hdr = &elf_symtab_hdr (abfd);
   local_got_entries = alpha_elf_tdata(abfd)->local_got_entries;
 
   /* Load the relocations for this section.  */
@@ -3813,13 +3870,6 @@ elf64_alpha_relax_section (bfd *abfd, asection *sec,
        }
     }
 
-  if (!elf64_alpha_size_plt_section (link_info))
-    return FALSE;
-  if (!elf64_alpha_size_got_sections (link_info))
-    return FALSE;
-  if (!elf64_alpha_size_rela_got_section (link_info))
-    return FALSE;
-
   if (isymbuf != NULL
       && symtab_hdr->contents != (unsigned char *) isymbuf)
     {
@@ -3915,9 +3965,11 @@ elf64_alpha_relocate_section_r (bfd *output_bfd ATTRIBUTE_UNUSED,
   unsigned long symtab_hdr_sh_info;
   Elf_Internal_Rela *rel;
   Elf_Internal_Rela *relend;
+  struct elf_link_hash_entry **sym_hashes;
   bfd_boolean ret_val = TRUE;
 
-  symtab_hdr_sh_info = elf_tdata (input_bfd)->symtab_hdr.sh_info;
+  symtab_hdr_sh_info = elf_symtab_hdr (input_bfd).sh_info;
+  sym_hashes = elf_sym_hashes (input_bfd);
 
   relend = relocs + input_section->reloc_count;
   for (rel = relocs; rel < relend; rel++)
@@ -3927,7 +3979,7 @@ elf64_alpha_relocate_section_r (bfd *output_bfd ATTRIBUTE_UNUSED,
       asection *sec;
       unsigned long r_type;
 
-      r_type = ELF64_R_TYPE(rel->r_info);
+      r_type = ELF64_R_TYPE (rel->r_info);
       if (r_type >= R_ALPHA_max)
        {
          (*_bfd_error_handler)
@@ -3938,22 +3990,49 @@ elf64_alpha_relocate_section_r (bfd *output_bfd ATTRIBUTE_UNUSED,
          continue;
        }
 
-      r_symndx = ELF64_R_SYM(rel->r_info);
-
       /* The symbol associated with GPDISP and LITUSE is
         immaterial.  Only the addend is significant.  */
       if (r_type == R_ALPHA_GPDISP || r_type == R_ALPHA_LITUSE)
        continue;
 
+      r_symndx = ELF64_R_SYM (rel->r_info);
       if (r_symndx < symtab_hdr_sh_info)
        {
          sym = local_syms + r_symndx;
-         if (ELF_ST_TYPE(sym->st_info) == STT_SECTION)
-           {
-             sec = local_sections[r_symndx];
-             rel->r_addend += sec->output_offset + sym->st_value;
-           }
+         sec = local_sections[r_symndx];
+       }
+      else
+       {
+         struct elf_link_hash_entry *h;
+
+         h = sym_hashes[r_symndx - symtab_hdr_sh_info];
+
+         while (h->root.type == bfd_link_hash_indirect
+                || h->root.type == bfd_link_hash_warning)
+           h = (struct elf_link_hash_entry *) h->root.u.i.link;
+
+         if (h->root.type != bfd_link_hash_defined
+             && h->root.type != bfd_link_hash_defweak)
+           continue;
+
+         sym = NULL;
+         sec = h->root.u.def.section;
+       }
+
+      if (sec != NULL && elf_discarded_section (sec))
+       {
+         /* For relocs against symbols from removed linkonce sections,
+            or sections discarded by a linker script, we just want the
+            section contents zeroed.  */
+         _bfd_clear_contents (elf64_alpha_howto_table + r_type,
+                              input_bfd, contents + rel->r_offset);
+         rel->r_info = 0;
+         rel->r_addend = 0;
+         continue;
        }
+
+      if (sym != NULL && ELF_ST_TYPE (sym->st_info) == STT_SECTION)
+       rel->r_addend += sec->output_offset;
     }
 
   return ret_val;
@@ -3977,6 +4056,8 @@ elf64_alpha_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
   struct alpha_elf_got_entry **local_got_entries;
   bfd_boolean ret_val;
 
+  BFD_ASSERT (is_alpha_elf (input_bfd));
+  
   /* Handle relocatable links with a smaller loop.  */
   if (info->relocatable)
     return elf64_alpha_relocate_section_r (output_bfd, info, input_bfd,
@@ -3987,7 +4068,7 @@ elf64_alpha_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
 
   ret_val = TRUE;
 
-  symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
+  symtab_hdr = &elf_symtab_hdr (input_bfd);
 
   dynobj = elf_hash_table (info)->dynobj;
   if (dynobj)
@@ -4153,6 +4234,17 @@ elf64_alpha_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
          gotent = h->got_entries;
        }
 
+      if (sec != NULL && elf_discarded_section (sec))
+       {
+         /* For relocs against symbols from removed linkonce sections,
+            or sections discarded by a linker script, we just want the
+            section contents zeroed.  Avoid any special processing.  */
+         _bfd_clear_contents (howto, input_bfd, contents + rel->r_offset);
+         rel->r_info = 0;
+         rel->r_addend = 0;
+         continue;
+       }
+
       addend = rel->r_addend;
       value += addend;
 
@@ -4212,18 +4304,6 @@ elf64_alpha_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
          goto default_reloc;
 
        case R_ALPHA_GPREL32:
-         /* If the target section was a removed linkonce section,
-            r_symndx will be zero.  In this case, assume that the
-            switch will not be used, so don't fill it in.  If we
-            do nothing here, we'll get relocation truncated messages,
-            due to the placement of the application above 4GB.  */
-         if (r_symndx == 0)
-           {
-             r = bfd_reloc_ok;
-             break;
-           }
-         /* FALLTHRU */
-
        case R_ALPHA_GPREL16:
        case R_ALPHA_GPRELLOW:
          if (dynamic_symbol_p)
@@ -4737,8 +4817,8 @@ elf64_alpha_finish_dynamic_symbol (bfd *output_bfd, struct bfd_link_info *info,
 
   /* Mark some specially defined symbols as absolute.  */
   if (strcmp (h->root.root.string, "_DYNAMIC") == 0
-      || strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0
-      || strcmp (h->root.root.string, "_PROCEDURE_LINKAGE_TABLE_") == 0)
+      || h == elf_hash_table (info)->hgot
+      || h == elf_hash_table (info)->hplt)
     sym->st_shndx = SHN_ABS;
 
   return TRUE;
@@ -4889,7 +4969,12 @@ elf64_alpha_final_link (bfd *abfd, struct bfd_link_info *info)
   const struct ecoff_debug_swap *swap
     = get_elf_backend_data (abfd)->elf_backend_ecoff_debug_swap;
   HDRR *symhdr = &debug.symbolic_header;
-  PTR mdebug_handle = NULL;
+  void * mdebug_handle = NULL;
+  struct alpha_elf_link_hash_table * htab;
+
+  htab = alpha_elf_hash_table (info);
+  if (htab == NULL)
+    return FALSE;
 
   /* Go through the sections and collect the mdebug information.  */
   mdebug_sec = NULL;
@@ -4998,15 +5083,11 @@ elf64_alpha_final_link (bfd *abfd, struct bfd_link_info *info)
              input_section = p->u.indirect.section;
              input_bfd = input_section->owner;
 
-             if (bfd_get_flavour (input_bfd) != bfd_target_elf_flavour
-                 || (get_elf_backend_data (input_bfd)
-                     ->elf_backend_ecoff_debug_swap) == NULL)
-               {
-                 /* I don't know what a non ALPHA ELF bfd would be
-                    doing with a .mdebug section, but I don't really
-                    want to deal with it.  */
-                 continue;
-               }
+             if (! is_alpha_elf (input_bfd))
+               /* I don't know what a non ALPHA ELF bfd would be
+                  doing with a .mdebug section, but I don't really
+                  want to deal with it.  */
+               continue;
 
              input_swap = (get_elf_backend_data (input_bfd)
                            ->elf_backend_ecoff_debug_swap);
@@ -5029,7 +5110,7 @@ elf64_alpha_final_link (bfd *abfd, struct bfd_link_info *info)
                 interesting information, try to find the symbol in
                 the linker global hash table and save the information
                 for the output external symbols.  */
-             eraw_src = input_debug.external_ext;
+             eraw_src = (char *) input_debug.external_ext;
              eraw_end = (eraw_src
                          + (input_debug.symbolic_header.iextMax
                             * input_swap->external_ext_size));
@@ -5048,8 +5129,7 @@ elf64_alpha_final_link (bfd *abfd, struct bfd_link_info *info)
                    continue;
 
                  name = input_debug.ssext + ext.asym.iss;
-                 h = alpha_elf_link_hash_lookup (alpha_elf_hash_table (info),
-                                                 name, FALSE, FALSE, TRUE);
+                 h = alpha_elf_link_hash_lookup (htab, name, FALSE, FALSE, TRUE);
                  if (h == NULL || h->esym.ifd != -2)
                    continue;
 
@@ -5113,7 +5193,7 @@ elf64_alpha_final_link (bfd *abfd, struct bfd_link_info *info)
   /* The .got subsections...  */
   {
     bfd *i, *dynobj = elf_hash_table(info)->dynobj;
-    for (i = alpha_elf_hash_table(info)->got_list;
+    for (i = htab->got_list;
         i != NULL;
         i = alpha_elf_tdata(i)->got_link_next)
       {
@@ -5162,44 +5242,11 @@ elf64_alpha_reloc_type_class (const Elf_Internal_Rela *rela)
     }
 }
 \f
-static struct bfd_elf_special_section const
-  alpha_special_sections_s[]=
-{
-  { ".sdata", 6, -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE + SHF_ALPHA_GPREL },
-  { ".sbss",  5, -2, SHT_NOBITS,   SHF_ALLOC + SHF_WRITE + SHF_ALPHA_GPREL },
-  { NULL,     0,  0, 0,            0 }
-};
-
-static struct bfd_elf_special_section const *
-  elf64_alpha_special_sections[27] =
+static const struct bfd_elf_special_section elf64_alpha_special_sections[] =
 {
-  NULL,                                /* 'a' */
-  NULL,                                /* 'b' */
-  NULL,                                /* 'c' */
-  NULL,                                /* 'd' */
-  NULL,                                /* 'e' */
-  NULL,                                /* 'f' */
-  NULL,                                /* 'g' */
-  NULL,                                /* 'h' */
-  NULL,                                /* 'i' */
-  NULL,                                /* 'j' */
-  NULL,                                /* 'k' */
-  NULL,                                /* 'l' */
-  NULL,                                /* 'm' */
-  NULL,                                /* 'n' */
-  NULL,                                /* 'o' */
-  NULL,                                /* 'p' */
-  NULL,                                /* 'q' */
-  NULL,                                /* 'r' */
-  alpha_special_sections_s,    /* 's' */
-  NULL,                                /* 't' */
-  NULL,                                /* 'u' */
-  NULL,                                /* 'v' */
-  NULL,                                /* 'w' */
-  NULL,                                /* 'x' */
-  NULL,                                /* 'y' */
-  NULL,                                /* 'z' */
-  NULL                         /* other */
+  { STRING_COMMA_LEN (".sbss"),  -2, SHT_NOBITS,   SHF_ALLOC + SHF_WRITE + SHF_ALPHA_GPREL },
+  { STRING_COMMA_LEN (".sdata"), -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE + SHF_ALPHA_GPREL },
+  { NULL,                     0,  0, 0,            0 }
 };
 
 /* ECOFF swapping routines.  These are used when dealing with the
@@ -5265,6 +5312,7 @@ static const struct elf_size_info alpha_elf_size_info =
   ELFCLASS64, EV_CURRENT,
   bfd_elf64_write_out_phdrs,
   bfd_elf64_write_shdrs_and_ehdr,
+  bfd_elf64_checksum_contents,
   bfd_elf64_write_relocs,
   bfd_elf64_swap_symbol_in,
   bfd_elf64_swap_symbol_out,
@@ -5283,12 +5331,15 @@ static const struct elf_size_info alpha_elf_size_info =
 #define ELF_ARCH               bfd_arch_alpha
 #define ELF_MACHINE_CODE       EM_ALPHA
 #define ELF_MAXPAGESIZE        0x10000
+#define ELF_COMMONPAGESIZE     0x2000
 
 #define bfd_elf64_bfd_link_hash_table_create \
   elf64_alpha_bfd_link_hash_table_create
 
 #define bfd_elf64_bfd_reloc_type_lookup \
   elf64_alpha_bfd_reloc_type_lookup
+#define bfd_elf64_bfd_reloc_name_lookup \
+  elf64_alpha_bfd_reloc_name_lookup
 #define elf_info_to_howto \
   elf64_alpha_info_to_howto
 
@@ -5313,16 +5364,22 @@ static const struct elf_size_info alpha_elf_size_info =
 
 #define elf_backend_add_symbol_hook \
   elf64_alpha_add_symbol_hook
+#define elf_backend_relocs_compatible \
+  _bfd_elf_relocs_compatible
 #define elf_backend_check_relocs \
   elf64_alpha_check_relocs
 #define elf_backend_create_dynamic_sections \
   elf64_alpha_create_dynamic_sections
 #define elf_backend_adjust_dynamic_symbol \
   elf64_alpha_adjust_dynamic_symbol
+#define elf_backend_merge_symbol_attribute \
+  elf64_alpha_merge_symbol_attribute
 #define elf_backend_always_size_sections \
   elf64_alpha_always_size_sections
 #define elf_backend_size_dynamic_sections \
   elf64_alpha_size_dynamic_sections
+#define elf_backend_omit_section_dynsym \
+  ((bfd_boolean (*) (bfd *, struct bfd_link_info *, asection *)) bfd_true)
 #define elf_backend_relocate_section \
   elf64_alpha_relocate_section
 #define elf_backend_finish_dynamic_symbol \
@@ -5357,6 +5414,8 @@ static const struct elf_size_info alpha_elf_size_info =
 #define TARGET_LITTLE_SYM      bfd_elf64_alpha_freebsd_vec
 #undef TARGET_LITTLE_NAME
 #define TARGET_LITTLE_NAME     "elf64-alpha-freebsd"
+#undef ELF_OSABI
+#define        ELF_OSABI               ELFOSABI_FREEBSD
 
 /* The kernel recognizes executables as valid only if they carry a
    "FreeBSD" label in the ELF header.  So we put this label on all
@@ -5371,7 +5430,7 @@ elf64_alpha_fbsd_post_process_headers (bfd * abfd,
   i_ehdrp = elf_elfheader (abfd);
 
   /* Put an ABI label supported by FreeBSD >= 4.1.  */
-  i_ehdrp->e_ident[EI_OSABI] = ELFOSABI_FREEBSD;
+  i_ehdrp->e_ident[EI_OSABI] = get_elf_backend_data (abfd)->elf_osabi;
 #ifdef OLD_FREEBSD_ABI_LABEL
   /* The ABI label supported by FreeBSD <= 4.0 is quite nonstandard.  */
   memcpy (&i_ehdrp->e_ident[EI_ABIVERSION], "FreeBSD", 8);
This page took 0.069187 seconds and 4 git commands to generate.