This is the mail archive of the binutils@sources.redhat.com mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

alpha tls support


Appears to work.  Need to do the gcc and ld.so support to be sure.


r~


include/elf/
        * alpha.h (R_ALPHA_TLSGD, R_ALPHA_TLSLDM, R_ALPHA_DTPMOD64,
        R_ALPHA_GOTDTPREL, R_ALPHA_DTPREL64, R_ALPHA_DTPRELHI,
        R_ALPHA_DTPRELLO, R_ALPHA_DTPREL16, R_ALPHA_GOTTPREL, R_ALPHA_TPREL64,
        R_ALPHA_TPRELHI, R_ALPHA_TPRELLO, R_ALPHA_TPREL16): New.

bfd/
        * elf64-alpha.c (ALPHA_ELF_LINK_HASH_LU_TLSGD,
        ALPHA_ELF_LINK_HASH_LU_TLSLDM, ALPHA_ELF_LINK_HASH_LU_FUNC): New.
        (ALPHA_ELF_GOT_ENTRY_RELOCS_DONE): Remove.
        (ALPHA_ELF_GOT_ENTRY_RELOCS_XLATED): Remove.
        (struct alpha_elf_got_entry): Add reloc_type, reloc_done, reloc_xlated.
        (struct alpha_elf_obj_tdata): Rename total_got_entries and
        n_local_got_entries to total_got_size and local_got_size.
        (elf64_alpha_howto, elf64_alpha_reloc_map): Update for TLS relocs.
        (alpha_got_entry_size): New.
        (elf64_alpha_relax_with_lituse): Use it.
        (elf64_alpha_relax_without_lituse): Likewise.
        (MAX_GOT_SIZE): Rename from MAX_GOT_ENTRIES.
        (get_got_entry): New.
        (elf64_alpha_check_relocs): Handle TLS relocs.  Reorganize.
        (elf64_alpha_adjust_dynamic_symbol): Test LU_FUNC as a mask.
        (elf64_alpha_merge_ind_symbols): Check gotent->reloc_type.
        (elf64_alpha_can_merge_gots, elf64_alpha_merge_gots): Likewise.
        (elf64_alpha_calc_got_offsets_for_symbol): Use alpha_got_entry_size.
        (elf64_alpha_calc_got_offsets): Likewise.
        (alpha_dynamic_entries_for_reloc): New.
        (elf64_alpha_calc_dynrel_sizes): Use it.
        (elf64_alpha_size_dynamic_sections): Likewise.
        (elf64_alpha_relocate_section): Handle TLS relocations.
        * reloc.c: Add Alpha TLS relocations.
        * bfd-in2.h, libbfd.h: Rebuild.

gas/
        * expr.h (operatorT): Add O_md17..O_md32.
        * config/tc-alpha.c (O_lituse_tlsgd, O_lituse_tlsldm, O_tlsgd,
        O_tlsldm, O_gotdtprel, O_dtprelhi, O_dtprello, O_dtprel, O_gottprel,
        O_tprelhi, O_tprello, O_tprel): New.
        (USER_RELOC_P, alpha_reloc_op_tag, debug_exp): Include them.
        (DUMMY_RELOC_LITUSE_TLSGD, DUMMY_RELOC_LITUSE_TLSLDM): New.
        (LITUSE_TLSGD, LITUSE_TLSLDM): New.
        (struct alpha_reloc_tag): Add master, saw_tlsgd, saw_tlsld,
        saw_lu_tlsgd, saw_lu_tlsldm.  Make multi_section_p a bit field.
        (md_apply_fix3): Handle TLS relocations.
        (alpha_force_relocation, alpha_fix_adjustable): Likewise.
        (alpha_adjust_symtab_relocs): Sort LITERAL relocs after the
        associated TLS reloc.  Check lituse_tls relocs match up.
        (emit_insn): Handle TLS relocations.
        (ldX_op): Remove.

gas/testsuite/
        * gas/alpha/elf-tls-1.s, gas/alpha/elf-tls-1.d: New.
        * gas/alpha/elf-tls-2.s, gas/alpha/elf-tls-1.l: New.
        * gas/alpha/elf-tls-3.s, gas/alpha/elf-tls-1.l: New.
        * gas/alpha/alpha.exp: Run them.

Index: bfd/elf64-alpha.c
===================================================================
RCS file: /cvs/src/src/bfd/elf64-alpha.c,v
retrieving revision 1.62
diff -c -p -d -r1.62 elf64-alpha.c
*** bfd/elf64-alpha.c	2 May 2002 17:46:59 -0000	1.62
--- bfd/elf64-alpha.c	30 May 2002 21:41:27 -0000
*************** static boolean elf64_alpha_size_got_sect
*** 109,119 ****
--- 109,124 ----
    PARAMS ((bfd *, struct bfd_link_info *));
  static boolean elf64_alpha_always_size_sections
    PARAMS ((bfd *, struct bfd_link_info *));
+ static int alpha_dynamic_entries_for_reloc
+   PARAMS ((int, int, int));
  static boolean elf64_alpha_calc_dynrel_sizes
    PARAMS ((struct alpha_elf_link_hash_entry *, struct bfd_link_info *));
  static boolean elf64_alpha_add_symbol_hook
    PARAMS ((bfd *, struct bfd_link_info *, const Elf_Internal_Sym *,
  	   const char **, flagword *, asection **, bfd_vma *));
+ static struct alpha_elf_got_entry *get_got_entry
+   PARAMS ((bfd *, struct alpha_elf_link_hash_entry *, unsigned long,
+ 	   unsigned long, bfd_vma));
  static boolean elf64_alpha_check_relocs
    PARAMS((bfd *, struct bfd_link_info *, asection *sec,
  	  const Elf_Internal_Rela *));
*************** struct alpha_elf_link_hash_entry
*** 149,158 ****
    int flags;
  
    /* Contexts (LITUSE) 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_FUNC 0x08
  
    /* Used to implement multiple .got subsections.  */
    struct alpha_elf_got_entry
--- 154,166 ----
    int flags;
  
    /* Contexts (LITUSE) 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
  
    /* Used to implement multiple .got subsections.  */
    struct alpha_elf_got_entry
*************** struct alpha_elf_link_hash_entry
*** 168,180 ****
      /* the .got offset for this entry.  */
      int got_offset;
  
!     int flags;
  
!     /* Additional flags.  */
! #define ALPHA_ELF_GOT_ENTRY_RELOCS_DONE 0x10
! #define ALPHA_ELF_GOT_ENTRY_RELOCS_XLATED 0x20
  
!     int use_count;
    } *got_entries;
  
    /* used to count non-got, non-plt relocations for delayed sizing
--- 176,195 ----
      /* the .got offset for this entry.  */
      int got_offset;
  
!     /* How many references to this entry?  */
!     int use_count;
  
!     /* The relocation type of this entry.  */
!     unsigned char reloc_type;
  
!     /* How a LITERAL is used.  */
!     unsigned char flags;
! 
!     /* Have we initialized the dynamic relocation for this entry?  */
!     unsigned char reloc_done;
! 
!     /* Have we adjusted this entry for SEC_MERGE?  */
!     unsigned char reloc_xlated;
    } *got_entries;
  
    /* used to count non-got, non-plt relocations for delayed sizing
*************** struct alpha_elf_obj_tdata
*** 361,372 ****
    /* For every got, this is the section.  */
    asection *got;
  
!   /* For every got, this is it's total number of *entries*.  */
!   int total_got_entries;
  
!   /* For every got, this is the sum of the number of *entries* required
       to hold all of the member object's local got.  */
!   int n_local_got_entries;
  };
  
  #define alpha_elf_tdata(abfd) \
--- 376,387 ----
    /* For every got, this is the section.  */
    asection *got;
  
!   /* For every got, this is it's total number of words.  */
!   int total_got_size;
  
!   /* For every got, this is the sum of the number of words required
       to hold all of the member object's local got.  */
!   int local_got_size;
  };
  
  #define alpha_elf_tdata(abfd) \
*************** static reloc_howto_type elf64_alpha_howt
*** 748,753 ****
--- 763,965 ----
  	 0x1fffff,		/* src_mask */
  	 0x1fffff,		/* dst_mask */
  	 true),			/* pcrel_offset */
+ 
+   /* Creates a tls_index for the symbol in the got.  */
+   HOWTO (R_ALPHA_TLSGD,		/* type */
+ 	 0,			/* rightshift */
+ 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+ 	 16,			/* bitsize */
+ 	 false,			/* pc_relative */
+ 	 0,			/* bitpos */
+ 	 complain_overflow_signed, /* complain_on_overflow */
+ 	 0,			/* special_function */
+ 	 "TLSGD",		/* name */
+ 	 false,			/* partial_inplace */
+ 	 0xffff,		/* src_mask */
+ 	 0xffff,		/* dst_mask */
+ 	 false),		/* pcrel_offset */
+ 
+   /* Creates a tls_index for the (current) module in the got.  */
+   HOWTO (R_ALPHA_TLSLDM,	/* type */
+ 	 0,			/* rightshift */
+ 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+ 	 16,			/* bitsize */
+ 	 false,			/* pc_relative */
+ 	 0,			/* bitpos */
+ 	 complain_overflow_signed, /* complain_on_overflow */
+ 	 0,			/* special_function */
+ 	 "TLSLDM",		/* name */
+ 	 false,			/* partial_inplace */
+ 	 0xffff,		/* src_mask */
+ 	 0xffff,		/* dst_mask */
+ 	 false),		/* pcrel_offset */
+ 
+   /* A dynamic relocation for a DTP module entry.  */
+   HOWTO (R_ALPHA_DTPMOD64,	/* type */
+ 	 0,			/* rightshift */
+ 	 4,			/* size (0 = byte, 1 = short, 2 = long) */
+ 	 64,			/* bitsize */
+ 	 false,			/* pc_relative */
+ 	 0,			/* bitpos */
+ 	 complain_overflow_bitfield, /* complain_on_overflow */
+ 	 0,			/* special_function */
+ 	 "DTPMOD64",		/* name */
+ 	 false,			/* partial_inplace */
+ 	 MINUS_ONE,		/* src_mask */
+ 	 MINUS_ONE,		/* dst_mask */
+ 	 false),		/* pcrel_offset */
+ 
+   /* Creates a 64-bit offset in the got for the displacement
+      from DTP to the target.  */
+   HOWTO (R_ALPHA_GOTDTPREL,	/* type */
+ 	 0,			/* rightshift */
+ 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+ 	 16,			/* bitsize */
+ 	 false,			/* pc_relative */
+ 	 0,			/* bitpos */
+ 	 complain_overflow_signed, /* complain_on_overflow */
+ 	 0,			/* special_function */
+ 	 "GOTDTPREL",		/* name */
+ 	 false,			/* partial_inplace */
+ 	 0xffff,		/* src_mask */
+ 	 0xffff,		/* dst_mask */
+ 	 false),		/* pcrel_offset */
+ 
+   /* A dynamic relocation for a displacement from DTP to the target.  */
+   HOWTO (R_ALPHA_DTPREL64,	/* type */
+ 	 0,			/* rightshift */
+ 	 4,			/* size (0 = byte, 1 = short, 2 = long) */
+ 	 64,			/* bitsize */
+ 	 false,			/* pc_relative */
+ 	 0,			/* bitpos */
+ 	 complain_overflow_bitfield, /* complain_on_overflow */
+ 	 0,			/* special_function */
+ 	 "DTPREL64",		/* name */
+ 	 false,			/* partial_inplace */
+ 	 MINUS_ONE,		/* src_mask */
+ 	 MINUS_ONE,		/* dst_mask */
+ 	 false),		/* pcrel_offset */
+ 
+   /* The high 16 bits of the displacement from DTP to the target.  */
+   HOWTO (R_ALPHA_DTPRELHI,	/* type */
+ 	 0,			/* rightshift */
+ 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+ 	 16,			/* bitsize */
+ 	 false,			/* pc_relative */
+ 	 0,			/* bitpos */
+ 	 complain_overflow_signed, /* complain_on_overflow */
+ 	 0,			/* special_function */
+ 	 "DTPRELHI",		/* name */
+ 	 false,			/* partial_inplace */
+ 	 0xffff,		/* src_mask */
+ 	 0xffff,		/* dst_mask */
+ 	 false),		/* pcrel_offset */
+ 
+   /* The low 16 bits of the displacement from DTP to the target.  */
+   HOWTO (R_ALPHA_DTPRELLO,	/* type */
+ 	 0,			/* rightshift */
+ 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+ 	 16,			/* bitsize */
+ 	 false,			/* pc_relative */
+ 	 0,			/* bitpos */
+ 	 complain_overflow_dont, /* complain_on_overflow */
+ 	 0,			/* special_function */
+ 	 "DTPRELLO",		/* name */
+ 	 false,			/* partial_inplace */
+ 	 0xffff,		/* src_mask */
+ 	 0xffff,		/* dst_mask */
+ 	 false),		/* pcrel_offset */
+ 
+   /* A 16-bit displacement from DTP to the target.  */
+   HOWTO (R_ALPHA_DTPREL16,	/* type */
+ 	 0,			/* rightshift */
+ 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+ 	 16,			/* bitsize */
+ 	 false,			/* pc_relative */
+ 	 0,			/* bitpos */
+ 	 complain_overflow_signed, /* complain_on_overflow */
+ 	 0,			/* special_function */
+ 	 "DTPREL16",		/* name */
+ 	 false,			/* partial_inplace */
+ 	 0xffff,		/* src_mask */
+ 	 0xffff,		/* dst_mask */
+ 	 false),		/* pcrel_offset */
+ 
+   /* Creates a 64-bit offset in the got for the displacement
+      from TP to the target.  */
+   HOWTO (R_ALPHA_GOTTPREL,	/* type */
+ 	 0,			/* rightshift */
+ 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+ 	 16,			/* bitsize */
+ 	 false,			/* pc_relative */
+ 	 0,			/* bitpos */
+ 	 complain_overflow_signed, /* complain_on_overflow */
+ 	 0,			/* special_function */
+ 	 "GOTTPREL",		/* name */
+ 	 false,			/* partial_inplace */
+ 	 0xffff,		/* src_mask */
+ 	 0xffff,		/* dst_mask */
+ 	 false),		/* pcrel_offset */
+ 
+   /* A dynamic relocation for a displacement from TP to the target.  */
+   HOWTO (R_ALPHA_TPREL64,	/* type */
+ 	 0,			/* rightshift */
+ 	 4,			/* size (0 = byte, 1 = short, 2 = long) */
+ 	 64,			/* bitsize */
+ 	 false,			/* pc_relative */
+ 	 0,			/* bitpos */
+ 	 complain_overflow_bitfield, /* complain_on_overflow */
+ 	 0,			/* special_function */
+ 	 "TPREL64",		/* name */
+ 	 false,			/* partial_inplace */
+ 	 MINUS_ONE,		/* src_mask */
+ 	 MINUS_ONE,		/* dst_mask */
+ 	 false),		/* pcrel_offset */
+ 
+   /* The high 16 bits of the displacement from TP to the target.  */
+   HOWTO (R_ALPHA_TPRELHI,	/* type */
+ 	 0,			/* rightshift */
+ 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+ 	 16,			/* bitsize */
+ 	 false,			/* pc_relative */
+ 	 0,			/* bitpos */
+ 	 complain_overflow_signed, /* complain_on_overflow */
+ 	 0,			/* special_function */
+ 	 "TPRELHI",		/* name */
+ 	 false,			/* partial_inplace */
+ 	 0xffff,		/* src_mask */
+ 	 0xffff,		/* dst_mask */
+ 	 false),		/* pcrel_offset */
+ 
+   /* The low 16 bits of the displacement from TP to the target.  */
+   HOWTO (R_ALPHA_TPRELLO,	/* type */
+ 	 0,			/* rightshift */
+ 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+ 	 16,			/* bitsize */
+ 	 false,			/* pc_relative */
+ 	 0,			/* bitpos */
+ 	 complain_overflow_dont, /* complain_on_overflow */
+ 	 0,			/* special_function */
+ 	 "TPRELLO",		/* name */
+ 	 false,			/* partial_inplace */
+ 	 0xffff,		/* src_mask */
+ 	 0xffff,		/* dst_mask */
+ 	 false),		/* pcrel_offset */
+ 
+   /* A 16-bit displacement from TP to the target.  */
+   HOWTO (R_ALPHA_TPREL16,	/* type */
+ 	 0,			/* rightshift */
+ 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+ 	 16,			/* bitsize */
+ 	 false,			/* pc_relative */
+ 	 0,			/* bitpos */
+ 	 complain_overflow_signed, /* complain_on_overflow */
+ 	 0,			/* special_function */
+ 	 "TPREL16",		/* name */
+ 	 false,			/* partial_inplace */
+ 	 0xffff,		/* src_mask */
+ 	 0xffff,		/* dst_mask */
+ 	 false),		/* pcrel_offset */
  };
  
  /* A relocation function which doesn't do anything.  */
