* elf-bfd.h (struct elf_reloc_cookie): Remove locsym_shndx,
[deliverable/binutils-gdb.git] / bfd / elf64-alpha.c
index e25e934aa6e9f0ff2f4214af5dc8f6d8c46ed525..36b0cb69d4c0cf1d0bf7825d19201b2881a43e5e 100644 (file)
@@ -73,7 +73,7 @@ static boolean elf64_alpha_mkobject
 static boolean elf64_alpha_object_p
   PARAMS((bfd *));
 static boolean elf64_alpha_section_from_shdr
-  PARAMS((bfd *, Elf64_Internal_Shdr *, char *));
+  PARAMS((bfd *, Elf64_Internal_Shdr *, const char *));
 static boolean elf64_alpha_section_flags
   PARAMS((flagword *, Elf64_Internal_Shdr *));
 static boolean elf64_alpha_fake_sections
@@ -106,13 +106,21 @@ static boolean elf64_alpha_calc_got_offsets_for_symbol
   PARAMS ((struct alpha_elf_link_hash_entry *, PTR));
 static void elf64_alpha_calc_got_offsets PARAMS ((struct bfd_link_info *));
 static boolean elf64_alpha_size_got_sections
-  PARAMS ((bfd *, struct bfd_link_info *));
+  PARAMS ((struct bfd_link_info *));
+static boolean elf64_alpha_size_plt_section
+  PARAMS ((struct bfd_link_info *));
+static boolean elf64_alpha_size_plt_section_1
+  PARAMS ((struct alpha_elf_link_hash_entry *, PTR));
 static boolean elf64_alpha_always_size_sections
   PARAMS ((bfd *, struct bfd_link_info *));
 static int alpha_dynamic_entries_for_reloc
   PARAMS ((int, int, int));
 static boolean elf64_alpha_calc_dynrel_sizes
   PARAMS ((struct alpha_elf_link_hash_entry *, struct bfd_link_info *));
+static boolean elf64_alpha_size_rela_got_section
+  PARAMS ((struct bfd_link_info *));
+static boolean elf64_alpha_size_rela_got_1
+  PARAMS ((struct alpha_elf_link_hash_entry *, struct bfd_link_info *));
 static boolean elf64_alpha_add_symbol_hook
   PARAMS ((bfd *, struct bfd_link_info *, const Elf_Internal_Sym *,
           const char **, flagword *, asection **, bfd_vma *));
@@ -126,6 +134,9 @@ static boolean elf64_alpha_adjust_dynamic_symbol
   PARAMS((struct bfd_link_info *, struct elf_link_hash_entry *));
 static boolean elf64_alpha_size_dynamic_sections
   PARAMS((bfd *, struct bfd_link_info *));
+static boolean elf64_alpha_relocate_section_r
+  PARAMS((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
+         Elf_Internal_Rela *, Elf_Internal_Sym *, asection **));
 static boolean elf64_alpha_relocate_section
   PARAMS((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
          Elf_Internal_Rela *, Elf_Internal_Sym *, asection **));
