* elfcode.h (elf_checksum_contents): Free contents.
[binutils-gdb.git] / bfd / elf64-alpha.c
index de8a90c333139fcd36da6c04597e2c795665db8f..02dd2abaf6b52e4858c2a019c1cce3feb3135fbb 100644 (file)
@@ -1,5 +1,6 @@
 /* Alpha specific support for 64-bit ELF
 /* Alpha specific support for 64-bit ELF
-   Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+   Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
+   2006, 2007, 2008, 2009, 2010, 2011, 2012
    Free Software Foundation, Inc.
    Contributed by Richard Henderson <rth@tamu.edu>.
 
    Free Software Foundation, Inc.
    Contributed by Richard Henderson <rth@tamu.edu>.
 
@@ -7,7 +8,7 @@
 
    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
 
    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,
    (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
 
    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.  */
 
 
 /* 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 "sysdep.h"
+#include "bfd.h"
 #include "libbfd.h"
 #include "elf-bfd.h"
 
 #include "libbfd.h"
 #include "elf-bfd.h"
 
 #include "ecoffswap.h"
 
 \f
 #include "ecoffswap.h"
 
 \f
-struct alpha_elf_link_hash_entry
+/* Instruction data for plt generation and relaxation.  */
+
+#define OP_LDA         0x08
+#define OP_LDAH                0x09
+#define OP_LDQ         0x29
+#define OP_BR          0x30
+#define OP_BSR         0x34
+
+#define INSN_LDA       (OP_LDA << 26)
+#define INSN_LDAH      (OP_LDAH << 26)
+#define INSN_LDQ       (OP_LDQ << 26)
+#define INSN_BR                (OP_BR << 26)
+
+#define INSN_ADDQ      0x40000400
+#define INSN_RDUNIQ    0x0000009e
+#define INSN_SUBQ      0x40000520
+#define INSN_S4SUBQ    0x40000560
+#define INSN_UNOP      0x2ffe0000
+
+#define INSN_JSR       0x68004000
+#define INSN_JMP       0x68000000
+#define INSN_JSR_MASK  0xfc00c000
+
+#define INSN_A(I,A)            (I | (A << 21))
+#define INSN_AB(I,A,B)         (I | (A << 21) | (B << 16))
+#define INSN_ABC(I,A,B,C)      (I | (A << 21) | (B << 16) | C)
+#define INSN_ABO(I,A,B,O)      (I | (A << 21) | (B << 16) | ((O) & 0xffff))
+#define INSN_AD(I,A,D)         (I | (A << 21) | (((D) >> 2) & 0x1fffff))
+
+/* PLT/GOT Stuff */
+
+/* Set by ld emulation.  Putting this into the link_info or hash structure
+   is simply working too hard.  */
+#ifdef USE_SECUREPLT
+bfd_boolean elf64_alpha_use_secureplt = TRUE;
+#else
+bfd_boolean elf64_alpha_use_secureplt = FALSE;
+#endif
+
+#define OLD_PLT_HEADER_SIZE    32
+#define OLD_PLT_ENTRY_SIZE     12
+#define NEW_PLT_HEADER_SIZE    36
+#define NEW_PLT_ENTRY_SIZE     4
+
+#define PLT_HEADER_SIZE \
+  (elf64_alpha_use_secureplt ? NEW_PLT_HEADER_SIZE : OLD_PLT_HEADER_SIZE)
+#define PLT_ENTRY_SIZE \
+  (elf64_alpha_use_secureplt ? NEW_PLT_ENTRY_SIZE : OLD_PLT_ENTRY_SIZE)
+
+#define MAX_GOT_SIZE           (64*1024)
+
+#define ELF_DYNAMIC_INTERPRETER "/usr/lib/ld.so"
+\f
+
+/* Used to implement multiple .got subsections.  */
+struct alpha_elf_got_entry
 {
 {
-  struct elf_link_hash_entry root;
+  struct alpha_elf_got_entry *next;
 
 
-  /* External symbol information.  */
-  EXTR esym;
+  /* Which .got subsection?  */
+  bfd *gotobj;
 
 
-  /* Cumulative flags for all the .got entries.  */
-  int flags;
+  /* The addend in effect for this entry.  */
+  bfd_vma addend;
 
 
-  /* Contexts in which a literal was referenced.  */
-#define ALPHA_ELF_LINK_HASH_LU_ADDR    0x01
-#define ALPHA_ELF_LINK_HASH_LU_MEM     0x02
-#define ALPHA_ELF_LINK_HASH_LU_BYTE    0x04
-#define ALPHA_ELF_LINK_HASH_LU_JSR     0x08
-#define ALPHA_ELF_LINK_HASH_LU_TLSGD   0x10
-#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
+  /* The .got offset for this entry.  */
+  int got_offset;
 
 
-  /* Used to implement multiple .got subsections.  */
-  struct alpha_elf_got_entry
-  {
-    struct alpha_elf_got_entry *next;
+  /* The .plt offset for this entry.  */
+  int plt_offset;
+
+  /* How many references to this entry?  */
+  int use_count;
 
 
-    /* Which .got subsection?  */
-    bfd *gotobj;
+  /* The relocation type of this entry.  */
+  unsigned char reloc_type;
 
 
-    /* The addend in effect for this entry.  */
-    bfd_vma addend;
+  /* How a LITERAL is used.  */
+  unsigned char flags;
 
 
-    /* The .got offset for this entry.  */
-    int got_offset;
+  /* Have we initialized the dynamic relocation for this entry?  */
+  unsigned char reloc_done;
 
 
-    /* How many references to this entry?  */
-    int use_count;
+  /* Have we adjusted this entry for SEC_MERGE?  */
+  unsigned char reloc_xlated;
+};
 
 
-    /* The relocation type of this entry.  */
-    unsigned char reloc_type;
+struct alpha_elf_reloc_entry
+{
+  struct alpha_elf_reloc_entry *next;
 
 
-    /* How a LITERAL is used.  */
-    unsigned char flags;
+  /* Which .reloc section? */
+  asection *srel;
 
 
-    /* Have we initialized the dynamic relocation for this entry?  */
-    unsigned char reloc_done;
+  /* What kind of relocation? */
+  unsigned int rtype;
 
 
-    /* Have we adjusted this entry for SEC_MERGE?  */
-    unsigned char reloc_xlated;
-  } *got_entries;
+  /* Is this against read-only section? */
+  unsigned int reltext : 1;
 
 
-  /* 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;
+  /* How many did we find?  */
+  unsigned long count;
+};
+
+struct alpha_elf_link_hash_entry
+{
+  struct elf_link_hash_entry root;
+
+  /* External symbol information.  */
+  EXTR esym;
 
 
-    /* Which .reloc section? */
-    asection *srel;
+  /* Cumulative flags for all the .got entries.  */
+  int flags;
 
 
-    /* What kind of relocation? */
-    unsigned int rtype;
+  /* Contexts in which a literal was referenced.  */
+#define ALPHA_ELF_LINK_HASH_LU_ADDR     0x01
+#define ALPHA_ELF_LINK_HASH_LU_MEM      0x02
+#define ALPHA_ELF_LINK_HASH_LU_BYTE     0x04
+#define ALPHA_ELF_LINK_HASH_LU_JSR      0x08
+#define ALPHA_ELF_LINK_HASH_LU_TLSGD    0x10
+#define ALPHA_ELF_LINK_HASH_LU_TLSLDM   0x20
+#define ALPHA_ELF_LINK_HASH_LU_JSRDIRECT 0x40
+#define ALPHA_ELF_LINK_HASH_LU_PLT      0x38
+#define ALPHA_ELF_LINK_HASH_TLS_IE      0x80
 
 
-    /* Is this against read-only section? */
-    unsigned int reltext : 1;
+  /* Used to implement multiple .got subsections.  */
+  struct alpha_elf_got_entry *got_entries;
 
 
-    /* How many did we find?  */
-    unsigned long count;
-  } *reloc_entries;
+  /* Used to count non-got, non-plt relocations for delayed sizing
+     of relocation sections.  */
+  struct alpha_elf_reloc_entry *reloc_entries;
 };
 
 /* Alpha ELF linker hash table.  */
 };
 
 /* Alpha ELF linker hash table.  */
@@ -128,6 +193,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 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.  */
 };
 
 /* Look up an entry in a Alpha ELF linker hash table.  */
@@ -142,20 +211,21 @@ struct alpha_elf_link_hash_table
 #define alpha_elf_link_hash_traverse(table, func, info)                        \
   (elf_link_hash_traverse                                              \
    (&(table)->root,                                                    \
 #define alpha_elf_link_hash_traverse(table, func, info)                        \
   (elf_link_hash_traverse                                              \
    (&(table)->root,                                                    \
-    (bfd_boolean (*) (struct elf_link_hash_entry *, PTR)) (func),      \
+    (bfd_boolean (*) (struct elf_link_hash_entry *, void *)) (func),   \
     (info)))
 
 /* Get the Alpha ELF linker hash table from a link_info structure.  */
 
 #define alpha_elf_hash_table(p) \
     (info)))
 
 /* 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.  */
 
 #define alpha_elf_sym_hashes(abfd) \
   ((struct alpha_elf_link_hash_entry **)elf_sym_hashes(abfd))
 
 
 /* Get the object's symbols as our own entry type.  */
 
 #define alpha_elf_sym_hashes(abfd) \
   ((struct alpha_elf_link_hash_entry **)elf_sym_hashes(abfd))
 
-/* Should we do dynamic things to this symbol?  This differs from the 
+/* 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.  */
    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.  */
