* merge.c (_bfd_merged_section_offset): Remove "addend" param.
[deliverable/binutils-gdb.git] / bfd / elf64-alpha.c
index aa8ca998c7e5c089d8242d13069e82c9118a2bc7..21785d50c30609ee5824e080b5eda5c297f8580f 100644 (file)
@@ -1,5 +1,5 @@
 /* Alpha specific support for 64-bit ELF
-   Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
+   Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
    Free Software Foundation, Inc.
    Contributed by Richard Henderson <rth@tamu.edu>.
 
@@ -47,7 +47,7 @@
 #define ECOFF_64
 #include "ecoffswap.h"
 
-static int alpha_elf_dynamic_symbol_p
+static bfd_boolean alpha_elf_dynamic_symbol_p
   PARAMS ((struct elf_link_hash_entry *, struct bfd_link_info *));
 static struct bfd_hash_entry * elf64_alpha_link_hash_newfunc
   PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *));
@@ -75,7 +75,7 @@ static bfd_boolean elf64_alpha_object_p
 static bfd_boolean elf64_alpha_section_from_shdr
   PARAMS ((bfd *, Elf_Internal_Shdr *, const char *));
 static bfd_boolean elf64_alpha_section_flags
-  PARAMS ((flagword *, Elf_Internal_Shdr *));
+  PARAMS ((flagword *, const Elf_Internal_Shdr *));
 static bfd_boolean elf64_alpha_fake_sections
   PARAMS ((bfd *, Elf_Internal_Shdr *, asection *));
 static bfd_boolean elf64_alpha_create_got_section
@@ -123,7 +123,7 @@ static bfd_boolean elf64_alpha_size_rela_got_section
 static bfd_boolean elf64_alpha_size_rela_got_1
   PARAMS ((struct alpha_elf_link_hash_entry *, struct bfd_link_info *));
 static bfd_boolean elf64_alpha_add_symbol_hook
-  PARAMS ((bfd *, struct bfd_link_info *, const Elf_Internal_Sym *,
+  PARAMS ((bfd *, struct bfd_link_info *, Elf_Internal_Sym *,
           const char **, flagword *, asection **, bfd_vma *));
 static struct alpha_elf_got_entry *get_got_entry
   PARAMS ((bfd *, struct alpha_elf_link_hash_entry *, unsigned long,
@@ -135,6 +135,9 @@ static bfd_boolean elf64_alpha_adjust_dynamic_symbol
   PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *));
 static bfd_boolean elf64_alpha_size_dynamic_sections
   PARAMS ((bfd *, struct bfd_link_info *));
+static void elf64_alpha_emit_dynrel
+  PARAMS ((bfd *, struct bfd_link_info *, asection *, asection *,
+          bfd_vma, long, long, bfd_vma));
 static bfd_boolean elf64_alpha_relocate_section_r
   PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
           Elf_Internal_Rela *, Elf_Internal_Sym *, asection **));
@@ -174,6 +177,11 @@ struct alpha_elf_link_hash_entry
 #define ALPHA_ELF_LINK_HASH_LU_TLSLDM  0x20
 #define ALPHA_ELF_LINK_HASH_LU_FUNC    0x38
 #define ALPHA_ELF_LINK_HASH_TLS_IE     0x40
+#define ALPHA_ELF_LINK_HASH_PLT_LOC    0x80
+
+  /* Used to undo the localization of a plt symbol.  */
+  asection *plt_old_section;
+  bfd_vma plt_old_value;
 
   /* Used to implement multiple .got subsections.  */
   struct alpha_elf_got_entry
@@ -261,47 +269,17 @@ struct alpha_elf_link_hash_table
 #define alpha_elf_sym_hashes(abfd) \
   ((struct alpha_elf_link_hash_entry **)elf_sym_hashes(abfd))
 
-/* Should we do dynamic things to this symbol?  */
+/* Should we do dynamic things to this symbol?  This differs from the 
+   generic version in that we never need to consider function pointer
+   equality wrt PLT entries -- we don't create a PLT entry if a symbol's
+   address is ever taken.  */
 
-static int
+static inline bfd_boolean
 alpha_elf_dynamic_symbol_p (h, info)
      struct elf_link_hash_entry *h;
      struct bfd_link_info *info;
 {
-  if (h == NULL)
-    return FALSE;
-
-  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->dynindx == -1)
-    return FALSE;
-
-  if (h->root.type == bfd_link_hash_undefweak
-      || h->root.type == bfd_link_hash_defweak)
-    return TRUE;
-
-  switch (ELF_ST_VISIBILITY (h->other))
-    {
-    case STV_DEFAULT:
-      break;
-    case STV_HIDDEN:
-    case STV_INTERNAL:
-      return FALSE;
-    case STV_PROTECTED:
-      if (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR)
-        return FALSE;
-      break;
-    }
-
-  if ((info->shared && !info->symbolic)
-      || ((h->elf_link_hash_flags
-          & (ELF_LINK_HASH_DEF_DYNAMIC | ELF_LINK_HASH_REF_REGULAR))
-         == (ELF_LINK_HASH_DEF_DYNAMIC | ELF_LINK_HASH_REF_REGULAR)))
-    return TRUE;
-
-  return FALSE;
+  return _bfd_elf_dynamic_symbol_p (h, info, 0);
 }
 
 /* Create an entry in a Alpha ELF linker hash table.  */
@@ -415,15 +393,6 @@ static bfd_boolean
 elf64_alpha_object_p (abfd)
      bfd *abfd;
 {
-  /* Allocate our special target data.  */
-  struct alpha_elf_obj_tdata *new_tdata;
-  bfd_size_type amt = sizeof (struct alpha_elf_obj_tdata);
-  new_tdata = bfd_zalloc (abfd, amt);
-  if (new_tdata == NULL)
-    return FALSE;
-  new_tdata->root = *abfd->tdata.elf_obj_data;
-  abfd->tdata.any = new_tdata;
-
   /* Set the right machine number for an Alpha ELF file.  */
   return bfd_default_set_arch_mach (abfd, bfd_arch_alpha, 0);
 }
@@ -1180,13 +1149,15 @@ elf64_alpha_info_to_howto (abfd, cache_ptr, dst)
   (r_type == R_ALPHA_TLSGD || r_type == R_ALPHA_TLSLDM ? 16 : 8)
 
 /* This is PT_TLS segment p_vaddr.  */
-#define alpha_get_dtprel_base(tlss) \
-  ((tlss)->start)
+#define alpha_get_dtprel_base(info) \
+  (elf_hash_table (info)->tls_sec->vma)
 
 /* Main program TLS (whose template starts at PT_TLS p_vaddr)
    is assigned offset round(16, PT_TLS p_align).  */