@@ -1388,14 +1399,16 @@ elf64_alpha_relax_with_lituse (info, symval, irel)
        case LITUSE_ALPHA_TLSGD:
        case LITUSE_ALPHA_TLSLDM:
          {
-           /* If not zero, place to jump without needing pv.  */
-           bfd_vma optdest = elf64_alpha_relax_opt_call (info, symval);
-           bfd_vma org = (info->sec->output_section->vma
-                          + info->sec->output_offset
-                          + urel->r_offset + 4);
+           bfd_vma optdest, org;
            bfd_signed_vma odisp;
 
+           /* If not zero, place to jump without needing pv.  */
+           optdest = elf64_alpha_relax_opt_call (info, symval);
+           org = (info->sec->output_section->vma
+                  + info->sec->output_offset
+                  + urel->r_offset + 4);
            odisp = (optdest ? optdest : symval) - org;
+
            if (odisp >= -0x400000 && odisp < 0x400000)
              {
                Elf_Internal_Rela *xrel;
@@ -1441,7 +1454,7 @@ elf64_alpha_relax_with_lituse (info, symval, irel)
                      R_ALPHA_GPDISP));
                if (gpdisp)
                  {
-                   bfd_byte *p_ldah = info->contents + gpdisp->r_offset; 
+                   bfd_byte *p_ldah = info->contents + gpdisp->r_offset;
                    bfd_byte *p_lda = p_ldah + gpdisp->r_addend;
                    unsigned int ldah = bfd_get_32 (info->abfd, p_ldah);
                    unsigned int lda = bfd_get_32 (info->abfd, p_lda);
@@ -1623,7 +1636,7 @@ elf64_alpha_relax_got_load (info, symval, irel, r_type)
     insn = (OP_LDA << 26) | (insn & (31 << 21)) | (31 << 16);
   bfd_put_32 (info->abfd, (bfd_vma) insn, info->contents + irel->r_offset);
   info->changed_contents = true;
-  
+
   switch (r_type)
     {
     case R_ALPHA_LITERAL:
@@ -1975,24 +1988,21 @@ elf64_alpha_relax_find_tls_segment (info, seg)
      struct elf_link_tls_segment *seg;
 {
   bfd *output_bfd = info->sec->output_section->owner;
-  asection *first_tls_sec = NULL, *o;
+  asection *o;
   unsigned int align;
   bfd_vma base, end;
 
   for (o = output_bfd->sections; o ; o = o->next)
     if ((o->flags & SEC_THREAD_LOCAL) != 0
         && (o->flags & SEC_LOAD) != 0)
-      {
-        first_tls_sec = o;
-        break;
-      }
-  if (!first_tls_sec)
+      break;
+  if (!o)
     return NULL;
 
-  base = first_tls_sec->vma;
+  base = o->vma;
   align = 0;
 
-  for (o = first_tls_sec; o && (o->flags & SEC_THREAD_LOCAL); o = o->next)
+  do
     {
       bfd_vma size;
 
@@ -2008,7 +2018,9 @@ elf64_alpha_relax_find_tls_segment (info, seg)
              size = lo->offset + lo->size;
        }
       end = o->vma + size;
+      o = o->next;
     }
+  while (o && (o->flags & SEC_THREAD_LOCAL));
 
   seg->start = base;
   seg->size = end - base;
@@ -2025,14 +2037,9 @@ elf64_alpha_relax_section (abfd, sec, link_info, again)
      boolean *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 *free_contents = NULL;
-  Elf64_External_Sym *extsyms;
-  Elf64_External_Sym *free_extsyms = NULL;
-  Elf_External_Sym_Shndx *shndx_buf = NULL;
+  Elf_Internal_Sym *isymbuf = NULL;
   struct alpha_elf_got_entry **local_got_entries;
   struct alpha_relax_info info;
   struct elf_link_tls_segment tls_segment;
@@ -2058,9 +2065,7 @@ elf64_alpha_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;
 
   memset(&info, 0, sizeof (info));
   info.abfd = abfd;
@@ -2070,7 +2075,7 @@ elf64_alpha_relax_section (abfd, sec, link_info, again)
   info.relocs = internal_relocs;
   info.relend = irelend = internal_relocs + sec->reloc_count;
 
-  /* Find the GP for this object.  Do not store the result back via 
+  /* Find the GP for this object.  Do not store the result back via
      _bfd_set_gp_value, since this could change again before final.  */
   info.gotobj = alpha_elf_tdata (abfd)->gotobj;
   if (info.gotobj)
@@ -2089,41 +2094,12 @@ elf64_alpha_relax_section (abfd, sec, link_info, again)
       info.contents = (bfd_byte *) bfd_malloc (sec->_raw_size);
       if (info.contents == NULL)
        goto error_return;
-      free_contents = info.contents;
 
       if (! bfd_get_section_contents (abfd, sec, info.contents,
                                      (file_ptr) 0, sec->_raw_size))
        goto error_return;
     }
 
-  /* Read this BFD's symbols.  */
-  if (symtab_hdr->contents != NULL)
-    extsyms = (Elf64_External_Sym *) symtab_hdr->contents;
-  else
-    {
-      bfd_size_type amt = symtab_hdr->sh_info * sizeof (Elf64_External_Sym);
-      extsyms = (Elf64_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 ((PTR) 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 ((PTR) shndx_buf, amt, abfd) != amt)
-       goto error_return;
-    }
-
   /* Compute the TLS segment information.  The version normally found in
      elf_hash_table (link_info)->tls_segment isn't built until final_link.
      ??? Probably should look into extracting this into a common function.  */
@@ -2132,7 +2108,6 @@ elf64_alpha_relax_section (abfd, sec, link_info, again)
   for (irel = internal_relocs; irel < irelend; irel++)
     {
       bfd_vma symval;
-      Elf_Internal_Sym isym;
       struct alpha_elf_got_entry *gotent;
       unsigned long r_type = ELF64_R_TYPE (irel->r_info);
 
@@ -2155,25 +2130,34 @@ elf64_alpha_relax_section (abfd, sec, link_info, again)
       if (ELF64_R_SYM (irel->r_info) < symtab_hdr->sh_info)
        {
          /* A local symbol.  */
-         Elf64_External_Sym *esym;
-         Elf_External_Sym_Shndx *shndx;
-
-         esym = extsyms + ELF64_R_SYM (irel->r_info);
-         shndx = shndx_buf + (shndx_buf ? ELF64_R_SYM (irel->r_info) : 0);
-         bfd_elf64_swap_symbol_in (abfd, esym, shndx, &isym);
-         if (isym.st_shndx == SHN_UNDEF)
-           info.tsec = bfd_und_section_ptr;
-         else if (isym.st_shndx == SHN_ABS)
+         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 == NULL)
+               goto error_return;
+           }
+
+         isym = isymbuf + ELF64_R_SYM (irel->r_info);
+         if (isym->st_shndx == SHN_UNDEF)
+           continue;
+         else if (isym->st_shndx == SHN_ABS)
            info.tsec = bfd_abs_section_ptr;
-         else if (isym.st_shndx == SHN_COMMON)
+         else if (isym->st_shndx == SHN_COMMON)
            info.tsec = bfd_com_section_ptr;
          else
-           info.tsec = bfd_section_from_elf_index (abfd, isym.st_shndx);
+           info.tsec = bfd_section_from_elf_index (abfd, isym->st_shndx);
 
          info.h = NULL;
-         info.other = isym.st_other;
+         info.other = isym->st_other;
          info.first_gotent = &local_got_entries[ELF64_R_SYM(irel->r_info)];
-         symval = isym.st_value;
+         symval = isym->st_value;
        }
       else
        {
@@ -2188,6 +2172,16 @@ elf64_alpha_relax_section (abfd, sec, link_info, again)
                 || h->root.root.type == bfd_link_hash_warning)
            h = (struct alpha_elf_link_hash_entry *)h->root.root.u.i.link;
 
+         /* If the symbol is undefined, we can't do anything with it.  */
+         if (h->root.root.type == bfd_link_hash_undefweak
+             || h->root.root.type == bfd_link_hash_undefined)
+           continue;
+
+         /* If the symbol isn't defined in the current module, again
+            we can't do anything.  */
+         if (!(h->root.elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR))
+           continue;
+
          info.h = h;
          info.tsec = h->root.root.u.def.section;
          info.other = h->root.other;
@@ -2251,20 +2245,30 @@ elf64_alpha_relax_section (abfd, sec, link_info, again)
        }
     }
 