*************** static const struct elf_reloc_map elf64_
*** 902,907 ****
--- 1114,1132 ----
    {BFD_RELOC_ALPHA_GPREL_LO16,		R_ALPHA_GPRELLOW},
    {BFD_RELOC_GPREL16,			R_ALPHA_GPREL16},
    {BFD_RELOC_ALPHA_BRSGP,		R_ALPHA_BRSGP},
+   {BFD_RELOC_ALPHA_TLSGD,		R_ALPHA_TLSGD},
+   {BFD_RELOC_ALPHA_TLSLDM,		R_ALPHA_TLSLDM},
+   {BFD_RELOC_ALPHA_DTPMOD64,		R_ALPHA_DTPMOD64},
+   {BFD_RELOC_ALPHA_GOTDTPREL16,		R_ALPHA_GOTDTPREL},
+   {BFD_RELOC_ALPHA_DTPREL64,		R_ALPHA_DTPREL64},
+   {BFD_RELOC_ALPHA_DTPREL_HI16,		R_ALPHA_DTPRELHI},
+   {BFD_RELOC_ALPHA_DTPREL_LO16,		R_ALPHA_DTPRELLO},
+   {BFD_RELOC_ALPHA_DTPREL16,		R_ALPHA_DTPREL16},
+   {BFD_RELOC_ALPHA_GOTTPREL16,		R_ALPHA_GOTTPREL},
+   {BFD_RELOC_ALPHA_TPREL64,		R_ALPHA_TPREL64},
+   {BFD_RELOC_ALPHA_TPREL_HI16,		R_ALPHA_TPRELHI},
+   {BFD_RELOC_ALPHA_TPREL_LO16,		R_ALPHA_TPRELLO},
+   {BFD_RELOC_ALPHA_TPREL16,		R_ALPHA_TPREL16},
  };
  
  /* Given a BFD reloc type, return a HOWTO structure.  */
*************** elf64_alpha_info_to_howto (abfd, cache_p
*** 936,941 ****
--- 1161,1170 ----
    BFD_ASSERT (r_type < (unsigned int) R_ALPHA_max);
    cache_ptr->howto = &elf64_alpha_howto_table[r_type];
  }