-#define alpha_get_tprel_base(tlss) \
-  ((tlss)->start - align_power ((bfd_vma) 16, (tlss)->align))
+#define alpha_get_tprel_base(info) \
+  (elf_hash_table (info)->tls_sec->vma                                 \
+   - align_power ((bfd_vma) 16,                                                \
+                 elf_hash_table (info)->tls_sec->alignment_power))
 \f
 /* These functions do relaxation for Alpha ELF.
 
@@ -1220,7 +1191,6 @@ struct alpha_relax_info
   Elf_Internal_Shdr *symtab_hdr;
   Elf_Internal_Rela *relocs, *relend;
   struct bfd_link_info *link_info;
-  struct elf_link_tls_segment *tls_segment;
   bfd_vma gp;
   bfd *gotobj;
   asection *tsec;
@@ -1246,8 +1216,6 @@ static bfd_boolean elf64_alpha_relax_gprelhilo
 static bfd_boolean elf64_alpha_relax_tls_get_addr
   PARAMS((struct alpha_relax_info *info, bfd_vma symval,
           Elf_Internal_Rela *irel, bfd_boolean));
-static struct elf_link_tls_segment *elf64_alpha_relax_find_tls_segment
-  PARAMS((struct alpha_relax_info *, struct elf_link_tls_segment *));
 static bfd_boolean elf64_alpha_relax_section
   PARAMS((bfd *abfd, asection *sec, struct bfd_link_info *link_info,
          bfd_boolean *again));
@@ -1546,7 +1514,7 @@ elf64_alpha_relax_opt_call (info, symval)
        }
       else
        {
-         tsec_relocs = (_bfd_elf64_link_read_relocs
+         tsec_relocs = (_bfd_elf_link_read_relocs
                         (info->abfd, info->tsec, (PTR) NULL,
                         (Elf_Internal_Rela *) NULL,
                         info->link_info->keep_memory));
@@ -1620,9 +1588,9 @@ elf64_alpha_relax_got_load (info, symval, irel, r_type)
     {
       bfd_vma dtp_base, tp_base;
 
-      BFD_ASSERT (info->tls_segment != NULL);
-      dtp_base = alpha_get_dtprel_base (info->tls_segment);
-      tp_base = alpha_get_tprel_base (info->tls_segment);
+      BFD_ASSERT (elf_hash_table (info->link_info)->tls_sec != NULL);
+      dtp_base = alpha_get_dtprel_base (info->link_info);
+      tp_base = alpha_get_tprel_base (info->link_info);
       disp = symval - (r_type == R_ALPHA_GOTDTPREL ? dtp_base : tp_base);
     }
 
@@ -1638,6 +1606,17 @@ elf64_alpha_relax_got_load (info, symval, irel, r_type)
   bfd_put_32 (info->abfd, (bfd_vma) insn, info->contents + irel->r_offset);
   info->changed_contents = TRUE;
 
+  /* Reduce the use count on this got entry by one, possibly
+     eliminating it.  */
+  if (--info->gotent->use_count == 0)
+    {
+      int sz = alpha_got_entry_size (r_type);
+      alpha_elf_tdata (info->gotobj)->total_got_size -= sz;
+      if (!info->h)
+       alpha_elf_tdata (info->gotobj)->local_got_size -= sz;
+    }
+
+  /* Smash the existing GOT relocation for its 16-bit immediate pair.  */
   switch (r_type)
     {
     case R_ALPHA_LITERAL:
@@ -1657,16 +1636,6 @@ elf64_alpha_relax_got_load (info, symval, irel, r_type)
   irel->r_info = ELF64_R_INFO (ELF64_R_SYM (irel->r_info), r_type);
   info->changed_relocs = TRUE;
 
-  /* Reduce the use count on this got entry by one, possibly
-     eliminating it.  */
-  if (--info->gotent->use_count == 0)
-    {
-      int sz = alpha_got_entry_size (r_type);
-      alpha_elf_tdata (info->gotobj)->total_got_size -= sz;
-      if (!info->h)
-       alpha_elf_tdata (info->gotobj)->local_got_size -= sz;
-    }
-
   /* ??? Search forward through this basic block looking for insns
      that use the target register.  Stop after an insn modifying the
      register is seen, or after a branch or call.
@@ -1748,15 +1717,11 @@ elf64_alpha_relax_tls_get_addr (info, symval, irel, is_gd)
   bfd_byte *pos[5];
   unsigned int insn;
   Elf_Internal_Rela *gpdisp, *hint;
-  bfd_boolean dynamic, use_gottprel;
+  bfd_boolean dynamic, use_gottprel, pos1_unusable;
+  unsigned long new_symndx;
 
   dynamic = alpha_elf_dynamic_symbol_p (&info->h->root, info->link_info);
 
-  /* ??? For LD relaxation, we need a symbol referencing the beginning
-     of the TLS segment.  */
-  if (!is_gd)
-    return TRUE;
-
   /* If a TLS symbol is accessed using IE at least once, there is no point
      to use dynamic model for it.  */
   if (is_gd && info->h && (info->h->flags & ALPHA_ELF_LINK_HASH_TLS_IE))
@@ -1793,15 +1758,20 @@ elf64_alpha_relax_tls_get_addr (info, symval, irel, is_gd)
   pos[2] = info->contents + irel[2].r_offset;
   pos[3] = info->contents + gpdisp->r_offset;
   pos[4] = pos[3] + gpdisp->r_addend;
+  pos1_unusable = FALSE;
 
-  /* Only positions 0 and 1 are allowed to be out of order.  */
-  if (pos[1] < pos[0])
+  /* Generally, the positions are not allowed to be out of order, lest the
+     modified insn sequence have different register lifetimes.  We can make
+     an exception when pos 1 is adjacent to pos 0.  */
+  if (pos[1] + 4 == pos[0])
     {
       bfd_byte *tmp = pos[0];
       pos[0] = pos[1];
       pos[1] = tmp;
     }
-  if (pos[1] >= pos[2] || pos[2] >= pos[3] || pos[3] >= pos[4])
+  else if (pos[1] < pos[0])
+    pos1_unusable = TRUE;
+  if (pos[1] >= pos[2] || pos[2] >= pos[3])
     return TRUE;
 
   /* Reduce the use count on the LITERAL relocation.  Do this before we
@@ -1857,6 +1827,7 @@ elf64_alpha_relax_tls_get_addr (info, symval, irel, is_gd)
      as appropriate.  */
 
   use_gottprel = FALSE;
+  new_symndx = is_gd ? ELF64_R_SYM (irel->r_info) : 0;
   switch (!dynamic && !info->link_info->shared)
     {
     case 1:
@@ -1864,8 +1835,8 @@ elf64_alpha_relax_tls_get_addr (info, symval, irel, is_gd)
        bfd_vma tp_base;
        bfd_signed_vma disp;
 
-       BFD_ASSERT (info->tls_segment != NULL);
-       tp_base = alpha_get_tprel_base (info->tls_segment);
+       BFD_ASSERT (elf_hash_table (info->link_info)->tls_sec != NULL);
+       tp_base = alpha_get_tprel_base (info->link_info);
        disp = symval - tp_base;
 
        if (disp >= -0x8000 && disp < 0x8000)
@@ -1875,13 +1846,13 @@ elf64_alpha_relax_tls_get_addr (info, symval, irel, is_gd)
            bfd_put_32 (info->abfd, (bfd_vma) INSN_UNOP, pos[1]);
 
            irel[0].r_offset = pos[0] - info->contents;
-           irel[0].r_info = ELF64_R_INFO (ELF64_R_SYM (irel->r_info),
-                                          R_ALPHA_TPREL16);
+           irel[0].r_info = ELF64_R_INFO (new_symndx, R_ALPHA_TPREL16);
            irel[1].r_info = ELF64_R_INFO (0, R_ALPHA_NONE);
            break;
          }
        else if (disp >= -(bfd_signed_vma) 0x80000000
-                && disp < (bfd_signed_vma) 0x7fff8000)
+                && disp < (bfd_signed_vma) 0x7fff8000
+                && !pos1_unusable)
          {
            insn = (OP_LDAH << 26) | (16 << 21) | (31 << 16);
            bfd_put_32 (info->abfd, (bfd_vma) insn, pos[0]);
@@ -1889,11 +1860,9 @@ elf64_alpha_relax_tls_get_addr (info, symval, irel, is_gd)
            bfd_put_32 (info->abfd, (bfd_vma) insn, pos[1]);
 
            irel[0].r_offset = pos[0] - info->contents;
-           irel[0].r_info = ELF64_R_INFO (ELF64_R_SYM (irel->r_info),
-                                          R_ALPHA_TPRELHI);
+           irel[0].r_info = ELF64_R_INFO (new_symndx, R_ALPHA_TPRELHI);
            irel[1].r_offset = pos[1] - info->contents;
-           irel[1].r_info = ELF64_R_INFO (ELF64_R_SYM (irel->r_info),
-                                          R_ALPHA_TPRELLO);
+           irel[1].r_info = ELF64_R_INFO (new_symndx, R_ALPHA_TPRELLO);
            break;
          }
       }