-  if (!elf64_alpha_size_got_sections (abfd, link_info))
+  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 (info.changed_relocs)
-    elf_section_data (sec)->relocs = internal_relocs;
-  else if (free_relocs != NULL)
-    free (free_relocs);
+  if (isymbuf != NULL
+      && symtab_hdr->contents != (unsigned char *) isymbuf)
+    {
+      if (!link_info->keep_memory)
+       free (isymbuf);
+      else
+       {
+         /* Cache the symbols for elf_link_input_bfd.  */
+         symtab_hdr->contents = (unsigned char *) isymbuf;
+       }
+    }
 
-  if (info.changed_contents)
-    elf_section_data (sec)->this_hdr.contents = info.contents;
-  else if (free_contents != NULL)
+  if (info.contents != NULL
+      && elf_section_data (sec)->this_hdr.contents != info.contents)
     {
-      if (! link_info->keep_memory)
-       free (free_contents);
+      if (!info.changed_contents && !link_info->keep_memory)
+       free (info.contents);
       else
        {
          /* Cache the section contents for elf_link_input_bfd.  */
@@ -2272,18 +2276,12 @@ elf64_alpha_relax_section (abfd, sec, link_info, again)
        }
     }
 
-  if (shndx_buf != NULL)
-    free (shndx_buf);
-
-  if (free_extsyms != NULL)
+  if (elf_section_data (sec)->relocs != internal_relocs)
     {
-      if (! link_info->keep_memory)
-       free (free_extsyms);
+      if (!info.changed_relocs)
+       free (internal_relocs);
       else
-       {
-         /* Cache the symbols for elf_link_input_bfd.  */
-         symtab_hdr->contents = (unsigned char *) extsyms;
-       }
+       elf_section_data (sec)->relocs = internal_relocs;
     }
 
   *again = info.changed_contents || info.changed_relocs;