@@ -217,8 +287,10 @@ elf64_alpha_bfd_link_hash_table_create (bfd *abfd)
   if (ret == (struct alpha_elf_link_hash_table *) NULL)
     return NULL;
 
   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;
     {
       free (ret);
       return NULL;
@@ -261,14 +333,16 @@ struct alpha_elf_obj_tdata
 #define alpha_elf_tdata(abfd) \
   ((struct alpha_elf_obj_tdata *) (abfd)->tdata.any)
 
 #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)
 {
 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
 }
 
 static bfd_boolean
@@ -283,7 +357,7 @@ elf64_alpha_object_p (bfd *abfd)
 static bfd_reloc_status_type
 elf64_alpha_reloc_nil (bfd *abfd ATTRIBUTE_UNUSED, arelent *reloc,
                       asymbol *sym ATTRIBUTE_UNUSED,
 static bfd_reloc_status_type
 elf64_alpha_reloc_nil (bfd *abfd ATTRIBUTE_UNUSED, arelent *reloc,
                       asymbol *sym ATTRIBUTE_UNUSED,
-                      PTR data ATTRIBUTE_UNUSED, asection *sec,
+                      void * data ATTRIBUTE_UNUSED, asection *sec,
                       bfd *output_bfd, char **error_message ATTRIBUTE_UNUSED)
 {
   if (output_bfd)
                       bfd *output_bfd, char **error_message ATTRIBUTE_UNUSED)
 {
   if (output_bfd)
@@ -296,7 +370,7 @@ elf64_alpha_reloc_nil (bfd *abfd ATTRIBUTE_UNUSED, arelent *reloc,
 static bfd_reloc_status_type
 elf64_alpha_reloc_bad (bfd *abfd ATTRIBUTE_UNUSED, arelent *reloc,
                       asymbol *sym ATTRIBUTE_UNUSED,
 static bfd_reloc_status_type
 elf64_alpha_reloc_bad (bfd *abfd ATTRIBUTE_UNUSED, arelent *reloc,
                       asymbol *sym ATTRIBUTE_UNUSED,
-                      PTR data ATTRIBUTE_UNUSED, asection *sec,
+                      void * data ATTRIBUTE_UNUSED, asection *sec,
                       bfd *output_bfd, char **error_message ATTRIBUTE_UNUSED)
 {
   if (output_bfd)
                       bfd *output_bfd, char **error_message ATTRIBUTE_UNUSED)
 {
   if (output_bfd)
@@ -348,7 +422,7 @@ elf64_alpha_do_reloc_gpdisp (bfd *abfd, bfd_vma gpdisp, bfd_byte *p_ldah,
 
 static bfd_reloc_status_type
 elf64_alpha_reloc_gpdisp (bfd *abfd, arelent *reloc_entry,
 
 static bfd_reloc_status_type
 elf64_alpha_reloc_gpdisp (bfd *abfd, arelent *reloc_entry,
-                         asymbol *sym ATTRIBUTE_UNUSED, PTR data,
+                         asymbol *sym ATTRIBUTE_UNUSED, void * data,
                          asection *input_section, bfd *output_bfd,
                          char **err_msg)
 {
                          asection *input_section, bfd *output_bfd,
                          char **err_msg)
 {
@@ -393,8 +467,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)
 
    from smaller values.  Start with zero, widen, *then* decrement.  */
 #define MINUS_ONE      (((bfd_vma)0) - 1)
 
+
 #define SKIP_HOWTO(N) \
 #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[] =
 {
 
 static reloc_howto_type elf64_alpha_howto_table[] =
 {
@@ -420,7 +495,7 @@ static reloc_howto_type elf64_alpha_howto_table[] =
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_bitfield, /* complain_on_overflow */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_bitfield, /* complain_on_overflow */
-        0,                     /* special_function */
+        bfd_elf_generic_reloc, /* special_function */
         "REFLONG",             /* name */
         FALSE,                 /* partial_inplace */
         0xffffffff,            /* src_mask */
         "REFLONG",             /* name */
         FALSE,                 /* partial_inplace */
         0xffffffff,            /* src_mask */
@@ -435,7 +510,7 @@ static reloc_howto_type elf64_alpha_howto_table[] =
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_bitfield, /* complain_on_overflow */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_bitfield, /* complain_on_overflow */
-        0,                     /* special_function */
+        bfd_elf_generic_reloc, /* special_function */
         "REFQUAD",             /* name */
         FALSE,                 /* partial_inplace */
         MINUS_ONE,             /* src_mask */
         "REFQUAD",             /* name */
         FALSE,                 /* partial_inplace */
         MINUS_ONE,             /* src_mask */
@@ -452,7 +527,7 @@ static reloc_howto_type elf64_alpha_howto_table[] =
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_bitfield, /* complain_on_overflow */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_bitfield, /* complain_on_overflow */
-        0,                     /* special_function */
+        bfd_elf_generic_reloc, /* special_function */
         "GPREL32",             /* name */
         FALSE,                 /* partial_inplace */
         0xffffffff,            /* src_mask */
         "GPREL32",             /* name */
         FALSE,                 /* partial_inplace */
         0xffffffff,            /* src_mask */
@@ -467,7 +542,7 @@ static reloc_howto_type elf64_alpha_howto_table[] =
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
-        0,                     /* special_function */
+        bfd_elf_generic_reloc, /* special_function */
         "ELF_LITERAL",         /* name */
         FALSE,                 /* partial_inplace */
         0xffff,                /* src_mask */
         "ELF_LITERAL",         /* name */
         FALSE,                 /* partial_inplace */
         0xffff,                /* src_mask */
@@ -533,7 +608,7 @@ static reloc_howto_type elf64_alpha_howto_table[] =
         TRUE,                  /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
         TRUE,                  /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
-        0,                     /* special_function */
+        bfd_elf_generic_reloc, /* special_function */
         "BRADDR",              /* name */
         FALSE,                 /* partial_inplace */
         0x1fffff,              /* src_mask */
         "BRADDR",              /* name */
         FALSE,                 /* partial_inplace */
         0x1fffff,              /* src_mask */
@@ -548,7 +623,7 @@ static reloc_howto_type elf64_alpha_howto_table[] =
         TRUE,                  /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
         TRUE,                  /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        0,                     /* special_function */
+        bfd_elf_generic_reloc, /* special_function */
         "HINT",                /* name */
         FALSE,                 /* partial_inplace */
         0x3fff,                /* src_mask */
         "HINT",                /* name */
         FALSE,                 /* partial_inplace */
         0x3fff,                /* src_mask */
@@ -563,7 +638,7 @@ static reloc_howto_type elf64_alpha_howto_table[] =
         TRUE,                  /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
         TRUE,                  /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
-        0,                     /* special_function */
+        bfd_elf_generic_reloc, /* special_function */
         "SREL16",              /* name */
         FALSE,                 /* partial_inplace */
         0xffff,                /* src_mask */
         "SREL16",              /* name */
         FALSE,                 /* partial_inplace */
         0xffff,                /* src_mask */
@@ -578,7 +653,7 @@ static reloc_howto_type elf64_alpha_howto_table[] =
         TRUE,                  /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
         TRUE,                  /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
-        0,                     /* special_function */
+        bfd_elf_generic_reloc, /* special_function */
         "SREL32",              /* name */
         FALSE,                 /* partial_inplace */
         0xffffffff,            /* src_mask */
         "SREL32",              /* name */
         FALSE,                 /* partial_inplace */
         0xffffffff,            /* src_mask */
@@ -593,7 +668,7 @@ static reloc_howto_type elf64_alpha_howto_table[] =
         TRUE,                  /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
         TRUE,                  /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
-        0,                     /* special_function */
+        bfd_elf_generic_reloc, /* special_function */
         "SREL64",              /* name */
         FALSE,                 /* partial_inplace */
         MINUS_ONE,             /* src_mask */
         "SREL64",              /* name */
         FALSE,                 /* partial_inplace */
         MINUS_ONE,             /* src_mask */
@@ -615,7 +690,7 @@ static reloc_howto_type elf64_alpha_howto_table[] =
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
-        0,                     /* special_function */
+        bfd_elf_generic_reloc, /* special_function */
         "GPRELHIGH",           /* name */
         FALSE,                 /* partial_inplace */
         0xffff,                /* src_mask */
         "GPRELHIGH",           /* name */
         FALSE,                 /* partial_inplace */
         0xffff,                /* src_mask */
@@ -630,7 +705,7 @@ static reloc_howto_type elf64_alpha_howto_table[] =
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        0,                     /* special_function */
+        bfd_elf_generic_reloc, /* special_function */
         "GPRELLOW",            /* name */
         FALSE,                 /* partial_inplace */
         0xffff,                /* src_mask */
         "GPRELLOW",            /* name */
         FALSE,                 /* partial_inplace */
         0xffff,                /* src_mask */
@@ -645,7 +720,7 @@ static reloc_howto_type elf64_alpha_howto_table[] =
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
-        0,                     /* special_function */
+        bfd_elf_generic_reloc, /* special_function */
         "GPREL16",             /* name */
         FALSE,                 /* partial_inplace */
         0xffff,                /* src_mask */
         "GPREL16",             /* name */
         FALSE,                 /* partial_inplace */
         0xffff,                /* src_mask */
@@ -731,7 +806,7 @@ static reloc_howto_type elf64_alpha_howto_table[] =
         TRUE,                  /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
         TRUE,                  /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
-        0,                     /* special_function */
+        bfd_elf_generic_reloc, /* special_function */
         "BRSGP",               /* name */
         FALSE,                 /* partial_inplace */
         0x1fffff,              /* src_mask */
         "BRSGP",               /* name */
         FALSE,                 /* partial_inplace */
         0x1fffff,              /* src_mask */
@@ -746,7 +821,7 @@ static reloc_howto_type elf64_alpha_howto_table[] =
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
-        0,                     /* special_function */
+        bfd_elf_generic_reloc, /* special_function */
         "TLSGD",               /* name */
         FALSE,                 /* partial_inplace */
         0xffff,                /* src_mask */
         "TLSGD",               /* name */
         FALSE,                 /* partial_inplace */
         0xffff,                /* src_mask */
@@ -761,7 +836,7 @@ static reloc_howto_type elf64_alpha_howto_table[] =
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
-        0,                     /* special_function */
+        bfd_elf_generic_reloc, /* special_function */
         "TLSLDM",              /* name */
         FALSE,                 /* partial_inplace */
         0xffff,                /* src_mask */
         "TLSLDM",              /* name */
         FALSE,                 /* partial_inplace */
         0xffff,                /* src_mask */
@@ -776,7 +851,7 @@ static reloc_howto_type elf64_alpha_howto_table[] =
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_bitfield, /* complain_on_overflow */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_bitfield, /* complain_on_overflow */
-        0,                     /* special_function */
+        bfd_elf_generic_reloc, /* special_function */
         "DTPMOD64",            /* name */
         FALSE,                 /* partial_inplace */
         MINUS_ONE,             /* src_mask */
         "DTPMOD64",            /* name */
         FALSE,                 /* partial_inplace */
         MINUS_ONE,             /* src_mask */
@@ -792,7 +867,7 @@ static reloc_howto_type elf64_alpha_howto_table[] =
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
-        0,                     /* special_function */
+        bfd_elf_generic_reloc, /* special_function */
         "GOTDTPREL",           /* name */
         FALSE,                 /* partial_inplace */
         0xffff,                /* src_mask */
         "GOTDTPREL",           /* name */
         FALSE,                 /* partial_inplace */
         0xffff,                /* src_mask */
@@ -807,7 +882,7 @@ static reloc_howto_type elf64_alpha_howto_table[] =
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_bitfield, /* complain_on_overflow */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_bitfield, /* complain_on_overflow */
-        0,                     /* special_function */
+        bfd_elf_generic_reloc, /* special_function */
         "DTPREL64",            /* name */
         FALSE,                 /* partial_inplace */
         MINUS_ONE,             /* src_mask */
         "DTPREL64",            /* name */
         FALSE,                 /* partial_inplace */
         MINUS_ONE,             /* src_mask */
@@ -822,7 +897,7 @@ static reloc_howto_type elf64_alpha_howto_table[] =
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
-        0,                     /* special_function */
+        bfd_elf_generic_reloc, /* special_function */
         "DTPRELHI",            /* name */
         FALSE,                 /* partial_inplace */
         0xffff,                /* src_mask */
         "DTPRELHI",            /* name */
         FALSE,                 /* partial_inplace */
         0xffff,                /* src_mask */
@@ -837,7 +912,7 @@ static reloc_howto_type elf64_alpha_howto_table[] =
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        0,                     /* special_function */
+        bfd_elf_generic_reloc, /* special_function */
         "DTPRELLO",            /* name */
         FALSE,                 /* partial_inplace */
         0xffff,                /* src_mask */
         "DTPRELLO",            /* name */
         FALSE,                 /* partial_inplace */
         0xffff,                /* src_mask */
@@ -852,7 +927,7 @@ static reloc_howto_type elf64_alpha_howto_table[] =
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
-        0,                     /* special_function */
+        bfd_elf_generic_reloc, /* special_function */
         "DTPREL16",            /* name */
         FALSE,                 /* partial_inplace */
         0xffff,                /* src_mask */
         "DTPREL16",            /* name */
         FALSE,                 /* partial_inplace */
         0xffff,                /* src_mask */
@@ -868,7 +943,7 @@ static reloc_howto_type elf64_alpha_howto_table[] =
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
-        0,                     /* special_function */
+        bfd_elf_generic_reloc, /* special_function */
         "GOTTPREL",            /* name */
         FALSE,                 /* partial_inplace */
         0xffff,                /* src_mask */
         "GOTTPREL",            /* name */
         FALSE,                 /* partial_inplace */
         0xffff,                /* src_mask */
@@ -883,7 +958,7 @@ static reloc_howto_type elf64_alpha_howto_table[] =
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_bitfield, /* complain_on_overflow */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_bitfield, /* complain_on_overflow */
-        0,                     /* special_function */
+        bfd_elf_generic_reloc, /* special_function */
         "TPREL64",             /* name */
         FALSE,                 /* partial_inplace */
         MINUS_ONE,             /* src_mask */
         "TPREL64",             /* name */
         FALSE,                 /* partial_inplace */
         MINUS_ONE,             /* src_mask */
@@ -898,7 +973,7 @@ static reloc_howto_type elf64_alpha_howto_table[] =
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
-        0,                     /* special_function */
+        bfd_elf_generic_reloc, /* special_function */
         "TPRELHI",             /* name */
         FALSE,                 /* partial_inplace */
         0xffff,                /* src_mask */
         "TPRELHI",             /* name */
         FALSE,                 /* partial_inplace */
         0xffff,                /* src_mask */
@@ -913,7 +988,7 @@ static reloc_howto_type elf64_alpha_howto_table[] =
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        0,                     /* special_function */
+        bfd_elf_generic_reloc, /* special_function */
         "TPRELLO",             /* name */
         FALSE,                 /* partial_inplace */
         0xffff,                /* src_mask */
         "TPRELLO",             /* name */
         FALSE,                 /* partial_inplace */
         0xffff,                /* src_mask */
@@ -928,7 +1003,7 @@ static reloc_howto_type elf64_alpha_howto_table[] =
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
-        0,                     /* special_function */
+        bfd_elf_generic_reloc, /* special_function */
         "TPREL16",             /* name */
         FALSE,                 /* partial_inplace */
         0xffff,                /* src_mask */
         "TPREL16",             /* name */
         FALSE,                 /* partial_inplace */
         0xffff,                /* src_mask */
@@ -995,6 +1070,23 @@ elf64_alpha_bfd_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
   return 0;
 }
 
   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
 /* Given an Alpha ELF reloc type, fill in an arelent structure.  */
 
 static void
@@ -1021,22 +1113,6 @@ elf64_alpha_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, arelent *cache_ptr,
    - align_power ((bfd_vma) 16,                                                \
                  elf_hash_table (info)->tls_sec->alignment_power))
 \f
    - align_power ((bfd_vma) 16,                                                \
                  elf_hash_table (info)->tls_sec->alignment_power))
 \f
-/* PLT/GOT Stuff */
-#define PLT_HEADER_SIZE 32
-#define PLT_HEADER_WORD1       (bfd_vma) 0xc3600000    /* br   $27,.+4     */
-#define PLT_HEADER_WORD2       (bfd_vma) 0xa77b000c    /* ldq  $27,12($27) */
-#define PLT_HEADER_WORD3       (bfd_vma) 0x47ff041f    /* nop              */
-#define PLT_HEADER_WORD4       (bfd_vma) 0x6b7b0000    /* jmp  $27,($27)   */
-
-#define PLT_ENTRY_SIZE 12
-#define PLT_ENTRY_WORD1                0xc3800000      /* br   $28, plt0   */
-#define PLT_ENTRY_WORD2                0
-#define PLT_ENTRY_WORD3                0
-
-#define MAX_GOT_SIZE           (64*1024)
-
-#define ELF_DYNAMIC_INTERPRETER "/usr/lib/ld.so"
-\f
 /* Handle an Alpha specific section when reading an object file.  This
    is called when bfd_section_from_shdr finds a section with an unknown
    type.
 /* Handle an Alpha specific section when reading an object file.  This
    is called when bfd_section_from_shdr finds a section with an unknown
    type.
@@ -1164,26 +1240,26 @@ static bfd_boolean
 elf64_alpha_create_got_section (bfd *abfd,
                                struct bfd_link_info *info ATTRIBUTE_UNUSED)
 {
 elf64_alpha_create_got_section (bfd *abfd,
                                struct bfd_link_info *info ATTRIBUTE_UNUSED)
 {
+  flagword flags;
   asection *s;
 
   asection *s;
 
-  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;
-    }
+  if (! is_alpha_elf (abfd))
+    return FALSE;
 
 
-  s = bfd_make_section_with_flags (abfd, ".got", (SEC_ALLOC | SEC_LOAD
-                                                 | SEC_HAS_CONTENTS
-                                                 | SEC_IN_MEMORY
-                                                 | SEC_LINKER_CREATED));
+  flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
+          | SEC_LINKER_CREATED);
+  s = bfd_make_section_anyway_with_flags (abfd, ".got", flags);
   if (s == NULL
       || !bfd_set_section_alignment (abfd, s, 3))
     return FALSE;
 
   alpha_elf_tdata (abfd)->got = s;
 
   if (s == NULL
       || !bfd_set_section_alignment (abfd, s, 3))
     return FALSE;
 
   alpha_elf_tdata (abfd)->got = s;
 
+  /* Make sure the object's gotobj is set to itself so that we default
+     to every object with its own .got.  We'll merge .gots later once
+     we've collected each object's info.  */
+  alpha_elf_tdata (abfd)->gotobj = abfd;
+
   return TRUE;
 }
 
   return TRUE;
 }
 
@@ -1193,59 +1269,55 @@ static bfd_boolean
 elf64_alpha_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
 {
   asection *s;
 elf64_alpha_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
 {
   asection *s;
+  flagword flags;
   struct elf_link_hash_entry *h;
   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.  */
 
 
   /* We need to create .plt, .rela.plt, .got, and .rela.got sections.  */
 
-  s = bfd_make_section_with_flags (abfd, ".plt",
-                                  (SEC_ALLOC | SEC_LOAD
-                                   | SEC_HAS_CONTENTS
-                                   | SEC_IN_MEMORY
-                                   | SEC_LINKER_CREATED
-                                   | SEC_CODE));
-  if (s == NULL
-      || ! bfd_set_section_alignment (abfd, s, 3))
+  flags = (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS | SEC_IN_MEMORY
+          | SEC_LINKER_CREATED
+          | (elf64_alpha_use_secureplt ? SEC_READONLY : 0));
+  s = bfd_make_section_anyway_with_flags (abfd, ".plt", flags);
+  if (s == NULL || ! bfd_set_section_alignment (abfd, s, 4))
     return FALSE;
 
   /* Define the symbol _PROCEDURE_LINKAGE_TABLE_ at the start of the
      .plt section.  */
     return FALSE;
 
   /* 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)))
+  h = _bfd_elf_define_linkage_sym (abfd, info, s,
+                                  "_PROCEDURE_LINKAGE_TABLE_");
+  elf_hash_table (info)->hplt = h;
+  if (h == NULL)
     return FALSE;
     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))
+  flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
+          | SEC_LINKER_CREATED | SEC_READONLY);
+  s = bfd_make_section_anyway_with_flags (abfd, ".rela.plt", flags);
+  if (s == NULL || ! bfd_set_section_alignment (abfd, s, 3))
     return FALSE;
 
     return FALSE;
 
-  s = bfd_make_section_with_flags (abfd, ".rela.plt",
-                                  (SEC_ALLOC | SEC_LOAD
-                                   | SEC_HAS_CONTENTS
-                                   | SEC_IN_MEMORY
-                                   | SEC_LINKER_CREATED
-                                   | SEC_READONLY));
-  if (s == NULL
-      || ! bfd_set_section_alignment (abfd, s, 3))
-    return FALSE;
+  if (elf64_alpha_use_secureplt)
+    {
+      flags = SEC_ALLOC | SEC_LINKER_CREATED;
+      s = bfd_make_section_anyway_with_flags (abfd, ".got.plt", flags);
+      if (s == NULL || ! bfd_set_section_alignment (abfd, s, 3))
+       return FALSE;
+    }
 
   /* We may or may not have created a .got section for this object, but
      we definitely havn't done the rest of the work.  */
 
 
   /* We may or may not have created a .got section for this object, but
      we definitely havn't done the rest of the work.  */
 
-  if (!elf64_alpha_create_got_section (abfd, info))
-    return FALSE;
+  if (alpha_elf_tdata(abfd)->gotobj == NULL)
+    {
+      if (!elf64_alpha_create_got_section (abfd, info))
+       return FALSE;
+    }
 
 
-  s = bfd_make_section_with_flags (abfd, ".rela.got",
-                                  (SEC_ALLOC | SEC_LOAD
-                                   | SEC_HAS_CONTENTS
-                                   | SEC_IN_MEMORY
-                                   | SEC_LINKER_CREATED
-                                   | SEC_READONLY));
+  flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
+          | SEC_LINKER_CREATED | SEC_READONLY);
+  s = bfd_make_section_anyway_with_flags (abfd, ".rela.got", flags);
   if (s == NULL
       || !bfd_set_section_alignment (abfd, s, 3))
     return FALSE;
   if (s == NULL
       || !bfd_set_section_alignment (abfd, s, 3))
     return FALSE;
@@ -1254,21 +1326,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.  */
      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;
   elf_hash_table (info)->hgot = h;
+  if (h == NULL)
+    return FALSE;
 
   return TRUE;
 }
 
   return TRUE;
 }
@@ -1315,17 +1377,17 @@ elf64_alpha_read_ecoff_info (bfd *abfd, asection *section,
     }
 
   READ (line, cbLineOffset, cbLine, sizeof (unsigned char), unsigned char *);
     }
 
   READ (line, cbLineOffset, cbLine, sizeof (unsigned char), unsigned char *);
-  READ (external_dnr, cbDnOffset, idnMax, swap->external_dnr_size, PTR);
-  READ (external_pdr, cbPdOffset, ipdMax, swap->external_pdr_size, PTR);
-  READ (external_sym, cbSymOffset, isymMax, swap->external_sym_size, PTR);
-  READ (external_opt, cbOptOffset, ioptMax, swap->external_opt_size, PTR);
+  READ (external_dnr, cbDnOffset, idnMax, swap->external_dnr_size, void *);
+  READ (external_pdr, cbPdOffset, ipdMax, swap->external_pdr_size, void *);
+  READ (external_sym, cbSymOffset, isymMax, swap->external_sym_size, void *);
+  READ (external_opt, cbOptOffset, ioptMax, swap->external_opt_size, void *);
   READ (external_aux, cbAuxOffset, iauxMax, sizeof (union aux_ext),
        union aux_ext *);
   READ (ss, cbSsOffset, issMax, sizeof (char), char *);
   READ (ssext, cbSsExtOffset, issExtMax, sizeof (char), char *);
   READ (external_aux, cbAuxOffset, iauxMax, sizeof (union aux_ext),
        union aux_ext *);
   READ (ss, cbSsOffset, issMax, sizeof (char), char *);
   READ (ssext, cbSsExtOffset, issExtMax, sizeof (char), char *);
-  READ (external_fdr, cbFdOffset, ifdMax, swap->external_fdr_size, PTR);
-  READ (external_rfd, cbRfdOffset, crfd, swap->external_rfd_size, PTR);
-  READ (external_ext, cbExtOffset, iextMax, swap->external_ext_size, PTR);
+  READ (external_fdr, cbFdOffset, ifdMax, swap->external_fdr_size, void *);
+  READ (external_rfd, cbRfdOffset, crfd, swap->external_rfd_size, void *);
+  READ (external_ext, cbExtOffset, iextMax, swap->external_ext_size, void *);
 #undef READ
 
   debug->fdr = NULL;
 #undef READ
 
   debug->fdr = NULL;
@@ -1387,9 +1449,10 @@ elf64_alpha_find_nearest_line (bfd *abfd, asection *section, asymbol **symbols,
 {
   asection *msec;
 
 {
   asection *msec;
 
-  if (_bfd_dwarf2_find_nearest_line (abfd, section, symbols, offset,
+  if (_bfd_dwarf2_find_nearest_line (abfd, dwarf_debug_sections,
+                                     section, symbols, offset,
                                     filename_ptr, functionname_ptr,
                                     filename_ptr, functionname_ptr,
-                                    line_ptr, 0,
+                                    line_ptr, NULL, 0,
                                     &elf_tdata (abfd)->dwarf2_find_line_info))
     return TRUE;
 
                                     &elf_tdata (abfd)->dwarf2_find_line_info))
     return TRUE;
 
@@ -1444,7 +1507,7 @@ elf64_alpha_find_nearest_line (bfd *abfd, asection *section, asymbol **symbols,
          fraw_end = (fraw_src
                      + fi->d.symbolic_header.ifdMax * external_fdr_size);
          for (; fraw_src < fraw_end; fraw_src += external_fdr_size, fdr_ptr++)
          fraw_end = (fraw_src
                      + fi->d.symbolic_header.ifdMax * external_fdr_size);
          for (; fraw_src < fraw_end; fraw_src += external_fdr_size, fdr_ptr++)
-           (*swap->swap_fdr_in) (abfd, (PTR) fraw_src, fdr_ptr);
+           (*swap->swap_fdr_in) (abfd, fraw_src, fdr_ptr);
 
          elf_tdata (abfd)->find_line_info = fi;
 
 
          elf_tdata (abfd)->find_line_info = fi;
 
@@ -1486,15 +1549,12 @@ struct extsym_info
 };
 
 static bfd_boolean
 };
 
 static bfd_boolean
-elf64_alpha_output_extsym (struct alpha_elf_link_hash_entry *h, PTR data)
+elf64_alpha_output_extsym (struct alpha_elf_link_hash_entry *h, void * data)
 {
   struct extsym_info *einfo = (struct extsym_info *) data;
   bfd_boolean strip;
   asection *sec, *output_section;
 
 {
   struct extsym_info *einfo = (struct extsym_info *) data;
   bfd_boolean strip;
   asection *sec, *output_section;
 
-  if (h->root.root.type == bfd_link_hash_warning)
-    h = (struct alpha_elf_link_hash_entry *) h->root.root.u.i.link;
-
   if (h->root.indx == -2)
     strip = FALSE;
   else if ((h->root.def_dynamic
   if (h->root.indx == -2)
     strip = FALSE;
   else if ((h->root.def_dynamic
@@ -1588,24 +1648,6 @@ elf64_alpha_output_extsym (struct alpha_elf_link_hash_entry *h, PTR data)
       else
        h->esym.asym.value = 0;
     }
       else
        h->esym.asym.value = 0;
     }
-  else if (h->root.needs_plt)
-    {
-      /* Set type and value for a symbol with a function stub.  */
-      h->esym.asym.st = stProc;
-      sec = bfd_get_section_by_name (einfo->abfd, ".plt");
-      if (sec == NULL)
-       h->esym.asym.value = 0;
-      else
-       {
-         output_section = sec->output_section;
-         if (output_section != NULL)
-           h->esym.asym.value = (h->root.plt.offset
-                                 + sec->output_offset
-                                 + output_section->vma);
-         else
-           h->esym.asym.value = 0;
-       }
-    }
 
   if (! bfd_ecoff_debug_one_external (einfo->abfd, einfo->debug, einfo->swap,
                                      h->root.root.root.string,
 
   if (! bfd_ecoff_debug_one_external (einfo->abfd, einfo->debug, einfo->swap,
                                      h->root.root.root.string,
@@ -1676,6 +1718,7 @@ get_got_entry (bfd *abfd, struct alpha_elf_link_hash_entry *h,
       gotent->gotobj = abfd;
       gotent->addend = r_addend;
       gotent->got_offset = -1;
       gotent->gotobj = abfd;
       gotent->addend = r_addend;
       gotent->got_offset = -1;
+      gotent->plt_offset = -1;
       gotent->use_count = 1;
       gotent->reloc_type = r_type;
       gotent->reloc_done = 0;
       gotent->use_count = 1;
       gotent->reloc_type = r_type;
       gotent->reloc_done = 0;
@@ -1695,6 +1738,16 @@ get_got_entry (bfd *abfd, struct alpha_elf_link_hash_entry *h,
   return gotent;
 }
 
   return gotent;
 }
 
+static bfd_boolean
+elf64_alpha_want_plt (struct alpha_elf_link_hash_entry *ah)
+{
+  return ((ah->root.type == STT_FUNC
+         || ah->root.root.type == bfd_link_hash_undefweak
+         || ah->root.root.type == bfd_link_hash_undefined)
+         && (ah->flags & ALPHA_ELF_LINK_HASH_LU_PLT) != 0
+         && (ah->flags & ~ALPHA_ELF_LINK_HASH_LU_PLT) == 0);
+}
+
 /* Handle dynamic relocations when doing an Alpha ELF link.  */
 
 static bfd_boolean
 /* Handle dynamic relocations when doing an Alpha ELF link.  */
 
 static bfd_boolean
@@ -1703,11 +1756,9 @@ elf64_alpha_check_relocs (bfd *abfd, struct bfd_link_info *info,
 {
   bfd *dynobj;
   asection *sreloc;
 {
   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;
   Elf_Internal_Shdr *symtab_hdr;
   struct alpha_elf_link_hash_entry **sym_hashes;
   const Elf_Internal_Rela *rel, *relend;
-  bfd_boolean got_created;
   bfd_size_type amt;
 
   if (info->relocatable)
   bfd_size_type amt;
 
   if (info->relocatable)
@@ -1722,15 +1773,15 @@ elf64_alpha_check_relocs (bfd *abfd, struct bfd_link_info *info,
   if ((sec->flags & SEC_ALLOC) == 0)
     return TRUE;
 
   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)
   if (dynobj == NULL)
-    elf_hash_table(info)->dynobj = dynobj = abfd;
+    elf_hash_table (info)->dynobj = dynobj = abfd;
 
   sreloc = NULL;
 
   sreloc = NULL;
-  rel_sec_name = NULL;
-  symtab_hdr = &elf_tdata(abfd)->symtab_hdr;
-  sym_hashes = alpha_elf_sym_hashes(abfd);
-  got_created = FALSE;
+  symtab_hdr = &elf_symtab_hdr (abfd);
+  sym_hashes = alpha_elf_sym_hashes (abfd);
 
   relend = relocs + sec->reloc_count;
   for (rel = relocs; rel < relend; ++rel)
 
   relend = relocs + sec->reloc_count;
   for (rel = relocs; rel < relend; ++rel)
@@ -1788,7 +1839,7 @@ elf64_alpha_check_relocs (bfd *abfd, struct bfd_link_info *info,
             This will be important when it comes to decide if we can
             create a .plt entry for a function symbol.  */
          while (++rel < relend && ELF64_R_TYPE (rel->r_info) == R_ALPHA_LITUSE)
             This will be important when it comes to decide if we can
             create a .plt entry for a function symbol.  */
          while (++rel < relend && ELF64_R_TYPE (rel->r_info) == R_ALPHA_LITUSE)
-           if (rel->r_addend >= 1 && rel->r_addend <= 5)
+           if (rel->r_addend >= 1 && rel->r_addend <= 6)
              gotent_flags |= 1 << rel->r_addend;
          --rel;
 
              gotent_flags |= 1 << rel->r_addend;
          --rel;
 
@@ -1814,8 +1865,8 @@ elf64_alpha_check_relocs (bfd *abfd, struct bfd_link_info *info,
 
        case R_ALPHA_TLSLDM:
          /* The symbol for a TLSLDM reloc is ignored.  Collapse the
 
        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;
+            reloc to the STN_UNDEF (0) symbol so that they all match.  */
+         r_symndx = STN_UNDEF;
          h = 0;
          maybe_dynamic = FALSE;
          /* FALLTHRU */
          h = 0;
          maybe_dynamic = FALSE;
          /* FALLTHRU */
@@ -1833,27 +1884,22 @@ elf64_alpha_check_relocs (bfd *abfd, struct bfd_link_info *info,
          break;
 
        case R_ALPHA_TPREL64:
          break;
 
        case R_ALPHA_TPREL64:
-         if (info->shared || maybe_dynamic)
+         if (info->shared && !info->pie)
+           {
+             info->flags |= DF_STATIC_TLS;
+             need = NEED_DYNREL;
+           }
+         else if (maybe_dynamic)
            need = NEED_DYNREL;
            need = NEED_DYNREL;
-         if (info->shared)
-           info->flags |= DF_STATIC_TLS;
          break;
        }
 
       if (need & NEED_GOT)
        {
          break;
        }
 
       if (need & NEED_GOT)
        {
-         if (!got_created)
+         if (alpha_elf_tdata(abfd)->gotobj == NULL)
            {
              if (!elf64_alpha_create_got_section (abfd, info))
                return FALSE;
            {
              if (!elf64_alpha_create_got_section (abfd, info))
                return FALSE;
-
-             /* Make sure the object's gotobj is set to itself so
-                that we default to every object with its own .got.
-                We'll merge .gots later once we've collected each
-                object's info.  */
-             alpha_elf_tdata(abfd)->gotobj = abfd;
-
-             got_created = 1;
            }
        }
 
            }
        }
 
@@ -1874,52 +1920,28 @@ elf64_alpha_check_relocs (bfd *abfd, struct bfd_link_info *info,
                  h->flags = gotent_flags;
 
                  /* Make a guess as to whether a .plt entry is needed.  */
                  h->flags = gotent_flags;
 
                  /* Make a guess as to whether a .plt entry is needed.  */
-                 if ((gotent_flags & ALPHA_ELF_LINK_HASH_LU_FUNC)
-                     && !(gotent_flags & ~ALPHA_ELF_LINK_HASH_LU_FUNC))
-                   h->root.needs_plt = 1;
-                 else
-                   h->root.needs_plt = 0;
-               }
+                 /* ??? It appears that we won't make it into
+                    adjust_dynamic_symbol for symbols that remain
+                    totally undefined.  Copying this check here means
+                    we can create a plt entry for them too.  */
+                 h->root.needs_plt
+                   = (maybe_dynamic && elf64_alpha_want_plt (h));
+               }
            }
        }
 
       if (need & NEED_DYNREL)
        {
            }
        }
 
       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
          /* 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)
            {
          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)
              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)
            }
 
          if (h)
@@ -1968,6 +1990,93 @@ elf64_alpha_check_relocs (bfd *abfd, struct bfd_link_info *info,
   return TRUE;
 }
 
   return TRUE;
 }
 
+/* Return the section that should be marked against GC for a given
+   relocation.  */
+
+static asection *
+elf64_alpha_gc_mark_hook (asection *sec, struct bfd_link_info *info,
+                         Elf_Internal_Rela *rel,
+                         struct elf_link_hash_entry *h, Elf_Internal_Sym *sym)
+{
+  /* These relocations don't really reference a symbol.  Instead we store
+     extra data in their addend slot.  Ignore the symbol.  */
+  switch (ELF64_R_TYPE (rel->r_info))
+    {
+    case R_ALPHA_LITUSE:
+    case R_ALPHA_GPDISP:
+    case R_ALPHA_HINT:
+      return NULL;
+    }
+
+  return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym);
+}
+
+/* Update the got entry reference counts for the section being removed.  */
+
+static bfd_boolean
+elf64_alpha_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info,
+                          asection *sec, const Elf_Internal_Rela *relocs)
+{
+  Elf_Internal_Shdr *symtab_hdr;
+  struct alpha_elf_link_hash_entry **sym_hashes;
+  const Elf_Internal_Rela *rel, *relend;
+
+  if (info->relocatable)
+    return TRUE;
+
+  symtab_hdr = &elf_symtab_hdr (abfd);
+  sym_hashes = alpha_elf_sym_hashes (abfd);
+
+  relend = relocs + sec->reloc_count;
+  for (rel = relocs; rel < relend; rel++)
+    {
+      unsigned long r_symndx, r_type;
+      struct alpha_elf_link_hash_entry *h = NULL;
+      struct alpha_elf_got_entry *gotent;
+
+      r_symndx = ELF64_R_SYM (rel->r_info);
+      if (r_symndx >= symtab_hdr->sh_info)
+       {
+         h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+         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;
+       }
+
+      r_type = ELF64_R_TYPE (rel->r_info);
+      switch (r_type)
+       {
+       case R_ALPHA_LITERAL:
+         /* ??? Ignore re-computation of gotent_flags.  We're not
+            carrying a use-count for each bit in that mask.  */
+
+       case R_ALPHA_TLSGD:
+       case R_ALPHA_GOTDTPREL:
+       case R_ALPHA_GOTTPREL:
+         /* Fetch the got entry from the tables.  */
+         gotent = get_got_entry (abfd, h, r_type, r_symndx, rel->r_addend);
+
+         /* The got entry *must* exist, since we should have created it
+            before during check_relocs.  Also note that get_got_entry
+            assumed this was going to be another use, and so incremented
+            the use count again.  Thus the use count must be at least the
+            one real use and the "use" we just added.  */
+         if (gotent == NULL || gotent->use_count < 2)
+           {
+             abort ();
+             return FALSE;
+           }
+         gotent->use_count -= 2;
+         break;
+
+       default:
+         break;
+       }
+    }
+
+  return TRUE;
+}
+
 /* Adjust a symbol defined by a dynamic object and referenced by a
    regular object.  The current definition is in some section of the
    dynamic object, but we're not including those sections.  We have to
 /* Adjust a symbol defined by a dynamic object and referenced by a
    regular object.  The current definition is in some section of the
    dynamic object, but we're not including those sections.  We have to
@@ -1986,42 +2095,26 @@ elf64_alpha_adjust_dynamic_symbol (struct bfd_link_info *info,
   ah = (struct alpha_elf_link_hash_entry *)h;
 
   /* Now that we've seen all of the input symbols, finalize our decision
   ah = (struct alpha_elf_link_hash_entry *)h;
 
   /* Now that we've seen all of the input symbols, finalize our decision
-     about whether this symbol should get a .plt entry.  */
-
-  if (alpha_elf_dynamic_symbol_p (h, info)
-      && ((h->type == STT_FUNC
-          && !(ah->flags & ALPHA_ELF_LINK_HASH_LU_ADDR))
-         || (h->type == STT_NOTYPE
-             && (ah->flags & ALPHA_ELF_LINK_HASH_LU_FUNC)
-             && !(ah->flags & ~ALPHA_ELF_LINK_HASH_LU_FUNC)))
-      /* Don't prevent otherwise valid programs from linking by attempting
-        to create a new .got entry somewhere.  A Correct Solution would be
-        to add a new .got section to a new object file and let it be merged
-        somewhere later.  But for now don't bother.  */
-      && ah->got_entries)
+     about whether this symbol should get a .plt entry.  Irritatingly, it
+     is common for folk to leave undefined symbols in shared libraries,
+     and they still expect lazy binding; accept undefined symbols in lieu
+     of STT_FUNC.  */
+  if (alpha_elf_dynamic_symbol_p (h, info) && elf64_alpha_want_plt (ah))
     {
     {
-      h->needs_plt = 1;
+      h->needs_plt = TRUE;
 
 
-      s = bfd_get_section_by_name(dynobj, ".plt");
+      s = bfd_get_linker_section (dynobj, ".plt");
       if (!s && !elf64_alpha_create_dynamic_sections (dynobj, info))
        return FALSE;
 
       if (!s && !elf64_alpha_create_dynamic_sections (dynobj, info))
        return FALSE;
 
-      /* The first bit of the .plt is reserved.  */
-      if (s->size == 0)
-       s->size = PLT_HEADER_SIZE;
-
-      h->plt.offset = s->size;
-      s->size += PLT_ENTRY_SIZE;
-
-      /* We also need a JMP_SLOT entry in the .rela.plt section.  */
-      s = bfd_get_section_by_name (dynobj, ".rela.plt");
-      BFD_ASSERT (s != NULL);
-      s->size += sizeof (Elf64_External_Rela);
+      /* We need one plt entry per got subsection.  Delay allocation of
+        the actual plt entries until size_plt_section, called from
+        size_dynamic_sections or during relaxation.  */
 
       return TRUE;
     }
   else
 
       return TRUE;
     }
   else
-    h->needs_plt = 0;
+    h->needs_plt = FALSE;
 
   /* If this is a weak symbol, and there is a real definition, the
      processor independent code will have arranged for us to see the
 
   /* If this is a weak symbol, and there is a real definition, the
      processor independent code will have arranged for us to see the
@@ -2043,27 +2136,46 @@ elf64_alpha_adjust_dynamic_symbol (struct bfd_link_info *info,
   return TRUE;
 }
 
   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.  */
 
 /* 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.  */
 
-static bfd_boolean
-elf64_alpha_merge_ind_symbols (struct alpha_elf_link_hash_entry *hi,
-                              PTR dummy ATTRIBUTE_UNUSED)
+static void
+elf64_alpha_copy_indirect_symbol (struct bfd_link_info *info,
+                                 struct elf_link_hash_entry *dir,
+                                 struct elf_link_hash_entry *ind)
 {
 {
-  struct alpha_elf_link_hash_entry *hs;
+  struct alpha_elf_link_hash_entry *hi
+    = (struct alpha_elf_link_hash_entry *) ind;
+  struct alpha_elf_link_hash_entry *hs
+    = (struct alpha_elf_link_hash_entry *) dir;
 
 
-  if (hi->root.root.type != bfd_link_hash_indirect)
-    return TRUE;
-  hs = hi;
-  do {
-    hs = (struct alpha_elf_link_hash_entry *)hs->root.root.u.i.link;
-  } while (hs->root.root.type == bfd_link_hash_indirect);
+  /* Do the merging in the superclass.  */
+  _bfd_elf_link_hash_copy_indirect(info, dir, ind);
 
   /* Merge the flags.  Whee.  */
 
   /* Merge the flags.  Whee.  */
-
   hs->flags |= hi->flags;
 
   hs->flags |= hi->flags;
 
+  /* ??? It's unclear to me what's really supposed to happen when
+     "merging" defweak and defined symbols, given that we don't
+     actually throw away the defweak.  This more-or-less copies
+     the logic related to got and plt entries in the superclass.  */
+  if (ind->root.type != bfd_link_hash_indirect)
+    return;
+
   /* Merge the .got entries.  Cannibalize the old symbol's list in
      doing so, since we don't need it anymore.  */
 
   /* Merge the .got entries.  Cannibalize the old symbol's list in
      doing so, since we don't need it anymore.  */
 
@@ -2116,8 +2228,6 @@ elf64_alpha_merge_ind_symbols (struct alpha_elf_link_hash_entry *hi,
        }
     }
   hi->reloc_entries = NULL;
        }
     }
   hi->reloc_entries = NULL;
-
-  return TRUE;
 }
 
 /* Is it possible to merge two object file's .got tables?  */
 }
 
 /* Is it possible to merge two object file's .got tables?  */
@@ -2282,14 +2392,10 @@ elf64_alpha_merge_gots (bfd *a, bfd *b)
 
 static bfd_boolean
 elf64_alpha_calc_got_offsets_for_symbol (struct alpha_elf_link_hash_entry *h,
 
 static bfd_boolean
 elf64_alpha_calc_got_offsets_for_symbol (struct alpha_elf_link_hash_entry *h,
-                                        PTR arg ATTRIBUTE_UNUSED)
+                                        void * arg ATTRIBUTE_UNUSED)
 {
 {
-  bfd_boolean result = TRUE;
   struct alpha_elf_got_entry *gotent;
 
   struct alpha_elf_got_entry *gotent;
 
-  if (h->root.root.type == bfd_link_hash_warning)
-    h = (struct alpha_elf_link_hash_entry *) h->root.root.u.i.link;
-
   for (gotent = h->got_entries; gotent; gotent = gotent->next)
     if (gotent->use_count > 0)
       {
   for (gotent = h->got_entries; gotent; gotent = gotent->next)
     if (gotent->use_count > 0)
       {
@@ -2297,25 +2403,24 @@ elf64_alpha_calc_got_offsets_for_symbol (struct alpha_elf_link_hash_entry *h,
        bfd_size_type *plge;
 
        td = alpha_elf_tdata (gotent->gotobj);
        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->size;
        gotent->got_offset = *plge;
        *plge += alpha_got_entry_size (gotent->reloc_type);
       }
 
        plge = &td->got->size;
        gotent->got_offset = *plge;
        *plge += alpha_got_entry_size (gotent->reloc_type);
       }
 
-  return result;
+  return TRUE;
 }
 
 static void
 elf64_alpha_calc_got_offsets (struct bfd_link_info *info)
 {
 }
 
 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.  */
 
   /* First, zero out the .got sizes, as we may be recalculating the
      .got after optimizing it.  */
@@ -2323,7 +2428,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_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);
 
                                elf64_alpha_calc_got_offsets_for_symbol,
                                NULL);
 
@@ -2361,9 +2466,12 @@ static bfd_boolean
 elf64_alpha_size_got_sections (struct bfd_link_info *info)
 {
   bfd *i, *got_list, *cur_got_obj = NULL;
 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.  */
 
   /* On the first time through, pretend we have an existing got list
      consisting of all of the input files.  */
@@ -2371,7 +2479,12 @@ elf64_alpha_size_got_sections (struct bfd_link_info *info)
     {
       for (i = info->input_bfds; i ; i = i->link_next)
        {
     {
       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;
 
          if (this_got == NULL)
            continue;
 
@@ -2398,13 +2511,13 @@ elf64_alpha_size_got_sections (struct bfd_link_info *info)
       if (got_list == NULL)
        return TRUE;
 
       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;
     }
 
   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)
     {
   i = alpha_elf_tdata(cur_got_obj)->got_link_next;
   while (i != NULL)
     {
@@ -2415,8 +2528,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;
          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
        {
        }
       else
        {
@@ -2427,75 +2538,87 @@ elf64_alpha_size_got_sections (struct bfd_link_info *info)
 
   /* Once the gots have been merged, fill in the got offsets for
      everything therein.  */
 
   /* 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;
 }
 
 static bfd_boolean
 
   return TRUE;
 }
 
 static bfd_boolean
-elf64_alpha_size_plt_section_1 (struct alpha_elf_link_hash_entry *h, PTR data)
+elf64_alpha_size_plt_section_1 (struct alpha_elf_link_hash_entry *h,
+                               void * data)
 {
   asection *splt = (asection *) data;
   struct alpha_elf_got_entry *gotent;
 {
   asection *splt = (asection *) data;
   struct alpha_elf_got_entry *gotent;
+  bfd_boolean saw_one = FALSE;
 
   /* If we didn't need an entry before, we still don't.  */
   if (!h->root.needs_plt)
     return TRUE;
 
 
   /* If we didn't need an entry before, we still don't.  */
   if (!h->root.needs_plt)
     return TRUE;
 
-  /* There must still be a LITERAL got entry for the function.  */
+  /* For each LITERAL got entry still in use, allocate a plt entry.  */
   for (gotent = h->got_entries; gotent ; gotent = gotent->next)
     if (gotent->reloc_type == R_ALPHA_LITERAL
        && gotent->use_count > 0)
   for (gotent = h->got_entries; gotent ; gotent = gotent->next)
     if (gotent->reloc_type == R_ALPHA_LITERAL
        && gotent->use_count > 0)
-      break;
+      {
+       if (splt->size == 0)
+         splt->size = PLT_HEADER_SIZE;
+       gotent->plt_offset = splt->size;
+       splt->size += PLT_ENTRY_SIZE;
+       saw_one = TRUE;
+      }
 
 
-  /* If there is, reset the PLT offset.  If not, there's no longer
-     a need for the PLT entry.  */
-  if (gotent)
-    {
-      if (splt->size == 0)
-       splt->size = PLT_HEADER_SIZE;
-      h->root.plt.offset = splt->size;
-      splt->size += PLT_ENTRY_SIZE;
-    }
-  else
-    {
-      h->root.needs_plt = 0;
-      h->root.plt.offset = -1;
-    }
+  /* If there weren't any, there's no longer a need for the PLT entry.  */
+  if (!saw_one)
+    h->root.needs_plt = FALSE;
 
   return TRUE;
 }
 
 
   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)
 {
 elf64_alpha_size_plt_section (struct bfd_link_info *info)
 {
-  asection *splt, *spltrel;
+  asection *splt, *spltrel, *sgotplt;
   unsigned long entries;
   bfd *dynobj;
   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;
 
   dynobj = elf_hash_table(info)->dynobj;
-  splt = bfd_get_section_by_name(dynobj, ".plt");
+  splt = bfd_get_linker_section (dynobj, ".plt");
   if (splt == NULL)
   if (splt == NULL)
-    return TRUE;
+    return;
 
   splt->size = 0;
 
 
   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.  */
                                elf64_alpha_size_plt_section_1, splt);
 
   /* Every plt entry requires a JMP_SLOT relocation.  */
-  spltrel = bfd_get_section_by_name (dynobj, ".rela.plt");
+  spltrel = bfd_get_linker_section (dynobj, ".rela.plt");
+  entries = 0;
   if (splt->size)
   if (splt->size)
-    entries = (splt->size - PLT_HEADER_SIZE) / PLT_ENTRY_SIZE;
-  else
-    entries = 0;
+    {
+      if (elf64_alpha_use_secureplt)
+       entries = (splt->size - NEW_PLT_HEADER_SIZE) / NEW_PLT_ENTRY_SIZE;
+      else
+       entries = (splt->size - OLD_PLT_HEADER_SIZE) / OLD_PLT_ENTRY_SIZE;
+    }
   spltrel->size = entries * sizeof (Elf64_External_Rela);
 
   spltrel->size = entries * sizeof (Elf64_External_Rela);
 
-  return TRUE;
+  /* When using the secureplt, we need two words somewhere in the data
+     segment for the dynamic linker to tell us where to go.  This is the
+     entire contents of the .got.plt section.  */
+  if (elf64_alpha_use_secureplt)
+    {
+      sgotplt = bfd_get_linker_section (dynobj, ".got.plt");
+      sgotplt->size = entries ? 16 : 0;
+    }
 }
 
 static bfd_boolean
 }
 
 static bfd_boolean
@@ -2503,20 +2626,20 @@ elf64_alpha_always_size_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
                                  struct bfd_link_info *info)
 {
   bfd *i;
                                  struct bfd_link_info *info)
 {
   bfd *i;
+  struct alpha_elf_link_hash_table * htab;
 
   if (info->relocatable)
     return TRUE;
 
 
   if (info->relocatable)
     return TRUE;
 
-  /* 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,
-                               NULL);
+  htab = alpha_elf_hash_table (info);
+  if (htab == NULL)
+    return FALSE;
 
   if (!elf64_alpha_size_got_sections (info))
     return FALSE;
 
   /* Allocate space for all of the .got subsections.  */
 
   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;
   for ( ; i ; i = alpha_elf_tdata(i)->got_link_next)
     {
       asection *s = alpha_elf_tdata(i)->got;
@@ -2534,7 +2657,7 @@ elf64_alpha_always_size_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
 /* The number of dynamic relocations required by a static relocation.  */
 
 static int
 /* The number of dynamic relocations required by a static relocation.  */
 
 static int
-alpha_dynamic_entries_for_reloc (int r_type, int dynamic, int shared)
+alpha_dynamic_entries_for_reloc (int r_type, int dynamic, int shared, int pie)
 {
   switch (r_type)
     {
 {
   switch (r_type)
     {
@@ -2544,16 +2667,18 @@ alpha_dynamic_entries_for_reloc (int r_type, int dynamic, int shared)
     case R_ALPHA_TLSLDM:
       return shared;
     case R_ALPHA_LITERAL:
     case R_ALPHA_TLSLDM:
       return shared;
     case R_ALPHA_LITERAL:
-    case R_ALPHA_GOTTPREL:
       return dynamic || shared;
       return dynamic || shared;
+    case R_ALPHA_GOTTPREL:
+      return dynamic || (shared && !pie);
     case R_ALPHA_GOTDTPREL:
       return dynamic;
 
     /* May appear in data sections.  */
     case R_ALPHA_REFLONG:
     case R_ALPHA_REFQUAD:
     case R_ALPHA_GOTDTPREL:
       return dynamic;
 
     /* May appear in data sections.  */
     case R_ALPHA_REFLONG:
     case R_ALPHA_REFQUAD:
-    case R_ALPHA_TPREL64:
       return dynamic || shared;
       return dynamic || shared;
+    case R_ALPHA_TPREL64:
+      return dynamic || (shared && !pie);
 
     /* Everything else is illegal.  We'll issue an error during
        relocate_section.  */
 
     /* Everything else is illegal.  We'll issue an error during
        relocate_section.  */
@@ -2572,9 +2697,6 @@ elf64_alpha_calc_dynrel_sizes (struct alpha_elf_link_hash_entry *h,
   struct alpha_elf_reloc_entry *relent;
   unsigned long entries;
 
   struct alpha_elf_reloc_entry *relent;
   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 was defined as a common symbol in a regular object
      file, and there was no definition in any dynamic object, then the
      linker will have allocated space for the symbol in a common
   /* If the symbol was defined as a common symbol in a regular object
      file, and there was no definition in any dynamic object, then the
      linker will have allocated space for the symbol in a common
@@ -2604,7 +2726,7 @@ elf64_alpha_calc_dynrel_sizes (struct alpha_elf_link_hash_entry *h,
   for (relent = h->reloc_entries; relent; relent = relent->next)
     {
       entries = alpha_dynamic_entries_for_reloc (relent->rtype, dynamic,
   for (relent = h->reloc_entries; relent; relent = relent->next)
     {
       entries = alpha_dynamic_entries_for_reloc (relent->rtype, dynamic,
-                                                info->shared);
+                                                info->shared, info->pie);
       if (entries)
        {
          relent->srel->size +=
       if (entries)
        {
          relent->srel->size +=
@@ -2628,8 +2750,10 @@ elf64_alpha_size_rela_got_1 (struct alpha_elf_link_hash_entry *h,
   struct alpha_elf_got_entry *gotent;
   unsigned long entries;
 
   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 we're using a plt for this symbol, then all of its relocations
+     for its got entries go into .rela.plt.  */
+  if (h->root.needs_plt)
+    return TRUE;
 
   /* 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
 
   /* 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
@@ -2645,18 +2769,13 @@ elf64_alpha_size_rela_got_1 (struct alpha_elf_link_hash_entry *h,
   entries = 0;
   for (gotent = h->got_entries; gotent ; gotent = gotent->next)
     if (gotent->use_count > 0)
   entries = 0;
   for (gotent = h->got_entries; gotent ; gotent = gotent->next)
     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.  */
-  if (h->root.plt.offset != MINUS_ONE)
-    entries--;
+      entries += alpha_dynamic_entries_for_reloc (gotent->reloc_type, dynamic,
+                                                 info->shared, info->pie);
 
   if (entries > 0)
     {
       bfd *dynobj = elf_hash_table(info)->dynobj;
 
   if (entries > 0)
     {
       bfd *dynobj = elf_hash_table(info)->dynobj;
-      asection *srel = bfd_get_section_by_name (dynobj, ".rela.got");
+      asection *srel = bfd_get_linker_section (dynobj, ".rela.got");
       BFD_ASSERT (srel != NULL);
       srel->size += sizeof (Elf64_External_Rela) * entries;
     }
       BFD_ASSERT (srel != NULL);
       srel->size += sizeof (Elf64_External_Rela) * entries;
     }
@@ -2666,18 +2785,23 @@ elf64_alpha_size_rela_got_1 (struct alpha_elf_link_hash_entry *h,
 
 /* Set the sizes of the dynamic relocation sections.  */
 
 
 /* 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;
 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;
 
   /* 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;
        i ; i = alpha_elf_tdata(i)->got_link_next)
     {
       bfd *j;
@@ -2696,24 +2820,22 @@ elf64_alpha_size_rela_got_section (struct bfd_link_info *info)
                 gotent ; gotent = gotent->next)
              if (gotent->use_count > 0)
                entries += (alpha_dynamic_entries_for_reloc
                 gotent ; gotent = gotent->next)
              if (gotent->use_count > 0)
                entries += (alpha_dynamic_entries_for_reloc
-                           (gotent->reloc_type, 0, info->shared));
+                           (gotent->reloc_type, 0, info->shared, info->pie));
        }
     }
 
   dynobj = elf_hash_table(info)->dynobj;
        }
     }
 
   dynobj = elf_hash_table(info)->dynobj;
-  srel = bfd_get_section_by_name (dynobj, ".rela.got");
+  srel = bfd_get_linker_section (dynobj, ".rela.got");
   if (!srel)
     {
       BFD_ASSERT (entries == 0);
   if (!srel)
     {
       BFD_ASSERT (entries == 0);
-      return TRUE;
+      return;
     }
   srel->size = sizeof (Elf64_External_Rela) * entries;
 
   /* Now do the non-local symbols.  */
     }
   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);
                                elf64_alpha_size_rela_got_1, info);
-
-  return TRUE;
 }
 
 /* Set the sizes of the dynamic sections.  */
 }
 
 /* Set the sizes of the dynamic sections.  */
@@ -2725,6 +2847,11 @@ elf64_alpha_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
   bfd *dynobj;
   asection *s;
   bfd_boolean relplt;
   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);
 
   dynobj = elf_hash_table(info)->dynobj;
   BFD_ASSERT(dynobj != NULL);
@@ -2734,7 +2861,7 @@ elf64_alpha_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
       /* Set the contents of the .interp section to the interpreter.  */
       if (info->executable)
        {
       /* Set the contents of the .interp section to the interpreter.  */
       if (info->executable)
        {
-         s = bfd_get_section_by_name (dynobj, ".interp");
+         s = bfd_get_linker_section (dynobj, ".interp");
          BFD_ASSERT (s != NULL);
          s->size = sizeof ELF_DYNAMIC_INTERPRETER;
          s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER;
          BFD_ASSERT (s != NULL);
          s->size = sizeof ELF_DYNAMIC_INTERPRETER;
          s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER;
@@ -2744,10 +2871,11 @@ 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.  */
         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);
                                    elf64_alpha_calc_dynrel_sizes, info);
 
       elf64_alpha_size_rela_got_section (info);
+      elf64_alpha_size_plt_section (info);
     }
   /* else we're not dynamic and by definition we don't need such things.  */
 
     }
   /* else we're not dynamic and by definition we don't need such things.  */
 
@@ -2758,7 +2886,6 @@ elf64_alpha_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
   for (s = dynobj->sections; s != NULL; s = s->next)
     {
       const char *name;
   for (s = dynobj->sections; s != NULL; s = s->next)
     {
       const char *name;
-      bfd_boolean strip;
 
       if (!(s->flags & SEC_LINKER_CREATED))
        continue;
 
       if (!(s->flags & SEC_LINKER_CREATED))
        continue;
@@ -2767,23 +2894,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);
 
         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
                relplt = TRUE;
 
              /* We use the reloc_count field as a counter if we need
@@ -2791,19 +2906,31 @@ elf64_alpha_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
              s->reloc_count = 0;
            }
        }
              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;
        }
 
        {
          /* 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.  */
+         if (!CONST_STRNEQ (name, ".got"))
+           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);
        {
          /* 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;
        }
     }
            return FALSE;
        }
     }
@@ -2831,6 +2958,10 @@ elf64_alpha_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
              || !add_dynamic_entry (DT_PLTREL, DT_RELA)
              || !add_dynamic_entry (DT_JMPREL, 0))
            return FALSE;
              || !add_dynamic_entry (DT_PLTREL, DT_RELA)
              || !add_dynamic_entry (DT_JMPREL, 0))
            return FALSE;
+
+         if (elf64_alpha_use_secureplt
+             && !add_dynamic_entry (DT_ALPHA_PLTRO, 1))
+           return FALSE;
        }
 
       if (!add_dynamic_entry (DT_RELA, 0)
        }
 
       if (!add_dynamic_entry (DT_RELA, 0)
@@ -2862,17 +2993,6 @@ elf64_alpha_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
    related to Alpha in particular.  They are by David Wall, then of
    DEC WRL.  */
 
    related to Alpha in particular.  They are by David Wall, then of
    DEC WRL.  */
 
-#define OP_LDA         0x08
-#define OP_LDAH                0x09
-#define INSN_JSR       0x68004000
-#define INSN_JSR_MASK  0xfc00c000
-#define OP_LDQ         0x29
-#define OP_BR          0x30
-#define OP_BSR         0x34
-#define INSN_UNOP      0x2ffe0000
-#define INSN_ADDQ      0x40000400
-#define INSN_RDUNIQ    0x0000009e
-
 struct alpha_relax_info
 {
   bfd *abfd;
 struct alpha_relax_info
 {
   bfd *abfd;
@@ -2932,7 +3052,8 @@ elf64_alpha_relax_got_load (struct alpha_relax_info *info, bfd_vma symval,
     return TRUE;
 
   /* Can't use local-exec relocations in shared libraries.  */
     return TRUE;
 
   /* Can't use local-exec relocations in shared libraries.  */
-  if (r_type == R_ALPHA_GOTTPREL && info->link_info->shared)
+  if (r_type == R_ALPHA_GOTTPREL
+      && (info->link_info->shared && !info->link_info->pie))
     return TRUE;
 
   if (r_type == R_ALPHA_LITERAL)
     return TRUE;
 
   if (r_type == R_ALPHA_LITERAL)
@@ -3050,7 +3171,7 @@ elf64_alpha_relax_opt_call (struct alpha_relax_info *info, bfd_vma symval)
       else
        {
          tsec_relocs = (_bfd_elf_link_read_relocs
       else
        {
          tsec_relocs = (_bfd_elf_link_read_relocs
-                        (info->abfd, info->tsec, (PTR) NULL,
+                        (info->abfd, info->tsec, NULL,
                         (Elf_Internal_Rela *) NULL,
                         info->link_info->keep_memory));
          if (tsec_relocs == NULL)
                         (Elf_Internal_Rela *) NULL,
                         info->link_info->keep_memory));
          if (tsec_relocs == NULL)
@@ -3079,7 +3200,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.   */
 
   /* 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;
 
       || info->gotobj != alpha_elf_tdata (info->tsec->owner)->gotobj)
     return 0;
 
@@ -3118,7 +3239,7 @@ elf64_alpha_relax_with_lituse (struct alpha_relax_info *info,
     {
       if (ELF64_R_TYPE (urel->r_info) != R_ALPHA_LITUSE)
        break;
     {
       if (ELF64_R_TYPE (urel->r_info) != R_ALPHA_LITUSE)
        break;
-      if (urel->r_addend <= 3)
+      if (urel->r_addend <= 6)
        flags |= 1 << urel->r_addend;
     }
 
        flags |= 1 << urel->r_addend;
     }
 
@@ -3213,6 +3334,7 @@ elf64_alpha_relax_with_lituse (struct alpha_relax_info *info,
        case LITUSE_ALPHA_JSR:
        case LITUSE_ALPHA_TLSGD:
        case LITUSE_ALPHA_TLSLDM:
        case LITUSE_ALPHA_JSR:
        case LITUSE_ALPHA_TLSGD:
        case LITUSE_ALPHA_TLSLDM:
+       case LITUSE_ALPHA_JSRDIRECT:
          {
            bfd_vma optdest, org;
            bfd_signed_vma odisp;
          {
            bfd_vma optdest, org;
            bfd_signed_vma odisp;
@@ -3345,9 +3467,9 @@ elf64_alpha_relax_tls_get_addr (struct alpha_relax_info *info, bfd_vma symval,
                                Elf_Internal_Rela *irel, bfd_boolean is_gd)
 {
   bfd_byte *pos[5];
                                Elf_Internal_Rela *irel, bfd_boolean is_gd)
 {
   bfd_byte *pos[5];
-  unsigned int insn;
+  unsigned int insn, tlsgd_reg;
   Elf_Internal_Rela *gpdisp, *hint;
   Elf_Internal_Rela *gpdisp, *hint;
-  bfd_boolean dynamic, use_gottprel, pos1_unusable;
+  bfd_boolean dynamic, use_gottprel;
   unsigned long new_symndx;
 
   dynamic = alpha_elf_dynamic_symbol_p (&info->h->root, info->link_info);
   unsigned long new_symndx;
 
   dynamic = alpha_elf_dynamic_symbol_p (&info->h->root, info->link_info);
@@ -3388,7 +3510,13 @@ elf64_alpha_relax_tls_get_addr (struct alpha_relax_info *info, bfd_vma symval,
   pos[2] = info->contents + irel[2].r_offset;
   pos[3] = info->contents + gpdisp->r_offset;
   pos[4] = pos[3] + gpdisp->r_addend;
   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;
+
+  /* Beware of the compiler hoisting part of the sequence out a loop
+     and adjusting the destination register for the TLSGD insn.  If this
+     happens, there will be a move into $16 before the JSR insn, so only
+     transformations of the first insn pair should use this register.  */
+  tlsgd_reg = bfd_get_32 (info->abfd, pos[0]);
+  tlsgd_reg = (tlsgd_reg >> 21) & 31;
 
   /* Generally, the positions are not allowed to be out of order, lest the
      modified insn sequence have different register lifetimes.  We can make
 
   /* Generally, the positions are not allowed to be out of order, lest the
      modified insn sequence have different register lifetimes.  We can make
@@ -3399,8 +3527,6 @@ elf64_alpha_relax_tls_get_addr (struct alpha_relax_info *info, bfd_vma symval,
       pos[0] = pos[1];
       pos[1] = tmp;
     }
       pos[0] = pos[1];
       pos[1] = tmp;
     }
-  else if (pos[1] < pos[0])
-    pos1_unusable = TRUE;
   if (pos[1] >= pos[2] || pos[2] >= pos[3])
     return TRUE;
 
   if (pos[1] >= pos[2] || pos[2] >= pos[3])
     return TRUE;
 
@@ -3457,7 +3583,8 @@ elf64_alpha_relax_tls_get_addr (struct alpha_relax_info *info, bfd_vma symval,
      as appropriate.  */
 
   use_gottprel = FALSE;
      as appropriate.  */
 
   use_gottprel = FALSE;
-  new_symndx = is_gd ? ELF64_R_SYM (irel->r_info) : 0;
+  new_symndx = is_gd ? ELF64_R_SYM (irel->r_info) : STN_UNDEF;
+
   switch (!dynamic && !info->link_info->shared)
     {
     case 1:
   switch (!dynamic && !info->link_info->shared)
     {
     case 1:
@@ -3471,7 +3598,7 @@ elf64_alpha_relax_tls_get_addr (struct alpha_relax_info *info, bfd_vma symval,
 
        if (disp >= -0x8000 && disp < 0x8000)
          {
 
        if (disp >= -0x8000 && disp < 0x8000)
          {
-           insn = (OP_LDA << 26) | (16 << 21) | (31 << 16);
+           insn = (OP_LDA << 26) | (tlsgd_reg << 21) | (31 << 16);
            bfd_put_32 (info->abfd, (bfd_vma) insn, pos[0]);
            bfd_put_32 (info->abfd, (bfd_vma) INSN_UNOP, pos[1]);
 
            bfd_put_32 (info->abfd, (bfd_vma) insn, pos[0]);
            bfd_put_32 (info->abfd, (bfd_vma) INSN_UNOP, pos[1]);
 
@@ -3482,11 +3609,11 @@ elf64_alpha_relax_tls_get_addr (struct alpha_relax_info *info, bfd_vma symval,
          }
        else if (disp >= -(bfd_signed_vma) 0x80000000
                 && disp < (bfd_signed_vma) 0x7fff8000
          }
        else if (disp >= -(bfd_signed_vma) 0x80000000
                 && disp < (bfd_signed_vma) 0x7fff8000
-                && !pos1_unusable)
+                && pos[0] + 4 == pos[1])
          {
          {
-           insn = (OP_LDAH << 26) | (16 << 21) | (31 << 16);
+           insn = (OP_LDAH << 26) | (tlsgd_reg << 21) | (31 << 16);
            bfd_put_32 (info->abfd, (bfd_vma) insn, pos[0]);
            bfd_put_32 (info->abfd, (bfd_vma) insn, pos[0]);
-           insn = (OP_LDA << 26) | (16 << 21) | (16 << 16);
+           insn = (OP_LDA << 26) | (tlsgd_reg << 21) | (tlsgd_reg << 16);
            bfd_put_32 (info->abfd, (bfd_vma) insn, pos[1]);
 
            irel[0].r_offset = pos[0] - info->contents;
            bfd_put_32 (info->abfd, (bfd_vma) insn, pos[1]);
 
            irel[0].r_offset = pos[0] - info->contents;
@@ -3501,7 +3628,7 @@ elf64_alpha_relax_tls_get_addr (struct alpha_relax_info *info, bfd_vma symval,
     default:
       use_gottprel = TRUE;
 
     default:
       use_gottprel = TRUE;
 
-      insn = (OP_LDQ << 26) | (16 << 21) | (29 << 16);
+      insn = (OP_LDQ << 26) | (tlsgd_reg << 21) | (29 << 16);
       bfd_put_32 (info->abfd, (bfd_vma) insn, pos[0]);
       bfd_put_32 (info->abfd, (bfd_vma) INSN_UNOP, pos[1]);
 
       bfd_put_32 (info->abfd, (bfd_vma) insn, pos[0]);
       bfd_put_32 (info->abfd, (bfd_vma) INSN_UNOP, pos[1]);
 
@@ -3591,8 +3718,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;
   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;
+
+  htab = alpha_elf_hash_table (link_info);
+  if (htab == NULL)
+    return FALSE;
 
 
-  /* We are not currently changing any sizes, so only one pass.  */
+  /* There's nothing to change, yet.  */
   *again = FALSE;
 
   if (link_info->relocatable
   *again = FALSE;
 
   if (link_info->relocatable
@@ -3601,12 +3733,30 @@ elf64_alpha_relax_section (bfd *abfd, asection *sec,
       || sec->reloc_count == 0)
     return TRUE;
 
       || 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.  */
   internal_relocs = (_bfd_elf_link_read_relocs
   local_got_entries = alpha_elf_tdata(abfd)->local_got_entries;
 
   /* Load the relocations for this section.  */
   internal_relocs = (_bfd_elf_link_read_relocs
-                    (abfd, sec, (PTR) NULL, (Elf_Internal_Rela *) NULL,
+                    (abfd, sec, NULL, (Elf_Internal_Rela *) NULL,
                      link_info->keep_memory));
   if (internal_relocs == NULL)
     return FALSE;
                      link_info->keep_memory));
   if (internal_relocs == NULL)
     return FALSE;
@@ -3659,8 +3809,8 @@ elf64_alpha_relax_section (bfd *abfd, asection *sec,
 
        case R_ALPHA_TLSLDM:
          /* The symbol for a TLSLDM reloc is ignored.  Collapse the
 
        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;
+             reloc to the STN_UNDEF (0) symbol so that they all match.  */
+         r_symndx = STN_UNDEF;
          break;
 
        default:
          break;
 
        default:
@@ -3810,13 +3960,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)
     {
   if (isymbuf != NULL
       && symtab_hdr->contents != (unsigned char *) isymbuf)
     {
@@ -3912,9 +4055,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;
   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;
 
   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++)
 
   relend = relocs + input_section->reloc_count;
   for (rel = relocs; rel < relend; rel++)
@@ -3924,7 +4069,7 @@ elf64_alpha_relocate_section_r (bfd *output_bfd ATTRIBUTE_UNUSED,
       asection *sec;
       unsigned long r_type;
 
       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)
       if (r_type >= R_ALPHA_max)
        {
          (*_bfd_error_handler)
@@ -3935,22 +4080,43 @@ elf64_alpha_relocate_section_r (bfd *output_bfd ATTRIBUTE_UNUSED,
          continue;
        }
 
          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;
 
       /* 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 (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 && discarded_section (sec))
+       RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
+                                        rel, 1, relend,
+                                        elf64_alpha_howto_table + r_type, 0,
+                                        contents);
+
+      if (sym != NULL && ELF_ST_TYPE (sym->st_info) == STT_SECTION)
+       rel->r_addend += sec->output_offset;
     }
 
   return ret_val;
     }
 
   return ret_val;
@@ -3974,6 +4140,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;
 
   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,
   /* Handle relocatable links with a smaller loop.  */
   if (info->relocatable)
     return elf64_alpha_relocate_section_r (output_bfd, info, input_bfd,
@@ -3984,11 +4152,11 @@ elf64_alpha_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
 
   ret_val = TRUE;
 
 
   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)
 
   dynobj = elf_hash_table (info)->dynobj;
   if (dynobj)
-    srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
+    srelgot = bfd_get_linker_section (dynobj, ".rela.got");
   else
     srelgot = NULL;
 
   else
     srelgot = NULL;
 
@@ -3997,9 +4165,9 @@ elf64_alpha_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
       const char *section_name;
       section_name = (bfd_elf_string_from_elf_section
                      (input_bfd, elf_elfheader(input_bfd)->e_shstrndx,
       const char *section_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_elf_single_rel_hdr (input_section)->sh_name));
       BFD_ASSERT(section_name != NULL);
       BFD_ASSERT(section_name != NULL);
-      srel = bfd_get_section_by_name (dynobj, section_name);
+      srel = bfd_get_linker_section (dynobj, section_name);
     }
   else
     srel = NULL;
     }
   else
     srel = NULL;
@@ -4047,6 +4215,7 @@ elf64_alpha_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
       bfd_vma value;
       bfd_vma addend;
       bfd_boolean dynamic_symbol_p;
       bfd_vma value;
       bfd_vma addend;
       bfd_boolean dynamic_symbol_p;
+      bfd_boolean unresolved_reloc = FALSE;
       bfd_boolean undef_weak_ref = FALSE;
       unsigned long r_type;
 
       bfd_boolean undef_weak_ref = FALSE;
       unsigned long r_type;
 
@@ -4065,9 +4234,9 @@ elf64_alpha_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
       r_symndx = ELF64_R_SYM(rel->r_info);
 
       /* The symbol for a TLSLDM reloc is ignored.  Collapse the
       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.  */
+        reloc to the STN_UNDEF (0) symbol so that they all match.  */
       if (r_type == R_ALPHA_TLSLDM)
       if (r_type == R_ALPHA_TLSLDM)
-       r_symndx = 0;
+       r_symndx = STN_UNDEF;
 
       if (r_symndx < symtab_hdr->sh_info)
        {
 
       if (r_symndx < symtab_hdr->sh_info)
        {
@@ -4077,17 +4246,17 @@ elf64_alpha_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
          msec = sec;
          value = _bfd_elf_rela_local_sym (output_bfd, sym, &msec, rel);
 
          msec = sec;
          value = _bfd_elf_rela_local_sym (output_bfd, sym, &msec, rel);
 
-         /* If this is a tp-relative relocation against sym 0,
+         /* If this is a tp-relative relocation against sym STN_UNDEF (0),
             this is hackery from relax_section.  Force the value to
             this is hackery from relax_section.  Force the value to
-            be the tls base.  */
-         if (r_symndx == 0
+            be the tls module base.  */
+         if (r_symndx == STN_UNDEF
              && (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))
              && (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;
+           value = dtp_base;
 
          if (local_got_entries)
            gotent = local_got_entries[r_symndx];
 
          if (local_got_entries)
            gotent = local_got_entries[r_symndx];
@@ -4098,7 +4267,7 @@ elf64_alpha_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
             unless it has been done already.  */
          if ((sec->flags & SEC_MERGE)
              && ELF_ST_TYPE (sym->st_info) == STT_SECTION
             unless it has been done already.  */
          if ((sec->flags & SEC_MERGE)
              && ELF_ST_TYPE (sym->st_info) == STT_SECTION
-             && sec->sec_info_type == ELF_INFO_TYPE_MERGE
+             && sec->sec_info_type == SEC_INFO_TYPE_MERGE
              && gotent
              && !gotent->reloc_xlated)
            {
              && gotent
              && !gotent->reloc_xlated)
            {
@@ -4128,7 +4297,6 @@ elf64_alpha_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
       else
        {
          bfd_boolean warned;
       else
        {
          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);
 
          struct elf_link_hash_entry *hh;
          struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (input_bfd);
 
@@ -4150,6 +4318,10 @@ elf64_alpha_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
          gotent = h->got_entries;
        }
 
          gotent = h->got_entries;
        }
 
+      if (sec != NULL && discarded_section (sec))
+       RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
+                                        rel, 1, relend, howto, 0, contents);
+
       addend = rel->r_addend;
       value += addend;
 
       addend = rel->r_addend;
       value += addend;
 
@@ -4209,18 +4381,6 @@ elf64_alpha_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
          goto default_reloc;
 
        case R_ALPHA_GPREL32:
          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)
        case R_ALPHA_GPREL16:
        case R_ALPHA_GPRELLOW:
          if (dynamic_symbol_p)
@@ -4358,7 +4518,7 @@ elf64_alpha_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
            else if (r_type == R_ALPHA_TPREL64)
              {
                BFD_ASSERT (elf_hash_table (info)->tls_sec != NULL);
            else if (r_type == R_ALPHA_TPREL64)
              {
                BFD_ASSERT (elf_hash_table (info)->tls_sec != NULL);
-               if (!info->shared)
+               if (!info->shared || info->pie)
                  {
                    value -= tp_base;
                    goto default_reloc;
                  {
                    value -= tp_base;
                    goto default_reloc;
@@ -4367,9 +4527,14 @@ elf64_alpha_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
                dynaddend = value - dtp_base;
              }
            else if (info->shared
                dynaddend = value - dtp_base;
              }
            else if (info->shared
-                    && r_symndx != 0
+                    && r_symndx != STN_UNDEF
                     && (input_section->flags & SEC_ALLOC)
                     && (input_section->flags & SEC_ALLOC)
-                    && !undef_weak_ref)
+                    && !undef_weak_ref
+                    && !(unresolved_reloc
+                         && (_bfd_elf_section_offset (output_bfd, info,
+                                                      input_section,
+                                                      rel->r_offset)
+                             == (bfd_vma) -1)))
              {
                if (r_type == R_ALPHA_REFLONG)
                  {
              {
                if (r_type == R_ALPHA_REFLONG)
                  {
@@ -4415,7 +4580,11 @@ elf64_alpha_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
          /* ??? .eh_frame references to discarded sections will be smashed
             to relocations against SHN_UNDEF.  The .eh_frame format allows
             NULL to be encoded as 0 in any format, so this works here.  */
          /* ??? .eh_frame references to discarded sections will be smashed
             to relocations against SHN_UNDEF.  The .eh_frame format allows
             NULL to be encoded as 0 in any format, so this works here.  */
-         if (r_symndx == 0)
+         if (r_symndx == STN_UNDEF
+             || (unresolved_reloc
+                 && _bfd_elf_section_offset (output_bfd, info,
+                                             input_section,
+                                             rel->r_offset) == (bfd_vma) -1))
            howto = (elf64_alpha_howto_table
                     + (r_type - R_ALPHA_SREL32 + R_ALPHA_REFLONG));
          goto default_reloc;
            howto = (elf64_alpha_howto_table
                     + (r_type - R_ALPHA_SREL32 + R_ALPHA_REFLONG));
          goto default_reloc;
@@ -4479,7 +4648,7 @@ elf64_alpha_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
        case R_ALPHA_TPRELHI:
        case R_ALPHA_TPRELLO:
        case R_ALPHA_TPREL16:
        case R_ALPHA_TPRELHI:
        case R_ALPHA_TPRELLO:
        case R_ALPHA_TPREL16:
-         if (info->shared)
+         if (info->shared && !info->pie)
            {
              (*_bfd_error_handler)
                (_("%B: TLS local exec code cannot be linked into shared objects"),
            {
              (*_bfd_error_handler)
                (_("%B: TLS local exec code cannot be linked into shared objects"),
@@ -4560,7 +4729,7 @@ elf64_alpha_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
 
            if (r_symndx < symtab_hdr->sh_info
                && sec != NULL && howto->pc_relative
 
            if (r_symndx < symtab_hdr->sh_info
                && sec != NULL && howto->pc_relative
-               && elf_discarded_section (sec))
+               && discarded_section (sec))
              break;
 
            if (h != NULL)
              break;
 
            if (h != NULL)
@@ -4599,9 +4768,10 @@ elf64_alpha_finish_dynamic_symbol (bfd *output_bfd, struct bfd_link_info *info,
                                   struct elf_link_hash_entry *h,
                                   Elf_Internal_Sym *sym)
 {
                                   struct elf_link_hash_entry *h,
                                   Elf_Internal_Sym *sym)
 {
+  struct alpha_elf_link_hash_entry *ah = (struct alpha_elf_link_hash_entry *)h;
   bfd *dynobj = elf_hash_table(info)->dynobj;
 
   bfd *dynobj = elf_hash_table(info)->dynobj;
 
-  if (h->plt.offset != MINUS_ONE)
+  if (h->needs_plt)
     {
       /* Fill in the .plt entry for this symbol.  */
       asection *splt, *sgot, *srel;
     {
       /* Fill in the .plt entry for this symbol.  */
       asection *splt, *sgot, *srel;
@@ -4613,83 +4783,71 @@ elf64_alpha_finish_dynamic_symbol (bfd *output_bfd, struct bfd_link_info *info,
 
       BFD_ASSERT (h->dynindx != -1);
 
 
       BFD_ASSERT (h->dynindx != -1);
 
-      /* The first .got entry will be updated by the .plt with the
-        address of the target function.  */
-      gotent = ((struct alpha_elf_link_hash_entry *) h)->got_entries;
-      BFD_ASSERT (gotent && gotent->addend == 0);
-
-      splt = bfd_get_section_by_name (dynobj, ".plt");
+      splt = bfd_get_linker_section (dynobj, ".plt");
       BFD_ASSERT (splt != NULL);
       BFD_ASSERT (splt != NULL);
-      srel = bfd_get_section_by_name (dynobj, ".rela.plt");
+      srel = bfd_get_linker_section (dynobj, ".rela.plt");
       BFD_ASSERT (srel != NULL);
       BFD_ASSERT (srel != NULL);
-      sgot = alpha_elf_tdata (gotent->gotobj)->got;
-      BFD_ASSERT (sgot != NULL);
 
 
-      got_addr = (sgot->output_section->vma
-                 + sgot->output_offset
-                 + gotent->got_offset);
-      plt_addr = (splt->output_section->vma
-                 + splt->output_offset
-                 + h->plt.offset);
-
-      plt_index = (h->plt.offset - PLT_HEADER_SIZE) / PLT_ENTRY_SIZE;
-
-      /* Fill in the entry in the procedure linkage table.  */
-      {
-       bfd_vma insn1, insn2, insn3;
-
-       insn1 = PLT_ENTRY_WORD1 | ((-(h->plt.offset + 4) >> 2) & 0x1fffff);
-       insn2 = PLT_ENTRY_WORD2;
-       insn3 = PLT_ENTRY_WORD3;
-
-       bfd_put_32 (output_bfd, insn1, splt->contents + h->plt.offset);
-       bfd_put_32 (output_bfd, insn2, splt->contents + h->plt.offset + 4);
-       bfd_put_32 (output_bfd, insn3, splt->contents + h->plt.offset + 8);
-      }
+      for (gotent = ah->got_entries; gotent ; gotent = gotent->next)
+       if (gotent->reloc_type == R_ALPHA_LITERAL
+           && gotent->use_count > 0)
+         {
+           unsigned int insn;
+           int disp;
 
 
-      /* Fill in the entry in the .rela.plt section.  */
-      outrel.r_offset = got_addr;
-      outrel.r_info = ELF64_R_INFO(h->dynindx, R_ALPHA_JMP_SLOT);
-      outrel.r_addend = 0;
+           sgot = alpha_elf_tdata (gotent->gotobj)->got;
+           BFD_ASSERT (sgot != NULL);
 
 
-      loc = srel->contents + plt_index * sizeof (Elf64_External_Rela);
-      bfd_elf64_swap_reloca_out (output_bfd, &outrel, loc);
+           BFD_ASSERT (gotent->got_offset != -1);
+           BFD_ASSERT (gotent->plt_offset != -1);
 
 
-      if (!h->def_regular)
-       {
-         /* Mark the symbol as undefined, rather than as defined in the
-            .plt section.  Leave the value alone.  */
-         sym->st_shndx = SHN_UNDEF;
-       }
+           got_addr = (sgot->output_section->vma
+                       + sgot->output_offset
+                       + gotent->got_offset);
+           plt_addr = (splt->output_section->vma
+                       + splt->output_offset
+                       + gotent->plt_offset);
 
 
-      /* Fill in the entries in the .got.  */
-      bfd_put_64 (output_bfd, plt_addr, sgot->contents + gotent->got_offset);
+           plt_index = (gotent->plt_offset-PLT_HEADER_SIZE) / PLT_ENTRY_SIZE;
 
 
-      /* Subsequent .got entries will continue to bounce through the .plt.  */
-      if (gotent->next)
-       {
-         srel = bfd_get_section_by_name (dynobj, ".rela.got");
-         BFD_ASSERT (! info->shared || srel != NULL);
+           /* Fill in the entry in the procedure linkage table.  */
+           if (elf64_alpha_use_secureplt)
+             {
+               disp = (PLT_HEADER_SIZE - 4) - (gotent->plt_offset + 4);
+               insn = INSN_AD (INSN_BR, 31, disp);
+               bfd_put_32 (output_bfd, insn,
+                           splt->contents + gotent->plt_offset);
 
 
-         gotent = gotent->next;
-         do
-           {
-             sgot = alpha_elf_tdata(gotent->gotobj)->got;
-             BFD_ASSERT(sgot != NULL);
-             BFD_ASSERT(gotent->addend == 0);
+               plt_index = ((gotent->plt_offset - NEW_PLT_HEADER_SIZE)
+                            / NEW_PLT_ENTRY_SIZE);
+             }
+           else
+             {
+               disp = -(gotent->plt_offset + 4);
+               insn = INSN_AD (INSN_BR, 28, disp);
+               bfd_put_32 (output_bfd, insn,
+                           splt->contents + gotent->plt_offset);
+               bfd_put_32 (output_bfd, INSN_UNOP,
+                           splt->contents + gotent->plt_offset + 4);
+               bfd_put_32 (output_bfd, INSN_UNOP,
+                           splt->contents + gotent->plt_offset + 8);
+
+               plt_index = ((gotent->plt_offset - OLD_PLT_HEADER_SIZE)
+                            / OLD_PLT_ENTRY_SIZE);
+             }
 
 
-             bfd_put_64 (output_bfd, plt_addr,
-                         sgot->contents + gotent->got_offset);
+           /* Fill in the entry in the .rela.plt section.  */
+           outrel.r_offset = got_addr;
+           outrel.r_info = ELF64_R_INFO(h->dynindx, R_ALPHA_JMP_SLOT);
+           outrel.r_addend = 0;
 
 
-             if (info->shared)
-               elf64_alpha_emit_dynrel (output_bfd, info, sgot, srel,
-                                        gotent->got_offset, 0,
-                                        R_ALPHA_RELATIVE, plt_addr);
+           loc = srel->contents + plt_index * sizeof (Elf64_External_Rela);
+           bfd_elf64_swap_reloca_out (output_bfd, &outrel, loc);
 
 
-             gotent = gotent->next;
-           }
-          while (gotent != NULL);
-       }
+           /* Fill in the entry in the .got.  */
+           bfd_put_64 (output_bfd, plt_addr,
+                       sgot->contents + gotent->got_offset);
+         }
     }
   else if (alpha_elf_dynamic_symbol_p (h, info))
     {
     }
   else if (alpha_elf_dynamic_symbol_p (h, info))
     {
@@ -4697,7 +4855,7 @@ elf64_alpha_finish_dynamic_symbol (bfd *output_bfd, struct bfd_link_info *info,
       asection *srel;
       struct alpha_elf_got_entry *gotent;
 
       asection *srel;
       struct alpha_elf_got_entry *gotent;
 
-      srel = bfd_get_section_by_name (dynobj, ".rela.got");
+      srel = bfd_get_linker_section (dynobj, ".rela.got");
       BFD_ASSERT (srel != NULL);
 
       for (gotent = ((struct alpha_elf_link_hash_entry *) h)->got_entries;
       BFD_ASSERT (srel != NULL);
 
       for (gotent = ((struct alpha_elf_link_hash_entry *) h)->got_entries;
@@ -4732,21 +4890,21 @@ elf64_alpha_finish_dynamic_symbol (bfd *output_bfd, struct bfd_link_info *info,
              abort ();
            }
 
              abort ();
            }
 
-         elf64_alpha_emit_dynrel (output_bfd, info, sgot, srel, 
+         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)
                                   gotent->got_offset, h->dynindx,
                                   r_type, gotent->addend);
 
          if (gotent->reloc_type == R_ALPHA_TLSGD)
-           elf64_alpha_emit_dynrel (output_bfd, info, sgot, srel, 
+           elf64_alpha_emit_dynrel (output_bfd, info, sgot, srel,
                                     gotent->got_offset + 8, h->dynindx,
                                     R_ALPHA_DTPREL64, gotent->addend);
        }
     }
 
   /* Mark some specially defined symbols as absolute.  */
                                     gotent->got_offset + 8, h->dynindx,
                                     R_ALPHA_DTPREL64, gotent->addend);
        }
     }
 
   /* 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)
+  if (h == elf_hash_table (info)->hdynamic
+      || h == elf_hash_table (info)->hgot
+      || h == elf_hash_table (info)->hplt)
     sym->st_shndx = SHN_ABS;
 
   return TRUE;
     sym->st_shndx = SHN_ABS;
 
   return TRUE;
@@ -4762,37 +4920,49 @@ elf64_alpha_finish_dynamic_sections (bfd *output_bfd,
   asection *sdyn;
 
   dynobj = elf_hash_table (info)->dynobj;
   asection *sdyn;
 
   dynobj = elf_hash_table (info)->dynobj;
-  sdyn = bfd_get_section_by_name (dynobj, ".dynamic");
+  sdyn = bfd_get_linker_section (dynobj, ".dynamic");
 
   if (elf_hash_table (info)->dynamic_sections_created)
     {
 
   if (elf_hash_table (info)->dynamic_sections_created)
     {
-      asection *splt;
+      asection *splt, *sgotplt, *srelaplt;
       Elf64_External_Dyn *dyncon, *dynconend;
       Elf64_External_Dyn *dyncon, *dynconend;
+      bfd_vma plt_vma, gotplt_vma;
 
 
-      splt = bfd_get_section_by_name (dynobj, ".plt");
+      splt = bfd_get_linker_section (dynobj, ".plt");
+      srelaplt = bfd_get_linker_section (output_bfd, ".rela.plt");
       BFD_ASSERT (splt != NULL && sdyn != NULL);
 
       BFD_ASSERT (splt != NULL && sdyn != NULL);
 
+      plt_vma = splt->output_section->vma + splt->output_offset;
+
+      gotplt_vma = 0;
+      if (elf64_alpha_use_secureplt)
+       {
+         sgotplt = bfd_get_linker_section (dynobj, ".got.plt");
+         BFD_ASSERT (sgotplt != NULL);
+         if (sgotplt->size > 0)
+           gotplt_vma = sgotplt->output_section->vma + sgotplt->output_offset;
+       }
+
       dyncon = (Elf64_External_Dyn *) sdyn->contents;
       dynconend = (Elf64_External_Dyn *) (sdyn->contents + sdyn->size);
       for (; dyncon < dynconend; dyncon++)
        {
          Elf_Internal_Dyn dyn;
       dyncon = (Elf64_External_Dyn *) sdyn->contents;
       dynconend = (Elf64_External_Dyn *) (sdyn->contents + sdyn->size);
       for (; dyncon < dynconend; dyncon++)
        {
          Elf_Internal_Dyn dyn;
-         const char *name;
-         asection *s;
 
          bfd_elf64_swap_dyn_in (dynobj, dyncon, &dyn);
 
          switch (dyn.d_tag)
            {
            case DT_PLTGOT:
 
          bfd_elf64_swap_dyn_in (dynobj, dyncon, &dyn);
 
          switch (dyn.d_tag)
            {
            case DT_PLTGOT:
-             name = ".plt";
-             goto get_vma;
+             dyn.d_un.d_ptr
+               = elf64_alpha_use_secureplt ? gotplt_vma : plt_vma;
+             break;
            case DT_PLTRELSZ:
            case DT_PLTRELSZ:
-             name = ".rela.plt";
-             goto get_size;
+             dyn.d_un.d_val = srelaplt ? srelaplt->size : 0;
+             break;
            case DT_JMPREL:
            case DT_JMPREL:
-             name = ".rela.plt";
-             goto get_vma;
+             dyn.d_un.d_ptr = srelaplt ? srelaplt->vma : 0;
+             break;
 
            case DT_RELASZ:
              /* My interpretation of the TIS v1.1 ELF document indicates
 
            case DT_RELASZ:
              /* My interpretation of the TIS v1.1 ELF document indicates
@@ -4800,36 +4970,69 @@ elf64_alpha_finish_dynamic_sections (bfd *output_bfd,
                 the rest of the BFD does.  It is, however, what the
                 glibc ld.so wants.  Do this fixup here until we found
                 out who is right.  */
                 the rest of the BFD does.  It is, however, what the
                 glibc ld.so wants.  Do this fixup here until we found
                 out who is right.  */
-             s = bfd_get_section_by_name (output_bfd, ".rela.plt");
-             if (s)
-               dyn.d_un.d_val -= s->size;
-             break;
-
-           get_vma:
-             s = bfd_get_section_by_name (output_bfd, name);
-             dyn.d_un.d_ptr = (s ? s->vma : 0);
-             break;
-
-           get_size:
-             s = bfd_get_section_by_name (output_bfd, name);
-             dyn.d_un.d_val = s->size;
+             if (srelaplt)
+               dyn.d_un.d_val -= srelaplt->size;
              break;
            }
 
          bfd_elf64_swap_dyn_out (output_bfd, &dyn, dyncon);
        }
 
              break;
            }
 
          bfd_elf64_swap_dyn_out (output_bfd, &dyn, dyncon);
        }
 
-      /* Initialize the PLT0 entry.  */
+      /* Initialize the plt header.  */
       if (splt->size > 0)
        {
       if (splt->size > 0)
        {
-         bfd_put_32 (output_bfd, PLT_HEADER_WORD1, splt->contents);
-         bfd_put_32 (output_bfd, PLT_HEADER_WORD2, splt->contents + 4);
-         bfd_put_32 (output_bfd, PLT_HEADER_WORD3, splt->contents + 8);
-         bfd_put_32 (output_bfd, PLT_HEADER_WORD4, splt->contents + 12);
+         unsigned int insn;
+         int ofs;
+
+         if (elf64_alpha_use_secureplt)
+           {
+             ofs = gotplt_vma - (plt_vma + PLT_HEADER_SIZE);
+
+             insn = INSN_ABC (INSN_SUBQ, 27, 28, 25);
+             bfd_put_32 (output_bfd, insn, splt->contents);
+
+             insn = INSN_ABO (INSN_LDAH, 28, 28, (ofs + 0x8000) >> 16);
+             bfd_put_32 (output_bfd, insn, splt->contents + 4);
 
 
-         /* The next two words will be filled in by ld.so */
-         bfd_put_64 (output_bfd, (bfd_vma) 0, splt->contents + 16);
-         bfd_put_64 (output_bfd, (bfd_vma) 0, splt->contents + 24);
+             insn = INSN_ABC (INSN_S4SUBQ, 25, 25, 25);
+             bfd_put_32 (output_bfd, insn, splt->contents + 8);
+
+             insn = INSN_ABO (INSN_LDA, 28, 28, ofs);
+             bfd_put_32 (output_bfd, insn, splt->contents + 12);
+
+             insn = INSN_ABO (INSN_LDQ, 27, 28, 0);
+             bfd_put_32 (output_bfd, insn, splt->contents + 16);
+
+             insn = INSN_ABC (INSN_ADDQ, 25, 25, 25);
+             bfd_put_32 (output_bfd, insn, splt->contents + 20);
+
+             insn = INSN_ABO (INSN_LDQ, 28, 28, 8);
+             bfd_put_32 (output_bfd, insn, splt->contents + 24);
+
+             insn = INSN_AB (INSN_JMP, 31, 27);
+             bfd_put_32 (output_bfd, insn, splt->contents + 28);
+
+             insn = INSN_AD (INSN_BR, 28, -PLT_HEADER_SIZE);
+             bfd_put_32 (output_bfd, insn, splt->contents + 32);
+           }
+         else
+           {
+             insn = INSN_AD (INSN_BR, 27, 0);  /* br $27, .+4 */
+             bfd_put_32 (output_bfd, insn, splt->contents);
+
+             insn = INSN_ABO (INSN_LDQ, 27, 27, 12);
+             bfd_put_32 (output_bfd, insn, splt->contents + 4);
+
+             insn = INSN_UNOP;
+             bfd_put_32 (output_bfd, insn, splt->contents + 8);
+
+             insn = INSN_AB (INSN_JMP, 27, 27);
+             bfd_put_32 (output_bfd, insn, splt->contents + 12);
+
+             /* The next two words will be filled in by ld.so.  */
+             bfd_put_64 (output_bfd, 0, splt->contents + 16);
+             bfd_put_64 (output_bfd, 0, splt->contents + 24);
+           }
 
          elf_section_data (splt->output_section)->this_hdr.sh_entsize = 0;
        }
 
          elf_section_data (splt->output_section)->this_hdr.sh_entsize = 0;
        }
@@ -4852,7 +5055,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;
   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;
 
   /* Go through the sections and collect the mdebug information.  */
   mdebug_sec = NULL;
@@ -4896,7 +5104,7 @@ elf64_alpha_final_link (bfd *abfd, struct bfd_link_info *info)
          debug.external_ext = debug.external_ext_end = NULL;
 
          mdebug_handle = bfd_ecoff_debug_init (abfd, &debug, swap, info);
          debug.external_ext = debug.external_ext_end = NULL;
 
          mdebug_handle = bfd_ecoff_debug_init (abfd, &debug, swap, info);
-         if (mdebug_handle == (PTR) NULL)
+         if (mdebug_handle == NULL)
            return FALSE;
 
          if (1)
            return FALSE;
 
          if (1)
@@ -4961,15 +5169,11 @@ elf64_alpha_final_link (bfd *abfd, struct bfd_link_info *info)
              input_section = p->u.indirect.section;
              input_bfd = input_section->owner;
 
              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);
 
              input_swap = (get_elf_backend_data (input_bfd)
                            ->elf_backend_ecoff_debug_swap);
@@ -4992,7 +5196,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.  */
                 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));
              eraw_end = (eraw_src
                          + (input_debug.symbolic_header.iextMax
                             * input_swap->external_ext_size));
@@ -5004,15 +5208,14 @@ elf64_alpha_final_link (bfd *abfd, struct bfd_link_info *info)
                  const char *name;
                  struct alpha_elf_link_hash_entry *h;
 
                  const char *name;
                  struct alpha_elf_link_hash_entry *h;
 
-                 (*input_swap->swap_ext_in) (input_bfd, (PTR) eraw_src, &ext);
+                 (*input_swap->swap_ext_in) (input_bfd, eraw_src, &ext);
                  if (ext.asym.sc == scNil
                      || ext.asym.sc == scUndefined
                      || ext.asym.sc == scSUndefined)
                    continue;
 
                  name = input_debug.ssext + ext.asym.iss;
                  if (ext.asym.sc == scNil
                      || ext.asym.sc == scUndefined
                      || ext.asym.sc == scSUndefined)
                    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;
 
                  if (h == NULL || h->esym.ifd != -2)
                    continue;
 
@@ -5052,7 +5255,7 @@ elf64_alpha_final_link (bfd *abfd, struct bfd_link_info *info)
          einfo.failed = FALSE;
          elf_link_hash_traverse (elf_hash_table (info),
                                  elf64_alpha_output_extsym,
          einfo.failed = FALSE;
          elf_link_hash_traverse (elf_hash_table (info),
                                  elf64_alpha_output_extsym,
-                                 (PTR) &einfo);
+                                 &einfo);
          if (einfo.failed)
            return FALSE;
 
          if (einfo.failed)
            return FALSE;
 
@@ -5076,7 +5279,7 @@ elf64_alpha_final_link (bfd *abfd, struct bfd_link_info *info)
   /* The .got subsections...  */
   {
     bfd *i, *dynobj = elf_hash_table(info)->dynobj;
   /* 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)
       {
         i != NULL;
         i = alpha_elf_tdata(i)->got_link_next)
       {
@@ -5125,44 +5328,11 @@ elf64_alpha_reloc_type_class (const Elf_Internal_Rela *rela)
     }
 }
 \f
     }
 }
 \f
-static struct bfd_elf_special_section const
-  alpha_special_sections_s[]=
+static const struct bfd_elf_special_section 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 }
-};
-
-static struct bfd_elf_special_section const *
-  elf64_alpha_special_sections[27] =
-{
-  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
 };
 
 /* ECOFF swapping routines.  These are used when dealing with the
@@ -5228,6 +5398,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,
   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,
   bfd_elf64_write_relocs,
   bfd_elf64_swap_symbol_in,
   bfd_elf64_swap_symbol_out,
@@ -5244,14 +5415,18 @@ static const struct elf_size_info alpha_elf_size_info =
 #define TARGET_LITTLE_SYM      bfd_elf64_alpha_vec
 #define TARGET_LITTLE_NAME     "elf64-alpha"
 #define ELF_ARCH               bfd_arch_alpha
 #define TARGET_LITTLE_SYM      bfd_elf64_alpha_vec
 #define TARGET_LITTLE_NAME     "elf64-alpha"
 #define ELF_ARCH               bfd_arch_alpha
+#define ELF_TARGET_ID          ALPHA_ELF_DATA
 #define ELF_MACHINE_CODE       EM_ALPHA
 #define ELF_MAXPAGESIZE        0x10000
 #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_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
 
 #define elf_info_to_howto \
   elf64_alpha_info_to_howto
 
@@ -5276,16 +5451,24 @@ static const struct elf_size_info alpha_elf_size_info =
 
 #define elf_backend_add_symbol_hook \
   elf64_alpha_add_symbol_hook
 
 #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_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_copy_indirect_symbol \
+  elf64_alpha_copy_indirect_symbol
 #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_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 \
 #define elf_backend_relocate_section \
   elf64_alpha_relocate_section
 #define elf_backend_finish_dynamic_symbol \
@@ -5297,6 +5480,10 @@ static const struct elf_size_info alpha_elf_size_info =
 #define elf_backend_reloc_type_class \
   elf64_alpha_reloc_type_class
 
 #define elf_backend_reloc_type_class \
   elf64_alpha_reloc_type_class
 
+#define elf_backend_can_gc_sections    1
+#define elf_backend_gc_mark_hook       elf64_alpha_gc_mark_hook
+#define elf_backend_gc_sweep_hook      elf64_alpha_gc_sweep_hook
+
 #define elf_backend_ecoff_debug_swap \
   &elf64_alpha_ecoff_debug_swap
 
 #define elf_backend_ecoff_debug_swap \
   &elf64_alpha_ecoff_debug_swap
 
@@ -5320,6 +5507,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"
 #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
 
 /* The kernel recognizes executables as valid only if they carry a
    "FreeBSD" label in the ELF header.  So we put this label on all
@@ -5334,7 +5523,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 = 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);
 #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);