@@ -1907,8 +1876,7 @@ elf64_alpha_relax_tls_get_addr (info, symval, irel, is_gd)
       bfd_put_32 (info->abfd, (bfd_vma) INSN_UNOP, pos[1]);
 
       irel[0].r_offset = pos[0] - info->contents;
-      irel[0].r_info = ELF64_R_INFO (ELF64_R_SYM (irel->r_info),
-                                    R_ALPHA_GOTTPREL);
+      irel[0].r_info = ELF64_R_INFO (new_symndx, R_ALPHA_GOTTPREL);
       irel[1].r_info = ELF64_R_INFO (0, R_ALPHA_NONE);
       break;
     }
@@ -1983,53 +1951,6 @@ elf64_alpha_relax_tls_get_addr (info, symval, irel, is_gd)
   return TRUE;
 }
 
-static struct elf_link_tls_segment *
-elf64_alpha_relax_find_tls_segment (info, seg)
-     struct alpha_relax_info *info;
-     struct elf_link_tls_segment *seg;
-{
-  bfd *output_bfd = info->sec->output_section->owner;
-  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)
-      break;
-  if (!o)
-    return NULL;
-
-  base = o->vma;
-  align = 0;
-
-  do
-    {
-      bfd_vma size;
-
-      if (bfd_get_section_alignment (output_bfd, o) > align)
-       align = bfd_get_section_alignment (output_bfd, o);
-
-      size = o->_raw_size;
-      if (size == 0 && (o->flags & SEC_HAS_CONTENTS) == 0)
-       {
-         struct bfd_link_order *lo;
-         for (lo = o->link_order_head; lo ; lo = lo->next)
-           if (size < lo->offset + lo->size)
-             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;
-  seg->align = align;
-
-  return seg;
-}
-
 static bfd_boolean
 elf64_alpha_relax_section (abfd, sec, link_info, again)
      bfd *abfd;
@@ -2043,12 +1964,11 @@ elf64_alpha_relax_section (abfd, sec, link_info, again)
   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;
 
   /* We are not currently changing any sizes, so only one pass.  */
   *again = FALSE;
 
-  if (link_info->relocateable
+  if (link_info->relocatable
       || (sec->flags & SEC_RELOC) == 0
       || sec->reloc_count == 0)
     return TRUE;
@@ -2062,7 +1982,7 @@ elf64_alpha_relax_section (abfd, sec, link_info, again)
   local_got_entries = alpha_elf_tdata(abfd)->local_got_entries;
 
   /* Load the relocations for this section.  */
-  internal_relocs = (_bfd_elf64_link_read_relocs
+  internal_relocs = (_bfd_elf_link_read_relocs
                     (abfd, sec, (PTR) NULL, (Elf_Internal_Rela *) NULL,
                      link_info->keep_memory));
   if (internal_relocs == NULL)
@@ -2101,16 +2021,12 @@ elf64_alpha_relax_section (abfd, sec, link_info, again)
        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.  */
-  info.tls_segment = elf64_alpha_relax_find_tls_segment (&info, &tls_segment);
-
   for (irel = internal_relocs; irel < irelend; irel++)
     {
       bfd_vma symval;
       struct alpha_elf_got_entry *gotent;
       unsigned long r_type = ELF64_R_TYPE (irel->r_info);
+      unsigned long r_symndx = ELF64_R_SYM (irel->r_info);
 
       /* Early exit for unhandled or unrelaxable relocations.  */
       switch (r_type)
@@ -2121,14 +2037,20 @@ elf64_alpha_relax_section (abfd, sec, link_info, again)
        case R_ALPHA_GOTDTPREL:
        case R_ALPHA_GOTTPREL:
        case R_ALPHA_TLSGD:
+         break;
+
        case R_ALPHA_TLSLDM:
+         /* The symbol for a TLSLDM reloc is ignored.  Collapse the
+             reloc to the 0 symbol so that they all match.  */
+         r_symndx = 0;
          break;
+
        default:
          continue;
        }
 
       /* Get the value of the symbol referred to by the reloc.  */
-      if (ELF64_R_SYM (irel->r_info) < symtab_hdr->sh_info)
+      if (r_symndx < symtab_hdr->sh_info)
        {
          /* A local symbol.  */
          Elf_Internal_Sym *isym;
@@ -2145,27 +2067,44 @@ elf64_alpha_relax_section (abfd, sec, link_info, again)
                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)
-           info.tsec = bfd_com_section_ptr;
+         isym = isymbuf + r_symndx;
+
+         /* Given the symbol for a TLSLDM reloc is ignored, this also
+            means forcing the symbol value to the tp base.  */
+         if (r_type == R_ALPHA_TLSLDM)
+           {
+             info.tsec = bfd_abs_section_ptr;
+             symval = alpha_get_tprel_base (info.link_info);
+           }
          else
-           info.tsec = bfd_section_from_elf_index (abfd, isym->st_shndx);
+           {
+             symval = isym->st_value;
+             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)
+               info.tsec = bfd_com_section_ptr;
+             else
+               info.tsec = bfd_section_from_elf_index (abfd, isym->st_shndx);
+           }
 
          info.h = NULL;
          info.other = isym->st_other;
-         info.first_gotent = &local_got_entries[ELF64_R_SYM(irel->r_info)];
-         symval = isym->st_value;
+         if (local_got_entries)
+           info.first_gotent = &local_got_entries[r_symndx];
+         else
+           {
+             info.first_gotent = &info.gotent;
+             info.gotent = NULL;
+           }
        }
       else
        {
          unsigned long indx;
          struct alpha_elf_link_hash_entry *h;
 
-         indx = ELF64_R_SYM (irel->r_info) - symtab_hdr->sh_info;
+         indx = r_symndx - symtab_hdr->sh_info;
          h = alpha_elf_sym_hashes (abfd)[indx];
          BFD_ASSERT (h != NULL);
 
@@ -2181,13 +2120,23 @@ elf64_alpha_relax_section (abfd, sec, link_info, again)
          /* 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;
+           {
+             /* Except for TLSGD relocs, which can sometimes be
+                relaxed to GOTTPREL relocs.  */
+             if (r_type != R_ALPHA_TLSGD)
+               continue;
+             info.tsec = bfd_abs_section_ptr;
+             symval = 0;
+           }
+         else
+           {
+             info.tsec = h->root.root.u.def.section;
+             symval = h->root.root.u.def.value;
+           }
 
          info.h = h;
-         info.tsec = h->root.root.u.def.section;
          info.other = h->root.other;
          info.first_gotent = &h->got_entries;
-         symval = h->root.root.u.def.value;
        }
 
       /* Search for the got entry to be used by this relocation.  */