@@ -2291,14 +2289,15 @@ elf64_alpha_relax_section (abfd, sec, link_info, again)
   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
+      && symtab_hdr->contents != (unsigned char *) isymbuf)
+    free (isymbuf);
+  if (info.contents != NULL
+      && elf_section_data (sec)->this_hdr.contents != info.contents)
+    free (info.contents);
+  if (internal_relocs != NULL
+      && elf_section_data (sec)->relocs != internal_relocs)
+    free (internal_relocs);
   return false;
 }
 \f
@@ -2327,7 +2326,7 @@ static boolean
 elf64_alpha_section_from_shdr (abfd, hdr, name)
      bfd *abfd;
      Elf64_Internal_Shdr *hdr;
-     char *name;
+     const char *name;
 {
   asection *newsect;
 
@@ -2579,9 +2578,8 @@ elf64_alpha_read_ecoff_info (abfd, section, debug)
   if (ext_hdr == NULL && swap->external_hdr_size != 0)
     goto error_return;
 
-  if (bfd_get_section_contents (abfd, section, ext_hdr, (file_ptr) 0,
-                               swap->external_hdr_size)
-      == false)
+  if (! bfd_get_section_contents (abfd, section, ext_hdr, (file_ptr) 0,
+                                 swap->external_hdr_size))
     goto error_return;
 
   symhdr = &debug->symbolic_header;
@@ -2947,11 +2945,10 @@ get_got_entry (abfd, h, r_type, r_symndx, r_addend)
          size *= sizeof (struct alpha_elf_got_entry *);
 
          local_got_entries
-           = (struct alpha_elf_got_entry **) bfd_alloc (abfd, size);
+           = (struct alpha_elf_got_entry **) bfd_zalloc (abfd, size);
          if (!local_got_entries)
            return NULL;
 
-         memset (local_got_entries, 0, (size_t) size);
          alpha_elf_tdata (abfd)->local_got_entries = local_got_entries;
        }
 
@@ -3650,8 +3647,7 @@ elf64_alpha_calc_got_offsets (info)
 /* Constructs the gots.  */
 
 static boolean
-elf64_alpha_size_got_sections (output_bfd, info)
-     bfd *output_bfd ATTRIBUTE_UNUSED;
+elf64_alpha_size_got_sections (info)
      struct bfd_link_info *info;
 {
   bfd *i, *got_list, *cur_got_obj = NULL;
@@ -3725,9 +3721,80 @@ elf64_alpha_size_got_sections (output_bfd, info)
   return true;
 }
 
+/* Called from relax_section to rebuild the PLT in light of
+   potential changes in the function's status.  */
+
+static boolean
+elf64_alpha_size_plt_section (info)
+     struct bfd_link_info *info;
+{
+  asection *splt, *spltrel;
+  unsigned long entries;
+  bfd *dynobj;
+
+  dynobj = elf_hash_table(info)->dynobj;
+  splt = bfd_get_section_by_name(dynobj, ".plt");
+  if (splt == NULL)
+    return true;
+
+  splt->_raw_size = 0;
+
+  alpha_elf_link_hash_traverse (alpha_elf_hash_table (info),
+                               elf64_alpha_size_plt_section_1, splt);
+
+  splt->_cooked_size = splt->_raw_size;
+
+  /* Every plt entry requires a JMP_SLOT relocation.  */
+  spltrel = bfd_get_section_by_name (dynobj, ".rela.plt");
+  if (splt->_raw_size)
+    entries = (splt->_raw_size - PLT_HEADER_SIZE) / PLT_ENTRY_SIZE;
+  else
+    entries = 0;
+  spltrel->_raw_size = entries * sizeof (Elf64_External_Rela);
+  spltrel->_cooked_size = spltrel->_raw_size;
+
+  return true;
+}
+
+static boolean
+elf64_alpha_size_plt_section_1 (h, data)
+     struct alpha_elf_link_hash_entry *h;
+     PTR data;
+{
+  asection *splt = (asection *) data;
+  struct alpha_elf_got_entry *gotent;
+
+  /* If we didn't need an entry before, we still don't.  */
+  if (!(h->root.elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT))
+    return true;
+
+  /* There must still be a LITERAL got entry for the function.  */
+  for (gotent = h->got_entries; gotent ; gotent = gotent->next)
+    if (gotent->reloc_type == R_ALPHA_LITERAL
+       && gotent->use_count > 0)
+      break;
+
+  /* If there is, reset the PLT offset.  If not, there's no longer
+     a need for the PLT entry.  */
+  if (gotent)
+    {
+      if (splt->_raw_size == 0)
+       splt->_raw_size = PLT_HEADER_SIZE;
+      h->root.plt.offset = splt->_raw_size;
+      splt->_raw_size += PLT_ENTRY_SIZE;
+    }
+  else
+    {
+      h->root.elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT;
+      h->root.plt.offset = -1;
+    }
+
+  return true;
+}
+
 static boolean
 elf64_alpha_always_size_sections (output_bfd, info)