+ 
+ /* These two relocations create a two-word entry in the got.  */
+ #define alpha_got_entry_size(r_type) \
+   (r_type == R_ALPHA_TLSGD || r_type == R_ALPHA_TLSLDM ? 16 : 8)
  
  /* These functions do relaxation for Alpha ELF.
  
*************** elf64_alpha_relax_with_lituse (info, sym
*** 1213,1226 ****
       got entry by one, possibly eliminating it.  */
    if (all_optimized)
      {
!       info->gotent->use_count -= 1;
!       alpha_elf_tdata (info->gotent->gotobj)->total_got_entries -= 1;
!       if (!info->h)
! 	alpha_elf_tdata (info->gotent->gotobj)->n_local_got_entries -= 1;
  
        /* If the literal instruction is no longer needed (it may have been
! 	 reused.  We can eliminate it.
! 	 ??? For now, I don't want to deal with compacting the section,
  	 so just nop it out.  */
        if (!lit_reused)
  	{
--- 1442,1458 ----
       got entry by one, possibly eliminating it.  */
    if (all_optimized)
      {
!       if (--info->gotent->use_count == 0)
! 	{
! 	  int sz = alpha_got_entry_size (info->gotent->reloc_type);
! 	  alpha_elf_tdata (info->gotent->gotobj)->total_got_size -= sz;
! 	  if (!info->h)
! 	    alpha_elf_tdata (info->gotent->gotobj)->local_got_size -= sz;
! 	}
  
        /* If the literal instruction is no longer needed (it may have been
! 	 reused.  We can eliminate it.  */
!       /* ??? For now, I don't want to deal with compacting the section,
  	 so just nop it out.  */
        if (!lit_reused)
  	{
*************** elf64_alpha_relax_without_lituse (info, 
*** 1349,1358 ****
  
    /* Reduce the use count on this got entry by one, possibly
       eliminating it.  */
!   info->gotent->use_count -= 1;
!   alpha_elf_tdata (info->gotent->gotobj)->total_got_entries -= 1;
!   if (!info->h)
!     alpha_elf_tdata (info->gotent->gotobj)->n_local_got_entries -= 1;
  
    /* ??? Search forward through this basic block looking for insns
       that use the target register.  Stop after an insn modifying the
--- 1581,1593 ----
  
    /* Reduce the use count on this got entry by one, possibly
       eliminating it.  */
!   if (--info->gotent->use_count == 0)
!     {
!       int sz = alpha_got_entry_size (info->gotent->reloc_type);
!       alpha_elf_tdata (info->gotent->gotobj)->total_got_size -= sz;
!       if (!info->h)
! 	alpha_elf_tdata (info->gotent->gotobj)->local_got_size -= sz;
!     }
  
    /* ??? Search forward through this basic block looking for insns
       that use the target register.  Stop after an insn modifying the
*************** elf64_alpha_relax_section (abfd, sec, li
*** 1643,1649 ****
  #define PLT_ENTRY_WORD2		0
  #define PLT_ENTRY_WORD3		0
  
! #define MAX_GOT_ENTRIES		(64*1024 / 8)
  
  #define ELF_DYNAMIC_INTERPRETER "/usr/lib/ld.so"
  
--- 1878,1884 ----
  #define PLT_ENTRY_WORD2		0
  #define PLT_ENTRY_WORD3		0
  
! #define MAX_GOT_SIZE		(64*1024)
  
  #define ELF_DYNAMIC_INTERPRETER "/usr/lib/ld.so"
  
*************** mips_elf_create_procedure_table (handle,
*** 2256,2261 ****
--- 2491,2576 ----
       struct ecoff_debug_info *debug;
  */
  
+ /* Search for and possibly create a got entry.  */
+ 
+ static struct alpha_elf_got_entry *
+ get_got_entry (abfd, h, r_type, r_symndx, r_addend)
+      bfd *abfd;
+      struct alpha_elf_link_hash_entry *h;
+      unsigned long r_type, r_symndx;
+      bfd_vma r_addend;
+ {
+   struct alpha_elf_got_entry *gotent;
+   struct alpha_elf_got_entry **slot;
+ 
+   if (h)
+     slot = &h->got_entries;
+   else
+     {
+       /* This is a local .got entry -- record for merge.  */
+ 
+       struct alpha_elf_got_entry **local_got_entries;
+ 
+       local_got_entries = alpha_elf_tdata(abfd)->local_got_entries;
+       if (!local_got_entries)
+ 	{
+ 	  bfd_size_type size;
+ 	  Elf_Internal_Shdr *symtab_hdr;
+ 
+ 	  symtab_hdr = &elf_tdata(abfd)->symtab_hdr;
+ 	  size = symtab_hdr->sh_info;
+ 	  size *= sizeof (struct alpha_elf_got_entry *);
+ 
+ 	  local_got_entries
+ 	    = (struct alpha_elf_got_entry **) bfd_alloc (abfd, size);
+ 	  if (!local_got_entries)
+ 	    return NULL;
+ 
+ 	  memset (local_got_entries, 0, (size_t) size);
+ 	  alpha_elf_tdata (abfd)->local_got_entries = local_got_entries;
+ 	}
+ 
+       slot = &local_got_entries[r_symndx];
+     }
+ 
+   for (gotent = *slot; gotent ; gotent = gotent->next)
+     if (gotent->gotobj == abfd
+ 	&& gotent->reloc_type == r_type
+ 	&& gotent->addend == r_addend)
+       break;
+ 
+   if (!gotent)
+     {
+       int entry_size;
+       bfd_size_type amt;
+ 
+       amt = sizeof (struct alpha_elf_got_entry);
+       gotent = (struct alpha_elf_got_entry *) bfd_alloc (abfd, amt);
+       if (!gotent)
+ 	return NULL;
+ 
+       gotent->gotobj = abfd;
+       gotent->addend = r_addend;
+       gotent->got_offset = -1;
+       gotent->use_count = 1;
+       gotent->reloc_type = r_type;
+       gotent->reloc_done = 0;
+       gotent->reloc_xlated = 0;
+ 
+       gotent->next = *slot;
+       *slot = gotent;
+ 
+       entry_size = alpha_got_entry_size (r_type);
+       alpha_elf_tdata (abfd)->total_got_size += entry_size;
+       if (!h)
+ 	alpha_elf_tdata(abfd)->local_got_size += entry_size;
+     }
+   else
+     gotent->use_count += 1;
+ 
+   return gotent;
+ }
+ 
  /* Handle dynamic relocations when doing an Alpha ELF link.  */
  
  static boolean
*************** elf64_alpha_check_relocs (abfd, info, se
*** 2270,2278 ****
    const char *rel_sec_name;
    Elf_Internal_Shdr *symtab_hdr;
    struct alpha_elf_link_hash_entry **sym_hashes;
-   struct alpha_elf_got_entry **local_got_entries;
    const Elf_Internal_Rela *rel, *relend;
!   int got_created;
    bfd_size_type amt;
  
    if (info->relocateable)
--- 2585,2592 ----
    const char *rel_sec_name;
    Elf_Internal_Shdr *symtab_hdr;
    struct alpha_elf_link_hash_entry **sym_hashes;
    const Elf_Internal_Rela *rel, *relend;
!   boolean got_created;
    bfd_size_type amt;
  
    if (info->relocateable)
*************** elf64_alpha_check_relocs (abfd, info, se
*** 2286,2299 ****
    rel_sec_name = NULL;
    symtab_hdr = &elf_tdata(abfd)->symtab_hdr;
    sym_hashes = alpha_elf_sym_hashes(abfd);
!   local_got_entries = alpha_elf_tdata(abfd)->local_got_entries;
!   got_created = 0;
  
    relend = relocs + sec->reloc_count;
    for (rel = relocs; rel < relend; ++rel)
      {
        unsigned long r_symndx, r_type;
        struct alpha_elf_link_hash_entry *h;
  
        r_symndx = ELF64_R_SYM (rel->r_info);
        if (r_symndx < symtab_hdr->sh_info)
--- 2600,2622 ----
    rel_sec_name = NULL;
    symtab_hdr = &elf_tdata(abfd)->symtab_hdr;
    sym_hashes = alpha_elf_sym_hashes(abfd);
!   got_created = false;
  
    relend = relocs + sec->reloc_count;
    for (rel = relocs; rel < relend; ++rel)
      {
+       enum {
+ 	NEED_GOT = 1,
+ 	NEED_GOT_ENTRY = 2,
+ 	NEED_DYNREL = 4
+       };
+ 
        unsigned long r_symndx, r_type;
        struct alpha_elf_link_hash_entry *h;
+       unsigned int gotent_flags;
+       boolean maybe_dynamic;
+       unsigned int need;
+       bfd_vma addend;
  
        r_symndx = ELF64_R_SYM (rel->r_info);
        if (r_symndx < symtab_hdr->sh_info)
*************** elf64_alpha_check_relocs (abfd, info, se
*** 2308,2432 ****
  
  	  h->root.elf_link_hash_flags |= ELF_LINK_HASH_REF_REGULAR;
  	}
        r_type = ELF64_R_TYPE (rel->r_info);
  
        switch (r_type)
  	{
  	case R_ALPHA_LITERAL:
! 	  {
! 	    struct alpha_elf_got_entry *gotent;
! 	    int flags = 0;
! 
! 	    if (h)
! 	      {
! 		/* Search for and possibly create a got entry.  */
! 		for (gotent = h->got_entries; gotent ; gotent = gotent->next)
! 		  if (gotent->gotobj == abfd &&
! 		      gotent->addend == rel->r_addend)
! 		    break;
! 
! 		if (!gotent)
! 		  {
! 		    amt = sizeof (struct alpha_elf_got_entry);
! 		    gotent = ((struct alpha_elf_got_entry *)
! 			      bfd_alloc (abfd, amt));
! 		    if (!gotent)
! 		      return false;
! 
! 		    gotent->gotobj = abfd;
! 		    gotent->addend = rel->r_addend;
! 		    gotent->got_offset = -1;
! 		    gotent->flags = 0;
! 		    gotent->use_count = 1;
! 
! 		    gotent->next = h->got_entries;
! 		    h->got_entries = gotent;
! 
! 		    alpha_elf_tdata (abfd)->total_got_entries++;
! 		  }
! 		else
! 		  gotent->use_count += 1;
! 	      }
! 	    else
! 	      {
! 		/* This is a local .got entry -- record for merge.  */
! 		if (!local_got_entries)
! 		  {
! 		    bfd_size_type size;
! 		    size = symtab_hdr->sh_info;
! 		    size *= sizeof (struct alpha_elf_got_entry *);
! 
! 		    local_got_entries = ((struct alpha_elf_got_entry **)
! 					 bfd_alloc (abfd, size));
! 		    if (!local_got_entries)
! 		      return false;
! 
! 		    memset (local_got_entries, 0, (size_t) size);
! 		    alpha_elf_tdata (abfd)->local_got_entries =
! 		      local_got_entries;
! 		  }
! 
! 		for (gotent = local_got_entries[ELF64_R_SYM(rel->r_info)];
! 		     gotent != NULL && gotent->addend != rel->r_addend;
! 		     gotent = gotent->next)
! 		  continue;
! 		if (!gotent)
! 		  {
! 		    amt = sizeof (struct alpha_elf_got_entry);
! 		    gotent = ((struct alpha_elf_got_entry *)
! 			      bfd_alloc (abfd, amt));
! 		    if (!gotent)
! 		      return false;
! 
! 		    gotent->gotobj = abfd;
! 		    gotent->addend = rel->r_addend;
! 		    gotent->got_offset = -1;
! 		    gotent->flags = 0;
! 		    gotent->use_count = 1;
! 
! 		    gotent->next = local_got_entries[ELF64_R_SYM(rel->r_info)];
! 		    local_got_entries[ELF64_R_SYM(rel->r_info)] = gotent;
! 
! 		    alpha_elf_tdata(abfd)->total_got_entries++;
! 		    alpha_elf_tdata(abfd)->n_local_got_entries++;
! 		  }
! 		else
! 		  gotent->use_count += 1;
! 	      }
  
! 	    /* Remember how this literal is used from its LITUSEs.
! 	       This will be important when it comes to decide if we can
! 	       create a .plt entry for a function symbol.  */
! 	    if (rel+1 < relend
! 		&& ELF64_R_TYPE (rel[1].r_info) == R_ALPHA_LITUSE)
! 	      {
! 		do
! 		  {
! 		    ++rel;
! 		    if (rel->r_addend >= 1 && rel->r_addend <= 3)
! 		      flags |= 1 << rel->r_addend;
! 		  }
! 		while (rel+1 < relend &&
! 		       ELF64_R_TYPE (rel[1].r_info) == R_ALPHA_LITUSE);
! 	      }
! 	    else
! 	      {
! 		/* No LITUSEs -- presumably the address is not being
! 		   loaded for nothing.  */
! 		flags = ALPHA_ELF_LINK_HASH_LU_ADDR;
! 	      }
  
! 	    gotent->flags |= flags;
! 	    if (h)
! 	      {
! 		/* Make a guess as to whether a .plt entry will be needed.  */
! 		if ((h->flags |= flags) == ALPHA_ELF_LINK_HASH_LU_FUNC)
! 		  h->root.elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT;
! 		else
! 		  h->root.elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT;
! 	      }
! 	  }
! 	  /* FALLTHRU */
  
  	case R_ALPHA_GPDISP:
  	case R_ALPHA_GPREL16:
--- 2631,2670 ----
  
  	  h->root.elf_link_hash_flags |= ELF_LINK_HASH_REF_REGULAR;
  	}
+ 
+       /* We can only get preliminary data on whether a symbol is
+          locally or externally defined, as not all of the input files
+          have yet been processed.  Do something with what we know, as
+          this may help reduce memory usage and processing time later.  */
+       maybe_dynamic = false;
+       if (h && ((info->shared
+ 		 && (!info->symbolic || info->allow_shlib_undefined))
+ 		|| ! (h->root.elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR)
+ 		|| h->root.type == bfd_link_hash_defweak))
+         maybe_dynamic = true;
+ 
+       need = 0;
+       gotent_flags = 0;
        r_type = ELF64_R_TYPE (rel->r_info);
+       addend = rel->r_addend;
  
        switch (r_type)
  	{
  	case R_ALPHA_LITERAL:
! 	  need = NEED_GOT | NEED_GOT_ENTRY;
  
! 	  /* Remember how this literal is used from its LITUSEs.
! 	     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)
! 	      gotent_flags |= 1 << rel->r_addend;
! 	  --rel;
  
! 	  /* No LITUSEs -- presumably the address is used somehow.  */
! 	  if (gotent_flags == 0)
! 	    gotent_flags = ALPHA_ELF_LINK_HASH_LU_ADDR;
! 	  break;
  
  	case R_ALPHA_GPDISP:
  	case R_ALPHA_GPREL16:
*************** elf64_alpha_check_relocs (abfd, info, se
*** 2434,2442 ****
  	case R_ALPHA_GPRELHIGH:
  	case R_ALPHA_GPRELLOW:
  	case R_ALPHA_BRSGP:
! 	  /* We don't actually use the .got here, but the sections must
! 	     be created before the linker maps input sections to output
! 	     sections.  */
  	  if (!got_created)
  	    {
  	      if (!elf64_alpha_create_got_section (abfd, info))
--- 2672,2708 ----
  	case R_ALPHA_GPRELHIGH:
  	case R_ALPHA_GPRELLOW:
  	case R_ALPHA_BRSGP:
! 	  need = NEED_GOT;
! 	  break;
! 
! 	case R_ALPHA_REFLONG:
! 	case R_ALPHA_REFQUAD:
! 	  if (info->shared || maybe_dynamic)
! 	    need = NEED_DYNREL;
! 	  break;
! 
! 	case R_ALPHA_TLSGD:
! 	case R_ALPHA_TLSLDM:
! 	case R_ALPHA_GOTDTPREL:
! 	  need = NEED_GOT | NEED_GOT_ENTRY;
! 	  break;
! 
! 	case R_ALPHA_GOTTPREL:
! 	  need = NEED_GOT | NEED_GOT_ENTRY;
! 	  if (info->shared)
! 	    info->flags |= DF_STATIC_TLS;
! 	  break;
! 
! 	case R_ALPHA_TPREL64:
! 	  if (info->shared || maybe_dynamic)
! 	    need = NEED_DYNREL;
! 	  if (info->shared)
! 	    info->flags |= DF_STATIC_TLS;
! 	  break;
! 	}
! 
!       if (need & NEED_GOT)
! 	{
  	  if (!got_created)
  	    {
  	      if (!elf64_alpha_create_got_section (abfd, info))
*************** elf64_alpha_check_relocs (abfd, info, se
*** 2450,2466 ****
  
  	      got_created = 1;
  	    }
! 	  break;
  
! 	case R_ALPHA_SREL16:
! 	case R_ALPHA_SREL32:
! 	case R_ALPHA_SREL64:
! 	  if (h == NULL)
! 	    break;
! 	  /* FALLTHRU */
  
! 	case R_ALPHA_REFLONG:
! 	case R_ALPHA_REFQUAD:
  	  if (rel_sec_name == NULL)
  	    {
  	      rel_sec_name = (bfd_elf_string_from_elf_section
--- 2716,2751 ----
  
  	      got_created = 1;
  	    }
! 	}
  
!       if (need & NEED_GOT_ENTRY)
! 	{
! 	  struct alpha_elf_got_entry *gotent;
  
! 	  gotent = get_got_entry (abfd, h, r_type, r_symndx, addend);
! 	  if (!gotent)
! 	    return false;
! 
! 	  if (gotent_flags)
! 	    {
! 	      gotent->flags |= gotent_flags;
! 	      if (h)
! 		{
! 		  gotent_flags |= h->flags;
! 		  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.elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT;
! 		  else
! 		    h->root.elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT;
! 	        }
! 	    }
! 	}
! 
!       if (need & NEED_DYNREL)
! 	{
  	  if (rel_sec_name == NULL)
  	    {
  	      rel_sec_name = (bfd_elf_string_from_elf_section
*************** elf64_alpha_check_relocs (abfd, info, se
*** 2538,2544 ****
  	      if (sec->flags & SEC_READONLY)
  		info->flags |= DF_TEXTREL;
  	    }
- 	  break;
  	}
      }
  
--- 2823,2828 ----
*************** elf64_alpha_adjust_dynamic_symbol (info,
*** 2570,2576 ****
        && ((h->type == STT_FUNC
  	   && !(ah->flags & ALPHA_ELF_LINK_HASH_LU_ADDR))
  	  || (h->type == STT_NOTYPE
! 	      && 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
--- 2854,2861 ----
        && ((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
*************** elf64_alpha_merge_ind_symbols (hi, dummy
*** 2667,2674 ****
  	{
  	  gin = gi->next;
  	  for (gs = gsh; gs ; gs = gs->next)
! 	    if (gi->gotobj == gs->gotobj && gi->addend == gs->addend)
! 	      goto got_found;
  	  gi->next = hs->got_entries;
  	  hs->got_entries = gi;
  	got_found:;
--- 2952,2964 ----
  	{
  	  gin = gi->next;
  	  for (gs = gsh; gs ; gs = gs->next)
! 	    if (gi->gotobj == gs->gotobj
! 		&& gi->reloc_type == gs->reloc_type
! 		&& gi->addend == gs->addend)
! 	      {
! 		gi->use_count += gs->use_count;
! 	        goto got_found;
! 	      }
  	  gi->next = hs->got_entries;
  	  hs->got_entries = gi;
  	got_found:;
*************** static boolean
*** 2710,2724 ****
  elf64_alpha_can_merge_gots (a, b)
       bfd *a, *b;
  {
!   int total = alpha_elf_tdata (a)->total_got_entries;
    bfd *bsub;
  
    /* Trivial quick fallout test.  */
!   if (total + alpha_elf_tdata (b)->total_got_entries <= MAX_GOT_ENTRIES)
      return true;
  
    /* By their nature, local .got entries cannot be merged.  */
!   if ((total += alpha_elf_tdata (b)->n_local_got_entries) > MAX_GOT_ENTRIES)
      return false;
  
    /* Failing the common trivial comparison, we must effectively
--- 3000,3014 ----
  elf64_alpha_can_merge_gots (a, b)
       bfd *a, *b;
  {
!   int total = alpha_elf_tdata (a)->total_got_size;
    bfd *bsub;
  
    /* Trivial quick fallout test.  */
!   if (total + alpha_elf_tdata (b)->total_got_size <= MAX_GOT_SIZE)
      return true;
  
    /* By their nature, local .got entries cannot be merged.  */
!   if ((total += alpha_elf_tdata (b)->local_got_size) > MAX_GOT_SIZE)
      return false;
  
    /* Failing the common trivial comparison, we must effectively
*************** elf64_alpha_can_merge_gots (a, b)
*** 2749,2758 ****
  	        continue;
  
  	      for (ae = h->got_entries; ae ; ae = ae->next)
! 	        if (ae->gotobj == a && ae->addend == be->addend)
  		  goto global_found;
  
! 	      if (++total > MAX_GOT_ENTRIES)
  	        return false;
  	    global_found:;
  	    }
--- 3039,3051 ----
  	        continue;
  
  	      for (ae = h->got_entries; ae ; ae = ae->next)
! 	        if (ae->gotobj == a
! 		    && ae->reloc_type == be->reloc_type
! 		    && ae->addend == be->addend)
  		  goto global_found;
  
! 	      total += alpha_got_entry_size (be->reloc_type);
! 	      if (total > MAX_GOT_SIZE)
  	        return false;
  	    global_found:;
  	    }
*************** static void
*** 2768,2781 ****
  elf64_alpha_merge_gots (a, b)
       bfd *a, *b;
  {
!   int total = alpha_elf_tdata (a)->total_got_entries;
    bfd *bsub;
  
    /* Remember local expansion.  */
    {
!     int e = alpha_elf_tdata (b)->n_local_got_entries;
      total += e;
!     alpha_elf_tdata (a)->n_local_got_entries += e;
    }
  
    for (bsub = b; bsub ; bsub = alpha_elf_tdata (bsub)->in_got_link_next)
--- 3061,3074 ----
  elf64_alpha_merge_gots (a, b)
       bfd *a, *b;
  {
!   int total = alpha_elf_tdata (a)->total_got_size;
    bfd *bsub;
  
    /* Remember local expansion.  */
    {
!     int e = alpha_elf_tdata (b)->local_got_size;
      total += e;
!     alpha_elf_tdata (a)->local_got_size += e;
    }
  
    for (bsub = b; bsub ; bsub = alpha_elf_tdata (bsub)->in_got_link_next)
*************** elf64_alpha_merge_gots (a, b)
*** 2825,2831 ****
  	        continue;
  
  	      for (ae = *start; ae ; ae = ae->next)
! 	        if (ae->gotobj == a && ae->addend == be->addend)
  		  {
  		    ae->flags |= be->flags;
  		    ae->use_count += be->use_count;
--- 3118,3126 ----
  	        continue;
  
  	      for (ae = *start; ae ; ae = ae->next)
! 	        if (ae->gotobj == a
! 		    && ae->reloc_type == be->reloc_type
! 		    && ae->addend == be->addend)
  		  {
  		    ae->flags |= be->flags;
  		    ae->use_count += be->use_count;
*************** elf64_alpha_merge_gots (a, b)
*** 2833,2839 ****
  		    goto global_found;
  		  }
  	      be->gotobj = a;
! 	      total += 1;
  
  	    global_found:;
  	    }
--- 3128,3134 ----
  		    goto global_found;
  		  }
  	      be->gotobj = a;
! 	      total += alpha_got_entry_size (be->reloc_type);
  
  	    global_found:;
  	    }
*************** elf64_alpha_merge_gots (a, b)
*** 2841,2847 ****
  
        alpha_elf_tdata (bsub)->gotobj = a;
      }
!   alpha_elf_tdata (a)->total_got_entries = total;
  
    /* Merge the two in_got chains.  */
    {
--- 3136,3142 ----
  
        alpha_elf_tdata (bsub)->gotobj = a;
      }
!   alpha_elf_tdata (a)->total_got_size = total;
  
    /* Merge the two in_got chains.  */
    {
*************** elf64_alpha_calc_got_offsets_for_symbol 
*** 2874,2880 ****
  	  = &alpha_elf_tdata (gotent->gotobj)->got->_raw_size;
  
  	gotent->got_offset = *plge;
! 	*plge += 8;
        }
  
    return true;
--- 3169,3175 ----
  	  = &alpha_elf_tdata (gotent->gotobj)->got->_raw_size;
  
  	gotent->got_offset = *plge;
! 	*plge += alpha_got_entry_size (gotent->reloc_type);
        }
  
    return true;
*************** elf64_alpha_calc_got_offsets (info)
*** 2916,2922 ****
  	      if (gotent->use_count > 0)
  	        {
  		  gotent->got_offset = got_offset;
! 		  got_offset += 8;
  	        }
  	}
  
--- 3211,3217 ----
  	      if (gotent->use_count > 0)
  	        {
  		  gotent->got_offset = got_offset;
! 		  got_offset += alpha_got_entry_size (gotent->reloc_type);
  	        }
  	}
  
*************** elf64_alpha_size_got_sections (output_bf
*** 2950,2962 ****
  	  /* We are assuming no merging has yet ocurred.  */
  	  BFD_ASSERT (this_got == i);
  
!           if (alpha_elf_tdata (this_got)->total_got_entries > MAX_GOT_ENTRIES)
  	    {
  	      /* Yikes! A single object file has too many entries.  */
  	      (*_bfd_error_handler)
  	        (_("%s: .got subsegment exceeds 64K (size %d)"),
  	         bfd_archive_filename (i),
! 	         alpha_elf_tdata (this_got)->total_got_entries * 8);
  	      return false;
  	    }
  
--- 3245,3257 ----
  	  /* We are assuming no merging has yet ocurred.  */
  	  BFD_ASSERT (this_got == i);
  
!           if (alpha_elf_tdata (this_got)->total_got_size > MAX_GOT_SIZE)
  	    {
  	      /* Yikes! A single object file has too many entries.  */
  	      (*_bfd_error_handler)
  	        (_("%s: .got subsegment exceeds 64K (size %d)"),
  	         bfd_archive_filename (i),
! 	         alpha_elf_tdata (this_got)->total_got_size);
  	      return false;
  	    }
  
*************** elf64_alpha_always_size_sections (output
*** 3037,3042 ****
--- 3332,3371 ----
    return true;
  }
  
+ /* The number of dynamic relocations required by a static relocation.  */
+ 
+ static int
+ alpha_dynamic_entries_for_reloc (r_type, dynamic, shared)
+      int r_type, dynamic, shared;
+ {
+   switch (r_type)
+     {
+     /* May appear in GOT entries.  */
+     case R_ALPHA_TLSGD:
+       return (dynamic ? 2 : shared ? 1 : 0);
+     case R_ALPHA_TLSLDM:
+       return shared;
+     case R_ALPHA_LITERAL:
+       return dynamic || shared;
+     case R_ALPHA_GOTDTPREL:
+     case R_ALPHA_GOTTPREL:
+       return dynamic;
+ 
+     /* May appear in data sections.  */
+     case R_ALPHA_REFLONG:
+     case R_ALPHA_REFQUAD:
+       return dynamic || shared;
+     case R_ALPHA_SREL64:
+     case R_ALPHA_TPREL64:
+       return dynamic;
+ 
+     /* Everything else is illegal.  We'll issue an error during
+        relocate_section.  */
+     default:
+       return 0;
+     }
+ }
+ 
  /* Work out the sizes of the dynamic relocation entries.  */
  
  static boolean
*************** elf64_alpha_calc_dynrel_sizes (h, info)
*** 3044,3049 ****
--- 3373,3383 ----
       struct alpha_elf_link_hash_entry *h;
       struct bfd_link_info *info;
  {
+   boolean dynamic;
+   struct alpha_elf_reloc_entry *relent;
+   struct alpha_elf_got_entry *gotent;
+   int entries;
+ 
    if (h->root.root.type == bfd_link_hash_warning)
      h = (struct alpha_elf_link_hash_entry *) h->root.root.u.i.link;
  
*************** elf64_alpha_calc_dynrel_sizes (h, info)
*** 3070,3110 ****
       natural form.  If this is a shared object, and it has been forced
       local, we'll need the same number of RELATIVE relocations.  */
  
!   if (alpha_elf_dynamic_symbol_p (&h->root, info) || info->shared)
!     {
!       struct alpha_elf_reloc_entry *relent;
!       bfd *dynobj;
!       struct alpha_elf_got_entry *gotent;
!       bfd_size_type count;
!       asection *srel;
! 
!       for (relent = h->reloc_entries; relent; relent = relent->next)
! 	if (relent->rtype == R_ALPHA_REFLONG
! 	    || relent->rtype == R_ALPHA_REFQUAD)
! 	  {
! 	    relent->srel->_raw_size +=
! 	      sizeof (Elf64_External_Rela) * relent->count;
! 	    if (relent->reltext)
! 	      info->flags |= DT_TEXTREL;
! 	  }
  
!       dynobj = elf_hash_table(info)->dynobj;
!       count = 0;
  
!       for (gotent = h->got_entries; gotent ; gotent = gotent->next)
! 	count++;
  
!       /* 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)
! 	count--;
  
!       if (count > 0)
! 	{
! 	  srel = bfd_get_section_by_name (dynobj, ".rela.got");
! 	  BFD_ASSERT (srel != NULL);
! 	  srel->_raw_size += sizeof (Elf64_External_Rela) * count;
! 	}
      }
  
    return true;
--- 3404,3440 ----
       natural form.  If this is a shared object, and it has been forced
       local, we'll need the same number of RELATIVE relocations.  */
  
!   dynamic = alpha_elf_dynamic_symbol_p (&h->root, info);
  
!   for (relent = h->reloc_entries; relent; relent = relent->next)
!     {
!       entries = alpha_dynamic_entries_for_reloc (relent->rtype, dynamic,
! 						 info->shared);
!       if (entries)
! 	{
! 	  relent->srel->_raw_size +=
! 	    entries * sizeof (Elf64_External_Rela) * relent->count;
! 	  if (relent->reltext)
! 	    info->flags |= DT_TEXTREL;
! 	}
!     }
  
!   entries = 0;
!   for (gotent = h->got_entries; gotent ; gotent = gotent->next)
!     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--;
  
!   if (entries > 0)
!     {
!       bfd *dynobj = elf_hash_table(info)->dynobj;
!       asection *srel = bfd_get_section_by_name (dynobj, ".rela.got");
!       BFD_ASSERT (srel != NULL);
!       srel->_raw_size += sizeof (Elf64_External_Rela) * entries;
      }
  
    return true;
*************** elf64_alpha_size_dynamic_sections (outpu
*** 3126,3131 ****
--- 3456,3464 ----
  
    if (elf_hash_table (info)->dynamic_sections_created)
      {
+       int entries;
+       bfd *i;
+ 
        /* Set the contents of the .interp section to the interpreter.  */
        if (!info->shared)
  	{
*************** elf64_alpha_size_dynamic_sections (outpu
*** 3143,3165 ****
  				    elf64_alpha_calc_dynrel_sizes,
  				    info);
  
!       /* When building shared libraries, each local .got entry needs a
! 	 RELATIVE reloc.  */
!       if (info->shared)
  	{
! 	  bfd *i;
! 	  asection *srel;
! 	  bfd_size_type count;
  
! 	  srel = bfd_get_section_by_name (dynobj, ".rela.got");
! 	  BFD_ASSERT (srel != NULL);
  
! 	  for (i = alpha_elf_hash_table(info)->got_list, count = 0;
! 	       i != NULL;
! 	       i = alpha_elf_tdata(i)->got_link_next)
! 	    count += alpha_elf_tdata(i)->n_local_got_entries;
  
! 	  srel->_raw_size += count * sizeof (Elf64_External_Rela);
  	}
      }
    /* else we're not dynamic and by definition we don't need such things.  */
--- 3476,3513 ----
  				    elf64_alpha_calc_dynrel_sizes,
  				    info);
  
!       /* Shared libraries often require RELATIVE relocs, and some relocs
! 	 require attention for the main application as well.  */
! 	 
!       entries = 0;
!       for (i = alpha_elf_hash_table(info)->got_list;
! 	   i ; i = alpha_elf_tdata(i)->got_link_next)
  	{
! 	  bfd *j;
  
! 	  for (j = i; j ; j = alpha_elf_tdata(j)->in_got_link_next)
! 	    {
! 	      struct alpha_elf_got_entry **local_got_entries, *gotent;
! 	      int k, n;
  
! 	      local_got_entries = alpha_elf_tdata(j)->local_got_entries;
! 	      if (!local_got_entries)
! 		continue;
  
! 	      for (k = 0, n = elf_tdata(j)->symtab_hdr.sh_info; k < n; ++k)
! 		for (gotent = local_got_entries[k];
! 		     gotent ; gotent = gotent->next)
! 		  if (gotent->use_count > 0)
! 		    entries += (alpha_dynamic_entries_for_reloc
! 				(gotent->reloc_type, 0, info->shared));
! 	    }
! 	}
! 
!       if (entries > 0)
! 	{
! 	  s = bfd_get_section_by_name (dynobj, ".rela.got");
! 	  BFD_ASSERT (s != NULL);
! 	  s->_raw_size += sizeof (Elf64_External_Rela) * entries;
  	}
      }
    /* else we're not dynamic and by definition we don't need such things.  */
*************** elf64_alpha_relocate_section (output_bfd
*** 3278,3337 ****
       Elf_Internal_Sym *local_syms;
       asection **local_sections;
  {
!   Elf_Internal_Shdr *symtab_hdr;
    Elf_Internal_Rela *rel;
    Elf_Internal_Rela *relend;
!   asection *sec, *sgot, *srel, *srelgot;
!   bfd *dynobj, *gotobj;
!   bfd_vma gp;
    boolean ret_val = true;
  
!   srelgot = srel = NULL;
!   symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
!   dynobj = elf_hash_table (info)->dynobj;
!   if (dynobj)
      {
!       srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
!     }
  
!   /* Find the gp value for this input bfd.  */
!   sgot = NULL;
!   gp = 0;
!   gotobj = alpha_elf_tdata (input_bfd)->gotobj;
!   if (gotobj)
!     {
!       sgot = alpha_elf_tdata (gotobj)->got;
!       gp = _bfd_get_gp_value (gotobj);
!       if (gp == 0)
  	{
! 	  gp = (sgot->output_section->vma
! 		+ sgot->output_offset
! 		+ 0x8000);
! 	  _bfd_set_gp_value (gotobj, gp);
! 	}
      }
  
    rel = relocs;
    relend = relocs + input_section->reloc_count;
    for (; rel < relend; rel++)
      {
!       int r_type;
        reloc_howto_type *howto;
        unsigned long r_symndx;
-       struct alpha_elf_link_hash_entry *h;
        Elf_Internal_Sym *sym;
!       bfd_vma relocation;
        bfd_vma addend;
!       bfd_reloc_status_type r;
  
        r_type = ELF64_R_TYPE(rel->r_info);
!       if (r_type < 0 || r_type >= (int) R_ALPHA_max)
  	{
  	  bfd_set_error (bfd_error_bad_value);
! 	  return false;
  	}
-       howto = elf64_alpha_howto_table + r_type;
  
        r_symndx = ELF64_R_SYM(rel->r_info);
  
        if (info->relocateable)
--- 3626,3710 ----
       Elf_Internal_Sym *local_syms;
       asection **local_sections;
  {
!   Elf_Internal_Shdr *symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
    Elf_Internal_Rela *rel;
    Elf_Internal_Rela *relend;
!   struct elf_link_tls_segment *tls_segment = NULL;
!   asection *sgot = NULL, *srel = NULL, *srelgot = NULL;
!   bfd *dynobj = NULL, *gotobj = NULL;
!   bfd_vma gp = 0, tp_base = 0, dtp_base = 0;
    boolean ret_val = true;
  
!   if (!info->relocateable)
      {
!       const char *name;
  
!       dynobj = elf_hash_table (info)->dynobj;
!       if (dynobj)
!         srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
! 
!       name = (bfd_elf_string_from_elf_section
! 	      (input_bfd, elf_elfheader(input_bfd)->e_shstrndx,
! 	       elf_section_data(input_section)->rel_hdr.sh_name));
!       BFD_ASSERT(name != NULL);
!       srel = bfd_get_section_by_name (dynobj, name);
! 
!       /* Find the gp value for this input bfd.  */
!       gotobj = alpha_elf_tdata (input_bfd)->gotobj;
!       if (gotobj)
  	{
! 	  sgot = alpha_elf_tdata (gotobj)->got;
! 	  gp = _bfd_get_gp_value (gotobj);
! 	  if (gp == 0)
! 	    {
! 	      gp = (sgot->output_section->vma
! 		    + sgot->output_offset
! 		    + 0x8000);
! 	      _bfd_set_gp_value (gotobj, gp);
! 	    }
!         }
! 
!       tls_segment = elf_hash_table (info)->tls_segment;
!       if (tls_segment)
!         {
!           /* This is PT_TLS segment p_vaddr.  */
!           dtp_base = tls_segment->start;
! 
!           /* Main program TLS (whose template starts at PT_TLS p_vaddr)
! 	     is assigned offset round(16, PT_TLS p_align).  */
!           tp_base = dtp_base - align_power (16, tls_segment->align);
!         }
      }
  
    rel = relocs;
    relend = relocs + input_section->reloc_count;
    for (; rel < relend; rel++)
      {
!       struct alpha_elf_link_hash_entry *h;
!       struct alpha_elf_got_entry *gotent;
!       bfd_reloc_status_type r;
        reloc_howto_type *howto;
        unsigned long r_symndx;
        Elf_Internal_Sym *sym;
!       asection *sec;
!       bfd_vma value;
        bfd_vma addend;
!       boolean dynamic_symbol_p;
!       boolean undef_weak_ref;
!       unsigned long r_type;
  
        r_type = ELF64_R_TYPE(rel->r_info);
!       if (r_type >= R_ALPHA_max)
  	{
+ 	  (*_bfd_error_handler)
+ 	    (_("%s: unknown relocation type %d"),
+ 	     bfd_archive_filename (input_bfd), (int)r_type);
  	  bfd_set_error (bfd_error_bad_value);
! 	  ret_val = false;
! 	  continue;
  	}
  
+       howto = elf64_alpha_howto_table + r_type;
        r_symndx = ELF64_R_SYM(rel->r_info);
  
        if (info->relocateable)
*************** elf64_alpha_relocate_section (output_bfd
*** 3364,3375 ****
        h = NULL;
        sym = NULL;
        sec = NULL;
  
        if (r_symndx < symtab_hdr->sh_info)
  	{
  	  sym = local_syms + r_symndx;
  	  sec = local_sections[r_symndx];
! 	  relocation = _bfd_elf_rela_local_sym (output_bfd, sym, sec, rel);
  	}
        else
  	{
--- 3737,3784 ----
        h = NULL;
        sym = NULL;
        sec = NULL;
+       undef_weak_ref = false;
  
        if (r_symndx < symtab_hdr->sh_info)
  	{
  	  sym = local_syms + r_symndx;
  	  sec = local_sections[r_symndx];
! 	  value = _bfd_elf_rela_local_sym (output_bfd, sym, sec, rel);
! 
! 	  gotent = alpha_elf_tdata(input_bfd)->local_got_entries[r_symndx];
! 
! 	  /* Need to adjust local GOT entries' addends for SEC_MERGE
! 	     unless it has been done already.  */
! 	  if ((sec->flags & SEC_MERGE)
! 	       && ELF_ST_TYPE (sym->st_info) == STT_SECTION
! 	       && (elf_section_data (sec)->sec_info_type
! 		   == ELF_INFO_TYPE_MERGE)
! 	       && !gotent->reloc_xlated)
! 	    {
! 	      struct alpha_elf_got_entry *ent;
! 	      asection *msec;
! 
! 	      for (ent = gotent; ent; ent = ent->next)
! 		{
! 		  ent->reloc_xlated = 1;
! 		  if (ent->use_count == 0)
! 		    continue;
! 		  msec = sec;
! 		  ent->addend =
! 		    _bfd_merged_section_offset (output_bfd, &msec,
! 						elf_section_data (sec)->
! 						  sec_info,
! 						sym->st_value + ent->addend,
! 						(bfd_vma) 0);
! 		  ent->addend -= sym->st_value;
! 		  ent->addend += msec->output_section->vma
! 				 + msec->output_offset
! 				 - sec->output_section->vma
! 				 - sec->output_offset;
! 		}
! 	    }
! 
! 	  dynamic_symbol_p = false;
  	}
        else
  	{
*************** elf64_alpha_relocate_section (output_bfd
*** 3379,3405 ****
  		 || h->root.root.type == bfd_link_hash_warning)
  	    h = (struct alpha_elf_link_hash_entry *)h->root.root.u.i.link;
  
  	  if (h->root.root.type == bfd_link_hash_defined
  	      || h->root.root.type == bfd_link_hash_defweak)
  	    {
  	      sec = h->root.root.u.def.section;
  
! 	      if (sec->output_section == NULL)
! 		relocation = 0;
! 	      else
! 		{
! 		  relocation = (h->root.root.u.def.value
! 				+ sec->output_section->vma
! 				+ sec->output_offset);
! 		}
  	    }
  	  else if (h->root.root.type == bfd_link_hash_undefweak)
! 	    relocation = 0;
  	  else if (info->shared
  		   && (!info->symbolic || info->allow_shlib_undefined)
  		   && !info->no_undefined
  		   && ELF_ST_VISIBILITY (h->root.other) == STV_DEFAULT)
! 	    relocation = 0;
  	  else
  	    {
  	      if (!((*info->callbacks->undefined_symbol)
--- 3788,3819 ----
  		 || h->root.root.type == bfd_link_hash_warning)
  	    h = (struct alpha_elf_link_hash_entry *)h->root.root.u.i.link;
  
+ 	  value = 0;
  	  if (h->root.root.type == bfd_link_hash_defined
  	      || h->root.root.type == bfd_link_hash_defweak)
  	    {
  	      sec = h->root.root.u.def.section;
  
! 	      /* Detect the cases that sym_sec->output_section is
! 		 expected to be NULL -- all cases in which the symbol
! 		 is defined in another shared module.  This includes
! 		 PLT relocs for which we've created a PLT entry and
! 		 other relocs for which we're prepared to create
! 		 dynamic relocations.  */
! 	      /* ??? Just accept it NULL and continue.  */
! 
! 	      if (sec->output_section != NULL)
! 		value = (h->root.root.u.def.value
! 			 + sec->output_section->vma
! 			      + sec->output_offset);
  	    }
  	  else if (h->root.root.type == bfd_link_hash_undefweak)
! 	    undef_weak_ref = true;
  	  else if (info->shared
  		   && (!info->symbolic || info->allow_shlib_undefined)
  		   && !info->no_undefined
  		   && ELF_ST_VISIBILITY (h->root.other) == STV_DEFAULT)
! 	    ;
  	  else
  	    {
  	      if (!((*info->callbacks->undefined_symbol)
*************** elf64_alpha_relocate_section (output_bfd
*** 3407,3417 ****
  		     input_section, rel->r_offset,
  		     (!info->shared || info->no_undefined
  		      || ELF_ST_VISIBILITY (h->root.other)))))
! 		ret_val = false;
! 	      relocation = 0;
  	    }
  	}
        addend = rel->r_addend;
  
        switch (r_type)
  	{
--- 3821,3844 ----
  		     input_section, rel->r_offset,
  		     (!info->shared || info->no_undefined
  		      || ELF_ST_VISIBILITY (h->root.other)))))
! 		return false;
! 	      ret_val = false;
! 	      continue;
  	    }
+ 
+           dynamic_symbol_p = alpha_elf_dynamic_symbol_p (&h->root, info);
+ 	  gotent = h->got_entries;
  	}
+ 
        addend = rel->r_addend;
+       value += addend;
+ 
+       /* Search for the proper got entry.  */
+       for (; gotent ; gotent = gotent->next)
+ 	if (gotent->gotobj == gotobj
+ 	    && gotent->reloc_type == r_type
+ 	    && gotent->addend == addend)
+ 	  break;
  
        switch (r_type)
  	{
*************** elf64_alpha_relocate_section (output_bfd
*** 3421,3544 ****
  
  	    BFD_ASSERT(gp != 0);
  
! 	    relocation = (input_section->output_section->vma
! 			  + input_section->output_offset
! 			  + rel->r_offset);
  
! 	    p_ldah = contents + rel->r_offset - input_section->vma;
  	    p_lda = p_ldah + rel->r_addend;
  
! 	    r = elf64_alpha_do_reloc_gpdisp (input_bfd, gp - relocation,
  					     p_ldah, p_lda);
  	  }
  	  break;
  
  	case R_ALPHA_LITERAL:
! 	  {
! 	    struct alpha_elf_got_entry *gotent;
! 	    boolean dynamic_symbol;
! 
! 	    BFD_ASSERT(sgot != NULL);
! 	    BFD_ASSERT(gp != 0);
! 
! 	    if (h != NULL)
! 	      {
! 		gotent = h->got_entries;
! 		dynamic_symbol = alpha_elf_dynamic_symbol_p (&h->root, info);
! 	      }
! 	    else
! 	      {
! 		gotent = (alpha_elf_tdata(input_bfd)->
! 			  local_got_entries[r_symndx]);
! 		dynamic_symbol = false;
! 
! 		/* Need to adjust local GOT entries' addends for SEC_MERGE
! 		   unless it has been done already.  */
! 		if ((sec->flags & SEC_MERGE)
! 		    && ELF_ST_TYPE (sym->st_info) == STT_SECTION
! 		    && (elf_section_data (sec)->sec_info_type
! 			== ELF_INFO_TYPE_MERGE)
! 		    && (gotent->flags & ALPHA_ELF_GOT_ENTRY_RELOCS_XLATED) == 0)
! 		  {
! 		    struct alpha_elf_got_entry *ent;
! 		    asection *msec;
! 
! 		    for (ent = gotent; ent; ent = ent->next)
! 		      {
! 			ent->flags |= ALPHA_ELF_GOT_ENTRY_RELOCS_XLATED;
! 			if (ent->use_count == 0)
! 			  continue;
! 			msec = sec;
! 			ent->addend =
! 			  _bfd_merged_section_offset (output_bfd, &msec,
! 						      elf_section_data (sec)->
! 						      sec_info,
! 						      sym->st_value
! 						      + ent->addend,
! 						      (bfd_vma) 0);
! 			ent->addend -= sym->st_value;
! 			ent->addend += msec->output_section->vma
! 				       + msec->output_offset
! 				       - sec->output_section->vma
! 				       - sec->output_offset;
! 		      }
! 		  }
! 	      }
! 
! 	    BFD_ASSERT(gotent != NULL);
! 
! 	    while (gotent->gotobj != gotobj || gotent->addend != addend)
! 	      gotent = gotent->next;
! 
! 	    BFD_ASSERT(gotent->use_count >= 1);
  
! 	    /* Initialize the .got entry's value.  */
! 	    if (!(gotent->flags & ALPHA_ELF_GOT_ENTRY_RELOCS_DONE))
! 	      {
! 		bfd_put_64 (output_bfd, relocation + addend,
! 			    sgot->contents + gotent->got_offset);
  
! 		/* If the symbol has been forced local, output a
! 		   RELATIVE reloc, otherwise it will be handled in
! 		   finish_dynamic_symbol.  */
! 		if (info->shared && !dynamic_symbol)
! 		  {
! 		    Elf_Internal_Rela outrel;
  
! 		    BFD_ASSERT(srelgot != NULL);
  
! 		    outrel.r_offset = (sgot->output_section->vma
! 				       + sgot->output_offset
! 				       + gotent->got_offset);
! 		    outrel.r_info = ELF64_R_INFO(0, R_ALPHA_RELATIVE);
! 		    outrel.r_addend = relocation + addend;
  
! 		    bfd_elf64_swap_reloca_out (output_bfd, &outrel,
! 					       ((Elf64_External_Rela *)
! 					        srelgot->contents)
! 					       + srelgot->reloc_count++);
! 		    BFD_ASSERT (sizeof (Elf64_External_Rela)
! 				* srelgot->reloc_count
! 				<= srelgot->_cooked_size);
! 		  }
  
! 		gotent->flags |= ALPHA_ELF_GOT_ENTRY_RELOCS_DONE;
! 	      }
  
! 	    /* Figure the gprel relocation.  */
! 	    addend = 0;
! 	    relocation = (sgot->output_section->vma
! 			  + sgot->output_offset
! 			  + gotent->got_offset);
! 	    relocation -= gp;
! 	  }
! 	  /* overflow handled by _bfd_final_link_relocate */
  	  goto default_reloc;
  
  	case R_ALPHA_GPREL16:
  	case R_ALPHA_GPREL32:
  	case R_ALPHA_GPRELLOW:
! 	  if (h && alpha_elf_dynamic_symbol_p (&h->root, info))
              {
                (*_bfd_error_handler)
                  (_("%s: gp-relative relocation against dynamic symbol %s"),
--- 3848,3913 ----
  
  	    BFD_ASSERT(gp != 0);
  
! 	    value = (input_section->output_section->vma
! 		     + input_section->output_offset
! 		     + rel->r_offset);
  
! 	    p_ldah = contents + rel->r_offset;
  	    p_lda = p_ldah + rel->r_addend;
  
! 	    r = elf64_alpha_do_reloc_gpdisp (input_bfd, gp - value,
  					     p_ldah, p_lda);
  	  }
  	  break;
  
  	case R_ALPHA_LITERAL:
! 	  BFD_ASSERT(sgot != NULL);
! 	  BFD_ASSERT(gp != 0);
! 	  BFD_ASSERT(gotent != NULL);
! 	  BFD_ASSERT(gotent->use_count >= 1);
  
! 	  if (!gotent->reloc_done)
! 	    {
! 	      gotent->reloc_done = 1;
  
! 	      bfd_put_64 (output_bfd, value,
! 			  sgot->contents + gotent->got_offset);
  
! 	      /* If the symbol has been forced local, output a
! 		 RELATIVE reloc, otherwise it will be handled in
! 		 finish_dynamic_symbol.  */
! 	      if (info->shared && !dynamic_symbol_p)
! 		{
! 		  Elf_Internal_Rela outrel;
  
! 		  BFD_ASSERT(srelgot != NULL);
  
! 		  outrel.r_offset = (sgot->output_section->vma
! 				     + sgot->output_offset
! 				     + gotent->got_offset);
! 		  outrel.r_info = ELF64_R_INFO (0, R_ALPHA_RELATIVE);
! 		  outrel.r_addend = value;
  
! 		  bfd_elf64_swap_reloca_out (output_bfd, &outrel,
! 					     ((Elf64_External_Rela *)
! 					      srelgot->contents)
! 					     + srelgot->reloc_count++);
! 		  BFD_ASSERT (sizeof (Elf64_External_Rela)
! 			      * srelgot->reloc_count
! 			      <= srelgot->_cooked_size);
! 		}
! 	    }
  
! 	  value = (sgot->output_section->vma
! 		   + sgot->output_offset
! 		   + gotent->got_offset);
! 	  value -= gp;
  	  goto default_reloc;
  
  	case R_ALPHA_GPREL16:
  	case R_ALPHA_GPREL32:
  	case R_ALPHA_GPRELLOW:
! 	  if (dynamic_symbol_p)
              {
                (*_bfd_error_handler)
                  (_("%s: gp-relative relocation against dynamic symbol %s"),
*************** elf64_alpha_relocate_section (output_bfd
*** 3546,3556 ****
                ret_val = false;
              }
  	  BFD_ASSERT(gp != 0);
! 	  relocation -= gp;
  	  goto default_reloc;
  
  	case R_ALPHA_GPRELHIGH:
! 	  if (h && alpha_elf_dynamic_symbol_p (&h->root, info))
              {
                (*_bfd_error_handler)
                  (_("%s: gp-relative relocation against dynamic symbol %s"),
--- 3915,3925 ----
                ret_val = false;
              }
  	  BFD_ASSERT(gp != 0);
! 	  value -= gp;
  	  goto default_reloc;
  
  	case R_ALPHA_GPRELHIGH:
! 	  if (dynamic_symbol_p)
              {
                (*_bfd_error_handler)
                  (_("%s: gp-relative relocation against dynamic symbol %s"),
*************** elf64_alpha_relocate_section (output_bfd
*** 3558,3584 ****
                ret_val = false;
              }
  	  BFD_ASSERT(gp != 0);
! 	  relocation -= gp;
! 	  relocation += addend;
! 	  addend = 0;
! 	  relocation = (((bfd_signed_vma) relocation >> 16)
! 			+ ((relocation >> 15) & 1));
  	  goto default_reloc;
  
  	case R_ALPHA_HINT:
  	  /* A call to a dynamic symbol is definitely out of range of
  	     the 16-bit displacement.  Don't bother writing anything.  */
! 	  if (h && alpha_elf_dynamic_symbol_p (&h->root, info))
  	    {
  	      r = bfd_reloc_ok;
  	      break;
  	    }
! 	  /* FALLTHRU */
  
  	case R_ALPHA_BRADDR:
  	  /* The regular PC-relative stuff measures from the start of
  	     the instruction rather than the end.  */
! 	  addend -= 4;
  	  goto default_reloc;
  
  	case R_ALPHA_BRSGP:
--- 3927,3960 ----
                ret_val = false;
              }
  	  BFD_ASSERT(gp != 0);
! 	  value -= gp;
! 	  value = ((bfd_signed_vma) value >> 16) + ((value >> 15) & 1);
  	  goto default_reloc;
  
  	case R_ALPHA_HINT:
  	  /* A call to a dynamic symbol is definitely out of range of
  	     the 16-bit displacement.  Don't bother writing anything.  */
! 	  if (dynamic_symbol_p)
  	    {
  	      r = bfd_reloc_ok;
  	      break;
  	    }
! 	  /* The regular PC-relative stuff measures from the start of
! 	     the instruction rather than the end.  */
! 	  value -= 4;
! 	  goto default_reloc;
  
  	case R_ALPHA_BRADDR:
+ 	  if (dynamic_symbol_p)
+             {
+               (*_bfd_error_handler)
+                 (_("%s: pc-relative relocation against dynamic symbol %s"),
+                  bfd_archive_filename (input_bfd), h->root.root.root.string);
+               ret_val = false;
+             }
  	  /* The regular PC-relative stuff measures from the start of
  	     the instruction rather than the end.  */
! 	  value -= 4;
  	  goto default_reloc;
  
  	case R_ALPHA_BRSGP:
*************** elf64_alpha_relocate_section (output_bfd
*** 3588,3594 ****
  
  	    /* The regular PC-relative stuff measures from the start of
  	       the instruction rather than the end.  */
! 	    addend -= 4;
  
  	    /* The source and destination gp must be the same.  Note that
  	       the source will always have an assigned gp, since we forced
--- 3964,3970 ----
  
  	    /* The regular PC-relative stuff measures from the start of
  	       the instruction rather than the end.  */
! 	    value -= 4;
  
  	    /* The source and destination gp must be the same.  Note that
  	       the source will always have an assigned gp, since we forced
*************** elf64_alpha_relocate_section (output_bfd
*** 3641,3681 ****
  
  	case R_ALPHA_REFLONG:
  	case R_ALPHA_REFQUAD:
  	  {
  	    Elf_Internal_Rela outrel;
  
  	    /* Careful here to remember RELATIVE relocations for global
  	       variables for symbolic shared objects.  */
  
! 	    if (h && alpha_elf_dynamic_symbol_p (&h->root, info))
  	      {
  		BFD_ASSERT(h->root.dynindx != -1);
! 		outrel.r_info = ELF64_R_INFO(h->root.dynindx, r_type);
  		outrel.r_addend = addend;
! 		addend = 0, relocation = 0;
  	      }
  	    else if (info->shared
  		     && r_symndx != 0
  		     && (input_section->flags & SEC_ALLOC))
  	      {
! 		outrel.r_info = ELF64_R_INFO(0, R_ALPHA_RELATIVE);
! 		outrel.r_addend = relocation + addend;
  	      }
  	    else
  	      goto default_reloc;
  
! 	    if (!srel)
! 	      {
! 		const char *name;
! 
! 		name = (bfd_elf_string_from_elf_section
! 			(input_bfd, elf_elfheader(input_bfd)->e_shstrndx,
! 			 elf_section_data(input_section)->rel_hdr.sh_name));
! 		BFD_ASSERT(name != NULL);
! 
! 		srel = bfd_get_section_by_name (dynobj, name);
! 		BFD_ASSERT(srel != NULL);
! 	      }
  
  	    outrel.r_offset =
  	      _bfd_elf_section_offset (output_bfd, info, input_section,
--- 4017,4068 ----
  
  	case R_ALPHA_REFLONG:
  	case R_ALPHA_REFQUAD:
+ 	case R_ALPHA_DTPREL64:
+ 	case R_ALPHA_TPREL64:
  	  {
  	    Elf_Internal_Rela outrel;
  
  	    /* Careful here to remember RELATIVE relocations for global
  	       variables for symbolic shared objects.  */
  
! 	    if (dynamic_symbol_p)
  	      {
  		BFD_ASSERT(h->root.dynindx != -1);
! 		outrel.r_info = ELF64_R_INFO (h->root.dynindx, r_type);
  		outrel.r_addend = addend;
! 		addend = 0, value = 0;
! 	      }
! 	    else if (r_type == R_ALPHA_DTPREL64)
! 	      {
! 		BFD_ASSERT(tls_segment != NULL);
! 		value -= dtp_base;
! 		goto default_reloc;
! 	      }
! 	    else if (r_type == R_ALPHA_TPREL64)
! 	      {
! 		BFD_ASSERT(tls_segment != NULL);
! 		value -= dtp_base;
! 		goto default_reloc;
  	      }
  	    else if (info->shared
  		     && r_symndx != 0
  		     && (input_section->flags & SEC_ALLOC))
  	      {
! 		if (r_type == R_ALPHA_REFLONG)
! 		  {
! 		    (*_bfd_error_handler)
! 		      (_("%s: unhandled dynamic relocation against %s"),
! 		       bfd_archive_filename (input_bfd),
! 		       h->root.root.root.string);
! 		    ret_val = false;
! 		  }
! 		outrel.r_info = ELF64_R_INFO (0, R_ALPHA_RELATIVE);
! 		outrel.r_addend = value;
  	      }
  	    else
  	      goto default_reloc;
  
! 	    BFD_ASSERT(srel != NULL);
  
  	    outrel.r_offset =
  	      _bfd_elf_section_offset (output_bfd, info, input_section,
*************** elf64_alpha_relocate_section (output_bfd
*** 3695,3702 ****
--- 4082,4098 ----
  	  }
  	  goto default_reloc;
  
+ 	case R_ALPHA_SREL16:
  	case R_ALPHA_SREL32:
  	case R_ALPHA_SREL64:
+ 	  if (dynamic_symbol_p)
+             {
+               (*_bfd_error_handler)
+                 (_("%s: pc-relative relocation against dynamic symbol %s"),
+                  bfd_archive_filename (input_bfd), h->root.root.root.string);
+               ret_val = false;
+             }
+ 
  	  /* ??? .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.  */
*************** elf64_alpha_relocate_section (output_bfd
*** 3705,3715 ****
  		     + (r_type - R_ALPHA_SREL32 + R_ALPHA_REFLONG));
  	  goto default_reloc;
  
  	default:
  	default_reloc:
  	  r = _bfd_final_link_relocate (howto, input_bfd, input_section,
! 					contents, rel->r_offset, relocation,
! 					addend);
  	  break;
  	}
  
--- 4101,4223 ----
  		     + (r_type - R_ALPHA_SREL32 + R_ALPHA_REFLONG));
  	  goto default_reloc;
  
+ 	case R_ALPHA_TLSLDM:
+ 	  /* Ignore the symbol for the relocation.  The result is always
+ 	     the current module.  */
+ 	  dynamic_symbol_p = 0;
+ 	  /* FALLTHRU */
+ 
+ 	case R_ALPHA_TLSGD:
+ 	  if (!gotent->reloc_done)
+ 	    {
+ 	      gotent->reloc_done = 1;
+ 
+ 	      /* Note that the module index for the main program is 1.  */
+ 	      bfd_put_64 (output_bfd, !info->shared && !dynamic_symbol_p,
+ 			  sgot->contents + gotent->got_offset);
+ 
+ 	      /* If the symbol has been forced local, output a
+ 		 DTPMOD64 reloc, otherwise it will be handled in
+ 		 finish_dynamic_symbol.  */
+ 	      if (info->shared && !dynamic_symbol_p)
+ 		{
+ 		  Elf_Internal_Rela outrel;
+ 
+ 		  BFD_ASSERT(srelgot != NULL);
+ 
+ 		  outrel.r_offset = (sgot->output_section->vma
+ 				     + sgot->output_offset
+ 				     + gotent->got_offset);
+ 		  /* ??? Proper dynindx here.  */
+ 		  outrel.r_info = ELF64_R_INFO (0, R_ALPHA_DTPMOD64);
+ 		  outrel.r_addend = 0;
+ 
+ 		  bfd_elf64_swap_reloca_out (output_bfd, &outrel,
+ 					     ((Elf64_External_Rela *)
+ 					      srelgot->contents)
+ 					     + srelgot->reloc_count++);
+ 		  BFD_ASSERT (sizeof (Elf64_External_Rela)
+ 			      * srelgot->reloc_count
+ 			      <= srelgot->_cooked_size);
+ 		}
+ 
+ 	      if (dynamic_symbol_p || r_type == R_ALPHA_TLSLDM)
+ 		value = 0;
+ 	      else
+ 		{
+ 		  BFD_ASSERT(tls_segment != NULL);
+ 	          value -= dtp_base;
+ 		}
+ 	      bfd_put_64 (output_bfd, value,
+ 			  sgot->contents + gotent->got_offset + 8);
+ 	    }
+ 
+ 	  value = (sgot->output_section->vma
+ 		   + sgot->output_offset
+ 		   + gotent->got_offset);
+ 	  value -= gp;
+ 	  goto default_reloc;
+ 
+ 	case R_ALPHA_DTPRELHI:
+ 	case R_ALPHA_DTPRELLO:
+ 	case R_ALPHA_DTPREL16:
+ 	  if (dynamic_symbol_p)
+             {
+               (*_bfd_error_handler)
+                 (_("%s: dtp-relative relocation against dynamic symbol %s"),
+                  bfd_archive_filename (input_bfd), h->root.root.root.string);
+               ret_val = false;
+             }
+ 	  BFD_ASSERT(tls_segment != NULL);
+ 	  value -= dtp_base;
+ 	  goto default_reloc;
+ 
+ 	case R_ALPHA_TPRELHI:
+ 	case R_ALPHA_TPRELLO:
+ 	case R_ALPHA_TPREL16:
+ 	  if (dynamic_symbol_p)
+             {
+               (*_bfd_error_handler)
+                 (_("%s: tp-relative relocation against dynamic symbol %s"),
+                  bfd_archive_filename (input_bfd), h->root.root.root.string);
+               ret_val = false;
+             }
+ 	  BFD_ASSERT(tls_segment != NULL);
+ 	  value -= tp_base;
+ 	  goto default_reloc;
+ 
+ 	case R_ALPHA_GOTDTPREL:
+ 	case R_ALPHA_GOTTPREL:
+ 	  BFD_ASSERT(sgot != NULL);
+ 	  BFD_ASSERT(gp != 0);
+ 	  BFD_ASSERT(gotent != NULL);
+ 	  BFD_ASSERT(gotent->use_count >= 1);
+ 
+ 	  if (!gotent->reloc_done)
+ 	    {
+ 	      gotent->reloc_done = 1;
+ 
+ 	      if (dynamic_symbol_p)
+ 		value = 0;
+ 	      else
+ 		{
+ 		  BFD_ASSERT(tls_segment != NULL);
+ 		  value -= (r_type == R_ALPHA_GOTDTPREL ? dtp_base : tp_base);
+ 		}
+ 	      bfd_put_64 (output_bfd, value,
+ 			  sgot->contents + gotent->got_offset);
+ 	    }
+ 
+ 	  value = (sgot->output_section->vma
+ 		   + sgot->output_offset
+ 		   + gotent->got_offset);
+ 	  value -= gp;
+ 	  goto default_reloc;
+ 
  	default:
  	default_reloc:
  	  r = _bfd_final_link_relocate (howto, input_bfd, input_section,
! 					contents, rel->r_offset, value, 0);
  	  break;
  	}
  
*************** elf64_alpha_finish_dynamic_symbol (outpu
*** 3881,3900 ****
        srel = bfd_get_section_by_name (dynobj, ".rela.got");
        BFD_ASSERT (srel != NULL);
  
-       outrel.r_info = ELF64_R_INFO (h->dynindx, R_ALPHA_GLOB_DAT);
        for (gotent = ((struct alpha_elf_link_hash_entry *) h)->got_entries;
  	   gotent != NULL;
  	   gotent = gotent->next)
  	{
  	  asection *sgot = alpha_elf_tdata (gotent->gotobj)->got;
  	  outrel.r_offset = (sgot->output_section->vma
  			     + sgot->output_offset
  			     + gotent->got_offset);
  	  outrel.r_addend = gotent->addend;
  
  	  bfd_elf64_swap_reloca_out (output_bfd, &outrel,
  				     ((Elf64_External_Rela *)srel->contents
  				      + srel->reloc_count++));
  	  BFD_ASSERT (sizeof (Elf64_External_Rela) * srel->reloc_count
  		      <= srel->_cooked_size);
  	}
--- 4389,4442 ----
        srel = bfd_get_section_by_name (dynobj, ".rela.got");
        BFD_ASSERT (srel != NULL);
  
        for (gotent = ((struct alpha_elf_link_hash_entry *) h)->got_entries;
  	   gotent != NULL;
  	   gotent = gotent->next)
  	{
  	  asection *sgot = alpha_elf_tdata (gotent->gotobj)->got;
+ 	  int r_type;
+ 
  	  outrel.r_offset = (sgot->output_section->vma
  			     + sgot->output_offset
  			     + gotent->got_offset);
+ 
+ 	  r_type = gotent->reloc_type;
+ 	  switch (r_type)
+ 	    {
+ 	    case R_ALPHA_LITERAL:
+ 	      r_type = R_ALPHA_GLOB_DAT;
+ 	      break;
+ 	    case R_ALPHA_TLSGD:
+ 	      r_type = R_ALPHA_DTPMOD64;
+ 	      break;
+ 	    case R_ALPHA_GOTDTPREL:
+ 	      r_type = R_ALPHA_DTPREL64;
+ 	      break;
+ 	    case R_ALPHA_GOTTPREL:
+ 	      r_type = R_ALPHA_TPREL64;
+ 	      break;
+ 	    case R_ALPHA_TLSLDM:
+ 	    default:
+ 	      abort ();
+ 	    }
+ 
+ 	  outrel.r_info = ELF64_R_INFO (h->dynindx, r_type);
  	  outrel.r_addend = gotent->addend;
  
  	  bfd_elf64_swap_reloca_out (output_bfd, &outrel,
  				     ((Elf64_External_Rela *)srel->contents
  				      + srel->reloc_count++));
+ 
+ 	  if (gotent->reloc_type == R_ALPHA_TLSGD)
+ 	    {
+ 	      outrel.r_offset += 8;
+ 	      outrel.r_info = ELF64_R_INFO (h->dynindx, R_ALPHA_DTPREL64);
+ 
+ 	      bfd_elf64_swap_reloca_out (output_bfd, &outrel,
+ 				         ((Elf64_External_Rela *)srel->contents
+ 				          + srel->reloc_count++));
+ 	    }
+ 
  	  BFD_ASSERT (sizeof (Elf64_External_Rela) * srel->reloc_count
  		      <= srel->_cooked_size);
  	}
Index: bfd/reloc.c
===================================================================
RCS file: /cvs/src/src/bfd/reloc.c,v
retrieving revision 1.59
diff -c -p -d -r1.59 reloc.c
*** bfd/reloc.c	30 May 2002 02:14:13 -0000	1.59
--- bfd/reloc.c	30 May 2002 21:41:27 -0000
*************** ENUMDOC
*** 1963,1968 ****
--- 1963,1997 ----
    STO_ALPHA_STD_GPLOAD.
  
  ENUM
+   BFD_RELOC_ALPHA_TLSGD
+ ENUMX
+   BFD_RELOC_ALPHA_TLSLDM
+ ENUMX
+   BFD_RELOC_ALPHA_DTPMOD64
+ ENUMX
+   BFD_RELOC_ALPHA_GOTDTPREL16
+ ENUMX
+   BFD_RELOC_ALPHA_DTPREL64
+ ENUMX
+   BFD_RELOC_ALPHA_DTPREL_HI16
+ ENUMX
+   BFD_RELOC_ALPHA_DTPREL_LO16
+ ENUMX
+   BFD_RELOC_ALPHA_DTPREL16
+ ENUMX
+   BFD_RELOC_ALPHA_GOTTPREL16
+ ENUMX
+   BFD_RELOC_ALPHA_TPREL64
+ ENUMX
+   BFD_RELOC_ALPHA_TPREL_HI16
+ ENUMX
+   BFD_RELOC_ALPHA_TPREL_LO16
+ ENUMX
+   BFD_RELOC_ALPHA_TPREL16
+ ENUMDOC
+   Alpha thread-local storage relocations.
+ 
+ ENUM
    BFD_RELOC_MIPS_JMP
  ENUMDOC
    Bits 27..2 of the relocation address shifted right 2 bits;
Index: gas/expr.h
===================================================================
RCS file: /cvs/src/src/gas/expr.h,v
retrieving revision 1.10
diff -c -p -d -r1.10 expr.h
*** gas/expr.h	8 Mar 2001 23:24:22 -0000	1.10
--- gas/expr.h	30 May 2002 21:41:27 -0000
*************** typedef enum {
*** 107,112 ****
--- 107,114 ----
    /* machine dependent operators */
    O_md1,  O_md2,  O_md3,  O_md4,  O_md5,  O_md6,  O_md7,  O_md8,
    O_md9,  O_md10, O_md11, O_md12, O_md13, O_md14, O_md15, O_md16,
+   O_md17, O_md18, O_md19, O_md20, O_md21, O_md22, O_md23, O_md24,
+   O_md25, O_md26, O_md27, O_md28, O_md29, O_md30, O_md31, O_md32,
    /* this must be the largest value */
    O_max
  } operatorT;
Index: gas/config/tc-alpha.c
===================================================================
RCS file: /cvs/src/src/gas/config/tc-alpha.c,v
retrieving revision 1.41
diff -c -p -d -r1.41 tc-alpha.c
*** gas/config/tc-alpha.c	23 May 2002 13:12:48 -0000	1.41
--- gas/config/tc-alpha.c	30 May 2002 21:41:27 -0000
*************** struct alpha_macro {
*** 106,135 ****
  #define O_pregister	O_md1	/* O_register, in parentheses */
  #define O_cpregister	O_md2	/* + a leading comma */
  
! /* Note, the alpha_reloc_op table below depends on the ordering
!    of O_literal .. O_gpre16.  */
  #define O_literal	O_md3	/* !literal relocation */
  #define O_lituse_addr	O_md4	/* !lituse_addr relocation */
  #define O_lituse_base	O_md5	/* !lituse_base relocation */
  #define O_lituse_bytoff	O_md6	/* !lituse_bytoff relocation */
  #define O_lituse_jsr	O_md7	/* !lituse_jsr relocation */
! #define O_gpdisp	O_md8	/* !gpdisp relocation */
! #define O_gprelhigh	O_md9	/* !gprelhigh relocation */
! #define O_gprellow	O_md10	/* !gprellow relocation */
! #define O_gprel		O_md11	/* !gprel relocation */
! #define O_samegp	O_md12	/* !samegp relocation */
  
  #define DUMMY_RELOC_LITUSE_ADDR		(BFD_RELOC_UNUSED + 1)
  #define DUMMY_RELOC_LITUSE_BASE		(BFD_RELOC_UNUSED + 2)
  #define DUMMY_RELOC_LITUSE_BYTOFF	(BFD_RELOC_UNUSED + 3)
  #define DUMMY_RELOC_LITUSE_JSR		(BFD_RELOC_UNUSED + 4)
  
  #define LITUSE_ADDR	0
  #define LITUSE_BASE	1
  #define LITUSE_BYTOFF	2
  #define LITUSE_JSR	3
  
! #define USER_RELOC_P(R) ((R) >= O_literal && (R) <= O_samegp)
  
  /* Macros for extracting the type and number of encoded register tokens */
  
--- 106,150 ----
  #define O_pregister	O_md1	/* O_register, in parentheses */
  #define O_cpregister	O_md2	/* + a leading comma */
  
! /* The alpha_reloc_op table below depends on the ordering of these.  */
  #define O_literal	O_md3	/* !literal relocation */
  #define O_lituse_addr	O_md4	/* !lituse_addr relocation */
  #define O_lituse_base	O_md5	/* !lituse_base relocation */
  #define O_lituse_bytoff	O_md6	/* !lituse_bytoff relocation */
  #define O_lituse_jsr	O_md7	/* !lituse_jsr relocation */
! #define O_lituse_tlsgd	O_md8	/* !lituse_tlsgd relocation */
! #define O_lituse_tlsldm	O_md9	/* !lituse_tlsldm relocation */
! #define O_gpdisp	O_md10	/* !gpdisp relocation */
! #define O_gprelhigh	O_md11	/* !gprelhigh relocation */
! #define O_gprellow	O_md12	/* !gprellow relocation */
! #define O_gprel		O_md13	/* !gprel relocation */
! #define O_samegp	O_md14	/* !samegp relocation */
! #define O_tlsgd		O_md15	/* !tlsgd relocation */
! #define O_tlsldm	O_md16	/* !tlsldm relocation */
! #define O_gotdtprel	O_md17	/* !gotdtprel relocation */
! #define O_dtprelhi	O_md18	/* !dtprelhi relocation */
! #define O_dtprello	O_md19	/* !dtprello relocation */
! #define O_dtprel	O_md20	/* !dtprel relocation */
! #define O_gottprel	O_md21	/* !gottprel relocation */
! #define O_tprelhi	O_md22	/* !tprelhi relocation */
! #define O_tprello	O_md23	/* !tprello relocation */
! #define O_tprel		O_md24	/* !tprel relocation */
  
  #define DUMMY_RELOC_LITUSE_ADDR		(BFD_RELOC_UNUSED + 1)
  #define DUMMY_RELOC_LITUSE_BASE		(BFD_RELOC_UNUSED + 2)
  #define DUMMY_RELOC_LITUSE_BYTOFF	(BFD_RELOC_UNUSED + 3)
  #define DUMMY_RELOC_LITUSE_JSR		(BFD_RELOC_UNUSED + 4)
+ #define DUMMY_RELOC_LITUSE_TLSGD	(BFD_RELOC_UNUSED + 5)
+ #define DUMMY_RELOC_LITUSE_TLSLDM	(BFD_RELOC_UNUSED + 6)
  
  #define LITUSE_ADDR	0
  #define LITUSE_BASE	1
  #define LITUSE_BYTOFF	2
  #define LITUSE_JSR	3
+ #define LITUSE_TLSGD	4
+ #define LITUSE_TLSLDM	5
  
! #define USER_RELOC_P(R) ((R) >= O_literal && (R) <= O_tprel)
  
  /* Macros for extracting the type and number of encoded register tokens */
  
*************** static const struct alpha_reloc_op_tag {
*** 496,506 ****
    DEF(lituse_base, DUMMY_RELOC_LITUSE_BASE, 1, 1),
    DEF(lituse_bytoff, DUMMY_RELOC_LITUSE_BYTOFF, 1, 1),
    DEF(lituse_jsr, DUMMY_RELOC_LITUSE_JSR, 1, 1),
    DEF(gpdisp, BFD_RELOC_ALPHA_GPDISP, 1, 1),
    DEF(gprelhigh, BFD_RELOC_ALPHA_GPREL_HI16, 0, 0),
    DEF(gprellow, BFD_RELOC_ALPHA_GPREL_LO16, 0, 0),
    DEF(gprel, BFD_RELOC_GPREL16, 0, 0),
!   DEF(samegp, BFD_RELOC_ALPHA_BRSGP, 0, 0)
  };
  
  #undef DEF
--- 511,533 ----
    DEF(lituse_base, DUMMY_RELOC_LITUSE_BASE, 1, 1),
    DEF(lituse_bytoff, DUMMY_RELOC_LITUSE_BYTOFF, 1, 1),
    DEF(lituse_jsr, DUMMY_RELOC_LITUSE_JSR, 1, 1),
+   DEF(lituse_tlsgd, DUMMY_RELOC_LITUSE_TLSGD, 1, 1),
+   DEF(lituse_tlsldm, DUMMY_RELOC_LITUSE_TLSLDM, 1, 1),
    DEF(gpdisp, BFD_RELOC_ALPHA_GPDISP, 1, 1),
    DEF(gprelhigh, BFD_RELOC_ALPHA_GPREL_HI16, 0, 0),
    DEF(gprellow, BFD_RELOC_ALPHA_GPREL_LO16, 0, 0),
    DEF(gprel, BFD_RELOC_GPREL16, 0, 0),
!   DEF(samegp, BFD_RELOC_ALPHA_BRSGP, 0, 0),
!   DEF(tlsgd, BFD_RELOC_ALPHA_TLSGD, 0, 1),
!   DEF(tlsldm, BFD_RELOC_ALPHA_TLSLDM, 0, 1),
!   DEF(gotdtprel, BFD_RELOC_ALPHA_GOTDTPREL16, 0, 0),
!   DEF(dtprelhi, BFD_RELOC_ALPHA_DTPREL_HI16, 0, 0),
!   DEF(dtprello, BFD_RELOC_ALPHA_DTPREL_LO16, 0, 0),
!   DEF(dtprel, BFD_RELOC_ALPHA_DTPREL16, 0, 0),
!   DEF(gottprel, BFD_RELOC_ALPHA_GOTTPREL16, 0, 0),
!   DEF(tprelhi, BFD_RELOC_ALPHA_TPREL_HI16, 0, 0),
!   DEF(tprello, BFD_RELOC_ALPHA_TPREL_LO16, 0, 0),
!   DEF(tprel, BFD_RELOC_ALPHA_TPREL16, 0, 0),
  };
  
  #undef DEF
*************** static const int alpha_num_reloc_op
*** 515,526 ****
  /* Structure to hold explict sequence information.  */
  struct alpha_reloc_tag
  {
!   fixS *slaves;			/* head of linked list of !literals */
    segT segment;			/* segment relocs are in or undefined_section*/
    long sequence;		/* sequence # */
    unsigned n_master;		/* # of literals */
    unsigned n_slaves;		/* # of lituses */
!   char multi_section_p;		/* True if more than one section was used */
    char string[1];		/* printable form of sequence to hash with */
  };
  
--- 542,558 ----
  /* Structure to hold explict sequence information.  */
  struct alpha_reloc_tag
  {
!   fixS *master;			/* the literal reloc */
!   fixS *slaves;			/* head of linked list of lituses */
    segT segment;			/* segment relocs are in or undefined_section*/
    long sequence;		/* sequence # */
    unsigned n_master;		/* # of literals */
    unsigned n_slaves;		/* # of lituses */
!   unsigned saw_tlsgd : 1;	/* true if ... */
!   unsigned saw_tlsldm : 1;
!   unsigned saw_lu_tlsgd : 1;
!   unsigned saw_lu_tlsldm : 1;
!   unsigned multi_section_p : 1;	/* true if more than one section was used */
    char string[1];		/* printable form of sequence to hash with */
  };
  
*************** md_apply_fix3 (fixP, valP, seg)
*** 1223,1228 ****
--- 1255,1270 ----
  
  #ifdef OBJ_ELF
      case BFD_RELOC_ALPHA_BRSGP:
+     case BFD_RELOC_ALPHA_TLSGD:
+     case BFD_RELOC_ALPHA_TLSLDM:
+     case BFD_RELOC_ALPHA_GOTDTPREL16:
+     case BFD_RELOC_ALPHA_DTPREL_HI16:
+     case BFD_RELOC_ALPHA_DTPREL_LO16:
+     case BFD_RELOC_ALPHA_DTPREL16:
+     case BFD_RELOC_ALPHA_GOTTPREL16:
+     case BFD_RELOC_ALPHA_TPREL_HI16:
+     case BFD_RELOC_ALPHA_TPREL_LO16:
+     case BFD_RELOC_ALPHA_TPREL16:
        return;
  #endif
  
*************** alpha_force_relocation (f)
*** 1441,1446 ****
--- 1483,1498 ----
      case BFD_RELOC_ALPHA_BRSGP:
      case BFD_RELOC_VTABLE_INHERIT:
      case BFD_RELOC_VTABLE_ENTRY:
+     case BFD_RELOC_ALPHA_TLSGD:
+     case BFD_RELOC_ALPHA_TLSLDM:
+     case BFD_RELOC_ALPHA_GOTDTPREL16:
+     case BFD_RELOC_ALPHA_DTPREL_HI16:
+     case BFD_RELOC_ALPHA_DTPREL_LO16:
+     case BFD_RELOC_ALPHA_DTPREL16:
+     case BFD_RELOC_ALPHA_GOTTPREL16:
+     case BFD_RELOC_ALPHA_TPREL_HI16:
+     case BFD_RELOC_ALPHA_TPREL_LO16:
+     case BFD_RELOC_ALPHA_TPREL16:
        return 1;
  
      case BFD_RELOC_23_PCREL_S2:
*************** alpha_fix_adjustable (f)
*** 1497,1502 ****
--- 1549,1568 ----
      case BFD_RELOC_ALPHA_HINT:
        return 1;
  
+     case BFD_RELOC_ALPHA_TLSGD:
+     case BFD_RELOC_ALPHA_TLSLDM:
+     case BFD_RELOC_ALPHA_GOTDTPREL16:
+     case BFD_RELOC_ALPHA_DTPREL_HI16:
+     case BFD_RELOC_ALPHA_DTPREL_LO16:
+     case BFD_RELOC_ALPHA_DTPREL16:
+     case BFD_RELOC_ALPHA_GOTTPREL16:
+     case BFD_RELOC_ALPHA_TPREL_HI16:
+     case BFD_RELOC_ALPHA_TPREL_LO16:
+     case BFD_RELOC_ALPHA_TPREL16:
+       /* ??? No idea why we can't return a reference to .tbss+10, but
+ 	 we're preventing this in the other assemblers.  Follow for now.  */
+       return 0;
+ 
      default:
        return 1;
      }
*************** alpha_adjust_symtab_relocs (abfd, sec, p
*** 1666,1672 ****
    fixS *fixp;
    fixS *next;
    fixS *slave;
-   unsigned long n_slaves = 0;
  
    /* If seginfo is NULL, we did not create this section; don't do
       anything with it.  By using a pointer to a pointer, we can update
--- 1732,1737 ----
*************** alpha_adjust_symtab_relocs (abfd, sec, p
*** 1689,1709 ****
        switch (fixp->fx_r_type)
  	{
  	case BFD_RELOC_ALPHA_LITUSE:
- 	  n_slaves++;
  	  if (fixp->tc_fix_data.info->n_master == 0)
  	    as_bad_where (fixp->fx_file, fixp->fx_line,
  			  _("No !literal!%ld was found"),
  			  fixp->tc_fix_data.info->sequence);
  	  break;
  
  	case BFD_RELOC_ALPHA_GPDISP_LO16:
- 	  n_slaves++;
  	  if (fixp->tc_fix_data.info->n_master == 0)
  	    as_bad_where (fixp->fx_file, fixp->fx_line,
  			  _("No ldah !gpdisp!%ld was found"),
  			  fixp->tc_fix_data.info->sequence);
  	  break;
  
  	default:
  	  *prevP = fixp;
  	  prevP = &fixp->fx_next;
--- 1754,1792 ----
        switch (fixp->fx_r_type)
  	{
  	case BFD_RELOC_ALPHA_LITUSE:
  	  if (fixp->tc_fix_data.info->n_master == 0)
  	    as_bad_where (fixp->fx_file, fixp->fx_line,
  			  _("No !literal!%ld was found"),
  			  fixp->tc_fix_data.info->sequence);
+ 	  if (fixp->fx_offset == LITUSE_TLSGD)
+ 	    {
+ 	      if (! fixp->tc_fix_data.info->saw_tlsgd)
+ 		as_bad_where (fixp->fx_file, fixp->fx_line,
+ 			      _("No !tlsgd!%ld was found"),
+ 			      fixp->tc_fix_data.info->sequence);
+ 	    }
+ 	  else if (fixp->fx_offset == LITUSE_TLSLDM)
+ 	    {
+ 	      if (! fixp->tc_fix_data.info->saw_tlsldm)
+ 		as_bad_where (fixp->fx_file, fixp->fx_line,
+ 			      _("No !tlsldm!%ld was found"),
+ 			      fixp->tc_fix_data.info->sequence);
+ 	    }
  	  break;
  
  	case BFD_RELOC_ALPHA_GPDISP_LO16:
  	  if (fixp->tc_fix_data.info->n_master == 0)
  	    as_bad_where (fixp->fx_file, fixp->fx_line,
  			  _("No ldah !gpdisp!%ld was found"),
  			  fixp->tc_fix_data.info->sequence);
  	  break;
  
+ 	case BFD_RELOC_ALPHA_ELF_LITERAL:
+ 	  if (fixp->tc_fix_data.info->saw_tlsgd
+ 	      || fixp->tc_fix_data.info->saw_tlsldm)
+ 	    break;
+ 	  /* FALLTHRU */
+ 
  	default:
  	  *prevP = fixp;
  	  prevP = &fixp->fx_next;
*************** alpha_adjust_symtab_relocs (abfd, sec, p
*** 1711,1720 ****
  	}
      }
  
!   /* If there were any dependent relocations, go and add them back to
!      the chain.  They are linked through the next_reloc field in
!      reverse order, so as we go through the next_reloc chain, we
!      effectively reverse the chain once again.
  
       Except if there is more than one !literal for a given sequence
       number.  In that case, the programmer and/or compiler is not sure
--- 1794,1803 ----
  	}
      }
  
!   /* Go back and re-chain dependent relocations.  They are currently
!      linked through the next_reloc field in reverse order, so as we
!      go through the next_reloc chain, we effectively reverse the chain
!      once again.
  
       Except if there is more than one !literal for a given sequence
       number.  In that case, the programmer and/or compiler is not sure
*************** alpha_adjust_symtab_relocs (abfd, sec, p
*** 1734,1739 ****
--- 1817,1843 ----
        next = fixp->fx_next;
        switch (fixp->fx_r_type)
  	{
+ 	case BFD_RELOC_ALPHA_TLSGD:
+ 	case BFD_RELOC_ALPHA_TLSLDM:
+ 	  if (!fixp->tc_fix_data.info)
+ 	    break;
+ 	  if (fixp->tc_fix_data.info->n_master == 0)
+ 	    break;
+ 	  else if (fixp->tc_fix_data.info->n_master > 1)
+ 	    {
+ 	      as_bad_where (fixp->fx_file, fixp->fx_line,
+ 			    _("too many !literal!%ld for %s"),
+ 			    fixp->tc_fix_data.info->sequence,
+ 			    (fixp->fx_r_type == BFD_RELOC_ALPHA_TLSGD
+ 			     ? "!tlsgd" : "!tlsldm"));
+ 	      break;
+ 	    }
+ 
+ 	  fixp->tc_fix_data.info->master->fx_next = fixp->fx_next;
+ 	  fixp->fx_next = fixp->tc_fix_data.info->master;
+ 	  fixp = fixp->fx_next;
+ 	  /* FALLTHRU */
+ 
  	case BFD_RELOC_ALPHA_ELF_LITERAL:
  	  if (fixp->tc_fix_data.info->n_master == 1
  	      && ! fixp->tc_fix_data.info->multi_section_p)
*************** debug_exp (tok, ntok)
*** 1820,1834 ****
  	case O_lituse_base:		name = "O_lituse_base";		break;
  	case O_lituse_bytoff:		name = "O_lituse_bytoff";	break;
  	case O_lituse_jsr:		name = "O_lituse_jsr";		break;
  	case O_gpdisp:			name = "O_gpdisp";		break;
  	case O_gprelhigh:		name = "O_gprelhigh";		break;
  	case O_gprellow:		name = "O_gprellow";		break;
  	case O_gprel:			name = "O_gprel";		break;
  	case O_samegp:			name = "O_samegp";		break;
! 	case O_md13:			name = "O_md13";		break;
! 	case O_md14:			name = "O_md14";		break;
! 	case O_md15:			name = "O_md15";		break;
! 	case O_md16:			name = "O_md16";		break;
  	}
  
        fprintf (stderr, ", %s(%s, %s, %d)", name,
--- 1924,1946 ----
  	case O_lituse_base:		name = "O_lituse_base";		break;
  	case O_lituse_bytoff:		name = "O_lituse_bytoff";	break;
  	case O_lituse_jsr:		name = "O_lituse_jsr";		break;
+ 	case O_lituse_tlsgd:		name = "O_lituse_tlsgd";	break;
+ 	case O_lituse_tlsldm:		name = "O_lituse_tlsldm";	break;
  	case O_gpdisp:			name = "O_gpdisp";		break;
  	case O_gprelhigh:		name = "O_gprelhigh";		break;
  	case O_gprellow:		name = "O_gprellow";		break;
  	case O_gprel:			name = "O_gprel";		break;
  	case O_samegp:			name = "O_samegp";		break;
! 	case O_tlsgd:			name = "O_tlsgd";		break;
! 	case O_tlsldm:			name = "O_tlsldm";		break;
! 	case O_gotdtprel:		name = "O_gotdtprel";		break;
! 	case O_dtprelhi:		name = "O_dtprelhi";		break;
! 	case O_dtprello:		name = "O_dtprello";		break;
! 	case O_dtprel:			name = "O_dtprel";		break;
! 	case O_gottprel:		name = "O_gottprel";		break;
! 	case O_tprelhi:			name = "O_tprelhi";		break;
! 	case O_tprello:			name = "O_tprello";		break;
! 	case O_tprel:			name = "O_tprel";		break;
  	}
  
        fprintf (stderr, ", %s(%s, %s, %d)", name,
*************** emit_insn (insn)
*** 2479,2485 ****
      {
        const struct alpha_operand *operand = (const struct alpha_operand *) 0;
        struct alpha_fixup *fixup = &insn->fixups[i];
!       struct alpha_reloc_tag *info;
        int size, pcrel;
        fixS *fixP;
  
--- 2591,2597 ----
      {
        const struct alpha_operand *operand = (const struct alpha_operand *) 0;
        struct alpha_fixup *fixup = &insn->fixups[i];
!       struct alpha_reloc_tag *info = NULL;
        int size, pcrel;
        fixS *fixP;
  
*************** emit_insn (insn)
*** 2521,2526 ****
--- 2633,2646 ----
  	case BFD_RELOC_GPREL16:
  	case BFD_RELOC_ALPHA_GPREL_HI16:
  	case BFD_RELOC_ALPHA_GPREL_LO16:
+ 	case BFD_RELOC_ALPHA_GOTDTPREL16:
+ 	case BFD_RELOC_ALPHA_DTPREL_HI16:
+ 	case BFD_RELOC_ALPHA_DTPREL_LO16:
+ 	case BFD_RELOC_ALPHA_DTPREL16:
+ 	case BFD_RELOC_ALPHA_GOTTPREL16:
+ 	case BFD_RELOC_ALPHA_TPREL_HI16:
+ 	case BFD_RELOC_ALPHA_TPREL_LO16:
+ 	case BFD_RELOC_ALPHA_TPREL16:
  	  fixP->fx_no_overflow = 1;
  	  break;
  
*************** emit_insn (insn)
*** 2555,2561 ****
--- 2675,2684 ----
  	case BFD_RELOC_ALPHA_ELF_LITERAL:
  	  fixP->fx_no_overflow = 1;
  
+ 	  if (insn->sequence == 0)
+ 	    break;
  	  info = get_alpha_reloc_tag (insn->sequence);
+ 	  info->master = fixP;
  	  info->n_master++;
  	  if (info->segment != now_seg)
  	    info->multi_section_p = 1;
*************** emit_insn (insn)
*** 2573,2584 ****
  	  goto do_lituse;
  	case DUMMY_RELOC_LITUSE_JSR:
  	  fixP->fx_offset = LITUSE_JSR;
  	do_lituse:
  	  fixP->fx_addsy = section_symbol (now_seg);
  	  fixP->fx_r_type = BFD_RELOC_ALPHA_LITUSE;
  
  	  info = get_alpha_reloc_tag (insn->sequence);
! 	  info->n_slaves++;
  	  fixP->tc_fix_data.info = info;
  	  fixP->tc_fix_data.next_reloc = info->slaves;
  	  info->slaves = fixP;
--- 2696,2726 ----
  	  goto do_lituse;
  	case DUMMY_RELOC_LITUSE_JSR:
  	  fixP->fx_offset = LITUSE_JSR;
+ 	  goto do_lituse;
+ 	case DUMMY_RELOC_LITUSE_TLSGD:
+ 	  fixP->fx_offset = LITUSE_TLSGD;
+ 	  goto do_lituse;
+ 	case DUMMY_RELOC_LITUSE_TLSLDM:
+ 	  fixP->fx_offset = LITUSE_TLSLDM;
+ 	  goto do_lituse;
  	do_lituse:
  	  fixP->fx_addsy = section_symbol (now_seg);
  	  fixP->fx_r_type = BFD_RELOC_ALPHA_LITUSE;
  
  	  info = get_alpha_reloc_tag (insn->sequence);
! 	  if (fixup->reloc == DUMMY_RELOC_LITUSE_TLSGD)
! 	    info->saw_lu_tlsgd = 1;
! 	  else if (fixup->reloc == DUMMY_RELOC_LITUSE_TLSLDM)
! 	    info->saw_lu_tlsldm = 1;
! 	  if (++info->n_slaves > 1)
! 	    {
! 	      if (info->saw_lu_tlsgd)
! 		as_bad (_("too many lituse insns for !lituse_tlsgd!%ld"),
! 		        insn->sequence);
! 	      else if (info->saw_lu_tlsldm)
! 		as_bad (_("too many lituse insns for !lituse_tlsldm!%ld"),
! 		        insn->sequence);
! 	    }
  	  fixP->tc_fix_data.info = info;
  	  fixP->tc_fix_data.next_reloc = info->slaves;
  	  info->slaves = fixP;
*************** emit_insn (insn)
*** 2586,2591 ****
--- 2728,2765 ----
  	    info->multi_section_p = 1;
  	  break;
  
+ 	case BFD_RELOC_ALPHA_TLSGD:
+ 	  fixP->fx_no_overflow = 1;
+ 
+ 	  if (insn->sequence == 0)
+ 	    break;
+ 	  info = get_alpha_reloc_tag (insn->sequence);
+ 	  if (info->saw_tlsgd)
+ 	    as_bad (_("duplicate !tlsgd!%ld"), insn->sequence);
+ 	  else if (info->saw_tlsldm)
+ 	    as_bad (_("sequence number in use for !tlsldm!%ld"),
+ 		    insn->sequence);
+ 	  else
+ 	    info->saw_tlsgd = 1;
+ 	  fixP->tc_fix_data.info = info;
+ 	  break;
+ 
+ 	case BFD_RELOC_ALPHA_TLSLDM:
+ 	  fixP->fx_no_overflow = 1;
+ 
+ 	  if (insn->sequence == 0)
+ 	    break;
+ 	  info = get_alpha_reloc_tag (insn->sequence);
+ 	  if (info->saw_tlsldm)
+ 	    as_bad (_("duplicate !tlsldm!%ld"), insn->sequence);
+ 	  else if (info->saw_tlsgd)
+ 	    as_bad (_("sequence number in use for !tlsgd!%ld"),
+ 		    insn->sequence);
+ 	  else
+ 	    info->saw_tlsldm = 1;
+ 	  fixP->tc_fix_data.info = info;
+ 	  break;
+ 
  	default:
  	  if ((int) fixup->reloc < 0)
  	    {
*************** static const char * const extXh_op[] = {
*** 2715,2721 ****
  static const char * const mskXl_op[] = { "mskbl", "mskwl", "mskll", "mskql" };
  static const char * const mskXh_op[] = { NULL,    "mskwh", "msklh", "mskqh" };
  static const char * const stX_op[] = { "stb", "stw", "stl", "stq" };
- static const char * const ldX_op[] = { "ldb", "ldw", "ldll", "ldq" };
  static const char * const ldXu_op[] = { "ldbu", "ldwu", NULL, NULL };
  
  /* Implement the ldgp macro.  */
--- 2889,2894 ----
Index: gas/testsuite/gas/alpha/alpha.exp
===================================================================
RCS file: /cvs/src/src/gas/testsuite/gas/alpha/alpha.exp,v
retrieving revision 1.3
diff -c -p -d -r1.3 alpha.exp
*** gas/testsuite/gas/alpha/alpha.exp	9 Feb 2002 22:55:06 -0000	1.3
--- gas/testsuite/gas/alpha/alpha.exp	30 May 2002 21:41:27 -0000
*************** if { [istarget alpha*-*-*] } then {
*** 29,34 ****
--- 29,37 ----
  	run_dump_test "elf-reloc-4"
  	run_dump_test "elf-reloc-5"
  	run_list_test "elf-reloc-6" ""
+ 	run_dump_test "elf-tls-1"
+ 	run_list_test "elf-tls-2" ""
+ 	run_list_test "elf-tls-3" ""
      }
  
      run_dump_test "fp"
Index: gas/testsuite/gas/alpha/elf-tls-1.d
===================================================================
RCS file: gas/testsuite/gas/alpha/elf-tls-1.d
diff -N gas/testsuite/gas/alpha/elf-tls-1.d
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- gas/testsuite/gas/alpha/elf-tls-1.d	30 May 2002 21:41:27 -0000
***************
*** 0 ****
--- 1,29 ----
+ #objdump: -r
+ #name: alpha elf-tls-1
+ 
+ .*:     file format elf64-alpha
+ 
+ RELOCATION RECORDS FOR \[\.text\]:
+ OFFSET           TYPE              VALUE 
+ 0*0000004 TLSGD             a
+ 0*0000000 ELF_LITERAL       __tls_get_addr
+ 0*0000008 LITUSE            \.text\+0x0*0000004
+ 0*0000008 HINT              __tls_get_addr
+ 0*000000c HINT              __tls_get_addr
+ 0*0000014 TLSLDM            b
+ 0*0000010 ELF_LITERAL       __tls_get_addr
+ 0*000000c LITUSE            \.text\+0x0*0000005
+ 0*0000018 TLSGD             c
+ 0*000001c TLSLDM            d
+ 0*0000020 TLSGD             e
+ 0*0000024 TLSLDM            f
+ 0*0000028 GOTDTPREL         g
+ 0*000002c DTPRELHI          h
+ 0*0000030 DTPRELLO          i
+ 0*0000034 DTPREL16          j
+ 0*0000038 GOTTPREL          k
+ 0*000003c TPRELHI           l
+ 0*0000040 TPRELLO           m
+ 0*0000044 TPREL16           n
+ 
+ 
Index: gas/testsuite/gas/alpha/elf-tls-1.s
===================================================================
RCS file: gas/testsuite/gas/alpha/elf-tls-1.s
diff -N gas/testsuite/gas/alpha/elf-tls-1.s
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- gas/testsuite/gas/alpha/elf-tls-1.s	30 May 2002 21:41:27 -0000
***************
*** 0 ****
--- 1,24 ----
+ 	.set nomacro
+ 	ldq	$27, __tls_get_addr($29)	!literal!1
+ 	ldq	$16, a($29)			!tlsgd!1
+ 	jsr	$26, ($27), __tls_get_addr	!lituse_tlsgd!1
+ 
+ 	jsr	$26, ($27), __tls_get_addr	!lituse_tlsldm!2
+ 	ldq	$27, __tls_get_addr($29)	!literal!2
+ 	ldq	$16, b($29)			!tlsldm!2
+ 
+ 	ldq	$16, c($29)			!tlsgd
+ 	ldq	$16, d($29)			!tlsldm
+ 
+ 	ldq	$16, e($29)			!tlsgd!3
+ 	ldq	$16, f($29)			!tlsldm!4
+ 
+ 	ldq	$16, g($29)			!gotdtprel
+ 	ldah	$16, h($31)			!dtprelhi
+ 	lda	$16, i($16)			!dtprello
+ 	lda	$16, j($31)			!dtprel
+ 
+ 	ldq	$16, k($29)			!gottprel
+ 	ldah	$16, l($31)			!tprelhi
+ 	lda	$16, m($16)			!tprello
+ 	lda	$16, n($31)			!tprel
Index: gas/testsuite/gas/alpha/elf-tls-2.l
===================================================================
RCS file: gas/testsuite/gas/alpha/elf-tls-2.l
diff -N gas/testsuite/gas/alpha/elf-tls-2.l
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- gas/testsuite/gas/alpha/elf-tls-2.l	30 May 2002 21:41:27 -0000
***************
*** 0 ****
--- 1,9 ----
+ .*: Assembler messages:
+ .*:5: Error: too many lituse insns for !lituse_tlsgd!1
+ .*:10: Error: too many lituse insns for !lituse_tlsldm!2
+ .*:15: Error: too many lituse insns for !lituse_tlsgd!3
+ .*:20: Error: too many lituse insns for !lituse_tlsldm!4
+ .*:23: Error: duplicate !tlsgd!5
+ .*:26: Error: duplicate !tlsldm!6
+ .*:29: Error: sequence number in use for !tlsgd!7
+ .*:32: Error: sequence number in use for !tlsldm!8
Index: gas/testsuite/gas/alpha/elf-tls-2.s
===================================================================
RCS file: gas/testsuite/gas/alpha/elf-tls-2.s
diff -N gas/testsuite/gas/alpha/elf-tls-2.s
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- gas/testsuite/gas/alpha/elf-tls-2.s	30 May 2002 21:41:27 -0000
***************
*** 0 ****
--- 1,32 ----
+ 	.set nomacro
+ 	ldq	$16, c($29)			!tlsgd!1
+ 	ldq	$27, __tls_get_addr($29)	!literal!1
+ 	jsr	$26, ($27), __tls_get_addr	!lituse_tlsgd!1
+ 	jsr	$26, ($27), __tls_get_addr	!lituse_jsr!1
+ 
+ 	ldq	$16, d($29)			!tlsldm!2
+ 	ldq	$27, __tls_get_addr($29)	!literal!2
+ 	jsr	$26, ($27), __tls_get_addr	!lituse_jsr!2
+ 	jsr	$26, ($27), __tls_get_addr	!lituse_tlsldm!2
+ 
+ 	ldq	$16, g($29)			!tlsgd!3
+ 	ldq	$27, __tls_get_addr($29)	!literal!3
+ 	jsr	$26, ($27), __tls_get_addr	!lituse_tlsgd!3
+ 	jsr	$26, ($27), __tls_get_addr	!lituse_tlsgd!3
+ 	
+ 	ldq	$16, h($29)			!tlsldm!4
+ 	ldq	$27, __tls_get_addr($29)	!literal!4
+ 	jsr	$26, ($27), __tls_get_addr	!lituse_tlsldm!4
+ 	jsr	$26, ($27), __tls_get_addr	!lituse_tlsldm!4
+ 
+ 	ldq	$16, i($29)			!tlsgd!5
+ 	ldq	$16, i($29)			!tlsgd!5
+ 
+ 	ldq	$16, j($29)			!tlsldm!6
+ 	ldq	$16, j($29)			!tlsldm!6
+ 
+ 	ldq	$16, k($29)			!tlsgd!7
+ 	ldq	$16, k($29)			!tlsldm!7
+ 
+ 	ldq	$16, l($29)			!tlsldm!8
+ 	ldq	$16, l($29)			!tlsgd!8
Index: gas/testsuite/gas/alpha/elf-tls-3.l
===================================================================
RCS file: gas/testsuite/gas/alpha/elf-tls-3.l
diff -N gas/testsuite/gas/alpha/elf-tls-3.l
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- gas/testsuite/gas/alpha/elf-tls-3.l	30 May 2002 21:41:27 -0000
***************
*** 0 ****
--- 1,7 ----
+ .*: Assembler messages:
+ .*:3: Error: No !tlsgd!1 was found
+ .*:6: Error: No !tlsldm!2 was found
+ .*:18: Error: No !tlsldm!5 was found
+ .*:22: Error: No !tlsgd!6 was found
+ .*:8: Error: too many !literal!3 for !tlsgd
+ .*:12: Error: too many !literal!4 for !tlsldm
Index: gas/testsuite/gas/alpha/elf-tls-3.s
===================================================================
RCS file: gas/testsuite/gas/alpha/elf-tls-3.s
diff -N gas/testsuite/gas/alpha/elf-tls-3.s
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- gas/testsuite/gas/alpha/elf-tls-3.s	30 May 2002 21:41:27 -0000
***************
*** 0 ****
--- 1,22 ----
+ 	.set nomacro
+ 	ldq	$27, __tls_get_addr($29)	!literal!1
+ 	jsr	$26, ($27), __tls_get_addr	!lituse_tlsgd!1
+ 
+ 	ldq	$27, __tls_get_addr($29)	!literal!2
+ 	jsr	$26, ($27), __tls_get_addr	!lituse_tlsldm!2
+ 
+ 	ldq	$16, a($29)			!tlsgd!3
+ 	ldq	$27, __tls_get_addr($29)	!literal!3
+ 	ldq	$27, __tls_get_addr($29)	!literal!3
+ 	
+ 	ldq	$16, b($29)			!tlsldm!4
+ 	ldq	$27, __tls_get_addr($29)	!literal!4
+ 	ldq	$27, __tls_get_addr($29)	!literal!4
+ 
+ 	ldq	$16, e($29)			!tlsgd!5
+ 	ldq	$27, __tls_get_addr($29)	!literal!5
+ 	jsr	$26, ($27), __tls_get_addr	!lituse_tlsldm!5
+ 	
+ 	ldq	$16, f($29)			!tlsldm!6
+ 	ldq	$27, __tls_get_addr($29)	!literal!6
+ 	jsr	$26, ($27), __tls_get_addr	!lituse_tlsgd!6
Index: include/elf/alpha.h
===================================================================
RCS file: /cvs/src/src/include/elf/alpha.h,v
retrieving revision 1.6
diff -c -p -d -r1.6 alpha.h
*** include/elf/alpha.h	9 Feb 2002 22:54:16 -0000	1.6
--- include/elf/alpha.h	30 May 2002 21:41:27 -0000
*************** START_RELOC_NUMBERS (elf_alpha_reloc_typ
*** 99,104 ****
--- 99,119 ----
       STO_ALPHA_STD_GPLOAD.  */
    RELOC_NUMBER (R_ALPHA_BRSGP, 28)
  
+   /* Thread-Local Storage.  */
+   RELOC_NUMBER (R_ALPHA_TLSGD, 29)
+   RELOC_NUMBER (R_ALPHA_TLSLDM, 30)
+   RELOC_NUMBER (R_ALPHA_DTPMOD64, 31)
+   RELOC_NUMBER (R_ALPHA_GOTDTPREL, 32)
+   RELOC_NUMBER (R_ALPHA_DTPREL64, 33)
+   RELOC_NUMBER (R_ALPHA_DTPRELHI, 34)
+   RELOC_NUMBER (R_ALPHA_DTPRELLO, 35)
+   RELOC_NUMBER (R_ALPHA_DTPREL16, 36)
+   RELOC_NUMBER (R_ALPHA_GOTTPREL, 37)
+   RELOC_NUMBER (R_ALPHA_TPREL64, 38)
+   RELOC_NUMBER (R_ALPHA_TPRELHI, 39)
+   RELOC_NUMBER (R_ALPHA_TPRELLO, 40)
+   RELOC_NUMBER (R_ALPHA_TPREL16, 41)
+ 
  END_RELOC_NUMBERS (R_ALPHA_max)
  
  #endif /* _ELF_ALPHA_H */


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]