@@ -2366,7 +2315,7 @@ elf64_alpha_section_from_shdr (abfd, hdr, name)
 static bfd_boolean
 elf64_alpha_section_flags (flags, hdr)
      flagword *flags;
-     Elf_Internal_Shdr *hdr;
+     const Elf_Internal_Shdr *hdr;
 {
   if (hdr->sh_flags & SHF_ALPHA_GPREL)
     *flags |= SEC_SMALL_DATA;
@@ -2414,14 +2363,14 @@ static bfd_boolean
 elf64_alpha_add_symbol_hook (abfd, info, sym, namep, flagsp, secp, valp)
      bfd *abfd;
      struct bfd_link_info *info;
-     const Elf_Internal_Sym *sym;
+     Elf_Internal_Sym *sym;
      const char **namep ATTRIBUTE_UNUSED;
      flagword *flagsp ATTRIBUTE_UNUSED;
      asection **secp;
      bfd_vma *valp;
 {
   if (sym->st_shndx == SHN_COMMON
-      && !info->relocateable
+      && !info->relocatable
       && sym->st_size <= elf_gp_size (abfd))
     {
       /* Common symbols less than or equal to -G nn bytes are
@@ -2455,8 +2404,13 @@ elf64_alpha_create_got_section(abfd, info)
 {
   asection *s;
 
-  if (bfd_get_section_by_name (abfd, ".got"))
-    return TRUE;
+  if ((s = bfd_get_section_by_name (abfd, ".got")))
+    {
+      /* Check for a non-linker created .got?  */
+      if (alpha_elf_tdata (abfd)->got == NULL)
+       alpha_elf_tdata (abfd)->got = s;
+      return TRUE;
+    }
 
   s = bfd_make_section (abfd, ".got");
   if (s == NULL
@@ -2508,7 +2462,7 @@ elf64_alpha_create_dynamic_sections (abfd, info)
   h->type = STT_OBJECT;
 
   if (info->shared
-      && ! _bfd_elf_link_record_dynamic_symbol (info, h))
+      && ! bfd_elf_link_record_dynamic_symbol (info, h))
     return FALSE;
 
   s = bfd_make_section (abfd, ".rela.plt");
@@ -2552,7 +2506,7 @@ elf64_alpha_create_dynamic_sections (abfd, info)
   h->type = STT_OBJECT;
 
   if (info->shared
-      && ! _bfd_elf_link_record_dynamic_symbol (info, h))
+      && ! bfd_elf_link_record_dynamic_symbol (info, h))
     return FALSE;
 
   elf_hash_table (info)->hgot = h;
@@ -2618,7 +2572,6 @@ elf64_alpha_read_ecoff_info (abfd, section, debug)
 #undef READ
 
   debug->fdr = NULL;
-  debug->adjust = NULL;
 
   return TRUE;
 
@@ -3013,7 +2966,7 @@ elf64_alpha_check_relocs (abfd, info, sec, relocs)
   bfd_boolean got_created;
   bfd_size_type amt;
 
-  if (info->relocateable)
+  if (info->relocatable)
     return TRUE;
 
   dynobj = elf_hash_table(info)->dynobj;
@@ -3062,7 +3015,7 @@ elf64_alpha_check_relocs (abfd, info, sec, relocs)
          this may help reduce memory usage and processing time later.  */
       maybe_dynamic = FALSE;
       if (h && ((info->shared
-                && (!info->symbolic || info->allow_shlib_undefined))
+                && (!info->symbolic || info->unresolved_syms_in_shared_libs == RM_IGNORE))
                || ! (h->root.elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR)
                || h->root.root.type == bfd_link_hash_defweak))
         maybe_dynamic = TRUE;
@@ -3105,8 +3058,15 @@ elf64_alpha_check_relocs (abfd, info, sec, relocs)
            need = NEED_DYNREL;
          break;
 
-       case R_ALPHA_TLSGD:
        case R_ALPHA_TLSLDM:
+         /* The symbol for a TLSLDM reloc is ignored.  Collapse the
+            reloc to the 0 symbol so that they all match.  */
+         r_symndx = 0;
+         h = 0;
+         maybe_dynamic = FALSE;
+         /* FALLTHRU */
+
+       case R_ALPHA_TLSGD:
        case R_ALPHA_GOTDTPREL:
          need = NEED_GOT | NEED_GOT_ENTRY;
          break;
@@ -3308,6 +3268,9 @@ elf64_alpha_adjust_dynamic_symbol (info, h)
       if (! info->shared
          && h->root.type != bfd_link_hash_defweak)
        {
+         ah->plt_old_section = h->root.u.def.section;
+         ah->plt_old_value = h->root.u.def.value;
+         ah->flags |= ALPHA_ELF_LINK_HASH_PLT_LOC;
          h->root.u.def.section = s;
          h->root.u.def.value = h->plt.offset;
        }
@@ -3583,6 +3546,7 @@ elf64_alpha_calc_got_offsets_for_symbol (h, arg)
      struct alpha_elf_link_hash_entry *h;
      PTR arg ATTRIBUTE_UNUSED;
 {
+  bfd_boolean result = TRUE;
   struct alpha_elf_got_entry *gotent;
 
   if (h->root.root.type == bfd_link_hash_warning)
@@ -3591,14 +3555,23 @@ elf64_alpha_calc_got_offsets_for_symbol (h, arg)
   for (gotent = h->got_entries; gotent; gotent = gotent->next)
     if (gotent->use_count > 0)
       {
-       bfd_size_type *plge
-         = &alpha_elf_tdata (gotent->gotobj)->got->_raw_size;
+       struct alpha_elf_obj_tdata *td;
+       bfd_size_type *plge;
 
+       td = alpha_elf_tdata (gotent->gotobj);
+       if (td == NULL)
+         {
+           _bfd_error_handler (_("Symbol %s has no GOT subsection for offset 0x%x"),
+                               h->root.root.root.string, gotent->got_offset);
+           result = FALSE;
+           continue;
+         }
+       plge = &td->got->_raw_size;
        gotent->got_offset = *plge;
        *plge += alpha_got_entry_size (gotent->reloc_type);
       }
 
-  return TRUE;
+  return result;
 }
 
 static void
@@ -3667,7 +3640,7 @@ elf64_alpha_size_got_sections (info)
          if (this_got == NULL)
            continue;
 
-         /* We are assuming no merging has yet ocurred.  */
+         /* We are assuming no merging has yet occurred.  */
          BFD_ASSERT (this_got == i);
 
           if (alpha_elf_tdata (this_got)->total_got_size > MAX_GOT_SIZE)
@@ -3789,6 +3762,14 @@ elf64_alpha_size_plt_section_1 (h, data)
     {
       h->root.elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT;
       h->root.plt.offset = -1;
+
+      /* Undo the definition frobbing begun in adjust_dynamic_symbol.  */
+      if (h->flags & ALPHA_ELF_LINK_HASH_PLT_LOC)
+       {
+         h->root.root.u.def.section = h->plt_old_section;
+         h->root.root.u.def.value = h->plt_old_value;
+         h->flags &= ~ALPHA_ELF_LINK_HASH_PLT_LOC;
+       }
     }
 
   return TRUE;