-     bfd *output_bfd;
+     bfd *output_bfd ATTRIBUTE_UNUSED;
      struct bfd_link_info *info;
 {
   bfd *i;
@@ -3740,7 +3807,7 @@ elf64_alpha_always_size_sections (output_bfd, info)
                                elf64_alpha_merge_ind_symbols,
                                NULL);
 
-  if (!elf64_alpha_size_got_sections (output_bfd, info))
+  if (!elf64_alpha_size_got_sections (info))
     return false;
 
   /* Allocate space for all of the .got subsections.  */
@@ -3802,8 +3869,7 @@ elf64_alpha_calc_dynrel_sizes (h, info)
 {
   boolean dynamic;
   struct alpha_elf_reloc_entry *relent;
-  struct alpha_elf_got_entry *gotent;
-  int entries;
+  unsigned long entries;
 
   if (h->root.root.type == bfd_link_hash_warning)
     h = (struct alpha_elf_link_hash_entry *) h->root.root.u.i.link;
@@ -3823,9 +3889,7 @@ elf64_alpha_calc_dynrel_sizes (h, info)
       && (h->root.root.type == bfd_link_hash_defined
          || h->root.root.type == bfd_link_hash_defweak)
       && !(h->root.root.u.def.section->owner->flags & DYNAMIC))
-    {
-      h->root.elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR;
-    }
+    h->root.elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR;
 
   /* If the symbol is dynamic, we'll need all the relocations in their
      natural form.  If this is a shared object, and it has been forced
@@ -3846,10 +3910,90 @@ elf64_alpha_calc_dynrel_sizes (h, info)
        }
     }
 
+  return true;
+}
+
+/* Set the sizes of the dynamic relocation sections.  */
+
+static boolean
+elf64_alpha_size_rela_got_section (info)
+     struct bfd_link_info *info;
+{
+  unsigned long entries;
+  bfd *i, *dynobj;
+  asection *srel;
+
+  /* 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;
+       i ; i = alpha_elf_tdata(i)->got_link_next)
+    {
+      bfd *j;
+
+      for (j = i; j ; j = alpha_elf_tdata(j)->in_got_link_next)
+       {
+         struct alpha_elf_got_entry **local_got_entries, *gotent;
+         int k, n;
+
+         local_got_entries = alpha_elf_tdata(j)->local_got_entries;
+         if (!local_got_entries)
+           continue;
+
+         for (k = 0, n = elf_tdata(j)->symtab_hdr.sh_info; k < n; ++k)
+           for (gotent = local_got_entries[k];
+                gotent ; gotent = gotent->next)
+             if (gotent->use_count > 0)
+               entries += (alpha_dynamic_entries_for_reloc
+                           (gotent->reloc_type, 0, info->shared));
+       }
+    }
+
+  dynobj = elf_hash_table(info)->dynobj;
+  srel = bfd_get_section_by_name (dynobj, ".rela.got");
+  if (!srel)
+    {
+      BFD_ASSERT (entries == 0);
+      return true;
+    }
+  srel->_raw_size = sizeof (Elf64_External_Rela) * entries;
+
+  /* Now do the non-local symbols.  */
+  alpha_elf_link_hash_traverse (alpha_elf_hash_table (info),
+                               elf64_alpha_size_rela_got_1, info);
+
+  srel->_cooked_size = srel->_raw_size;
+
+  return true;
+}
+
+/* Subroutine of elf64_alpha_size_rela_got_section for doing the
+   global symbols.  */
+
+static boolean
+elf64_alpha_size_rela_got_1 (h, info)
+     struct alpha_elf_link_hash_entry *h;
+     struct bfd_link_info *info;
+{
+  boolean dynamic;
+  struct alpha_elf_got_entry *gotent;
+  unsigned long entries;
+
+  if (h->root.root.type == bfd_link_hash_warning)
+    h = (struct alpha_elf_link_hash_entry *) h->root.root.u.i.link;
+
+  /* If the symbol is dynamic, we'll need all the relocations in their
+     natural form.  If this is a shared object, and it has been forced
+     local, we'll need the same number of RELATIVE relocations.  */
+
+  dynamic = alpha_elf_dynamic_symbol_p (&h->root, info);
+
   entries = 0;
   for (gotent = h->got_entries; gotent ; gotent = gotent->next)
-    entries += alpha_dynamic_entries_for_reloc (gotent->reloc_type,
-                                               dynamic, info->shared);
+    if (gotent->use_count > 0)
+      entries += alpha_dynamic_entries_for_reloc (gotent->reloc_type,
+                                                 dynamic, info->shared);
 
   /* If we are using a .plt entry, subtract one, as the first
      reference uses a .rela.plt entry instead.  */
@@ -3883,9 +4027,6 @@ elf64_alpha_size_dynamic_sections (output_bfd, info)
 
   if (elf_hash_table (info)->dynamic_sections_created)
     {
-      int entries;
-      bfd *i;
-
       /* Set the contents of the .interp section to the interpreter.  */
       if (!info->shared)
        {
@@ -3900,42 +4041,9 @@ elf64_alpha_size_dynamic_sections (output_bfd, info)
         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),
-                                   elf64_alpha_calc_dynrel_sizes,
-                                   info);
-
-      /* 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;
-          i ; i = alpha_elf_tdata(i)->got_link_next)
-       {
-         bfd *j;
-
-         for (j = i; j ; j = alpha_elf_tdata(j)->in_got_link_next)
-           {
-             struct alpha_elf_got_entry **local_got_entries, *gotent;
-             int k, n;
-
-             local_got_entries = alpha_elf_tdata(j)->local_got_entries;
-             if (!local_got_entries)
-               continue;
-
-             for (k = 0, n = elf_tdata(j)->symtab_hdr.sh_info; k < n; ++k)
-               for (gotent = local_got_entries[k];
-                    gotent ; gotent = gotent->next)
-                 if (gotent->use_count > 0)
-                   entries += (alpha_dynamic_entries_for_reloc
-                               (gotent->reloc_type, 0, info->shared));
-           }
-       }
+                                   elf64_alpha_calc_dynrel_sizes, info);
 
-      if (entries > 0)
-       {
-         s = bfd_get_section_by_name (dynobj, ".rela.got");
-         BFD_ASSERT (s != NULL);
-         s->_raw_size += sizeof (Elf64_External_Rela) * entries;
-       }
+      elf64_alpha_size_rela_got_section (info);
     }
   /* else we're not dynamic and by definition we don't need such things.  */
 
@@ -4039,6 +4147,71 @@ elf64_alpha_size_dynamic_sections (output_bfd, info)
   return true;
 }
 
+/* Relocate an Alpha ELF section for a relocatable 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.  */
+
+static boolean
+elf64_alpha_relocate_section_r (output_bfd, info, input_bfd, input_section,
+                               contents, relocs, local_syms, local_sections)
+     bfd *output_bfd ATTRIBUTE_UNUSED;
+     struct bfd_link_info *info ATTRIBUTE_UNUSED;
+     bfd *input_bfd;
+     asection *input_section;
+     bfd_byte *contents ATTRIBUTE_UNUSED;
+     Elf_Internal_Rela *relocs;
+     Elf_Internal_Sym *local_syms;
+     asection **local_sections;
+{
+  unsigned long symtab_hdr_sh_info;
+  Elf_Internal_Rela *rel;
+  Elf_Internal_Rela *relend;
+  boolean ret_val = true;
+
+  symtab_hdr_sh_info = elf_tdata (input_bfd)->symtab_hdr.sh_info;
+
+  relend = relocs + input_section->reloc_count;
+  for (rel = relocs; rel < relend; rel++)
+    {
+      unsigned long r_symndx;
+      Elf_Internal_Sym *sym;
+      asection *sec;
+      unsigned long r_type;
+
+      r_type = ELF64_R_TYPE(rel->r_info);
+      if (r_type >= R_ALPHA_max)
+       {
+         (*_bfd_error_handler)
+           (_("%s: unknown relocation type %d"),
+            bfd_archive_filename (input_bfd), (int)r_type);
+         bfd_set_error (bfd_error_bad_value);
+         ret_val = false;
+         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;
+
+      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;
+           }
+       }
+    }
+
+  return ret_val;
+}
+
 /* Relocate an Alpha ELF section.  */
 
 static boolean