@@ -3801,7 +3782,7 @@ elf64_alpha_always_size_sections (output_bfd, info)
 {
   bfd *i;
 
-  if (info->relocateable)
+  if (info->relocatable)
     return TRUE;
 
   /* First, take care of the indirect symbols created by versioning.  */
@@ -3842,18 +3823,16 @@ alpha_dynamic_entries_for_reloc (r_type, dynamic, shared)
     case R_ALPHA_TLSLDM:
       return shared;
     case R_ALPHA_LITERAL:
+    case R_ALPHA_GOTTPREL:
       return dynamic || shared;
     case R_ALPHA_GOTDTPREL:
-    case R_ALPHA_GOTTPREL:
       return dynamic;
 
     /* May appear in data sections.  */
     case R_ALPHA_REFLONG:
     case R_ALPHA_REFQUAD:
-      return dynamic || shared;
-    case R_ALPHA_SREL64:
     case R_ALPHA_TPREL64:
-      return dynamic;
+      return dynamic || shared;
 
     /* Everything else is illegal.  We'll issue an error during
        relocate_section.  */
@@ -4030,7 +4009,7 @@ elf64_alpha_size_dynamic_sections (output_bfd, info)
   if (elf_hash_table (info)->dynamic_sections_created)
     {
       /* Set the contents of the .interp section to the interpreter.  */
-      if (!info->shared)
+      if (info->executable)
        {
          s = bfd_get_section_by_name (dynobj, ".interp");
          BFD_ASSERT (s != NULL);
@@ -4114,9 +4093,9 @@ elf64_alpha_size_dynamic_sections (output_bfd, info)
         the .dynamic section.  The DT_DEBUG entry is filled in by the
         dynamic linker and used by the debugger.  */
 #define add_dynamic_entry(TAG, VAL) \
-  bfd_elf64_add_dynamic_entry (info, (bfd_vma) (TAG), (bfd_vma) (VAL))
+  _bfd_elf_add_dynamic_entry (info, TAG, VAL)
 
-      if (!info->shared)
+      if (info->executable)
        {
          if (!add_dynamic_entry (DT_DEBUG, 0))
            return FALSE;
@@ -4147,6 +4126,38 @@ elf64_alpha_size_dynamic_sections (output_bfd, info)
   return TRUE;
 }
 
+/* Emit a dynamic relocation for (DYNINDX, RTYPE, ADDEND) at (SEC, OFFSET)
+   into the next available slot in SREL.  */
+
+static void
+elf64_alpha_emit_dynrel (abfd, info, sec, srel, offset, dynindx, rtype, addend)
+     bfd *abfd;
+     struct bfd_link_info *info;
+     asection *sec, *srel;
+     bfd_vma offset, addend;
+     long dynindx, rtype;
+{
+  Elf_Internal_Rela outrel;
+  bfd_byte *loc;
+
+  BFD_ASSERT (srel != NULL);
+
+  outrel.r_info = ELF64_R_INFO (dynindx, rtype);
+  outrel.r_addend = addend;
+
+  offset = _bfd_elf_section_offset (abfd, info, sec, offset);
+  if ((offset | 1) != (bfd_vma) -1)
+    outrel.r_offset = sec->output_section->vma + sec->output_offset + offset;
+  else
+    memset (&outrel, 0, sizeof (outrel));
+
+  loc = srel->contents;
+  loc += srel->reloc_count++ * sizeof (Elf64_External_Rela);
+  bfd_elf64_swap_reloca_out (abfd, &outrel, loc);
+  BFD_ASSERT (sizeof (Elf64_External_Rela) * srel->reloc_count
+             <= srel->_cooked_size);
+}
+
 /* Relocate an Alpha ELF section for a relocatable link.
 
    We don't have to change anything unless the reloc is against a section
@@ -4229,7 +4240,6 @@ elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section,
   Elf_Internal_Shdr *symtab_hdr;
   Elf_Internal_Rela *rel;
   Elf_Internal_Rela *relend;
-  struct elf_link_tls_segment *tls_segment;
   asection *sgot, *srel, *srelgot;
   bfd *dynobj, *gotobj;
   bfd_vma gp, tp_base, dtp_base;
@@ -4238,7 +4248,7 @@ elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section,
   const char *section_name;
 
   /* Handle relocatable links with a smaller loop.  */
-  if (info->relocateable)
+  if (info->relocatable)
     return elf64_alpha_relocate_section_r (output_bfd, info, input_bfd,
                                           input_section, contents, relocs,
                                           local_syms, local_sections);
@@ -4283,11 +4293,10 @@ elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section,
 
   local_got_entries = alpha_elf_tdata(input_bfd)->local_got_entries;
 
-  tls_segment = elf_hash_table (info)->tls_segment;
-  if (tls_segment)
+  if (elf_hash_table (info)->tls_sec != NULL)
     {
-      dtp_base = alpha_get_dtprel_base (tls_segment);
-      tp_base = alpha_get_tprel_base (tls_segment);
+      dtp_base = alpha_get_dtprel_base (info);
+      tp_base = alpha_get_tprel_base (info);
     }
   else
     dtp_base = tp_base = 0;
@@ -4322,11 +4331,30 @@ 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);
 
+      /* The symbol for a TLSLDM reloc is ignored.  Collapse the
+        reloc to the 0 symbol so that they all match.  */
+      if (r_type == R_ALPHA_TLSLDM)
+       r_symndx = 0;
+
       if (r_symndx < symtab_hdr->sh_info)
        {
+         asection *msec;
          sym = local_syms + r_symndx;
          sec = local_sections[r_symndx];
-         value = _bfd_elf_rela_local_sym (output_bfd, sym, sec, rel);
+         msec = sec;
+         value = _bfd_elf_rela_local_sym (output_bfd, sym, &msec, rel);
+
+         /* If this is a tp-relative relocation against sym 0,
+            this is hackery from relax_section.  Force the value to
+            be the tls base.  */
+         if (r_symndx == 0
+             && (r_type == R_ALPHA_TLSLDM
+                 || r_type == R_ALPHA_GOTTPREL
+                 || r_type == R_ALPHA_TPREL64
+                 || r_type == R_ALPHA_TPRELHI
+                 || r_type == R_ALPHA_TPRELLO
+                 || r_type == R_ALPHA_TPREL16))
+           value = tp_base;
 
          if (local_got_entries)
            gotent = local_got_entries[r_symndx];
@@ -4337,13 +4365,11 @@ elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section,
             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)
+             && sec->sec_info_type == ELF_INFO_TYPE_MERGE
              && gotent
              && !gotent->reloc_xlated)
            {
              struct alpha_elf_got_entry *ent;
-             asection *msec;
 
              for (ent = gotent; ent; ent = ent->next)
                {
@@ -4355,8 +4381,7 @@ elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section,
                    _bfd_merged_section_offset (output_bfd, &msec,
                                                elf_section_data (sec)->
                                                  sec_info,
-                                               sym->st_value + ent->addend,
-                                               (bfd_vma) 0);
+                                               sym->st_value + ent->addend);
                  ent->addend -= sym->st_value;
                  ent->addend += msec->output_section->vma
                                 + msec->output_offset
@@ -4369,50 +4394,25 @@ elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section,
        }
       else
        {
-         h = alpha_elf_sym_hashes (input_bfd)[r_symndx - symtab_hdr->sh_info];
+         bfd_boolean warned;
+         bfd_boolean unresolved_reloc;
+         struct elf_link_hash_entry *hh;
+         struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (input_bfd);
 
-         while (h->root.root.type == bfd_link_hash_indirect
-                || h->root.root.type == bfd_link_hash_warning)
-           h = (struct alpha_elf_link_hash_entry *)h->root.root.u.i.link;
+         RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
+                                  r_symndx, symtab_hdr, sym_hashes,
+                                  hh, sec, value,
+                                  unresolved_reloc, warned);
 
-         value = 0;
-         if (h->root.root.type == bfd_link_hash_defined
-             || h->root.root.type == bfd_link_hash_defweak)
-           {
-             sec = h->root.root.u.def.section;
-
-             /* Detect the cases that sym_sec->output_section is
-                expected to be NULL -- all cases in which the symbol
-                is defined in another shared module.  This includes
-                PLT relocs for which we've created a PLT entry and
-                other relocs for which we're prepared to create
-                dynamic relocations.  */
-             /* ??? Just accept it NULL and continue.  */
-
-             if (sec->output_section != NULL)
-               value = (h->root.root.u.def.value
-                        + sec->output_section->vma
-                             + sec->output_offset);
-           }
-         else if (h->root.root.type == bfd_link_hash_undefweak)
+         if (warned)
+           continue;
+
+         if (value == 0
+             && ! unresolved_reloc
+             && hh->root.type == bfd_link_hash_undefweak)
            undef_weak_ref = TRUE;
-         else if (info->shared
-                  && (!info->symbolic || info->allow_shlib_undefined)
-                  && !info->no_undefined
-                  && ELF_ST_VISIBILITY (h->root.other) == STV_DEFAULT)
-           ;
-         else
-           {
-             if (!((*info->callbacks->undefined_symbol)
-                   (info, h->root.root.root.string, input_bfd,
-                    input_section, rel->r_offset,
-                    (!info->shared || info->no_undefined
-                     || ELF_ST_VISIBILITY (h->root.other)))))
-               return FALSE;
-             ret_val = FALSE;
-             continue;
-           }
 
+         h = (struct alpha_elf_link_hash_entry *) hh;
           dynamic_symbol_p = alpha_elf_dynamic_symbol_p (&h->root, info);
          gotent = h->got_entries;
        }
@@ -4464,25 +4464,9 @@ elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section,
                 RELATIVE reloc, otherwise it will be handled in
                 finish_dynamic_symbol.  */
              if (info->shared && !dynamic_symbol_p)
-               {
-                 Elf_Internal_Rela outrel;
-                 bfd_byte *loc;
-
-                 BFD_ASSERT(srelgot != NULL);
-
-                 outrel.r_offset = (sgot->output_section->vma
-                                    + sgot->output_offset
-                                    + gotent->got_offset);
-                 outrel.r_info = ELF64_R_INFO (0, R_ALPHA_RELATIVE);
-                 outrel.r_addend = value;
-
-                 loc = srelgot->contents;
-                 loc += srelgot->reloc_count++ * sizeof (Elf64_External_Rela);
-                 bfd_elf64_swap_reloca_out (output_bfd, &outrel, loc);
-                 BFD_ASSERT (sizeof (Elf64_External_Rela)
-                             * srelgot->reloc_count
-                             <= srelgot->_cooked_size);
-               }
+               elf64_alpha_emit_dynrel (output_bfd, info, sgot, srelgot,
+                                        gotent->got_offset, 0,
+                                        R_ALPHA_RELATIVE, value);
            }
 
          value = (sgot->output_section->vma
@@ -4491,8 +4475,20 @@ elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section,
          value -= gp;
          goto default_reloc;
 
-       case R_ALPHA_GPREL16:
        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)
             {
@@ -4607,8 +4603,8 @@ elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section,
        case R_ALPHA_DTPREL64:
        case R_ALPHA_TPREL64:
          {
-           Elf_Internal_Rela outrel;
-           bfd_byte *loc;
+           long dynindx, dyntype = r_type;
+           bfd_vma dynaddend;
 
            /* Careful here to remember RELATIVE relocations for global
               variables for symbolic shared objects.  */
@@ -4616,21 +4612,26 @@ elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section,
            if (dynamic_symbol_p)
              {
                BFD_ASSERT(h->root.dynindx != -1);
-               outrel.r_info = ELF64_R_INFO (h->root.dynindx, r_type);
-               outrel.r_addend = addend;
+               dynindx = h->root.dynindx;
+               dynaddend = addend;
                addend = 0, value = 0;
              }
            else if (r_type == R_ALPHA_DTPREL64)
              {
-               BFD_ASSERT(tls_segment != NULL);
+               BFD_ASSERT (elf_hash_table (info)->tls_sec != NULL);
                value -= dtp_base;
                goto default_reloc;
              }
            else if (r_type == R_ALPHA_TPREL64)
              {
-               BFD_ASSERT(tls_segment != NULL);
-               value -= dtp_base;
-               goto default_reloc;
+               BFD_ASSERT (elf_hash_table (info)->tls_sec != NULL);
+               if (!info->shared)
+                 {
+                   value -= tp_base;
+                   goto default_reloc;
+                 }
+               dynindx = 0;
+               dynaddend = value - dtp_base;
              }
            else if (info->shared
                     && r_symndx != 0
@@ -4644,28 +4645,16 @@ elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section,
                       h->root.root.root.string);
                    ret_val = FALSE;
                  }
-               outrel.r_info = ELF64_R_INFO (0, R_ALPHA_RELATIVE);
-               outrel.r_addend = value;
+               dynindx = 0;
+               dyntype = R_ALPHA_RELATIVE;
+               dynaddend = value;
              }
            else
              goto default_reloc;
 
-           BFD_ASSERT(srel != NULL);
-
-           outrel.r_offset =
-             _bfd_elf_section_offset (output_bfd, info, input_section,
-                                      rel->r_offset);
-           if ((outrel.r_offset | 1) != (bfd_vma) -1)
-             outrel.r_offset += (input_section->output_section->vma
-                                 + input_section->output_offset);
-           else
-             memset (&outrel, 0, sizeof outrel);
-
-           loc = srel->contents;
-           loc += srel->reloc_count++ * sizeof (Elf64_External_Rela);
-           bfd_elf64_swap_reloca_out (output_bfd, &outrel, loc);
-           BFD_ASSERT (sizeof (Elf64_External_Rela) * srel->reloc_count
-                       <= srel->_cooked_size);
+           elf64_alpha_emit_dynrel (output_bfd, info, input_section,
+                                    srel, rel->r_offset, dynindx,
+                                    dyntype, dynaddend);
          }
          goto default_reloc;
 
@@ -4707,32 +4696,15 @@ elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section,
                 DTPMOD64 reloc, otherwise it will be handled in
                 finish_dynamic_symbol.  */
              if (info->shared && !dynamic_symbol_p)
-               {
-                 Elf_Internal_Rela outrel;
-                 bfd_byte *loc;
-
-                 BFD_ASSERT(srelgot != NULL);
-
-                 outrel.r_offset = (sgot->output_section->vma
-                                    + sgot->output_offset
-                                    + gotent->got_offset);
-                 /* ??? Proper dynindx here.  */
-                 outrel.r_info = ELF64_R_INFO (0, R_ALPHA_DTPMOD64);
-                 outrel.r_addend = 0;
-
-                 loc = srelgot->contents;
-                 loc += srelgot->reloc_count++ * sizeof (Elf64_External_Rela);
-                 bfd_elf64_swap_reloca_out (output_bfd, &outrel, loc);
-                 BFD_ASSERT (sizeof (Elf64_External_Rela)
-                             * srelgot->reloc_count
-                             <= srelgot->_cooked_size);
-               }
+               elf64_alpha_emit_dynrel (output_bfd, info, sgot, srelgot,
+                                        gotent->got_offset, 0,
+                                        R_ALPHA_DTPMOD64, 0);
 
              if (dynamic_symbol_p || r_type == R_ALPHA_TLSLDM)
                value = 0;
              else
                {
-                 BFD_ASSERT(tls_segment != NULL);
+                 BFD_ASSERT (elf_hash_table (info)->tls_sec != NULL);
                  value -= dtp_base;
                }
              bfd_put_64 (output_bfd, value,
@@ -4755,7 +4727,7 @@ elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section,
                  bfd_archive_filename (input_bfd), h->root.root.root.string);
               ret_val = FALSE;
             }
-         BFD_ASSERT(tls_segment != NULL);
+         BFD_ASSERT (elf_hash_table (info)->tls_sec != NULL);
          value -= dtp_base;
          if (r_type == R_ALPHA_DTPRELHI)
            value = ((bfd_signed_vma) value >> 16) + ((value >> 15) & 1);
@@ -4778,7 +4750,7 @@ elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section,
                  bfd_archive_filename (input_bfd), h->root.root.root.string);
               ret_val = FALSE;
             }