@@ -4053,67 +4226,86 @@ elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section,
      Elf_Internal_Sym *local_syms;
      asection **local_sections;
 {
-  Elf_Internal_Shdr *symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
+  Elf_Internal_Shdr *symtab_hdr;
   Elf_Internal_Rela *rel;
   Elf_Internal_Rela *relend;
-  struct elf_link_tls_segment *tls_segment = NULL;
-  asection *sgot = NULL, *srel = NULL, *srelgot = NULL;
-  bfd *dynobj = NULL, *gotobj = NULL;
-  bfd_vma gp = 0, tp_base = 0, dtp_base = 0;
-  boolean ret_val = true;
+  struct elf_link_tls_segment *tls_segment;
+  asection *sgot, *srel, *srelgot;
+  bfd *dynobj, *gotobj;
+  bfd_vma gp, tp_base, dtp_base;
+  struct alpha_elf_got_entry **local_got_entries;
+  boolean ret_val;
+  const char *section_name;
 
-  if (!info->relocateable)
-    {
-      const char *name;
+  /* Handle relocatable links with a smaller loop.  */
+  if (info->relocateable)
+    return elf64_alpha_relocate_section_r (output_bfd, info, input_bfd,
+                                          input_section, contents, relocs,
+                                          local_syms, local_sections);
+
+  /* This is a final link.  */
+
+  ret_val = true;
+
+  symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
 
-      dynobj = elf_hash_table (info)->dynobj;
-      if (dynobj)
-        srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
+  dynobj = elf_hash_table (info)->dynobj;
+  if (dynobj)
+    srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
+  else
+    srelgot = NULL;
 
-      name = (bfd_elf_string_from_elf_section
-             (input_bfd, elf_elfheader(input_bfd)->e_shstrndx,
-              elf_section_data(input_section)->rel_hdr.sh_name));
-      BFD_ASSERT(name != NULL);
-      srel = bfd_get_section_by_name (dynobj, name);
+  section_name = (bfd_elf_string_from_elf_section
+                 (input_bfd, elf_elfheader(input_bfd)->e_shstrndx,
+                  elf_section_data(input_section)->rel_hdr.sh_name));
+  BFD_ASSERT(section_name != NULL);
+  srel = bfd_get_section_by_name (dynobj, section_name);
 
-      /* Find the gp value for this input bfd.  */
-      gotobj = alpha_elf_tdata (input_bfd)->gotobj;
-      if (gotobj)
+  /* Find the gp value for this input bfd.  */
+  gotobj = alpha_elf_tdata (input_bfd)->gotobj;
+  if (gotobj)
+    {
+      sgot = alpha_elf_tdata (gotobj)->got;
+      gp = _bfd_get_gp_value (gotobj);
+      if (gp == 0)
        {
-         sgot = alpha_elf_tdata (gotobj)->got;
-         gp = _bfd_get_gp_value (gotobj);
-         if (gp == 0)
-           {
-             gp = (sgot->output_section->vma
-                   + sgot->output_offset
-                   + 0x8000);
-             _bfd_set_gp_value (gotobj, gp);
-           }
-        }
+         gp = (sgot->output_section->vma
+               + sgot->output_offset
+               + 0x8000);
+         _bfd_set_gp_value (gotobj, gp);
+       }
+    }
+  else
+    {
+      sgot = NULL;
+      gp = 0;
+    }
 
-      tls_segment = elf_hash_table (info)->tls_segment;
-      if (tls_segment)
-        {
-          dtp_base = alpha_get_dtprel_base (tls_segment);
-          tp_base = alpha_get_tprel_base (tls_segment);
-        }
+  local_got_entries = alpha_elf_tdata(input_bfd)->local_got_entries;
+
+  tls_segment = elf_hash_table (info)->tls_segment;
+  if (tls_segment)
+    {
+      dtp_base = alpha_get_dtprel_base (tls_segment);
+      tp_base = alpha_get_tprel_base (tls_segment);
     }
+  else
+    dtp_base = tp_base = 0;
 
-  rel = relocs;
   relend = relocs + input_section->reloc_count;
-  for (; rel < relend; rel++)
+  for (rel = relocs; rel < relend; rel++)
     {
-      struct alpha_elf_link_hash_entry *h;
+      struct alpha_elf_link_hash_entry *h = NULL;
       struct alpha_elf_got_entry *gotent;
       bfd_reloc_status_type r;
       reloc_howto_type *howto;
       unsigned long r_symndx;
-      Elf_Internal_Sym *sym;
-      asection *sec;
+      Elf_Internal_Sym *sym = NULL;
+      asection *sec = NULL;
       bfd_vma value;
       bfd_vma addend;
       boolean dynamic_symbol_p;
-      boolean undef_weak_ref;
+      boolean undef_weak_ref = false;
       unsigned long r_type;
 
       r_type = ELF64_R_TYPE(rel->r_info);
@@ -4130,53 +4322,25 @@ elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section,
       howto = elf64_alpha_howto_table + r_type;
       r_symndx = ELF64_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.  */
-
-         /* 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;
-
-         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;
-               }
-           }
-
-         continue;
-       }
-
-      /* This is a final link.  */
-
-      h = NULL;
-      sym = NULL;
-      sec = NULL;
-      undef_weak_ref = false;
-
       if (r_symndx < symtab_hdr->sh_info)
        {
          sym = local_syms + r_symndx;
          sec = local_sections[r_symndx];
          value = _bfd_elf_rela_local_sym (output_bfd, sym, sec, rel);
 
-         gotent = alpha_elf_tdata(input_bfd)->local_got_entries[r_symndx];
+         if (local_got_entries)
+           gotent = local_got_entries[r_symndx];
+         else
+           gotent = NULL;
 
          /* Need to adjust local GOT entries' addends for SEC_MERGE
             unless it has been done already.  */
          if ((sec->flags & SEC_MERGE)
-              && ELF_ST_TYPE (sym->st_info) == STT_SECTION
-              && (elf_section_data (sec)->sec_info_type
-                  == ELF_INFO_TYPE_MERGE)
-              && !gotent->reloc_xlated)
+             && ELF_ST_TYPE (sym->st_info) == STT_SECTION
+             && (elf_section_data (sec)->sec_info_type
+                 == ELF_INFO_TYPE_MERGE)
+             && gotent
+             && !gotent->reloc_xlated)
            {
              struct alpha_elf_got_entry *ent;
              asection *msec;
@@ -4392,7 +4556,7 @@ elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section,
            /* The source and destination gp must be the same.  Note that
               the source will always have an assigned gp, since we forced
               one in check_relocs, but that the destination may not, as
-              it might not have had any relocations at all.  Also take 
+              it might not have had any relocations at all.  Also take
               care not to crash if H is an undefined symbol.  */
            if (h != NULL && sec != NULL
                && alpha_elf_tdata (sec->owner)->gotobj
@@ -4827,9 +4991,13 @@ elf64_alpha_finish_dynamic_symbol (output_bfd, info, h, sym)
           gotent != NULL;
           gotent = gotent->next)
        {
-         asection *sgot = alpha_elf_tdata (gotent->gotobj)->got;
+         asection *sgot;
          int r_type;
 
+         if (gotent->use_count == 0)
+           continue;
+
+         sgot = alpha_elf_tdata (gotent->gotobj)->got;
          outrel.r_offset = (sgot->output_section->vma
                             + sgot->output_offset
                             + gotent->got_offset);
@@ -5331,6 +5499,7 @@ const struct elf_size_info alpha_elf_size_info =
   bfd_elf64_write_out_phdrs,
   bfd_elf64_write_shdrs_and_ehdr,
   bfd_elf64_write_relocs,
+  bfd_elf64_swap_symbol_in,
   bfd_elf64_swap_symbol_out,
   bfd_elf64_slurp_reloc_table,
   bfd_elf64_slurp_symbol_table,
This page took 0.033192 seconds and 4 git commands to generate.