-         BFD_ASSERT(tls_segment != NULL);
+         BFD_ASSERT (elf_hash_table (info)->tls_sec != NULL);
          value -= tp_base;
          if (r_type == R_ALPHA_TPRELHI)
            value = ((bfd_signed_vma) value >> 16) + ((value >> 15) & 1);
@@ -4799,8 +4771,19 @@ elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section,
                value = 0;
              else
                {
-                 BFD_ASSERT(tls_segment != NULL);
-                 value -= (r_type == R_ALPHA_GOTDTPREL ? dtp_base : tp_base);
+                 BFD_ASSERT (elf_hash_table (info)->tls_sec != NULL);
+                 if (r_type == R_ALPHA_GOTDTPREL)
+                   value -= dtp_base;
+                 else if (!info->shared)
+                   value -= tp_base;
+                 else
+                   {
+                     elf64_alpha_emit_dynrel (output_bfd, info, sgot, srelgot,
+                                              gotent->got_offset, 0,
+                                              R_ALPHA_TPREL64,
+                                              value - dtp_base);
+                     value = 0;
+                   }
                }
              bfd_put_64 (output_bfd, value,
                          sgot->contents + gotent->got_offset);
@@ -4957,19 +4940,9 @@ elf64_alpha_finish_dynamic_symbol (output_bfd, info, h, sym)
                          sgot->contents + gotent->got_offset);
 
              if (info->shared)
-               {
-                 outrel.r_offset = (sgot->output_section->vma
-                                    + sgot->output_offset
-                                    + gotent->got_offset);
-                 outrel.r_info = ELF64_R_INFO(0, R_ALPHA_RELATIVE);
-                 outrel.r_addend = plt_addr;
-
-                 loc = srel->contents;
-                 loc += srel->reloc_count++ * sizeof (Elf64_External_Rela);
-                 bfd_elf64_swap_reloca_out (output_bfd, &outrel, loc);
-                 BFD_ASSERT (sizeof (Elf64_External_Rela) * srel->reloc_count
-                             <= srel->_cooked_size);
-               }
+               elf64_alpha_emit_dynrel (output_bfd, info, sgot, srel,
+                                        gotent->got_offset, 0,
+                                        R_ALPHA_RELATIVE, plt_addr);
 
              gotent = gotent->next;
            }
@@ -4980,8 +4953,6 @@ elf64_alpha_finish_dynamic_symbol (output_bfd, info, h, sym)
     {
       /* Fill in the dynamic relocations for this symbol's .got entries.  */
       asection *srel;
-      Elf_Internal_Rela outrel;
-      bfd_byte *loc;
       struct alpha_elf_got_entry *gotent;
 
       srel = bfd_get_section_by_name (dynobj, ".rela.got");
@@ -4992,15 +4963,12 @@ elf64_alpha_finish_dynamic_symbol (output_bfd, info, h, sym)
           gotent = gotent->next)
        {
          asection *sgot;
-         int r_type;
+         long 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);
 
          r_type = gotent->reloc_type;
          switch (r_type)
@@ -5022,25 +4990,14 @@ elf64_alpha_finish_dynamic_symbol (output_bfd, info, h, sym)
              abort ();
            }
 
-         outrel.r_info = ELF64_R_INFO (h->dynindx, r_type);
-         outrel.r_addend = gotent->addend;
-
-         loc = srel->contents;
-         loc += srel->reloc_count++ * sizeof (Elf64_External_Rela);
-         bfd_elf64_swap_reloca_out (output_bfd, &outrel, loc);
+         elf64_alpha_emit_dynrel (output_bfd, info, sgot, srel, 
+                                  gotent->got_offset, h->dynindx,
+                                  r_type, gotent->addend);
 
          if (gotent->reloc_type == R_ALPHA_TLSGD)
-           {
-             outrel.r_offset += 8;
-             outrel.r_info = ELF64_R_INFO (h->dynindx, R_ALPHA_DTPREL64);
-
-             loc = srel->contents;
-             loc += srel->reloc_count++ * sizeof (Elf64_External_Rela);
-             bfd_elf64_swap_reloca_out (output_bfd, &outrel, loc);
-           }
-
-         BFD_ASSERT (sizeof (Elf64_External_Rela) * srel->reloc_count
-                     <= srel->_cooked_size);
+           elf64_alpha_emit_dynrel (output_bfd, info, sgot, srel, 
+                                    gotent->got_offset + 8, h->dynindx,
+                                    R_ALPHA_DTPREL64, gotent->addend);
        }
     }
 
@@ -5125,7 +5082,7 @@ elf64_alpha_finish_dynamic_sections (output_bfd, info)
          bfd_elf64_swap_dyn_out (output_bfd, &dyn, dyncon);
        }
 
-      /* Initialize the PLT0 entry */
+      /* Initialize the PLT0 entry */
       if (splt->_raw_size > 0)
        {
          bfd_put_32 (output_bfd, PLT_HEADER_WORD1, splt->contents);
@@ -5376,7 +5333,7 @@ elf64_alpha_final_link (abfd, info)
     }
 
   /* Invoke the regular ELF backend linker to do all the work.  */
-  if (! bfd_elf64_bfd_final_link (abfd, info))
+  if (! bfd_elf_final_link (abfd, info))
     return FALSE;
 
   /* Now write out the computed sections.  */
@@ -5434,6 +5391,13 @@ elf64_alpha_reloc_type_class (rela)
     }
 }
 \f
+static struct bfd_elf_special_section const elf64_alpha_special_sections[]=
+{
+  { ".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 }
+};
+
 /* ECOFF swapping routines.  These are used when dealing with the
    .mdebug section, which is in the ECOFF debugging format.  Copied
    from elf32-mips.c.  */
@@ -5493,7 +5457,7 @@ static const struct elf_size_info alpha_elf_size_info =
   sizeof (Elf_External_Note),
   8,
   1,
-  64, 8,
+  64, 3,
   ELFCLASS64, EV_CURRENT,
   bfd_elf64_write_out_phdrs,
   bfd_elf64_write_shdrs_and_ehdr,
@@ -5572,12 +5536,14 @@ static const struct elf_size_info alpha_elf_size_info =
 #define elf_backend_size_info \
   alpha_elf_size_info
 
+#define elf_backend_special_sections \
+  elf64_alpha_special_sections
+
 /* A few constants that determine how the .plt section is set up.  */
 #define elf_backend_want_got_plt 0
 #define elf_backend_plt_readonly 0
 #define elf_backend_want_plt_sym 1
 #define elf_backend_got_header_size 0
-#define elf_backend_plt_header_size PLT_HEADER_SIZE
 
 #include "elf64-target.h"
 \f
This page took 0.039291 seconds and 4 git commands to generate.