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]

ppc64 tls support


Here's the ppc64 TLS support.  As noted in a previous email, this patch
also changes got relocations to handle an addend a little more sensibly.

Oh yeah, I spent some effort to make --emit-relocs work when tls
optimization edits code and relocs, something I think other back-ends
don't bother to do..

include/elf/ChangeLog
	* ppc.h: Add TLS relocs.  Format.
	* ppc64.h: Likewise.

bfd/ChangeLog
	* reloc.c: Add PPC and PPC64 TLS relocs.
	* libbfd.h: Regenerate.
	* bfd-in2.h: Regenerate.
	* elf64-ppc.c (TP_OFFSET, DTP_OFFSET): Declare.
	(ppc64_elf_howto_raw): Add TLS howto's.  Adjust R_PPC64_NONE to be
	against a 32 bit field.
	(ppc64_elf_reloc_type_lookup): Handle TLS relocs.
	(_ppc64_elf_section_data): Add t_symndx and comments.
	(ppc64_elf_section_data): Use elf_section_data macro.
	(ppc64_elf_new_section_hook): American spelling.
	(struct got_entry, struct plt_entry): New.
	(MUST_BE_DYN_RELOC): Rename from IS_ABSOLUTE_RELOC.
	(struct ppc_stub_hash_entry): Add "addend" field.
	(struct ppc_link_hash_entry): Add "tls_type".
	(TLS_TLS, TLS_GD_LD, TLS_LD, TLS_TPREL, TLS_DTPREL,
	TLS_EXPLICIT): Define.
	(struct ppc_link_hash_table): Add tls_sec, tls_get_addr, tlsld_got.
	(link_hash_newfunc): Init new fields.
	(ppc64_elf_link_hash_table_create): Likewise.  Set init_relcount and
	init_offset to NULL.
	(ppc64_elf_copy_indirect_symbol): Copy got and plt info.  Don't call
	_bfd_elf_link_hash_copy_indirect, rather insert relevant code from
	there.
	(update_local_sym_info, update_plt_info): New functions.
	(ppc64_elf_check_relocs): Use them.  Handle TLS relocs.  Adjust GOT
	handling to use got.glist rather than got.refcount.  Likewise for PLT.
	(ppc64_elf_gc_sweep_hook): Handle TLS relocs, new GOT and PLT lists.
	(func_desc_adjust): Adjust for new PLT list.
	(ppc64_elf_adjust_dynamic_symbol): Likewise.
	(get_sym_h, get_tls_type): New functions.
	(ppc64_elf_edit_opd): Remove unused variable.  Use get_sym_h.
	(ppc64_elf_tls_optimize): New function.
	(allocate_dynrelocs): Adjust for new PLT and GOT lists.  Allocate
	TLS relocs.
	(ppc64_elf_size_dynamic_sections): Likewise.
	(ppc_type_of_stub): Adjust for new PLT list.
	(ppc_build_one_stub): Likewise.
	(ppc64_elf_size_stubs): Likewise.  Use get_sym_h.  Treat __tls_get_addr
	calls specially.
	(ppc64_elf_relocate_section): Adjust for new GOT and PLT lists.  Handle
	TLS relocs.  Report local syms using bfd_elf_local_sym_name.  Don't
	init GOT entries that have a reloc.  Generate GOT relocs here..
	(ppc64_elf_finish_dynamic_symbol): ..not here.  Adjust for PLT list.
	* elf64-ppc.h (ppc64_elf_tls_optimize): Declare.

gas/ChangeLog
	* config/tc-ppc.c (mapping): Handle new TLS reloc specs.
	(ppc_elf_suffix): Don't warn for x+off@got when ppc64 and don't
	accept x@got+off etc.
	(md_assemble): Handle TLS relocs.
	(ppc_force_relocation): Force for all TLS relocs.
	(ppc_fix_adjustable): Likewise.
	(md_apply_fix3): Handle TLS relocs.

ld/ChangeLog
	* emultempl/ppc64elf.em (ppc_before_allocation): Size sections then
	call ppc64_elf_tls_optimize.

ld/testsuite/ChangeLog
	* ld-powerpc/powerpc.exp (supports_ppc64): New.
	(ppcelftests): Force 32 bit mode.
	(ppc64elftests): New.
	* ld-powerpc/tls.d: New.
	* ld-powerpc/tls.g: New.
	* ld-powerpc/tls.s: New.
	* ld-powerpc/tls.t: New.
	* ld-powerpc/tlsexe.d: New.
	* ld-powerpc/tlsexe.g: New.
	* ld-powerpc/tlsexe.r: New.
	* ld-powerpc/tlsexe.t: New.
	* ld-powerpc/tlsexetoc.d: New.
	* ld-powerpc/tlsexetoc.g: New.
	* ld-powerpc/tlsexetoc.r: New.
	* ld-powerpc/tlsexetoc.t: New.
	* ld-powerpc/tlslib.s: New.
	* ld-powerpc/tlsso.d: New.
	* ld-powerpc/tlsso.g: New.
	* ld-powerpc/tlsso.r: New.
	* ld-powerpc/tlsso.t: New.
	* ld-powerpc/tlstoc.d: New.
	* ld-powerpc/tlstoc.g: New.
	* ld-powerpc/tlstoc.s: New.
	* ld-powerpc/tlstoc.t: New.
	* ld-powerpc/tlstocso.d: New.
	* ld-powerpc/tlstocso.g: New.
	* ld-powerpc/tlstocso.r: New.
	* ld-powerpc/tlstocso.t: New.

-- 
Alan Modra
IBM OzLabs - Linux Technology Centre

Index: include/elf/ppc.h
===================================================================
RCS file: /cvs/src/src/include/elf/ppc.h,v
retrieving revision 1.9
diff -u -p -d -r1.9 ppc.h
--- include/elf/ppc.h	16 Jan 2003 04:08:47 -0000	1.9
+++ include/elf/ppc.h	4 Feb 2003 14:02:29 -0000
@@ -32,71 +32,101 @@ Foundation, Inc., 59 Temple Place - Suit
 
 /* Relocations.  */
 START_RELOC_NUMBERS (elf_ppc_reloc_type)
-  RELOC_NUMBER (R_PPC_NONE, 0)
-  RELOC_NUMBER (R_PPC_ADDR32, 1)
-  RELOC_NUMBER (R_PPC_ADDR24, 2)
-  RELOC_NUMBER (R_PPC_ADDR16, 3)
-  RELOC_NUMBER (R_PPC_ADDR16_LO, 4)
-  RELOC_NUMBER (R_PPC_ADDR16_HI, 5)
-  RELOC_NUMBER (R_PPC_ADDR16_HA, 6)
-  RELOC_NUMBER (R_PPC_ADDR14, 7)
-  RELOC_NUMBER (R_PPC_ADDR14_BRTAKEN, 8)
-  RELOC_NUMBER (R_PPC_ADDR14_BRNTAKEN, 9)
-  RELOC_NUMBER (R_PPC_REL24, 10)
-  RELOC_NUMBER (R_PPC_REL14, 11)
-  RELOC_NUMBER (R_PPC_REL14_BRTAKEN, 12)
-  RELOC_NUMBER (R_PPC_REL14_BRNTAKEN, 13)
-  RELOC_NUMBER (R_PPC_GOT16, 14)
-  RELOC_NUMBER (R_PPC_GOT16_LO, 15)
-  RELOC_NUMBER (R_PPC_GOT16_HI, 16)
-  RELOC_NUMBER (R_PPC_GOT16_HA, 17)
-  RELOC_NUMBER (R_PPC_PLTREL24, 18)
-  RELOC_NUMBER (R_PPC_COPY, 19)
-  RELOC_NUMBER (R_PPC_GLOB_DAT, 20)
-  RELOC_NUMBER (R_PPC_JMP_SLOT, 21)
-  RELOC_NUMBER (R_PPC_RELATIVE, 22)
-  RELOC_NUMBER (R_PPC_LOCAL24PC, 23)
-  RELOC_NUMBER (R_PPC_UADDR32, 24)
-  RELOC_NUMBER (R_PPC_UADDR16, 25)
-  RELOC_NUMBER (R_PPC_REL32, 26)
-  RELOC_NUMBER (R_PPC_PLT32, 27)
-  RELOC_NUMBER (R_PPC_PLTREL32, 28)
-  RELOC_NUMBER (R_PPC_PLT16_LO, 29)
-  RELOC_NUMBER (R_PPC_PLT16_HI, 30)
-  RELOC_NUMBER (R_PPC_PLT16_HA, 31)
-  RELOC_NUMBER (R_PPC_SDAREL16, 32)
-  RELOC_NUMBER (R_PPC_SECTOFF, 33)
-  RELOC_NUMBER (R_PPC_SECTOFF_LO, 34)
-  RELOC_NUMBER (R_PPC_SECTOFF_HI, 35)
-  RELOC_NUMBER (R_PPC_SECTOFF_HA, 36)
-  RELOC_NUMBER (R_PPC_ADDR30, 37)
+  RELOC_NUMBER (R_PPC_NONE,		  0)
+  RELOC_NUMBER (R_PPC_ADDR32,		  1)
+  RELOC_NUMBER (R_PPC_ADDR24,		  2)
+  RELOC_NUMBER (R_PPC_ADDR16,		  3)
+  RELOC_NUMBER (R_PPC_ADDR16_LO,	  4)
+  RELOC_NUMBER (R_PPC_ADDR16_HI,	  5)
+  RELOC_NUMBER (R_PPC_ADDR16_HA,	  6)
+  RELOC_NUMBER (R_PPC_ADDR14,		  7)
+  RELOC_NUMBER (R_PPC_ADDR14_BRTAKEN,	  8)
+  RELOC_NUMBER (R_PPC_ADDR14_BRNTAKEN,	  9)
+  RELOC_NUMBER (R_PPC_REL24,		 10)
+  RELOC_NUMBER (R_PPC_REL14,		 11)
+  RELOC_NUMBER (R_PPC_REL14_BRTAKEN,	 12)
+  RELOC_NUMBER (R_PPC_REL14_BRNTAKEN,	 13)
+  RELOC_NUMBER (R_PPC_GOT16,		 14)
+  RELOC_NUMBER (R_PPC_GOT16_LO,		 15)
+  RELOC_NUMBER (R_PPC_GOT16_HI,		 16)
+  RELOC_NUMBER (R_PPC_GOT16_HA,		 17)
+  RELOC_NUMBER (R_PPC_PLTREL24,		 18)
+  RELOC_NUMBER (R_PPC_COPY,		 19)
+  RELOC_NUMBER (R_PPC_GLOB_DAT,		 20)
+  RELOC_NUMBER (R_PPC_JMP_SLOT,		 21)
+  RELOC_NUMBER (R_PPC_RELATIVE,		 22)
+  RELOC_NUMBER (R_PPC_LOCAL24PC,	 23)
+  RELOC_NUMBER (R_PPC_UADDR32,		 24)
+  RELOC_NUMBER (R_PPC_UADDR16,		 25)
+  RELOC_NUMBER (R_PPC_REL32,		 26)
+  RELOC_NUMBER (R_PPC_PLT32,		 27)
+  RELOC_NUMBER (R_PPC_PLTREL32,		 28)
+  RELOC_NUMBER (R_PPC_PLT16_LO,		 29)
+  RELOC_NUMBER (R_PPC_PLT16_HI,		 30)
+  RELOC_NUMBER (R_PPC_PLT16_HA,		 31)
+  RELOC_NUMBER (R_PPC_SDAREL16,		 32)
+  RELOC_NUMBER (R_PPC_SECTOFF,		 33)
+  RELOC_NUMBER (R_PPC_SECTOFF_LO,	 34)
+  RELOC_NUMBER (R_PPC_SECTOFF_HI,	 35)
+  RELOC_NUMBER (R_PPC_SECTOFF_HA,	 36)
+  RELOC_NUMBER (R_PPC_ADDR30,		 37)
+
+  /* Relocs added to support TLS.  */
+  RELOC_NUMBER (R_PPC_TLS,		 67)
+  RELOC_NUMBER (R_PPC_DTPMOD64,		 68)
+  RELOC_NUMBER (R_PPC_TPREL16,		 69)
+  RELOC_NUMBER (R_PPC_TPREL16_LO,	 70)
+  RELOC_NUMBER (R_PPC_TPREL16_HI,	 71)
+  RELOC_NUMBER (R_PPC_TPREL16_HA,	 72)
+  RELOC_NUMBER (R_PPC_TPREL64,		 73)
+  RELOC_NUMBER (R_PPC_DTPREL16,		 74)
+  RELOC_NUMBER (R_PPC_DTPREL16_LO,	 75)
+  RELOC_NUMBER (R_PPC_DTPREL16_HI,	 76)
+  RELOC_NUMBER (R_PPC_DTPREL16_HA,	 77)
+  RELOC_NUMBER (R_PPC_DTPREL64,		 78)
+  RELOC_NUMBER (R_PPC_GOT_TLSGD16,	 79)
+  RELOC_NUMBER (R_PPC_GOT_TLSGD16_LO,	 80)
+  RELOC_NUMBER (R_PPC_GOT_TLSGD16_HI,	 81)
+  RELOC_NUMBER (R_PPC_GOT_TLSGD16_HA,	 82)
+  RELOC_NUMBER (R_PPC_GOT_TLSLD16,	 83)
+  RELOC_NUMBER (R_PPC_GOT_TLSLD16_LO,	 84)
+  RELOC_NUMBER (R_PPC_GOT_TLSLD16_HI,	 85)
+  RELOC_NUMBER (R_PPC_GOT_TLSLD16_HA,	 86)
+  RELOC_NUMBER (R_PPC_GOT_TPREL16,	 87)
+  RELOC_NUMBER (R_PPC_GOT_TPREL16_LO,	 88)
+  RELOC_NUMBER (R_PPC_GOT_TPREL16_HI,	 89)
+  RELOC_NUMBER (R_PPC_GOT_TPREL16_HA,	 90)
+  RELOC_NUMBER (R_PPC_GOT_DTPREL16,	 91)
+  RELOC_NUMBER (R_PPC_GOT_DTPREL16_LO,	 92)
+  RELOC_NUMBER (R_PPC_GOT_DTPREL16_HI,	 93)
+  RELOC_NUMBER (R_PPC_GOT_DTPREL16_HA,	 94)
 
 /* The remaining relocs are from the Embedded ELF ABI, and are not
    in the SVR4 ELF ABI.  */
-  RELOC_NUMBER (R_PPC_EMB_NADDR32, 101)
-  RELOC_NUMBER (R_PPC_EMB_NADDR16, 102)
-  RELOC_NUMBER (R_PPC_EMB_NADDR16_LO, 103)
-  RELOC_NUMBER (R_PPC_EMB_NADDR16_HI, 104)
-  RELOC_NUMBER (R_PPC_EMB_NADDR16_HA, 105)
-  RELOC_NUMBER (R_PPC_EMB_SDAI16, 106)
-  RELOC_NUMBER (R_PPC_EMB_SDA2I16, 107)
-  RELOC_NUMBER (R_PPC_EMB_SDA2REL, 108)
-  RELOC_NUMBER (R_PPC_EMB_SDA21, 109)
-  RELOC_NUMBER (R_PPC_EMB_MRKREF, 110)
-  RELOC_NUMBER (R_PPC_EMB_RELSEC16, 111)
-  RELOC_NUMBER (R_PPC_EMB_RELST_LO, 112)
-  RELOC_NUMBER (R_PPC_EMB_RELST_HI, 113)
-  RELOC_NUMBER (R_PPC_EMB_RELST_HA, 114)
-  RELOC_NUMBER (R_PPC_EMB_BIT_FLD, 115)
-  RELOC_NUMBER (R_PPC_EMB_RELSDA, 116)
+  RELOC_NUMBER (R_PPC_EMB_NADDR32,	101)
+  RELOC_NUMBER (R_PPC_EMB_NADDR16,	102)
+  RELOC_NUMBER (R_PPC_EMB_NADDR16_LO,	103)
+  RELOC_NUMBER (R_PPC_EMB_NADDR16_HI,	104)
+  RELOC_NUMBER (R_PPC_EMB_NADDR16_HA,	105)
+  RELOC_NUMBER (R_PPC_EMB_SDAI16,	106)
+  RELOC_NUMBER (R_PPC_EMB_SDA2I16,	107)
+  RELOC_NUMBER (R_PPC_EMB_SDA2REL,	108)
+  RELOC_NUMBER (R_PPC_EMB_SDA21,	109)
+  RELOC_NUMBER (R_PPC_EMB_MRKREF,	110)
+  RELOC_NUMBER (R_PPC_EMB_RELSEC16,	111)
+  RELOC_NUMBER (R_PPC_EMB_RELST_LO,	112)
+  RELOC_NUMBER (R_PPC_EMB_RELST_HI,	113)
+  RELOC_NUMBER (R_PPC_EMB_RELST_HA,	114)
+  RELOC_NUMBER (R_PPC_EMB_BIT_FLD,	115)
+  RELOC_NUMBER (R_PPC_EMB_RELSDA,	116)
 
   /* These are GNU extensions to enable C++ vtable garbage collection.  */
-  RELOC_NUMBER (R_PPC_GNU_VTINHERIT, 253)
-  RELOC_NUMBER (R_PPC_GNU_VTENTRY, 254)
+  RELOC_NUMBER (R_PPC_GNU_VTINHERIT,	253)
+  RELOC_NUMBER (R_PPC_GNU_VTENTRY,	254)
 
 /* This is a phony reloc to handle any old fashioned TOC16 references
    that may still be in object files.  */
-  RELOC_NUMBER (R_PPC_TOC16, 255)
+  RELOC_NUMBER (R_PPC_TOC16,		255)
 
 END_RELOC_NUMBERS (R_PPC_max)
 
Index: include/elf/ppc64.h
===================================================================
RCS file: /cvs/src/src/include/elf/ppc64.h,v
retrieving revision 1.1
diff -u -p -d -r1.1 ppc64.h
--- include/elf/ppc64.h	16 Jan 2003 04:08:47 -0000	1.1
+++ include/elf/ppc64.h	4 Feb 2003 14:02:29 -0000
@@ -24,82 +24,127 @@ Foundation, Inc., 59 Temple Place - Suit
 
 /* Relocations.  */
 START_RELOC_NUMBERS (elf_ppc64_reloc_type)
-  RELOC_NUMBER (R_PPC64_NONE,		  0)
-  RELOC_NUMBER (R_PPC64_ADDR32,		  1)
-  RELOC_NUMBER (R_PPC64_ADDR24,		  2)
-  RELOC_NUMBER (R_PPC64_ADDR16,		  3)
-  RELOC_NUMBER (R_PPC64_ADDR16_LO,	  4)
-  RELOC_NUMBER (R_PPC64_ADDR16_HI,	  5)
-  RELOC_NUMBER (R_PPC64_ADDR16_HA,	  6)
-  RELOC_NUMBER (R_PPC64_ADDR14,		  7)
-  RELOC_NUMBER (R_PPC64_ADDR14_BRTAKEN,	  8)
-  RELOC_NUMBER (R_PPC64_ADDR14_BRNTAKEN,  9)
-  RELOC_NUMBER (R_PPC64_REL24,		 10)
-  RELOC_NUMBER (R_PPC64_REL14,		 11)
-  RELOC_NUMBER (R_PPC64_REL14_BRTAKEN,	 12)
-  RELOC_NUMBER (R_PPC64_REL14_BRNTAKEN,	 13)
-  RELOC_NUMBER (R_PPC64_GOT16,		 14)
-  RELOC_NUMBER (R_PPC64_GOT16_LO,	 15)
-  RELOC_NUMBER (R_PPC64_GOT16_HI,	 16)
-  RELOC_NUMBER (R_PPC64_GOT16_HA,	 17)
+  RELOC_NUMBER (R_PPC64_NONE,		     0)
+  RELOC_NUMBER (R_PPC64_ADDR32,		     1)
+  RELOC_NUMBER (R_PPC64_ADDR24,		     2)
+  RELOC_NUMBER (R_PPC64_ADDR16,		     3)
+  RELOC_NUMBER (R_PPC64_ADDR16_LO,	     4)
+  RELOC_NUMBER (R_PPC64_ADDR16_HI,	     5)
+  RELOC_NUMBER (R_PPC64_ADDR16_HA,	     6)
+  RELOC_NUMBER (R_PPC64_ADDR14,		     7)
+  RELOC_NUMBER (R_PPC64_ADDR14_BRTAKEN,	     8)
+  RELOC_NUMBER (R_PPC64_ADDR14_BRNTAKEN,     9)
+  RELOC_NUMBER (R_PPC64_REL24,		    10)
+  RELOC_NUMBER (R_PPC64_REL14,		    11)
+  RELOC_NUMBER (R_PPC64_REL14_BRTAKEN,	    12)
+  RELOC_NUMBER (R_PPC64_REL14_BRNTAKEN,	    13)
+  RELOC_NUMBER (R_PPC64_GOT16,		    14)
+  RELOC_NUMBER (R_PPC64_GOT16_LO,	    15)
+  RELOC_NUMBER (R_PPC64_GOT16_HI,	    16)
+  RELOC_NUMBER (R_PPC64_GOT16_HA,	    17)
   /* 18 unused.  32-bit reloc is R_PPC_PLTREL24.  */
-  RELOC_NUMBER (R_PPC64_COPY,		 19)
-  RELOC_NUMBER (R_PPC64_GLOB_DAT,	 20)
-  RELOC_NUMBER (R_PPC64_JMP_SLOT,	 21)
-  RELOC_NUMBER (R_PPC64_RELATIVE,	 22)
+  RELOC_NUMBER (R_PPC64_COPY,		    19)
+  RELOC_NUMBER (R_PPC64_GLOB_DAT,	    20)
+  RELOC_NUMBER (R_PPC64_JMP_SLOT,	    21)
+  RELOC_NUMBER (R_PPC64_RELATIVE,	    22)
   /* 23 unused.  32-bit reloc is R_PPC_LOCAL24PC.  */
-  RELOC_NUMBER (R_PPC64_UADDR32,	 24)
-  RELOC_NUMBER (R_PPC64_UADDR16,	 25)
-  RELOC_NUMBER (R_PPC64_REL32,		 26)
-  RELOC_NUMBER (R_PPC64_PLT32,		 27)
-  RELOC_NUMBER (R_PPC64_PLTREL32,	 28)
-  RELOC_NUMBER (R_PPC64_PLT16_LO,	 29)
-  RELOC_NUMBER (R_PPC64_PLT16_HI,	 30)
-  RELOC_NUMBER (R_PPC64_PLT16_HA,	 31)
+  RELOC_NUMBER (R_PPC64_UADDR32,	    24)
+  RELOC_NUMBER (R_PPC64_UADDR16,	    25)
+  RELOC_NUMBER (R_PPC64_REL32,		    26)
+  RELOC_NUMBER (R_PPC64_PLT32,		    27)
+  RELOC_NUMBER (R_PPC64_PLTREL32,	    28)
+  RELOC_NUMBER (R_PPC64_PLT16_LO,	    29)
+  RELOC_NUMBER (R_PPC64_PLT16_HI,	    30)
+  RELOC_NUMBER (R_PPC64_PLT16_HA,	    31)
   /* 32 unused.  32-bit reloc is R_PPC_SDAREL16.  */
-  RELOC_NUMBER (R_PPC64_SECTOFF,	 33)
-  RELOC_NUMBER (R_PPC64_SECTOFF_LO,	 34)
-  RELOC_NUMBER (R_PPC64_SECTOFF_HI,	 35)
-  RELOC_NUMBER (R_PPC64_SECTOFF_HA,	 36)
-  RELOC_NUMBER (R_PPC64_REL30,		 37)
-  RELOC_NUMBER (R_PPC64_ADDR64,		 38)
-  RELOC_NUMBER (R_PPC64_ADDR16_HIGHER,	 39)
-  RELOC_NUMBER (R_PPC64_ADDR16_HIGHERA,	 40)
-  RELOC_NUMBER (R_PPC64_ADDR16_HIGHEST,	 41)
-  RELOC_NUMBER (R_PPC64_ADDR16_HIGHESTA, 42)
-  RELOC_NUMBER (R_PPC64_UADDR64,	 43)
-  RELOC_NUMBER (R_PPC64_REL64,		 44)
-  RELOC_NUMBER (R_PPC64_PLT64,		 45)
-  RELOC_NUMBER (R_PPC64_PLTREL64,	 46)
-  RELOC_NUMBER (R_PPC64_TOC16,		 47)
-  RELOC_NUMBER (R_PPC64_TOC16_LO,	 48)
-  RELOC_NUMBER (R_PPC64_TOC16_HI,	 49)
-  RELOC_NUMBER (R_PPC64_TOC16_HA,	 50)
-  RELOC_NUMBER (R_PPC64_TOC,		 51)
-  RELOC_NUMBER (R_PPC64_PLTGOT16,	 52)
-  RELOC_NUMBER (R_PPC64_PLTGOT16_LO,	 53)
-  RELOC_NUMBER (R_PPC64_PLTGOT16_HI,	 54)
-  RELOC_NUMBER (R_PPC64_PLTGOT16_HA,	 55)
+  RELOC_NUMBER (R_PPC64_SECTOFF,	    33)
+  RELOC_NUMBER (R_PPC64_SECTOFF_LO,	    34)
+  RELOC_NUMBER (R_PPC64_SECTOFF_HI,	    35)
+  RELOC_NUMBER (R_PPC64_SECTOFF_HA,	    36)
+  RELOC_NUMBER (R_PPC64_REL30,		    37)
+  RELOC_NUMBER (R_PPC64_ADDR64,		    38)
+  RELOC_NUMBER (R_PPC64_ADDR16_HIGHER,	    39)
+  RELOC_NUMBER (R_PPC64_ADDR16_HIGHERA,	    40)
+  RELOC_NUMBER (R_PPC64_ADDR16_HIGHEST,	    41)
+  RELOC_NUMBER (R_PPC64_ADDR16_HIGHESTA,    42)
+  RELOC_NUMBER (R_PPC64_UADDR64,	    43)
+  RELOC_NUMBER (R_PPC64_REL64,		    44)
+  RELOC_NUMBER (R_PPC64_PLT64,		    45)
+  RELOC_NUMBER (R_PPC64_PLTREL64,	    46)
+  RELOC_NUMBER (R_PPC64_TOC16,		    47)
+  RELOC_NUMBER (R_PPC64_TOC16_LO,	    48)
+  RELOC_NUMBER (R_PPC64_TOC16_HI,	    49)
+  RELOC_NUMBER (R_PPC64_TOC16_HA,	    50)
+  RELOC_NUMBER (R_PPC64_TOC,		    51)
+  RELOC_NUMBER (R_PPC64_PLTGOT16,	    52)
+  RELOC_NUMBER (R_PPC64_PLTGOT16_LO,	    53)
+  RELOC_NUMBER (R_PPC64_PLTGOT16_HI,	    54)
+  RELOC_NUMBER (R_PPC64_PLTGOT16_HA,	    55)
 
-/* The following relocs were added in the 64-bit PowerPC ELF ABI
-   revision 1.2. */
-  RELOC_NUMBER (R_PPC64_ADDR16_DS,	 56)
-  RELOC_NUMBER (R_PPC64_ADDR16_LO_DS,	 57)
-  RELOC_NUMBER (R_PPC64_GOT16_DS,	 58)
-  RELOC_NUMBER (R_PPC64_GOT16_LO_DS,	 59)
-  RELOC_NUMBER (R_PPC64_PLT16_LO_DS,	 60)
-  RELOC_NUMBER (R_PPC64_SECTOFF_DS,	 61)
-  RELOC_NUMBER (R_PPC64_SECTOFF_LO_DS,	 62)
-  RELOC_NUMBER (R_PPC64_TOC16_DS,	 63)
-  RELOC_NUMBER (R_PPC64_TOC16_LO_DS,	 64)
-  RELOC_NUMBER (R_PPC64_PLTGOT16_DS,	 65)
-  RELOC_NUMBER (R_PPC64_PLTGOT16_LO_DS,	 66)
+  /* The following relocs were added in the 64-bit PowerPC ELF ABI
+     revision 1.2. */
+  RELOC_NUMBER (R_PPC64_ADDR16_DS,	    56)
+  RELOC_NUMBER (R_PPC64_ADDR16_LO_DS,	    57)
+  RELOC_NUMBER (R_PPC64_GOT16_DS,	    58)
+  RELOC_NUMBER (R_PPC64_GOT16_LO_DS,	    59)
+  RELOC_NUMBER (R_PPC64_PLT16_LO_DS,	    60)
+  RELOC_NUMBER (R_PPC64_SECTOFF_DS,	    61)
+  RELOC_NUMBER (R_PPC64_SECTOFF_LO_DS,	    62)
+  RELOC_NUMBER (R_PPC64_TOC16_DS,	    63)
+  RELOC_NUMBER (R_PPC64_TOC16_LO_DS,	    64)
+  RELOC_NUMBER (R_PPC64_PLTGOT16_DS,	    65)
+  RELOC_NUMBER (R_PPC64_PLTGOT16_LO_DS,	    66)
+
+  /* Relocs added to support TLS.  PowerPC64 ELF ABI revision 1.5.  */
+  RELOC_NUMBER (R_PPC64_TLS,		    67)
+  RELOC_NUMBER (R_PPC64_DTPMOD64,	    68)
+  RELOC_NUMBER (R_PPC64_TPREL16,	    69)
+  RELOC_NUMBER (R_PPC64_TPREL16_LO,	    70)
+  RELOC_NUMBER (R_PPC64_TPREL16_HI,	    71)
+  RELOC_NUMBER (R_PPC64_TPREL16_HA,	    72)
+  RELOC_NUMBER (R_PPC64_TPREL64,	    73)
+  RELOC_NUMBER (R_PPC64_DTPREL16,	    74)
+  RELOC_NUMBER (R_PPC64_DTPREL16_LO,	    75)
+  RELOC_NUMBER (R_PPC64_DTPREL16_HI,	    76)
+  RELOC_NUMBER (R_PPC64_DTPREL16_HA,	    77)
+  RELOC_NUMBER (R_PPC64_DTPREL64,	    78)
+  RELOC_NUMBER (R_PPC64_GOT_TLSGD16,	    79)
+  RELOC_NUMBER (R_PPC64_GOT_TLSGD16_LO,	    80)
+  RELOC_NUMBER (R_PPC64_GOT_TLSGD16_HI,	    81)
+  RELOC_NUMBER (R_PPC64_GOT_TLSGD16_HA,	    82)
+  RELOC_NUMBER (R_PPC64_GOT_TLSLD16,	    83)
+  RELOC_NUMBER (R_PPC64_GOT_TLSLD16_LO,	    84)
+  RELOC_NUMBER (R_PPC64_GOT_TLSLD16_HI,	    85)
+  RELOC_NUMBER (R_PPC64_GOT_TLSLD16_HA,	    86)
+  RELOC_NUMBER (R_PPC64_GOT_TPREL16_DS,	    87)
+  RELOC_NUMBER (R_PPC64_GOT_TPREL16_LO_DS,  88)
+  RELOC_NUMBER (R_PPC64_GOT_TPREL16_HI,	    89)
+  RELOC_NUMBER (R_PPC64_GOT_TPREL16_HA,	    90)
+  RELOC_NUMBER (R_PPC64_GOT_DTPREL16_DS,    91)
+  RELOC_NUMBER (R_PPC64_GOT_DTPREL16_LO_DS, 92)
+  RELOC_NUMBER (R_PPC64_GOT_DTPREL16_HI,    93)
+  RELOC_NUMBER (R_PPC64_GOT_DTPREL16_HA,    94)
+  RELOC_NUMBER (R_PPC64_TPREL16_DS,	    95)
+  RELOC_NUMBER (R_PPC64_TPREL16_LO_DS,	    96)
+  RELOC_NUMBER (R_PPC64_TPREL16_HIGHER,	    97)
+  RELOC_NUMBER (R_PPC64_TPREL16_HIGHERA,    98)
+  RELOC_NUMBER (R_PPC64_TPREL16_HIGHEST,    99)
+  RELOC_NUMBER (R_PPC64_TPREL16_HIGHESTA,  100)
+  RELOC_NUMBER (R_PPC64_DTPREL16_DS,	   101)
+  RELOC_NUMBER (R_PPC64_DTPREL16_LO_DS,	   102)
+  RELOC_NUMBER (R_PPC64_DTPREL16_HIGHER,   103)
+  RELOC_NUMBER (R_PPC64_DTPREL16_HIGHERA,  104)
+  RELOC_NUMBER (R_PPC64_DTPREL16_HIGHEST,  105)
+  RELOC_NUMBER (R_PPC64_DTPREL16_HIGHESTA, 106)
 
   /* These are GNU extensions to enable C++ vtable garbage collection.  */
-  RELOC_NUMBER (R_PPC64_GNU_VTINHERIT,	253)
-  RELOC_NUMBER (R_PPC64_GNU_VTENTRY,	254)
+  RELOC_NUMBER (R_PPC64_GNU_VTINHERIT,	   253)
+  RELOC_NUMBER (R_PPC64_GNU_VTENTRY,	   254)
 
 END_RELOC_NUMBERS (R_PPC64_max)
+
+#define IS_TLS_RELOC(R) \
+  ((R) >= R_PPC64_TLS && (R) <= R_PPC64_DTPREL16_HIGHESTA)
 
 /* Specify the start of the .glink section.  */
 #define DT_PPC64_GLINK		DT_LOPROC
Index: bfd/elf64-ppc.c
===================================================================
RCS file: /cvs/src/src/bfd/elf64-ppc.c,v
retrieving revision 1.79
diff -u -p -d -r1.79 elf64-ppc.c
--- bfd/elf64-ppc.c	23 Jan 2003 11:51:32 -0000	1.79
+++ bfd/elf64-ppc.c	4 Feb 2003 14:02:14 -0000
@@ -71,7 +71,11 @@ static bfd_boolean ppc64_elf_new_section
 #define PLT_INITIAL_ENTRY_SIZE PLT_ENTRY_SIZE
 
 /* TOC base pointers offset from start of TOC.  */
-#define TOC_BASE_OFF (0x8000)
+#define TOC_BASE_OFF	0x8000
+
+/* Offset of tp and dtp pointers from start of TLS block.  */
+#define TP_OFFSET	0x7000
+#define DTP_OFFSET	0x8000
 
 /* .plt call stub instructions.  */
 #define ADDIS_R12_R2	0x3d820000	/* addis %r12,%r2,xxx@ha     */
@@ -134,8 +138,8 @@ static reloc_howto_type ppc64_elf_howto_
   /* This reloc does nothing.  */
   HOWTO (R_PPC64_NONE,		/* type */
 	 0,			/* rightshift */
-	 0,			/* size (0 = byte, 1 = short, 2 = long) */
-	 8,			/* bitsize */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 32,			/* bitsize */
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
 	 complain_overflow_dont, /* complain_on_overflow */
@@ -1152,6 +1156,616 @@ static reloc_howto_type ppc64_elf_howto_
 	 0xfffc,		/* dst_mask */
 	 FALSE),		/* pcrel_offset */
 
+  /* Marker reloc for TLS.  */
+  HOWTO (R_PPC64_TLS,
+	 0,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 32,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 bfd_elf_generic_reloc,	/* special_function */
+	 "R_PPC64_TLS",		/* name */
+	 FALSE,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0,			/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+
+  /* Computes the load module index of the load module that contains the
+     definition of its TLS sym.  */
+  HOWTO (R_PPC64_DTPMOD64,
+	 0,			/* rightshift */
+	 4,			/* size (0 = byte, 1 = short, 2 = long) */
+	 64,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 ppc64_elf_unhandled_reloc, /* special_function */
+	 "R_PPC64_DTPMOD64",	/* name */
+	 FALSE,			/* partial_inplace */
+	 0,			/* src_mask */
+	 ONES (64),		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+
+  /* Computes a dtv-relative displacement, the difference between the value
+     of sym+add and the base address of the thread-local storage block that
+     contains the definition of sym, minus 0x8000.  */
+  HOWTO (R_PPC64_DTPREL64,
+	 0,			/* rightshift */
+	 4,			/* size (0 = byte, 1 = short, 2 = long) */
+	 64,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 ppc64_elf_unhandled_reloc, /* special_function */
+	 "R_PPC64_DTPREL64",	/* name */
+	 FALSE,			/* partial_inplace */
+	 0,			/* src_mask */
+	 ONES (64),		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+
+  /* A 16 bit dtprel reloc.  */
+  HOWTO (R_PPC64_DTPREL16,
+	 0,			/* rightshift */
+	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_signed, /* complain_on_overflow */
+	 ppc64_elf_unhandled_reloc, /* special_function */
+	 "R_PPC64_DTPREL16",	/* name */
+	 FALSE,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0xffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+
+  /* Like DTPREL16, but no overflow.  */
+  HOWTO (R_PPC64_DTPREL16_LO,
+	 0,			/* rightshift */
+	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 ppc64_elf_unhandled_reloc, /* special_function */
+	 "R_PPC64_DTPREL16_LO",	/* name */
+	 FALSE,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0xffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+
+  /* Like DTPREL16_LO, but next higher group of 16 bits.  */
+  HOWTO (R_PPC64_DTPREL16_HI,
+	 16,			/* rightshift */
+	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 ppc64_elf_unhandled_reloc, /* special_function */
+	 "R_PPC64_DTPREL16_HI",	/* name */
+	 FALSE,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0xffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+
+  /* Like DTPREL16_HI, but adjust for low 16 bits.  */
+  HOWTO (R_PPC64_DTPREL16_HA,
+	 16,			/* rightshift */
+	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 ppc64_elf_unhandled_reloc, /* special_function */
+	 "R_PPC64_DTPREL16_HA",	/* name */
+	 FALSE,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0xffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+
+  /* Like DTPREL16_HI, but next higher group of 16 bits.  */
+  HOWTO (R_PPC64_DTPREL16_HIGHER,
+	 32,			/* rightshift */
+	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 ppc64_elf_unhandled_reloc, /* special_function */
+	 "R_PPC64_DTPREL16_HIGHER", /* name */
+	 FALSE,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0xffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+
+  /* Like DTPREL16_HIGHER, but adjust for low 16 bits.  */
+  HOWTO (R_PPC64_DTPREL16_HIGHERA,
+	 32,			/* rightshift */
+	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 ppc64_elf_unhandled_reloc, /* special_function */
+	 "R_PPC64_DTPREL16_HIGHERA", /* name */
+	 FALSE,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0xffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+
+  /* Like DTPREL16_HIGHER, but next higher group of 16 bits.  */
+  HOWTO (R_PPC64_DTPREL16_HIGHEST,
+	 48,			/* rightshift */
+	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 ppc64_elf_unhandled_reloc, /* special_function */
+	 "R_PPC64_DTPREL16_HIGHEST", /* name */
+	 FALSE,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0xffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+
+  /* Like DTPREL16_HIGHEST, but adjust for low 16 bits.  */
+  HOWTO (R_PPC64_DTPREL16_HIGHESTA,
+	 48,			/* rightshift */
+	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 ppc64_elf_unhandled_reloc, /* special_function */
+	 "R_PPC64_DTPREL16_HIGHESTA", /* name */
+	 FALSE,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0xffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+
+  /* Like DTPREL16, but for insns with a DS field.  */
+  HOWTO (R_PPC64_DTPREL16_DS,
+	 0,			/* rightshift */
+	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_signed, /* complain_on_overflow */
+	 ppc64_elf_unhandled_reloc, /* special_function */
+	 "R_PPC64_DTPREL16_DS",	/* name */
+	 FALSE,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0xfffc,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+
+  /* Like DTPREL16_DS, but no overflow.  */
+  HOWTO (R_PPC64_DTPREL16_LO_DS,
+	 0,			/* rightshift */
+	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 ppc64_elf_unhandled_reloc, /* special_function */
+	 "R_PPC64_DTPREL16_LO_DS", /* name */
+	 FALSE,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0xfffc,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+
+  /* Computes a tp-relative displacement, the difference between the value of
+     sym+add and the value of the thread pointer (r13).  */
+  HOWTO (R_PPC64_TPREL64,
+	 0,			/* rightshift */
+	 4,			/* size (0 = byte, 1 = short, 2 = long) */
+	 64,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 ppc64_elf_unhandled_reloc, /* special_function */
+	 "R_PPC64_TPREL64",	/* name */
+	 FALSE,			/* partial_inplace */
+	 0,			/* src_mask */
+	 ONES (64),		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+
+  /* A 16 bit tprel reloc.  */
+  HOWTO (R_PPC64_TPREL16,
+	 0,			/* rightshift */
+	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_signed, /* complain_on_overflow */
+	 ppc64_elf_unhandled_reloc, /* special_function */
+	 "R_PPC64_TPREL16",	/* name */
+	 FALSE,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0xffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+
+  /* Like TPREL16, but no overflow.  */
+  HOWTO (R_PPC64_TPREL16_LO,
+	 0,			/* rightshift */
+	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 ppc64_elf_unhandled_reloc, /* special_function */
+	 "R_PPC64_TPREL16_LO",	/* name */
+	 FALSE,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0xffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+
+  /* Like TPREL16_LO, but next higher group of 16 bits.  */
+  HOWTO (R_PPC64_TPREL16_HI,
+	 16,			/* rightshift */
+	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 ppc64_elf_unhandled_reloc, /* special_function */
+	 "R_PPC64_TPREL16_HI",	/* name */
+	 FALSE,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0xffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+
+  /* Like TPREL16_HI, but adjust for low 16 bits.  */
+  HOWTO (R_PPC64_TPREL16_HA,
+	 16,			/* rightshift */
+	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 ppc64_elf_unhandled_reloc, /* special_function */
+	 "R_PPC64_TPREL16_HA",	/* name */
+	 FALSE,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0xffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+
+  /* Like TPREL16_HI, but next higher group of 16 bits.  */
+  HOWTO (R_PPC64_TPREL16_HIGHER,
+	 32,			/* rightshift */
+	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 ppc64_elf_unhandled_reloc, /* special_function */
+	 "R_PPC64_TPREL16_HIGHER",	/* name */
+	 FALSE,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0xffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+
+  /* Like TPREL16_HIGHER, but adjust for low 16 bits.  */
+  HOWTO (R_PPC64_TPREL16_HIGHERA,
+	 32,			/* rightshift */
+	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 ppc64_elf_unhandled_reloc, /* special_function */
+	 "R_PPC64_TPREL16_HIGHERA", /* name */
+	 FALSE,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0xffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+
+  /* Like TPREL16_HIGHER, but next higher group of 16 bits.  */
+  HOWTO (R_PPC64_TPREL16_HIGHEST,
+	 48,			/* rightshift */
+	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 ppc64_elf_unhandled_reloc, /* special_function */
+	 "R_PPC64_TPREL16_HIGHEST", /* name */
+	 FALSE,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0xffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+
+  /* Like TPREL16_HIGHEST, but adjust for low 16 bits.  */
+  HOWTO (R_PPC64_TPREL16_HIGHESTA,
+	 48,			/* rightshift */
+	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 ppc64_elf_unhandled_reloc, /* special_function */
+	 "R_PPC64_TPREL16_HIGHESTA", /* name */
+	 FALSE,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0xffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+
+  /* Like TPREL16, but for insns with a DS field.  */
+  HOWTO (R_PPC64_TPREL16_DS,
+	 0,			/* rightshift */
+	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_signed, /* complain_on_overflow */
+	 ppc64_elf_unhandled_reloc, /* special_function */
+	 "R_PPC64_TPREL16_DS",	/* name */
+	 FALSE,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0xfffc,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+
+  /* Like TPREL16_DS, but no overflow.  */
+  HOWTO (R_PPC64_TPREL16_LO_DS,
+	 0,			/* rightshift */
+	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 ppc64_elf_unhandled_reloc, /* special_function */
+	 "R_PPC64_TPREL16_LO_DS", /* name */
+	 FALSE,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0xfffc,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+
+  /* Allocates two contiguous entries in the GOT to hold a tls_index structure,
+     with values (sym+add)@dtpmod and (sym+add)@dtprel, and computes the offset
+     to the first entry relative to the TOC base (r2).  */
+  HOWTO (R_PPC64_GOT_TLSGD16,
+	 0,			/* rightshift */
+	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_signed, /* complain_on_overflow */
+	 ppc64_elf_unhandled_reloc, /* special_function */
+	 "R_PPC64_GOT_TLSGD16",	/* name */
+	 FALSE,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0xffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+
+  /* Like GOT_TLSGD16, but no overflow.  */
+  HOWTO (R_PPC64_GOT_TLSGD16_LO,
+	 0,			/* rightshift */
+	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 ppc64_elf_unhandled_reloc, /* special_function */
+	 "R_PPC64_GOT_TLSGD16_LO", /* name */
+	 FALSE,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0xffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+
+  /* Like GOT_TLSGD16_LO, but next higher group of 16 bits.  */
+  HOWTO (R_PPC64_GOT_TLSGD16_HI,
+	 16,			/* rightshift */
+	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 ppc64_elf_unhandled_reloc, /* special_function */
+	 "R_PPC64_GOT_TLSGD16_HI", /* name */
+	 FALSE,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0xffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+
+  /* Like GOT_TLSGD16_HI, but adjust for low 16 bits.  */
+  HOWTO (R_PPC64_GOT_TLSGD16_HA,
+	 16,			/* rightshift */
+	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 ppc64_elf_unhandled_reloc, /* special_function */
+	 "R_PPC64_GOT_TLSGD16_HA", /* name */
+	 FALSE,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0xffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+
+  /* Allocates two contiguous entries in the GOT to hold a tls_index structure,
+     with values (sym+add)@dtpmod and zero, and computes the offset to the
+     first entry relative to the TOC base (r2).  */
+  HOWTO (R_PPC64_GOT_TLSLD16,
+	 0,			/* rightshift */
+	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_signed, /* complain_on_overflow */
+	 ppc64_elf_unhandled_reloc, /* special_function */
+	 "R_PPC64_GOT_TLSLD16",	/* name */
+	 FALSE,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0xffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+
+  /* Like GOT_TLSLD16, but no overflow.  */
+  HOWTO (R_PPC64_GOT_TLSLD16_LO,
+	 0,			/* rightshift */
+	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 ppc64_elf_unhandled_reloc, /* special_function */
+	 "R_PPC64_GOT_TLSLD16_LO", /* name */
+	 FALSE,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0xffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+
+  /* Like GOT_TLSLD16_LO, but next higher group of 16 bits.  */
+  HOWTO (R_PPC64_GOT_TLSLD16_HI,
+	 16,			/* rightshift */
+	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 ppc64_elf_unhandled_reloc, /* special_function */
+	 "R_PPC64_GOT_TLSLD16_HI", /* name */
+	 FALSE,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0xffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+
+  /* Like GOT_TLSLD16_HI, but adjust for low 16 bits.  */
+  HOWTO (R_PPC64_GOT_TLSLD16_HA,
+	 16,			/* rightshift */
+	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 ppc64_elf_unhandled_reloc, /* special_function */
+	 "R_PPC64_GOT_TLSLD16_HA", /* name */
+	 FALSE,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0xffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+
+  /* Allocates an entry in the GOT with value (sym+add)@dtprel, and computes
+     the offset to the entry relative to the TOC base (r2).  */
+  HOWTO (R_PPC64_GOT_DTPREL16_DS,
+	 0,			/* rightshift */
+	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_signed, /* complain_on_overflow */
+	 ppc64_elf_unhandled_reloc, /* special_function */
+	 "R_PPC64_GOT_DTPREL16_DS", /* name */
+	 FALSE,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0xfffc,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+
+  /* Like GOT_DTPREL16_DS, but no overflow.  */
+  HOWTO (R_PPC64_GOT_DTPREL16_LO_DS,
+	 0,			/* rightshift */
+	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 ppc64_elf_unhandled_reloc, /* special_function */
+	 "R_PPC64_GOT_DTPREL16_LO_DS", /* name */
+	 FALSE,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0xfffc,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+
+  /* Like GOT_DTPREL16_LO_DS, but next higher group of 16 bits.  */
+  HOWTO (R_PPC64_GOT_DTPREL16_HI,
+	 16,			/* rightshift */
+	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 ppc64_elf_unhandled_reloc, /* special_function */
+	 "R_PPC64_GOT_DTPREL16_HI", /* name */
+	 FALSE,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0xffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+
+  /* Like GOT_DTPREL16_HI, but adjust for low 16 bits.  */
+  HOWTO (R_PPC64_GOT_DTPREL16_HA,
+	 16,			/* rightshift */
+	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 ppc64_elf_unhandled_reloc, /* special_function */
+	 "R_PPC64_GOT_DTPREL16_HA", /* name */
+	 FALSE,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0xffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+
+  /* Allocates an entry in the GOT with value (sym+add)@tprel, and computes the
+     offset to the entry relative to the TOC base (r2).  */
+  HOWTO (R_PPC64_GOT_TPREL16_DS,
+	 0,			/* rightshift */
+	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_signed, /* complain_on_overflow */
+	 ppc64_elf_unhandled_reloc, /* special_function */
+	 "R_PPC64_GOT_TPREL16_DS", /* name */
+	 FALSE,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0xffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+
+  /* Like GOT_TPREL16_DS, but no overflow.  */
+  HOWTO (R_PPC64_GOT_TPREL16_LO_DS,
+	 0,			/* rightshift */
+	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 ppc64_elf_unhandled_reloc, /* special_function */
+	 "R_PPC64_GOT_TPREL16_LO_DS", /* name */
+	 FALSE,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0xffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+
+  /* Like GOT_TPREL16_LO_DS, but next higher group of 16 bits.  */
+  HOWTO (R_PPC64_GOT_TPREL16_HI,
+	 16,			/* rightshift */
+	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 ppc64_elf_unhandled_reloc, /* special_function */
+	 "R_PPC64_GOT_TPREL16_HI", /* name */
+	 FALSE,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0xffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+
+  /* Like GOT_TPREL16_HI, but adjust for low 16 bits.  */
+  HOWTO (R_PPC64_GOT_TPREL16_HA,
+	 16,			/* rightshift */
+	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 ppc64_elf_unhandled_reloc, /* special_function */
+	 "R_PPC64_GOT_TPREL16_HA", /* name */
+	 FALSE,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0xffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+
   /* GNU extension to record C++ vtable hierarchy.  */
   HOWTO (R_PPC64_GNU_VTINHERIT,	/* type */
 	 0,			/* rightshift */
@@ -1208,7 +1822,7 @@ ppc64_elf_reloc_type_lookup (abfd, code)
      bfd *abfd ATTRIBUTE_UNUSED;
      bfd_reloc_code_real_type code;
 {
-  enum elf_ppc64_reloc_type ppc_reloc = R_PPC64_NONE;
+  enum elf_ppc64_reloc_type r = R_PPC64_NONE;
 
   if (!ppc64_elf_howto_table[R_PPC64_ADDR32])
     /* Initialize howto table if needed.  */
@@ -1219,131 +1833,211 @@ ppc64_elf_reloc_type_lookup (abfd, code)
     default:
       return (reloc_howto_type *) NULL;
 
-    case BFD_RELOC_NONE:		 ppc_reloc = R_PPC64_NONE;
+    case BFD_RELOC_NONE:			r = R_PPC64_NONE;
       break;
-    case BFD_RELOC_32:			 ppc_reloc = R_PPC64_ADDR32;
+    case BFD_RELOC_32:				r = R_PPC64_ADDR32;
       break;
-    case BFD_RELOC_PPC_BA26:		 ppc_reloc = R_PPC64_ADDR24;
+    case BFD_RELOC_PPC_BA26:			r = R_PPC64_ADDR24;
       break;
-    case BFD_RELOC_16:			 ppc_reloc = R_PPC64_ADDR16;
+    case BFD_RELOC_16:				r = R_PPC64_ADDR16;
       break;
-    case BFD_RELOC_LO16:		 ppc_reloc = R_PPC64_ADDR16_LO;
+    case BFD_RELOC_LO16:			r = R_PPC64_ADDR16_LO;
       break;
-    case BFD_RELOC_HI16:		 ppc_reloc = R_PPC64_ADDR16_HI;
+    case BFD_RELOC_HI16:			r = R_PPC64_ADDR16_HI;
       break;
-    case BFD_RELOC_HI16_S:		 ppc_reloc = R_PPC64_ADDR16_HA;
+    case BFD_RELOC_HI16_S:			r = R_PPC64_ADDR16_HA;
       break;
-    case BFD_RELOC_PPC_BA16:		 ppc_reloc = R_PPC64_ADDR14;
+    case BFD_RELOC_PPC_BA16:			r = R_PPC64_ADDR14;
       break;
-    case BFD_RELOC_PPC_BA16_BRTAKEN:	 ppc_reloc = R_PPC64_ADDR14_BRTAKEN;
+    case BFD_RELOC_PPC_BA16_BRTAKEN:		r = R_PPC64_ADDR14_BRTAKEN;
       break;
-    case BFD_RELOC_PPC_BA16_BRNTAKEN:	 ppc_reloc = R_PPC64_ADDR14_BRNTAKEN;
+    case BFD_RELOC_PPC_BA16_BRNTAKEN:		r = R_PPC64_ADDR14_BRNTAKEN;
       break;
-    case BFD_RELOC_PPC_B26:		 ppc_reloc = R_PPC64_REL24;
+    case BFD_RELOC_PPC_B26:			r = R_PPC64_REL24;
       break;
-    case BFD_RELOC_PPC_B16:		 ppc_reloc = R_PPC64_REL14;
+    case BFD_RELOC_PPC_B16:			r = R_PPC64_REL14;
       break;
-    case BFD_RELOC_PPC_B16_BRTAKEN:	 ppc_reloc = R_PPC64_REL14_BRTAKEN;
+    case BFD_RELOC_PPC_B16_BRTAKEN:		r = R_PPC64_REL14_BRTAKEN;
       break;
-    case BFD_RELOC_PPC_B16_BRNTAKEN:	 ppc_reloc = R_PPC64_REL14_BRNTAKEN;
+    case BFD_RELOC_PPC_B16_BRNTAKEN:		r = R_PPC64_REL14_BRNTAKEN;
       break;
-    case BFD_RELOC_16_GOTOFF:		 ppc_reloc = R_PPC64_GOT16;
+    case BFD_RELOC_16_GOTOFF:			r = R_PPC64_GOT16;
       break;
-    case BFD_RELOC_LO16_GOTOFF:		 ppc_reloc = R_PPC64_GOT16_LO;
+    case BFD_RELOC_LO16_GOTOFF:			r = R_PPC64_GOT16_LO;
       break;
-    case BFD_RELOC_HI16_GOTOFF:		 ppc_reloc = R_PPC64_GOT16_HI;
+    case BFD_RELOC_HI16_GOTOFF:			r = R_PPC64_GOT16_HI;
       break;
-    case BFD_RELOC_HI16_S_GOTOFF:	 ppc_reloc = R_PPC64_GOT16_HA;
+    case BFD_RELOC_HI16_S_GOTOFF:		r = R_PPC64_GOT16_HA;
       break;
-    case BFD_RELOC_PPC_COPY:		 ppc_reloc = R_PPC64_COPY;
+    case BFD_RELOC_PPC_COPY:			r = R_PPC64_COPY;
       break;
-    case BFD_RELOC_PPC_GLOB_DAT:	 ppc_reloc = R_PPC64_GLOB_DAT;
+    case BFD_RELOC_PPC_GLOB_DAT:		r = R_PPC64_GLOB_DAT;
       break;
-    case BFD_RELOC_32_PCREL:		 ppc_reloc = R_PPC64_REL32;
+    case BFD_RELOC_32_PCREL:			r = R_PPC64_REL32;
       break;
-    case BFD_RELOC_32_PLTOFF:		 ppc_reloc = R_PPC64_PLT32;
+    case BFD_RELOC_32_PLTOFF:			r = R_PPC64_PLT32;
       break;
-    case BFD_RELOC_32_PLT_PCREL:	 ppc_reloc = R_PPC64_PLTREL32;
+    case BFD_RELOC_32_PLT_PCREL:		r = R_PPC64_PLTREL32;
       break;
-    case BFD_RELOC_LO16_PLTOFF:		 ppc_reloc = R_PPC64_PLT16_LO;
+    case BFD_RELOC_LO16_PLTOFF:			r = R_PPC64_PLT16_LO;
       break;
-    case BFD_RELOC_HI16_PLTOFF:		 ppc_reloc = R_PPC64_PLT16_HI;
+    case BFD_RELOC_HI16_PLTOFF:			r = R_PPC64_PLT16_HI;
       break;
-    case BFD_RELOC_HI16_S_PLTOFF:	 ppc_reloc = R_PPC64_PLT16_HA;
+    case BFD_RELOC_HI16_S_PLTOFF:		r = R_PPC64_PLT16_HA;
       break;
-    case BFD_RELOC_16_BASEREL:		 ppc_reloc = R_PPC64_SECTOFF;
+    case BFD_RELOC_16_BASEREL:			r = R_PPC64_SECTOFF;
       break;
-    case BFD_RELOC_LO16_BASEREL:	 ppc_reloc = R_PPC64_SECTOFF_LO;
+    case BFD_RELOC_LO16_BASEREL:		r = R_PPC64_SECTOFF_LO;
       break;
-    case BFD_RELOC_HI16_BASEREL:	 ppc_reloc = R_PPC64_SECTOFF_HI;
+    case BFD_RELOC_HI16_BASEREL:		r = R_PPC64_SECTOFF_HI;
       break;
-    case BFD_RELOC_HI16_S_BASEREL:	 ppc_reloc = R_PPC64_SECTOFF_HA;
+    case BFD_RELOC_HI16_S_BASEREL:		r = R_PPC64_SECTOFF_HA;
       break;
-    case BFD_RELOC_CTOR:		 ppc_reloc = R_PPC64_ADDR64;
+    case BFD_RELOC_CTOR:			r = R_PPC64_ADDR64;
       break;
-    case BFD_RELOC_64:			 ppc_reloc = R_PPC64_ADDR64;
+    case BFD_RELOC_64:				r = R_PPC64_ADDR64;
       break;
-    case BFD_RELOC_PPC64_HIGHER:	 ppc_reloc = R_PPC64_ADDR16_HIGHER;
+    case BFD_RELOC_PPC64_HIGHER:		r = R_PPC64_ADDR16_HIGHER;
       break;
-    case BFD_RELOC_PPC64_HIGHER_S:	 ppc_reloc = R_PPC64_ADDR16_HIGHERA;
+    case BFD_RELOC_PPC64_HIGHER_S:		r = R_PPC64_ADDR16_HIGHERA;
       break;
-    case BFD_RELOC_PPC64_HIGHEST:	 ppc_reloc = R_PPC64_ADDR16_HIGHEST;
+    case BFD_RELOC_PPC64_HIGHEST:		r = R_PPC64_ADDR16_HIGHEST;
       break;
-    case BFD_RELOC_PPC64_HIGHEST_S:	 ppc_reloc = R_PPC64_ADDR16_HIGHESTA;
+    case BFD_RELOC_PPC64_HIGHEST_S:		r = R_PPC64_ADDR16_HIGHESTA;
       break;
-    case BFD_RELOC_64_PCREL:		 ppc_reloc = R_PPC64_REL64;
+    case BFD_RELOC_64_PCREL:			r = R_PPC64_REL64;
       break;
-    case BFD_RELOC_64_PLTOFF:		 ppc_reloc = R_PPC64_PLT64;
+    case BFD_RELOC_64_PLTOFF:			r = R_PPC64_PLT64;
       break;
-    case BFD_RELOC_64_PLT_PCREL:	 ppc_reloc = R_PPC64_PLTREL64;
+    case BFD_RELOC_64_PLT_PCREL:		r = R_PPC64_PLTREL64;
       break;
-    case BFD_RELOC_PPC_TOC16:		 ppc_reloc = R_PPC64_TOC16;
+    case BFD_RELOC_PPC_TOC16:			r = R_PPC64_TOC16;
       break;
-    case BFD_RELOC_PPC64_TOC16_LO:	 ppc_reloc = R_PPC64_TOC16_LO;
+    case BFD_RELOC_PPC64_TOC16_LO:		r = R_PPC64_TOC16_LO;
       break;
-    case BFD_RELOC_PPC64_TOC16_HI:	 ppc_reloc = R_PPC64_TOC16_HI;
+    case BFD_RELOC_PPC64_TOC16_HI:		r = R_PPC64_TOC16_HI;
       break;
-    case BFD_RELOC_PPC64_TOC16_HA:	 ppc_reloc = R_PPC64_TOC16_HA;
+    case BFD_RELOC_PPC64_TOC16_HA:		r = R_PPC64_TOC16_HA;
       break;
-    case BFD_RELOC_PPC64_TOC:		 ppc_reloc = R_PPC64_TOC;
+    case BFD_RELOC_PPC64_TOC:			r = R_PPC64_TOC;
       break;
-    case BFD_RELOC_PPC64_PLTGOT16:	 ppc_reloc = R_PPC64_PLTGOT16;
+    case BFD_RELOC_PPC64_PLTGOT16:		r = R_PPC64_PLTGOT16;
       break;
-    case BFD_RELOC_PPC64_PLTGOT16_LO:	 ppc_reloc = R_PPC64_PLTGOT16_LO;
+    case BFD_RELOC_PPC64_PLTGOT16_LO:		r = R_PPC64_PLTGOT16_LO;
       break;
-    case BFD_RELOC_PPC64_PLTGOT16_HI:	 ppc_reloc = R_PPC64_PLTGOT16_HI;
+    case BFD_RELOC_PPC64_PLTGOT16_HI:		r = R_PPC64_PLTGOT16_HI;
       break;
-    case BFD_RELOC_PPC64_PLTGOT16_HA:	 ppc_reloc = R_PPC64_PLTGOT16_HA;
+    case BFD_RELOC_PPC64_PLTGOT16_HA:		r = R_PPC64_PLTGOT16_HA;
       break;
-    case BFD_RELOC_PPC64_ADDR16_DS:      ppc_reloc = R_PPC64_ADDR16_DS;
+    case BFD_RELOC_PPC64_ADDR16_DS:		r = R_PPC64_ADDR16_DS;
       break;
-    case BFD_RELOC_PPC64_ADDR16_LO_DS:   ppc_reloc = R_PPC64_ADDR16_LO_DS;
+    case BFD_RELOC_PPC64_ADDR16_LO_DS:		r = R_PPC64_ADDR16_LO_DS;
       break;
-    case BFD_RELOC_PPC64_GOT16_DS:       ppc_reloc = R_PPC64_GOT16_DS;
+    case BFD_RELOC_PPC64_GOT16_DS:		r = R_PPC64_GOT16_DS;
       break;
-    case BFD_RELOC_PPC64_GOT16_LO_DS:    ppc_reloc = R_PPC64_GOT16_LO_DS;
+    case BFD_RELOC_PPC64_GOT16_LO_DS:		r = R_PPC64_GOT16_LO_DS;
       break;
-    case BFD_RELOC_PPC64_PLT16_LO_DS:    ppc_reloc = R_PPC64_PLT16_LO_DS;
+    case BFD_RELOC_PPC64_PLT16_LO_DS:		r = R_PPC64_PLT16_LO_DS;
       break;
-    case BFD_RELOC_PPC64_SECTOFF_DS:     ppc_reloc = R_PPC64_SECTOFF_DS;
+    case BFD_RELOC_PPC64_SECTOFF_DS:		r = R_PPC64_SECTOFF_DS;
       break;
-    case BFD_RELOC_PPC64_SECTOFF_LO_DS:  ppc_reloc = R_PPC64_SECTOFF_LO_DS;
+    case BFD_RELOC_PPC64_SECTOFF_LO_DS:		r = R_PPC64_SECTOFF_LO_DS;
       break;
-    case BFD_RELOC_PPC64_TOC16_DS:       ppc_reloc = R_PPC64_TOC16_DS;
+    case BFD_RELOC_PPC64_TOC16_DS:		r = R_PPC64_TOC16_DS;
       break;
-    case BFD_RELOC_PPC64_TOC16_LO_DS:    ppc_reloc = R_PPC64_TOC16_LO_DS;
+    case BFD_RELOC_PPC64_TOC16_LO_DS:		r = R_PPC64_TOC16_LO_DS;
       break;
-    case BFD_RELOC_PPC64_PLTGOT16_DS:    ppc_reloc = R_PPC64_PLTGOT16_DS;
+    case BFD_RELOC_PPC64_PLTGOT16_DS:		r = R_PPC64_PLTGOT16_DS;
       break;
-    case BFD_RELOC_PPC64_PLTGOT16_LO_DS: ppc_reloc = R_PPC64_PLTGOT16_LO_DS;
+    case BFD_RELOC_PPC64_PLTGOT16_LO_DS:	r = R_PPC64_PLTGOT16_LO_DS;
       break;
-    case BFD_RELOC_VTABLE_INHERIT:	 ppc_reloc = R_PPC64_GNU_VTINHERIT;
+    case BFD_RELOC_PPC_TLS:			r = R_PPC64_TLS;
       break;
-    case BFD_RELOC_VTABLE_ENTRY:	 ppc_reloc = R_PPC64_GNU_VTENTRY;
+    case BFD_RELOC_PPC_DTPMOD:			r = R_PPC64_DTPMOD64;
+      break;
+    case BFD_RELOC_PPC_TPREL16:			r = R_PPC64_TPREL16;
+      break;
+    case BFD_RELOC_PPC_TPREL16_LO:		r = R_PPC64_TPREL16_LO;
+      break;
+    case BFD_RELOC_PPC_TPREL16_HI:		r = R_PPC64_TPREL16_HI;
+      break;
+    case BFD_RELOC_PPC_TPREL16_HA:		r = R_PPC64_TPREL16_HA;
+      break;
+    case BFD_RELOC_PPC_TPREL:			r = R_PPC64_TPREL64;
+      break;
+    case BFD_RELOC_PPC_DTPREL16:		r = R_PPC64_DTPREL16;
+      break;
+    case BFD_RELOC_PPC_DTPREL16_LO:		r = R_PPC64_DTPREL16_LO;
+      break;
+    case BFD_RELOC_PPC_DTPREL16_HI:		r = R_PPC64_DTPREL16_HI;
+      break;
+    case BFD_RELOC_PPC_DTPREL16_HA:		r = R_PPC64_DTPREL16_HA;
+      break;
+    case BFD_RELOC_PPC_DTPREL:			r = R_PPC64_DTPREL64;
+      break;
+    case BFD_RELOC_PPC_GOT_TLSGD16:		r = R_PPC64_GOT_TLSGD16;
+      break;
+    case BFD_RELOC_PPC_GOT_TLSGD16_LO:		r = R_PPC64_GOT_TLSGD16_LO;
+      break;
+    case BFD_RELOC_PPC_GOT_TLSGD16_HI:		r = R_PPC64_GOT_TLSGD16_HI;
+      break;
+    case BFD_RELOC_PPC_GOT_TLSGD16_HA:		r = R_PPC64_GOT_TLSGD16_HA;
+      break;
+    case BFD_RELOC_PPC_GOT_TLSLD16:		r = R_PPC64_GOT_TLSLD16;
+      break;
+    case BFD_RELOC_PPC_GOT_TLSLD16_LO:		r = R_PPC64_GOT_TLSLD16_LO;
+      break;
+    case BFD_RELOC_PPC_GOT_TLSLD16_HI:		r = R_PPC64_GOT_TLSLD16_HI;
+      break;
+    case BFD_RELOC_PPC_GOT_TLSLD16_HA:		r = R_PPC64_GOT_TLSLD16_HA;
+      break;
+    case BFD_RELOC_PPC_GOT_TPREL16:		r = R_PPC64_GOT_TPREL16_DS;
+      break;
+    case BFD_RELOC_PPC_GOT_TPREL16_LO:		r = R_PPC64_GOT_TPREL16_LO_DS;
+      break;
+    case BFD_RELOC_PPC_GOT_TPREL16_HI:		r = R_PPC64_GOT_TPREL16_HI;
+      break;
+    case BFD_RELOC_PPC_GOT_TPREL16_HA:		r = R_PPC64_GOT_TPREL16_HA;
+      break;
+    case BFD_RELOC_PPC_GOT_DTPREL16:		r = R_PPC64_GOT_DTPREL16_DS;
+      break;
+    case BFD_RELOC_PPC_GOT_DTPREL16_LO:		r = R_PPC64_GOT_DTPREL16_LO_DS;
+      break;
+    case BFD_RELOC_PPC_GOT_DTPREL16_HI:		r = R_PPC64_GOT_DTPREL16_HI;
+      break;
+    case BFD_RELOC_PPC_GOT_DTPREL16_HA:		r = R_PPC64_GOT_DTPREL16_HA;
+      break;
+    case BFD_RELOC_PPC64_TPREL16_DS:		r = R_PPC64_TPREL16_DS;
+      break;
+    case BFD_RELOC_PPC64_TPREL16_LO_DS:		r = R_PPC64_TPREL16_LO_DS;
+      break;
+    case BFD_RELOC_PPC64_TPREL16_HIGHER:	r = R_PPC64_TPREL16_HIGHER;
+      break;
+    case BFD_RELOC_PPC64_TPREL16_HIGHERA:	r = R_PPC64_TPREL16_HIGHERA;
+      break;
+    case BFD_RELOC_PPC64_TPREL16_HIGHEST:	r = R_PPC64_TPREL16_HIGHEST;
+      break;
+    case BFD_RELOC_PPC64_TPREL16_HIGHESTA:	r = R_PPC64_TPREL16_HIGHESTA;
+      break;
+    case BFD_RELOC_PPC64_DTPREL16_DS:		r = R_PPC64_DTPREL16_DS;
+      break;
+    case BFD_RELOC_PPC64_DTPREL16_LO_DS:	r = R_PPC64_DTPREL16_LO_DS;
+      break;
+    case BFD_RELOC_PPC64_DTPREL16_HIGHER:	r = R_PPC64_DTPREL16_HIGHER;
+      break;
+    case BFD_RELOC_PPC64_DTPREL16_HIGHERA:	r = R_PPC64_DTPREL16_HIGHERA;
+      break;
+    case BFD_RELOC_PPC64_DTPREL16_HIGHEST:	r = R_PPC64_DTPREL16_HIGHEST;
+      break;
+    case BFD_RELOC_PPC64_DTPREL16_HIGHESTA:	r = R_PPC64_DTPREL16_HIGHESTA;
+      break;
+    case BFD_RELOC_VTABLE_INHERIT:		r = R_PPC64_GNU_VTINHERIT;
+      break;
+    case BFD_RELOC_VTABLE_ENTRY:		r = R_PPC64_GNU_VTENTRY;
       break;
     }
 
-  return ppc64_elf_howto_table[(int) ppc_reloc];
+  return ppc64_elf_howto_table[(int) r];
 };
 
 /* Set the howto pointer for a PowerPC ELF reloc.  */
@@ -1681,15 +2375,23 @@ ppc64_elf_merge_private_bfd_data (ibfd, 
 struct _ppc64_elf_section_data
 {
   struct bfd_elf_section_data elf;
+
+  /* An array with one entry for each opd function descriptor.  */
   union
   {
+    /* Points to the function code section for local opd entries.  */
     asection **func_sec;
+    /* After editing .opd, adjust references to opd local syms.  */
     long *adjust;
   } opd;
+
+  /* An array for toc sections, indexed by offset/8.
+     Specifies the relocation symbol index used at a given toc offset.  */
+  unsigned *t_symndx;
 };
 
 #define ppc64_elf_section_data(sec) \
-  ((struct _ppc64_elf_section_data *) (sec)->used_by_bfd)
+  ((struct _ppc64_elf_section_data *) elf_section_data (sec))
 
 static bfd_boolean
 ppc64_elf_new_section_hook (abfd, sec)
@@ -1747,7 +2449,7 @@ ppc64_elf_new_section_hook (abfd, sec)
    .
    .	.foo_stub:
    .		addis	12,2,Lfoo@toc@ha	# in practice, the call stub
-   .		addi	12,12,Lfoo@toc@l	# is slightly optimised, but
+   .		addi	12,12,Lfoo@toc@l	# is slightly optimized, but
    .		std	2,40(1)			# this is the general idea
    .		ld	11,0(12)
    .		ld	2,8(12)
@@ -1795,10 +2497,41 @@ struct ppc_dyn_relocs
   bfd_size_type pc_count;
 };
 
+/* Track GOT entries needed for a given symbol.  We might need more
+   than one got entry per symbol.  */
+struct got_entry
+{
+  struct got_entry *next;
+
+  bfd_vma addend;
+
+  union
+    {
+      bfd_signed_vma refcount;
+      bfd_vma offset;
+    } got;
+
+  char tls_type;
+};
+
+/* The same for PLT.  */
+struct plt_entry
+{
+  struct plt_entry *next;
+
+  bfd_vma addend;
+
+  union
+    {
+      bfd_signed_vma refcount;
+      bfd_vma offset;
+    } plt;
+};
+
 /* Of those relocs that might be copied as dynamic relocs, this macro
-   selects between relative and absolute types.  */
+   selects those that must be copied when linking a shared library.  */
 
-#define IS_ABSOLUTE_RELOC(RTYPE)		\
+#define MUST_BE_DYN_RELOC(RTYPE)		\
   ((RTYPE) != R_PPC64_REL32			\
    && (RTYPE) != R_PPC64_REL64			\
    && (RTYPE) != R_PPC64_REL30)
@@ -1860,6 +2593,9 @@ struct ppc_stub_hash_entry {
   /* The symbol table entry, if any, that this was derived from.  */
   struct ppc_link_hash_entry *h;
 
+  /* And the reloc addend that this was derived from.  */
+  bfd_vma addend;
+
   /* Where this stub is being called from, or, in the case of combined
      stub sections, the first input section in the group.  */
   asection *id_sec;
@@ -1895,6 +2631,16 @@ struct ppc_link_hash_entry
   unsigned int is_func:1;
   unsigned int is_func_descriptor:1;
   unsigned int is_entry:1;
+
+  /* Contexts in which symbol is used in the GOT (or TOC).
+     Linker optimization will result in various transformations.  */
+#define TLS_TLS		1	/* Any TLS reloc.  */
+#define TLS_GD_LD	2	/* GD or LD reloc requiring 2 got slots. */
+#define TLS_LD		4	/* LD reloc. */
+#define TLS_TPREL	8	/* TPREL reloc, => IE. */
+#define TLS_DTPREL     16	/* DTPREL reloc, => LD. */
+#define TLS_EXPLICIT   32	/* Marks TOC section relocs. */
+  char tls_type;
 };
 
 /* ppc64 ELF linker hash table.  */
@@ -1941,6 +2687,18 @@ struct ppc_link_hash_table
   asection *sbrlt;
   asection *srelbrlt;
 
+  /* Short-cut to first output tls section.  */
+  asection *tls_sec;
+
+  /* Shortcut to .__tls_get_addr.  */
+  struct elf_link_hash_entry *tls_get_addr;
+
+  /* TLS local dynamic got entry handling.  */
+  union {
+    bfd_signed_vma refcount;
+    bfd_vma offset;
+  } tlsld_got;
+
   /* Set on error.  */
   unsigned int stub_error;
 
@@ -1985,6 +2743,10 @@ static bfd_boolean ppc64_elf_create_dyna
 static void ppc64_elf_copy_indirect_symbol
   PARAMS ((struct elf_backend_data *, struct elf_link_hash_entry *,
 	   struct elf_link_hash_entry *));
+static bfd_boolean update_local_sym_info
+  PARAMS ((bfd *, Elf_Internal_Shdr *, unsigned long, bfd_vma, int));
+static bfd_boolean update_plt_info
+  PARAMS ((bfd *, struct ppc_link_hash_entry *, bfd_vma));
 static bfd_boolean ppc64_elf_check_relocs
   PARAMS ((bfd *, struct bfd_link_info *, asection *,
 	   const Elf_Internal_Rela *));
@@ -2002,6 +2764,11 @@ static bfd_boolean ppc64_elf_adjust_dyna
   PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *));
 static void ppc64_elf_hide_symbol
   PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *, bfd_boolean));
+static bfd_boolean get_sym_h
+  PARAMS ((struct elf_link_hash_entry **, Elf_Internal_Sym **, asection **,
+	   char **, Elf_Internal_Sym **, unsigned long, bfd *));
+static bfd_boolean get_tls_type
+  PARAMS ((char **, Elf_Internal_Sym **, const Elf_Internal_Rela *, bfd *));
 static bfd_boolean allocate_dynrelocs
   PARAMS ((struct elf_link_hash_entry *, PTR));
 static bfd_boolean readonly_dynrelocs
@@ -2010,7 +2777,7 @@ static enum elf_reloc_type_class ppc64_e
   PARAMS ((const Elf_Internal_Rela *));
 static bfd_boolean ppc64_elf_size_dynamic_sections
   PARAMS ((bfd *, struct bfd_link_info *));
-static INLINE enum ppc_stub_type ppc_type_of_stub
+static enum ppc_stub_type ppc_type_of_stub
   PARAMS ((asection *, const Elf_Internal_Rela *,
 	   struct ppc_link_hash_entry **, bfd_vma));
 static bfd_byte *build_plt_stub
@@ -2142,6 +2909,7 @@ link_hash_newfunc (entry, table, string)
       eh->is_func = 0;
       eh->is_func_descriptor = 0;
       eh->is_entry = 0;
+      eh->tls_type = 0;
     }
 
   return entry;
@@ -2188,11 +2956,15 @@ ppc64_elf_link_hash_table_create (abfd)
   htab->sfpr = NULL;
   htab->sbrlt = NULL;
   htab->srelbrlt = NULL;
+  htab->tls_sec = NULL;
+  htab->tlsld_got.refcount = 0;
   htab->stub_error = 0;
   htab->has_14bit_branch = 0;
   htab->have_undefweak = 0;
   htab->stub_iteration = 0;
   htab->sym_sec.abfd = NULL;
+  htab->elf.init_refcount.glist = NULL;
+  htab->elf.init_offset.glist = NULL;
 
   return &htab->elf.root;
 }
@@ -2471,7 +3243,7 @@ ppc64_elf_create_dynamic_sections (dynob
 
 static void
 ppc64_elf_copy_indirect_symbol (bed, dir, ind)
-     struct elf_backend_data *bed;
+     struct elf_backend_data *bed ATTRIBUTE_UNUSED;
      struct elf_link_hash_entry *dir, *ind;
 {
   struct ppc_link_hash_entry *edir, *eind;
@@ -2479,6 +3251,7 @@ ppc64_elf_copy_indirect_symbol (bed, dir
   edir = (struct ppc_link_hash_entry *) dir;
   eind = (struct ppc_link_hash_entry *) ind;
 
+  /* Copy over any dynamic relocs we may have on the indirect sym.  */
   if (eind->dyn_relocs != NULL)
     {
       if (edir->dyn_relocs != NULL)
@@ -2486,7 +3259,7 @@ ppc64_elf_copy_indirect_symbol (bed, dir
 	  struct ppc_dyn_relocs **pp;
 	  struct ppc_dyn_relocs *p;
 
-	  if (ind->root.type == bfd_link_hash_indirect)
+	  if (eind->elf.root.type == bfd_link_hash_indirect)
 	    abort ();
 
 	  /* Add reloc counts against the weak sym to the strong sym
@@ -2513,11 +3286,90 @@ ppc64_elf_copy_indirect_symbol (bed, dir
       eind->dyn_relocs = NULL;
     }
 
+  /* Do the same for got entries.  */
+  if (eind->elf.got.glist != NULL)
+    {
+      if (edir->elf.got.glist != NULL)
+	{
+	  struct got_entry **entp;
+	  struct got_entry *ent;
+
+	  for (entp = &eind->elf.got.glist; (ent = *entp) != NULL; )
+	    {
+	      struct got_entry *dent;
+
+	      for (dent = edir->elf.got.glist; dent != NULL; dent = dent->next)
+		if (dent->addend == ent->addend
+		    && dent->tls_type == ent->tls_type)
+		  {
+		    dent->got.refcount += ent->got.refcount;
+		    *entp = ent->next;
+		    break;
+		  }
+	      if (dent == NULL)
+		entp = &ent->next;
+	    }
+	  *entp = edir->elf.got.glist;
+	}
+
+      edir->elf.got.glist = eind->elf.got.glist;
+      eind->elf.got.glist = NULL;
+    }
+
+  /* And plt entries.  */
+  if (eind->elf.plt.plist != NULL)
+    {
+      if (edir->elf.plt.plist != NULL)
+	{
+	  struct plt_entry **entp;
+	  struct plt_entry *ent;
+
+	  for (entp = &eind->elf.plt.plist; (ent = *entp) != NULL; )
+	    {
+	      struct plt_entry *dent;
+
+	      for (dent = edir->elf.plt.plist; dent != NULL; dent = dent->next)
+		if (dent->addend == ent->addend)
+		  {
+		    dent->plt.refcount += ent->plt.refcount;
+		    *entp = ent->next;
+		    break;
+		  }
+	      if (dent == NULL)
+		entp = &ent->next;
+	    }
+	  *entp = edir->elf.plt.plist;
+	}
+
+      edir->elf.plt.plist = eind->elf.plt.plist;
+      eind->elf.plt.plist = NULL;
+    }
+
   edir->is_func |= eind->is_func;
   edir->is_func_descriptor |= eind->is_func_descriptor;
   edir->is_entry |= eind->is_entry;
 
-  _bfd_elf_link_hash_copy_indirect (bed, dir, ind);
+  /* Copy down any references that we may have already seen to the
+     symbol which just became indirect.  */
+  edir->elf.elf_link_hash_flags |=
+    (eind->elf.elf_link_hash_flags
+     & (ELF_LINK_HASH_REF_DYNAMIC
+	| ELF_LINK_HASH_REF_REGULAR
+	| ELF_LINK_HASH_REF_REGULAR_NONWEAK
+	| ELF_LINK_NON_GOT_REF));
+
+  if (eind->elf.root.type != bfd_link_hash_indirect)
+    return;
+
+  if (edir->elf.dynindx == -1)
+    {
+      edir->elf.dynindx = eind->elf.dynindx;
+      edir->elf.dynstr_index = eind->elf.dynstr_index;
+      eind->elf.dynindx = -1;
+      eind->elf.dynstr_index = 0;
+    }
+  else
+    BFD_ASSERT (eind->elf.dynindx == -1);
 }
 
 /* Set a flag, used by ppc64_elf_gc_mark_hook, on the entry symbol and
@@ -2542,6 +3394,83 @@ ppc64_elf_mark_entry_syms (info)
   return TRUE;
 }
 
+static bfd_boolean
+update_local_sym_info (abfd, symtab_hdr, r_symndx, r_addend, tls_type)
+     bfd *abfd;
+     Elf_Internal_Shdr *symtab_hdr;
+     unsigned long r_symndx;
+     bfd_vma r_addend;
+     int tls_type;
+{
+  struct got_entry **local_got_ents = elf_local_got_ents (abfd);
+  char *local_got_tls_types;
+
+  if (local_got_ents == NULL)
+    {
+      bfd_size_type size = symtab_hdr->sh_info;
+
+      size *= sizeof (*local_got_ents) + sizeof (char);
+      local_got_ents = (struct got_entry **) bfd_zalloc (abfd, size);
+      if (local_got_ents == NULL)
+	return FALSE;
+      elf_local_got_ents (abfd) = local_got_ents;
+    }
+
+  if ((tls_type & TLS_EXPLICIT) == 0)
+    {
+      struct got_entry *ent;
+
+      for (ent = local_got_ents[r_symndx]; ent != NULL; ent = ent->next)
+	if (ent->addend == r_addend && ent->tls_type == tls_type)
+	  break;
+      if (ent == NULL)
+	{
+	  bfd_size_type amt = sizeof (*ent);
+	  ent = (struct got_entry *) bfd_alloc (abfd, amt);
+	  if (ent == NULL)
+	    return FALSE;
+	  ent->next = local_got_ents[r_symndx];
+	  ent->addend = r_addend;
+	  ent->tls_type = tls_type;
+	  ent->got.refcount = 0;
+	  local_got_ents[r_symndx] = ent;
+	}
+      ent->got.refcount += 1;
+    }
+
+  local_got_tls_types = (char *) (local_got_ents + symtab_hdr->sh_info);
+  local_got_tls_types[r_symndx] |= tls_type;
+  return TRUE;
+}
+
+static bfd_boolean
+update_plt_info (abfd, eh, addend)
+     bfd *abfd;
+     struct ppc_link_hash_entry *eh;
+     bfd_vma addend;
+{
+  struct plt_entry *ent;
+
+  for (ent = eh->elf.plt.plist; ent != NULL; ent = ent->next)
+    if (ent->addend == addend)
+      break;
+  if (ent == NULL)
+    {
+      bfd_size_type amt = sizeof (*ent);
+      ent = (struct plt_entry *) bfd_alloc (abfd, amt);
+      if (ent == NULL)
+	return FALSE;
+      ent->next = eh->elf.plt.plist;
+      ent->addend = addend;
+      ent->plt.refcount = 0;
+      eh->elf.plt.plist = ent;
+    }
+  ent->plt.refcount += 1;
+  eh->elf.elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT;
+  eh->is_func = 1;
+  return TRUE;
+}
+
 /* Look through the relocs for a section during the first phase, and
    calculate needed space in the global offset table, procedure
    linkage table, and dynamic reloc sections.  */
@@ -2610,6 +3539,7 @@ ppc64_elf_check_relocs (abfd, info, sec,
       unsigned long r_symndx;
       struct elf_link_hash_entry *h;
       enum elf_ppc64_reloc_type r_type;
+      int tls_type = 0;
 
       r_symndx = ELF64_R_SYM (rel->r_info);
       if (r_symndx < symtab_hdr->sh_info)
@@ -2620,14 +3550,45 @@ ppc64_elf_check_relocs (abfd, info, sec,
       r_type = (enum elf_ppc64_reloc_type) ELF64_R_TYPE (rel->r_info);
       switch (r_type)
 	{
-	  /* GOT16 relocations */
+	case R_PPC64_GOT_TLSLD16:
+	case R_PPC64_GOT_TLSLD16_LO:
+	case R_PPC64_GOT_TLSLD16_HI:
+	case R_PPC64_GOT_TLSLD16_HA:
+	  htab->tlsld_got.refcount += 1;
+	  tls_type = TLS_TLS | TLS_GD_LD | TLS_LD;
+	  goto dogottls;
+
+	case R_PPC64_GOT_TLSGD16:
+	case R_PPC64_GOT_TLSGD16_LO:
+	case R_PPC64_GOT_TLSGD16_HI:
+	case R_PPC64_GOT_TLSGD16_HA:
+	  tls_type = TLS_TLS | TLS_GD_LD;
+	  goto dogottls;
+
+	case R_PPC64_GOT_TPREL16_DS:
+	case R_PPC64_GOT_TPREL16_LO_DS:
+	case R_PPC64_GOT_TPREL16_HI:
+	case R_PPC64_GOT_TPREL16_HA:
+	  if (info->shared)
+	    info->flags |= DF_STATIC_TLS;
+	  tls_type = TLS_TLS | TLS_TPREL;
+	  goto dogottls;
+
+	case R_PPC64_GOT_DTPREL16_DS:
+	case R_PPC64_GOT_DTPREL16_LO_DS:
+	case R_PPC64_GOT_DTPREL16_HI:
+	case R_PPC64_GOT_DTPREL16_HA:
+	  tls_type = TLS_TLS | TLS_DTPREL;
+	dogottls:
+	  sec->has_tls_reloc = 1;
+	  /* Fall thru */
+
 	case R_PPC64_GOT16:
 	case R_PPC64_GOT16_DS:
 	case R_PPC64_GOT16_HA:
 	case R_PPC64_GOT16_HI:
 	case R_PPC64_GOT16_LO:
 	case R_PPC64_GOT16_LO_DS:
-
 	  /* This symbol requires a global offset table entry.  */
 	  if (htab->sgot == NULL
 	      && !create_got_section (htab->elf.dynobj, info))
@@ -2635,28 +3596,34 @@ ppc64_elf_check_relocs (abfd, info, sec,
 
 	  if (h != NULL)
 	    {
-	      h->got.refcount += 1;
-	    }
-	  else
-	    {
-	      bfd_signed_vma *local_got_refcounts;
+	      struct ppc_link_hash_entry *eh;
+	      struct got_entry *ent;
 
-	      /* This is a global offset table entry for a local symbol.  */
-	      local_got_refcounts = elf_local_got_refcounts (abfd);
-	      if (local_got_refcounts == NULL)
+	      eh = (struct ppc_link_hash_entry *) h;
+	      for (ent = eh->elf.got.glist; ent != NULL; ent = ent->next)
+		if (ent->addend == rel->r_addend
+		    && ent->tls_type == tls_type)
+		  break;
+	      if (ent == NULL)
 		{
-		  bfd_size_type size;
-
-		  size = symtab_hdr->sh_info;
-		  size *= sizeof (bfd_signed_vma);
-		  local_got_refcounts = ((bfd_signed_vma *)
-					 bfd_zalloc (abfd, size));
-		  if (local_got_refcounts == NULL)
+		  bfd_size_type amt = sizeof (*ent);
+		  ent = (struct got_entry *) bfd_alloc (abfd, amt);
+		  if (ent == NULL)
 		    return FALSE;
-		  elf_local_got_refcounts (abfd) = local_got_refcounts;
+		  ent->next = eh->elf.got.glist;
+		  ent->addend = rel->r_addend;
+		  ent->tls_type = tls_type;
+		  ent->got.refcount = 0;
+		  eh->elf.got.glist = ent;
 		}
-	      local_got_refcounts[r_symndx] += 1;
+	      ent->got.refcount += 1;
+	      eh->tls_type |= tls_type;
 	    }
+	  else
+	    /* This is a global offset table entry for a local symbol.  */
+	    if (!update_local_sym_info (abfd, symtab_hdr, r_symndx,
+					rel->r_addend, tls_type))
+	      return FALSE;
 	  break;
 
 	case R_PPC64_PLT16_HA:
@@ -2676,10 +3643,10 @@ ppc64_elf_check_relocs (abfd, info, sec,
 	      bfd_set_error (bfd_error_bad_value);
 	      return FALSE;
 	    }
-
-	  h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT;
-	  h->plt.refcount += 1;
-	  ((struct ppc_link_hash_entry *) h)->is_func = 1;
+	  else
+	    if (!update_plt_info (abfd, (struct ppc_link_hash_entry *) h,
+				  rel->r_addend))
+	      return FALSE;
 	  break;
 
 	  /* The following relocations don't need to propagate the
@@ -2697,6 +3664,16 @@ ppc64_elf_check_relocs (abfd, info, sec,
 	case R_PPC64_TOC16_HA:
 	case R_PPC64_TOC16_DS:
 	case R_PPC64_TOC16_LO_DS:
+	case R_PPC64_DTPREL16:
+	case R_PPC64_DTPREL16_LO:
+	case R_PPC64_DTPREL16_HI:
+	case R_PPC64_DTPREL16_HA:
+	case R_PPC64_DTPREL16_DS:
+	case R_PPC64_DTPREL16_LO_DS:
+	case R_PPC64_DTPREL16_HIGHER:
+	case R_PPC64_DTPREL16_HIGHERA:
+	case R_PPC64_DTPREL16_HIGHEST:
+	case R_PPC64_DTPREL16_HIGHESTA:
 	  break;
 
 	  /* This relocation describes the C++ object vtable hierarchy.
@@ -2726,9 +3703,82 @@ ppc64_elf_check_relocs (abfd, info, sec,
 	    {
 	      /* We may need a .plt entry if the function this reloc
 		 refers to is in a shared lib.  */
-	      h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT;
-	      h->plt.refcount += 1;
-	      ((struct ppc_link_hash_entry *) h)->is_func = 1;
+	      if (!update_plt_info (abfd, (struct ppc_link_hash_entry *) h,
+				    rel->r_addend))
+		return FALSE;
+	      if (h == htab->tls_get_addr)
+		sec->has_tls_reloc = 1;
+	      else if (strcmp (h->root.root.string, ".__tls_get_addr") == 0)
+		{
+		  htab->tls_get_addr = h;
+		  sec->has_tls_reloc = 1;
+		}
+	    }
+	  break;
+
+	case R_PPC64_TPREL64:
+	  tls_type = TLS_EXPLICIT | TLS_TLS | TLS_TPREL;
+	  if (info->shared)
+	    info->flags |= DF_STATIC_TLS;
+	  goto dotlstoc;
+
+	case R_PPC64_DTPMOD64:
+	  if (rel + 1 < rel_end
+	      && rel[1].r_info == ELF64_R_INFO (r_symndx, R_PPC64_DTPREL64)
+	      && rel[1].r_offset == rel->r_offset + 8)
+	    tls_type = TLS_EXPLICIT | TLS_TLS | TLS_GD_LD;
+	  else
+	    tls_type = TLS_EXPLICIT | TLS_TLS | TLS_GD_LD | TLS_LD;
+	  goto dotlstoc;
+
+	case R_PPC64_DTPREL64:
+	  tls_type = TLS_EXPLICIT | TLS_TLS | TLS_DTPREL;
+	  if (rel != relocs
+	      && rel[-1].r_info == ELF64_R_INFO (r_symndx, R_PPC64_DTPMOD64)
+	      && rel[-1].r_offset == rel->r_offset - 8)
+	    /* This is the second reloc of a dtpmod, dtprel pair.
+	       Don't mark with TLS_DTPREL.  */
+	    goto dodyn;
+
+	dotlstoc:
+	  sec->has_tls_reloc = 1;
+	  if (h != NULL)
+	    {
+	      struct ppc_link_hash_entry *eh;
+	      eh = (struct ppc_link_hash_entry *) h;
+	      eh->tls_type |= tls_type;
+	    }
+	  else
+	    if (!update_local_sym_info (abfd, symtab_hdr, r_symndx,
+					rel->r_addend, tls_type))
+	      return FALSE;
+
+	  if (ppc64_elf_section_data (sec)->t_symndx == NULL)
+	    {
+	      bfd_size_type amt = sec->_raw_size * sizeof (unsigned) / 8;
+	      ppc64_elf_section_data (sec)->t_symndx
+		= (unsigned *) bfd_zalloc (abfd, amt);
+	      if (ppc64_elf_section_data (sec)->t_symndx == NULL)
+		return FALSE;
+	    }
+	  BFD_ASSERT (rel->r_offset % 8 == 0);
+	  ppc64_elf_section_data (sec)->t_symndx[rel->r_offset / 8] = r_symndx;
+	  goto dodyn;
+
+	case R_PPC64_TPREL16:
+	case R_PPC64_TPREL16_LO:
+	case R_PPC64_TPREL16_HI:
+	case R_PPC64_TPREL16_HA:
+	case R_PPC64_TPREL16_DS:
+	case R_PPC64_TPREL16_LO_DS:
+	case R_PPC64_TPREL16_HIGHER:
+	case R_PPC64_TPREL16_HIGHERA:
+	case R_PPC64_TPREL16_HIGHEST:
+	case R_PPC64_TPREL16_HIGHESTA:
+	  if (info->shared)
+	    {
+	      info->flags |= DF_STATIC_TLS;
+	      goto dodyn;
 	    }
 	  break;
 
@@ -2814,9 +3864,10 @@ ppc64_elf_check_relocs (abfd, info, sec,
 	     may need to keep relocations for symbols satisfied by a
 	     dynamic library if we manage to avoid copy relocs for the
 	     symbol.  */
+	dodyn:
 	  if ((info->shared
 	       && (sec->flags & SEC_ALLOC) != 0
-	       && (IS_ABSOLUTE_RELOC (r_type)
+	       && (MUST_BE_DYN_RELOC (r_type)
 		   || (h != NULL
 		       && (! info->symbolic
 			   || h->root.type == bfd_link_hash_defweak
@@ -2914,7 +3965,7 @@ ppc64_elf_check_relocs (abfd, info, sec,
 		}
 
 	      p->count += 1;
-	      if (!IS_ABSOLUTE_RELOC (r_type))
+	      if (!MUST_BE_DYN_RELOC (r_type))
 		p->pc_count += 1;
 	    }
 	  break;
@@ -3004,20 +4055,22 @@ ppc64_elf_gc_mark_hook (sec, info, rel, 
 static bfd_boolean
 ppc64_elf_gc_sweep_hook (abfd, info, sec, relocs)
      bfd *abfd;
-     struct bfd_link_info *info ATTRIBUTE_UNUSED;
+     struct bfd_link_info *info;
      asection *sec;
      const Elf_Internal_Rela *relocs;
 {
+  struct ppc_link_hash_table *htab;
   Elf_Internal_Shdr *symtab_hdr;
   struct elf_link_hash_entry **sym_hashes;
-  bfd_signed_vma *local_got_refcounts;
+  struct got_entry **local_got_ents;
   const Elf_Internal_Rela *rel, *relend;
 
   elf_section_data (sec)->local_dynrel = NULL;
 
+  htab = ppc_hash_table (info);
   symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
   sym_hashes = elf_sym_hashes (abfd);
-  local_got_refcounts = elf_local_got_refcounts (abfd);
+  local_got_ents = elf_local_got_ents (abfd);
 
   relend = relocs + sec->reloc_count;
   for (rel = relocs; rel < relend; rel++)
@@ -3025,28 +4078,68 @@ ppc64_elf_gc_sweep_hook (abfd, info, sec
       unsigned long r_symndx;
       enum elf_ppc64_reloc_type r_type;
       struct elf_link_hash_entry *h;
+      char tls_type = 0;
 
       r_symndx = ELF64_R_SYM (rel->r_info);
       r_type = (enum elf_ppc64_reloc_type) ELF64_R_TYPE (rel->r_info);
       switch (r_type)
 	{
+	case R_PPC64_GOT_TLSLD16:
+	case R_PPC64_GOT_TLSLD16_LO:
+	case R_PPC64_GOT_TLSLD16_HI:
+	case R_PPC64_GOT_TLSLD16_HA:
+	  htab->tlsld_got.refcount -= 1;
+	  tls_type = TLS_TLS | TLS_GD_LD | TLS_LD;
+	  goto dogot;
+
+	case R_PPC64_GOT_TLSGD16:
+	case R_PPC64_GOT_TLSGD16_LO:
+	case R_PPC64_GOT_TLSGD16_HI:
+	case R_PPC64_GOT_TLSGD16_HA:
+	  tls_type = TLS_TLS | TLS_GD_LD;
+	  goto dogot;
+
+	case R_PPC64_GOT_TPREL16_DS:
+	case R_PPC64_GOT_TPREL16_LO_DS:
+	case R_PPC64_GOT_TPREL16_HI:
+	case R_PPC64_GOT_TPREL16_HA:
+	  tls_type = TLS_TLS | TLS_TPREL;
+	  goto dogot;
+
+	case R_PPC64_GOT_DTPREL16_DS:
+	case R_PPC64_GOT_DTPREL16_LO_DS:
+	case R_PPC64_GOT_DTPREL16_HI:
+	case R_PPC64_GOT_DTPREL16_HA:
+	  tls_type = TLS_TLS | TLS_DTPREL;
+	  goto dogot;
+
 	case R_PPC64_GOT16:
 	case R_PPC64_GOT16_DS:
 	case R_PPC64_GOT16_HA:
 	case R_PPC64_GOT16_HI:
 	case R_PPC64_GOT16_LO:
 	case R_PPC64_GOT16_LO_DS:
-	  if (r_symndx >= symtab_hdr->sh_info)
-	    {
-	      h = sym_hashes[r_symndx - symtab_hdr->sh_info];
-	      if (h->got.refcount > 0)
-		h->got.refcount--;
-	    }
-	  else
-	    {
-	      if (local_got_refcounts[r_symndx] > 0)
-		local_got_refcounts[r_symndx]--;
-	    }
+	dogot:
+	  {
+	    struct got_entry *ent;
+
+	    if (r_symndx >= symtab_hdr->sh_info)
+	      {
+		h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+		ent = h->got.glist;
+	      }
+	    else
+	      ent = local_got_ents[r_symndx];
+
+	    for (; ent != NULL; ent = ent->next)
+	      if (ent->addend == rel->r_addend
+		  && ent->tls_type == tls_type)
+		break;
+	    if (ent == NULL)
+	      abort ();
+	    if (ent->got.refcount > 0)
+	      ent->got.refcount -= 1;
+	  }
 	  break;
 
 	case R_PPC64_PLT16_HA:
@@ -3054,23 +4147,22 @@ ppc64_elf_gc_sweep_hook (abfd, info, sec
 	case R_PPC64_PLT16_LO:
 	case R_PPC64_PLT32:
 	case R_PPC64_PLT64:
-	  if (r_symndx >= symtab_hdr->sh_info)
-	    {
-	      h = sym_hashes[r_symndx - symtab_hdr->sh_info];
-	      if (h->plt.refcount > 0)
-		h->plt.refcount--;
-	    }
-	  break;
-
 	case R_PPC64_REL14:
 	case R_PPC64_REL14_BRNTAKEN:
 	case R_PPC64_REL14_BRTAKEN:
 	case R_PPC64_REL24:
 	  if (r_symndx >= symtab_hdr->sh_info)
 	    {
+	      struct plt_entry *ent;
+
 	      h = sym_hashes[r_symndx - symtab_hdr->sh_info];
-	      if (h->plt.refcount > 0)
-		h->plt.refcount--;
+	      for (ent = h->plt.plist; ent != NULL; ent = ent->next)
+		if (ent->addend == rel->r_addend)
+		  break;
+	      if (ent == NULL)
+		abort ();
+	      if (ent->plt.refcount > 0)
+		ent->plt.refcount -= 1;
 	    }
 	  break;
 
@@ -3098,6 +4190,9 @@ ppc64_elf_gc_sweep_hook (abfd, info, sec
 	    }
 	  break;
 
+	case R_PPC64_DTPMOD64:
+	case R_PPC64_DTPREL64:
+	case R_PPC64_TPREL64:
 	case R_PPC64_ADDR14:
 	case R_PPC64_ADDR14_BRNTAKEN:
 	case R_PPC64_ADDR14_BRTAKEN:
@@ -3155,6 +4250,7 @@ func_desc_adjust (h, inf)
 {
   struct bfd_link_info *info;
   struct ppc_link_hash_table *htab;
+  struct plt_entry *ent;
 
   if (h->root.type == bfd_link_hash_indirect)
     return TRUE;
@@ -3174,7 +4270,10 @@ func_desc_adjust (h, inf)
       && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR))
     htab->have_undefweak = TRUE;
 
-  if (h->plt.refcount > 0
+  for (ent = h->plt.plist; ent != NULL; ent = ent->next)
+    if (ent->plt.refcount > 0)
+      break;
+  if (ent != NULL
       && h->root.root.string[0] == '.'
       && h->root.root.string[1] != '\0')
     {
@@ -3233,7 +4332,7 @@ func_desc_adjust (h, inf)
 					  | ELF_LINK_NON_GOT_REF));
 	  if (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT)
 	    {
-	      fdh->plt.refcount = h->plt.refcount;
+	      fdh->plt.plist = h->plt.plist;
 	      fdh->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT;
 	    }
 	  ((struct ppc_link_hash_entry *) fdh)->is_func_descriptor = 1;
@@ -3405,20 +4504,24 @@ ppc64_elf_adjust_dynamic_symbol (info, h
     {
       /* Clear procedure linkage table information for any symbol that
 	 won't need a .plt entry.  */
+      struct plt_entry *ent;
+      for (ent = h->plt.plist; ent != NULL; ent = ent->next)
+	if (ent->plt.refcount > 0)
+	  break;
       if (!((struct ppc_link_hash_entry *) h)->is_func_descriptor
-	  || h->plt.refcount <= 0
+	  || ent == NULL
 	  || (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) != 0
 	  || (! info->shared
 	      && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) == 0
 	      && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC) == 0))
 	{
-	  h->plt.offset = (bfd_vma) -1;
+	  h->plt.plist = NULL;
 	  h->elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT;
 	}
       return TRUE;
     }
   else
-    h->plt.offset = (bfd_vma) -1;
+    h->plt.plist = NULL;
 
   /* If this is a weak symbol, and there is a real definition, the
      processor independent code will have arranged for us to see the
@@ -3567,17 +4670,147 @@ ppc64_elf_hide_symbol (info, h, force_lo
     }
 }
 
+static bfd_boolean
+get_sym_h (hp, symp, symsecp, tlstypep, locsymsp, r_symndx, ibfd)
+     struct elf_link_hash_entry **hp;
+     Elf_Internal_Sym **symp;
+     asection **symsecp;
+     char **tlstypep;
+     Elf_Internal_Sym **locsymsp;
+     unsigned long r_symndx;
+     bfd *ibfd;
+{
+  Elf_Internal_Shdr *symtab_hdr = &elf_tdata (ibfd)->symtab_hdr;
+
+  if (r_symndx >= symtab_hdr->sh_info)
+    {
+      struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (ibfd);
+      struct elf_link_hash_entry *h;
+
+      h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+      while (h->root.type == bfd_link_hash_indirect
+	     || h->root.type == bfd_link_hash_warning)
+	h = (struct elf_link_hash_entry *) h->root.u.i.link;
+
+      if (hp != NULL)
+	*hp = h;
+
+      if (symp != NULL)
+	*symp = NULL;
+
+      if (symsecp != NULL)
+	{
+	  asection *symsec = NULL;
+	  if (h->root.type == bfd_link_hash_defined
+	      || h->root.type == bfd_link_hash_defweak)
+	    symsec = h->root.u.def.section;
+	  *symsecp = symsec;
+	}
+
+      if (tlstypep != NULL)
+	{
+	  struct ppc_link_hash_entry *eh;
+
+	  eh = (struct ppc_link_hash_entry *) h;
+	  *tlstypep = &eh->tls_type;
+	}
+    }
+  else
+    {
+      Elf_Internal_Sym *sym;
+      Elf_Internal_Sym *locsyms = *locsymsp;
+
+      if (locsyms == NULL)
+	{
+	  locsyms = (Elf_Internal_Sym *) symtab_hdr->contents;
+	  if (locsyms == NULL)
+	    locsyms = bfd_elf_get_elf_syms (ibfd, symtab_hdr,
+					    symtab_hdr->sh_info,
+					    0, NULL, NULL, NULL);
+	  if (locsyms == NULL)
+	    return FALSE;
+	  *locsymsp = locsyms;
+	}
+      sym = locsyms + r_symndx;
+
+      if (hp != NULL)
+	*hp = NULL;
+
+      if (symp != NULL)
+	*symp = sym;
+
+      if (symsecp != NULL)
+	{
+	  asection *symsec = NULL;
+	  if ((sym->st_shndx != SHN_UNDEF
+	       && sym->st_shndx < SHN_LORESERVE)
+	      || sym->st_shndx > SHN_HIRESERVE)
+	    symsec = bfd_section_from_elf_index (ibfd, sym->st_shndx);
+	  *symsecp = symsec;
+	}
+
+      if (tlstypep != NULL)
+	{
+	  struct got_entry **lgot_ents;
+	  char *tlstype;
+
+	  tlstype = NULL;
+	  lgot_ents = elf_local_got_ents (ibfd);
+	  if (lgot_ents != NULL)
+	    {
+	      char *lgot_types = (char *) (lgot_ents + symtab_hdr->sh_info);
+	      tlstype = &lgot_types[r_symndx];
+	    }
+	  *tlstypep = tlstype;
+	}
+    }
+  return TRUE;
+}
+
+static bfd_boolean
+get_tls_type (tls_type, locsymsp, rel, ibfd)
+     char **tls_type;
+     Elf_Internal_Sym **locsymsp;
+     const Elf_Internal_Rela *rel;
+     bfd *ibfd;
+{
+  unsigned long r_symndx;
+  struct elf_link_hash_entry *h;
+  Elf_Internal_Sym *sym;
+  asection *sec;
+  bfd_vma off;
+
+  r_symndx = ELF64_R_SYM (rel->r_info);
+  if (!get_sym_h (&h, &sym, &sec, tls_type, locsymsp, r_symndx, ibfd))
+    return FALSE;
+
+  if ((*tls_type != NULL && **tls_type != 0)
+      || sec == NULL
+      || ppc64_elf_section_data (sec)->t_symndx == NULL)
+    return TRUE;
+
+  /* Look inside a TOC section too.  */
+  if (h != NULL)
+    {
+      BFD_ASSERT (h->root.type == bfd_link_hash_defined);
+      off = h->root.u.def.value;
+    }
+  else
+    off = sym->st_value;
+  off += rel->r_addend;
+  BFD_ASSERT (off % 8 == 0);
+  r_symndx = ppc64_elf_section_data (sec)->t_symndx[off / 8];
+  return get_sym_h (&h, &sym, NULL, tls_type, locsymsp, r_symndx, ibfd);
+}
+
 bfd_boolean
 ppc64_elf_edit_opd (obfd, info)
      bfd *obfd;
      struct bfd_link_info *info;
 {
   bfd *ibfd;
-  unsigned int bfd_indx;
 
-  for (bfd_indx = 0, ibfd = info->input_bfds;
-       ibfd != NULL;
-       ibfd = ibfd->link_next, bfd_indx++)
+  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
     {
       asection *sec;
       Elf_Internal_Rela *relstart, *rel, *relend;
@@ -3672,44 +4905,22 @@ ppc64_elf_edit_opd (obfd, info)
 	    }
 
 	  r_symndx = ELF64_R_SYM (rel->r_info);
-	  sym_sec = NULL;
-	  h = NULL;
-	  sym = NULL;
-	  if (r_symndx >= symtab_hdr->sh_info)
-	    {
-	      h = sym_hashes[r_symndx - symtab_hdr->sh_info];
-	      while (h->root.type == bfd_link_hash_indirect
-		     || h->root.type == bfd_link_hash_warning)
-		h = (struct elf_link_hash_entry *) h->root.u.i.link;
-	      if (h->root.type == bfd_link_hash_defined
-		  || h->root.type == bfd_link_hash_defweak)
-		sym_sec = h->root.u.def.section;
-	    }
-	  else
-	    {
-	      if (local_syms == NULL)
-		{
-		  local_syms = (Elf_Internal_Sym *) symtab_hdr->contents;
-		  if (local_syms == NULL)
-		    local_syms = bfd_elf_get_elf_syms (ibfd, symtab_hdr,
-						       symtab_hdr->sh_info, 0,
-						       NULL, NULL, NULL);
-		  if (local_syms == NULL)
-		    goto error_free_rel;
-		}
-	      sym = local_syms + r_symndx;
-	      if ((sym->st_shndx != SHN_UNDEF
-		   && sym->st_shndx < SHN_LORESERVE)
-		  || sym->st_shndx > SHN_HIRESERVE)
-		sym_sec = bfd_section_from_elf_index (ibfd, sym->st_shndx);
-	    }
+	  if (!get_sym_h (&h, &sym, &sym_sec, NULL, &local_syms,
+			  r_symndx, ibfd))
+	    goto error_free_rel;
 
 	  if (sym_sec == NULL || sym_sec->owner == NULL)
 	    {
+	      const char *sym_name;
+	      if (h != NULL)
+		sym_name = h->root.root.string;
+	      else
+		sym_name = bfd_elf_local_sym_name (ibfd, sym);
+
 	      (*_bfd_error_handler)
 		(_("%s: undefined sym `%s' in .opd section"),
 		 bfd_archive_filename (ibfd),
-		 h != NULL ? h->root.root.string : "<local symbol>");
+		 sym_name);
 	      need_edit = FALSE;
 	      break;
 	    }
@@ -3774,28 +4985,8 @@ ppc64_elf_edit_opd (obfd, info)
 		  Elf_Internal_Sym *sym;
 
 		  r_symndx = ELF64_R_SYM (rel->r_info);
-		  sym_sec = NULL;
-		  h = NULL;
-		  sym = NULL;
-		  if (r_symndx >= symtab_hdr->sh_info)
-		    {
-		      h = sym_hashes[r_symndx - symtab_hdr->sh_info];
-		      while (h->root.type == bfd_link_hash_indirect
-			     || h->root.type == bfd_link_hash_warning)
-			h = (struct elf_link_hash_entry *) h->root.u.i.link;
-		      if (h->root.type == bfd_link_hash_defined
-			  || h->root.type == bfd_link_hash_defweak)
-			sym_sec = h->root.u.def.section;
-		    }
-		  else
-		    {
-		      sym = local_syms + r_symndx;
-		      if ((sym->st_shndx != SHN_UNDEF
-			   && sym->st_shndx < SHN_LORESERVE)
-			  || sym->st_shndx > SHN_HIRESERVE)
-			sym_sec = bfd_section_from_elf_index (ibfd,
-							      sym->st_shndx);
-		    }
+		  get_sym_h (&h, &sym, &sym_sec, NULL, &local_syms,
+			     r_symndx, ibfd);
 
 		  skip = (sym_sec->owner != ibfd
 			  || sym_sec->output_section == bfd_abs_section_ptr);
@@ -3918,6 +5109,326 @@ ppc64_elf_edit_opd (obfd, info)
   return TRUE;
 }
 
+/* Run through all the TLS relocs looking for optimization
+   opportunities.  The linker has been hacked (see ppc64elf.em) to do
+   a preliminary section layout so that we know the TLS segment
+   offsets.  We can't optimize earlier because some optimizations need
+   to know the tp offset, and we need to optimize before allocating
+   dynamic relocations.  */
+
+bfd_boolean
+ppc64_elf_tls_optimize (obfd, info)
+     bfd *obfd;
+     struct bfd_link_info *info;
+{
+  asection *tls;
+  bfd *ibfd;
+  asection *sec;
+  struct ppc_link_hash_table *htab;
+
+  if (info->relocateable)
+    return TRUE;
+
+  for (tls = obfd->sections; tls != NULL; tls = tls->next)
+    if ((tls->flags & (SEC_THREAD_LOCAL | SEC_LOAD))
+	== (SEC_THREAD_LOCAL | SEC_LOAD))
+      break;
+  if (tls == NULL)
+    return TRUE;
+
+  htab = ppc_hash_table (info);
+  htab->tls_sec = tls;
+
+  if (info->shared)
+    return TRUE;
+
+  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
+    {
+      Elf_Internal_Sym *locsyms = NULL;
+
+      for (sec = ibfd->sections; sec != NULL; sec = sec->next)
+	if (sec->has_tls_reloc && !bfd_is_abs_section (sec->output_section))
+	  {
+	    Elf_Internal_Rela *relstart, *rel, *relend;
+	    int expecting_tls_get_addr;
+
+	    /* Read the relocations.  */
+	    relstart = _bfd_elf64_link_read_relocs (ibfd, sec, (PTR) NULL,
+						    (Elf_Internal_Rela *) NULL,
+						    info->keep_memory);
+	    if (relstart == NULL)
+	      return FALSE;
+
+	    expecting_tls_get_addr = 0;
+	    relend = relstart + sec->reloc_count;
+	    for (rel = relstart; rel < relend; rel++)
+	      {
+		enum elf_ppc64_reloc_type r_type;
+		unsigned long r_symndx;
+		struct elf_link_hash_entry *h;
+		Elf_Internal_Sym *sym;
+		asection *sym_sec;
+		char *tls_type;
+		char tls_set, tls_clear, got_tls_type = 0;
+		bfd_vma value;
+		bfd_boolean ok_tprel;
+
+		r_symndx = ELF64_R_SYM (rel->r_info);
+		if (!get_sym_h (&h, &sym, &sym_sec, &tls_type, &locsyms,
+				r_symndx, ibfd))
+		  {
+		  err_free_rel:
+		    if (elf_section_data (sec)->relocs != relstart)
+		      free (relstart);
+		    if (locsyms != NULL
+			&& (elf_tdata (ibfd)->symtab_hdr.contents
+			    != (unsigned char *) locsyms))
+		      free (locsyms);
+		    return FALSE;
+		  }
+
+		if (h != NULL)
+		  {
+		    if (h->root.type != bfd_link_hash_defined
+			&& h->root.type != bfd_link_hash_defweak)
+		      continue;
+		    value = h->root.u.def.value;
+		  }
+		else
+		  value = sym->st_value;
+		ok_tprel = FALSE;
+		if (sym_sec != NULL && sym_sec->output_section != NULL)
+		  {
+		    value += sym_sec->output_offset;
+		    value += sym_sec->output_section->vma;
+		    value -= htab->tls_sec->vma;
+		    ok_tprel = (value + TP_OFFSET + ((bfd_vma) 1 << 31)
+				< (bfd_vma) 1 << 32);
+		  }
+
+		r_type
+		  = (enum elf_ppc64_reloc_type) ELF64_R_TYPE (rel->r_info);
+		switch (r_type)
+		  {
+		  case R_PPC64_GOT_TLSLD16:
+		  case R_PPC64_GOT_TLSLD16_LO:
+		  case R_PPC64_GOT_TLSLD16_HI:
+		  case R_PPC64_GOT_TLSLD16_HA:
+		    htab->tlsld_got.refcount -= 1;
+		    if (ok_tprel)
+		      /* LD -> LE */
+		      tls_set = 0;
+		    else
+		      /* We still need a GOT entry as the offset is
+			 too big.  ie. LD -> IE.  */
+		      tls_set = TLS_TLS | TLS_TPREL;
+		    tls_clear = TLS_GD_LD;
+		    got_tls_type = TLS_TLS | TLS_GD_LD | TLS_LD;
+		    expecting_tls_get_addr = 1;
+		    break;
+
+		  case R_PPC64_GOT_TLSGD16:
+		  case R_PPC64_GOT_TLSGD16_LO:
+		  case R_PPC64_GOT_TLSGD16_HI:
+		  case R_PPC64_GOT_TLSGD16_HA:
+		    if (ok_tprel
+			&& (h == NULL
+			    || ((h->elf_link_hash_flags
+				 & ELF_LINK_HASH_DEF_REGULAR) != 0
+				&& ((h->elf_link_hash_flags
+				     & ELF_LINK_FORCED_LOCAL) != 0
+				    || !info->shared
+				    || info->symbolic))))
+		      /* GD -> LE */
+		      tls_set = 0;
+		    else
+		      /* GD -> IE */
+		      tls_set = TLS_TLS | TLS_TPREL;
+		    tls_clear = TLS_GD_LD;
+		    got_tls_type = TLS_TLS | TLS_GD_LD;
+		    expecting_tls_get_addr = 1;
+		    break;
+
+		  case R_PPC64_GOT_TPREL16_DS:
+		  case R_PPC64_GOT_TPREL16_LO_DS:
+		  case R_PPC64_GOT_TPREL16_HI:
+		  case R_PPC64_GOT_TPREL16_HA:
+		    expecting_tls_get_addr = 0;
+		    if (ok_tprel)
+		      {
+			/* IE -> LE */
+			tls_set = 0;
+			tls_clear = TLS_TPREL;
+			got_tls_type = TLS_TLS | TLS_TPREL;
+			break;
+		      }
+		    else
+		      continue;
+
+		  case R_PPC64_REL14:
+		  case R_PPC64_REL14_BRTAKEN:
+		  case R_PPC64_REL14_BRNTAKEN:
+		  case R_PPC64_REL24:
+		    if (h != NULL
+			&& h == htab->tls_get_addr)
+		      {
+			if (!expecting_tls_get_addr
+			    && rel != relstart
+			    && ((ELF64_R_TYPE (rel[-1].r_info)
+				 == R_PPC64_TOC16)
+				|| (ELF64_R_TYPE (rel[-1].r_info)
+				    == R_PPC64_TOC16_LO)))
+			  {
+			    /* Check for toc tls entries.  */
+			    char *toc_tls;
+
+			    if (!get_tls_type (&toc_tls, &locsyms,
+					       rel - 1, ibfd))
+			      goto err_free_rel;
+			    if (toc_tls != NULL)
+			      expecting_tls_get_addr = *toc_tls != 0;
+			  }
+
+			if (expecting_tls_get_addr)
+			  {
+			    struct plt_entry *ent;
+			    for (ent = h->plt.plist; ent; ent = ent->next)
+			      if (ent->addend == 0)
+				{
+				  if (ent->plt.refcount > 0)
+				    ent->plt.refcount -= 1;
+				  break;
+				}
+			  }
+		      }
+		    expecting_tls_get_addr = 0;
+		    continue;
+
+		  case R_PPC64_TPREL64:
+		    expecting_tls_get_addr = 0;
+		    if (ok_tprel)
+		      {
+			/* IE -> LE */
+			tls_set = TLS_EXPLICIT;
+			tls_clear = TLS_TPREL;
+			break;
+		      }
+		    else
+		      continue;
+
+		  case R_PPC64_DTPMOD64:
+		    expecting_tls_get_addr = 0;
+		    if ((*tls_type & TLS_LD) == 0)
+		      {
+			if ((h == NULL
+			     || ((h->elf_link_hash_flags
+				  & ELF_LINK_HASH_DEF_REGULAR) != 0
+				 && ((h->elf_link_hash_flags
+				      & ELF_LINK_FORCED_LOCAL) != 0
+				     || !info->shared
+				     || info->symbolic)))
+			    && ok_tprel)
+			  /* GD -> LE */
+			  tls_set = TLS_EXPLICIT;
+			else
+			  /* GD -> IE */
+			  tls_set = TLS_EXPLICIT | TLS_TPREL;
+			tls_clear = TLS_GD_LD;
+		      }
+		    else
+		      {
+			if (ok_tprel)
+			  /* LD -> LE */
+			  tls_set = TLS_EXPLICIT;
+			else
+			  /* LD -> IE */
+			  tls_set = TLS_EXPLICIT | TLS_TPREL;
+			tls_clear = TLS_GD_LD;
+		      }
+		    break;
+
+		  default:
+		    expecting_tls_get_addr = 0;
+		    continue;
+		  }
+
+		if ((tls_set & TLS_EXPLICIT) == 0)
+		  {
+		    struct got_entry *ent;
+
+		    /* Adjust got entry for this reloc.  */
+		    if (h != NULL)
+		      ent = h->got.glist;
+		    else
+		      ent = elf_local_got_ents (ibfd)[r_symndx];
+
+		    for (; ent != NULL; ent = ent->next)
+		      if (ent->addend == rel->r_addend
+			  && ent->tls_type == got_tls_type)
+			break;
+		    if (ent == NULL)
+		      abort ();
+
+		    if (tls_set == 0)
+		      {
+			/* We managed to get rid of a got entry.  */
+			if (ent->got.refcount > 0)
+			  ent->got.refcount -= 1;
+		      }
+		    else
+		      ent->tls_type = tls_set;
+		  }
+		else if (h != NULL)
+		  {
+		    struct ppc_link_hash_entry * eh;
+		    struct ppc_dyn_relocs **pp;
+		    struct ppc_dyn_relocs *p;
+
+		    /* Adjust dynamic relocs.  */
+		    eh = (struct ppc_link_hash_entry *) h;
+		    for (pp = &eh->dyn_relocs;
+			 (p = *pp) != NULL;
+			 pp = &p->next)
+		      if (p->sec == sec)
+			{
+			  /* If we got rid of a DTPMOD/DTPREL reloc
+			     pair then we'll lose one or two dyn
+			     relocs.  */
+			  if (tls_clear == TLS_GD_LD
+			      && rel + 1 < relend
+			      && (rel[1].r_info
+				  == ELF64_R_INFO (r_symndx, R_PPC64_DTPREL64))
+			      && rel[1].r_offset == rel->r_offset + 8)
+			    p->count -= 1;
+			  if (tls_set == TLS_EXPLICIT)
+			    p->count -= 1;
+			  if (p->count == 0)
+			    *pp = p->next;
+			  break;
+			}
+		  }
+
+		*tls_type |= tls_set;
+		*tls_type &= ~tls_clear;
+	      }
+
+	    if (elf_section_data (sec)->relocs != relstart)
+	      free (relstart);
+	  }
+
+      if (locsyms != NULL
+	  && (elf_tdata (ibfd)->symtab_hdr.contents
+	      != (unsigned char *) locsyms))
+	{
+	  if (!info->keep_memory)
+	    free (locsyms);
+	  else
+	    elf_tdata (ibfd)->symtab_hdr.contents = (unsigned char *) locsyms;
+	}
+    }
+  return TRUE;
+}
+
 /* This is the condition under which ppc64_elf_finish_dynamic_symbol
    will be called from elflink.h.  If elflink.h doesn't call our
    finish_dynamic_symbol routine, we'll need to do something about
@@ -3942,6 +5453,7 @@ allocate_dynrelocs (h, inf)
   asection *s;
   struct ppc_link_hash_entry *eh;
   struct ppc_dyn_relocs *p;
+  struct got_entry *gent;
 
   if (h->root.type == bfd_link_hash_indirect)
     return TRUE;
@@ -3953,71 +5465,86 @@ allocate_dynrelocs (h, inf)
   htab = ppc_hash_table (info);
 
   if (htab->elf.dynamic_sections_created
-      && h->plt.refcount > 0
-      && h->dynindx != -1)
+      && h->dynindx != -1
+      && WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, info, h))
     {
-      BFD_ASSERT (((struct ppc_link_hash_entry *) h)->is_func_descriptor);
+      struct plt_entry *pent;
+      bfd_boolean doneone = FALSE;
+      for (pent = h->plt.plist; pent != NULL; pent = pent->next)
+	if (pent->plt.refcount > 0)
+	  {
+	    BFD_ASSERT (((struct ppc_link_hash_entry *) h)->is_func_descriptor);
 
-      if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, info, h))
-	{
-	  /* If this is the first .plt entry, make room for the special
-	     first entry.  */
-	  s = htab->splt;
-	  if (s->_raw_size == 0)
-	    s->_raw_size += PLT_INITIAL_ENTRY_SIZE;
+	    /* If this is the first .plt entry, make room for the special
+	       first entry.  */
+	    s = htab->splt;
+	    if (s->_raw_size == 0)
+	      s->_raw_size += PLT_INITIAL_ENTRY_SIZE;
 
-	  h->plt.offset = s->_raw_size;
+	    pent->plt.offset = s->_raw_size;
 
-	  /* Make room for this entry.  */
-	  s->_raw_size += PLT_ENTRY_SIZE;
+	    /* Make room for this entry.  */
+	    s->_raw_size += PLT_ENTRY_SIZE;
 
-	  /* Make room for the .glink code.  */
-	  s = htab->sglink;
-	  if (s->_raw_size == 0)
-	    s->_raw_size += GLINK_CALL_STUB_SIZE;
-	  /* We need bigger stubs past index 32767.  */
-	  if (s->_raw_size >= GLINK_CALL_STUB_SIZE + 32768*2*4)
-	    s->_raw_size += 4;
-	  s->_raw_size += 2*4;
+	    /* Make room for the .glink code.  */
+	    s = htab->sglink;
+	    if (s->_raw_size == 0)
+	      s->_raw_size += GLINK_CALL_STUB_SIZE;
+	    /* We need bigger stubs past index 32767.  */
+	    if (s->_raw_size >= GLINK_CALL_STUB_SIZE + 32768*2*4)
+	      s->_raw_size += 4;
+	    s->_raw_size += 2*4;
 
-	  /* We also need to make an entry in the .rela.plt section.  */
-	  s = htab->srelplt;
-	  s->_raw_size += sizeof (Elf64_External_Rela);
-	}
-      else
+	    /* We also need to make an entry in the .rela.plt section.  */
+	    s = htab->srelplt;
+	    s->_raw_size += sizeof (Elf64_External_Rela);
+	    doneone = TRUE;
+	  }
+	else
+	  pent->plt.offset = (bfd_vma) -1;
+      if (!doneone)
 	{
-	  h->plt.offset = (bfd_vma) -1;
+	  h->plt.plist = NULL;
 	  h->elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT;
 	}
     }
   else
     {
-      h->plt.offset = (bfd_vma) -1;
+      h->plt.plist = NULL;
       h->elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT;
     }
 
-  if (h->got.refcount > 0)
-    {
-      bfd_boolean dyn;
+  for (gent = h->got.glist; gent != NULL; gent = gent->next)
+    if (gent->got.refcount > 0)
+      {
+	/* Make sure this symbol is output as a dynamic symbol.
+	   Undefined weak syms won't yet be marked as dynamic.  */
+	if (h->dynindx == -1
+	    && (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0)
+	  {
+	    if (! bfd_elf64_link_record_dynamic_symbol (info, h))
+	      return FALSE;
+	  }
 
-      /* Make sure this symbol is output as a dynamic symbol.
-	 Undefined weak syms won't yet be marked as dynamic.  */
-      if (h->dynindx == -1
-	  && (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0)
-	{
-	  if (! bfd_elf64_link_record_dynamic_symbol (info, h))
-	    return FALSE;
-	}
+	if ((gent->tls_type & TLS_LD) != 0)
+	  gent->got.offset = htab->tlsld_got.offset;
+	else
+	  {
+	    bfd_boolean dyn;
 
-      s = htab->sgot;
-      h->got.offset = s->_raw_size;
-      s->_raw_size += 8;
-      dyn = htab->elf.dynamic_sections_created;
-      if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info, h))
-	htab->srelgot->_raw_size += sizeof (Elf64_External_Rela);
-    }
-  else
-    h->got.offset = (bfd_vma) -1;
+	    s = htab->sgot;
+	    gent->got.offset = s->_raw_size;
+	    s->_raw_size += (gent->tls_type & TLS_GD_LD) != 0 ? 16 : 8;
+	    dyn = htab->elf.dynamic_sections_created;
+	    if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info, h))
+	      htab->srelgot->_raw_size
+		+= ((gent->tls_type & TLS_GD_LD) != 0
+		    ? 2 * sizeof (Elf64_External_Rela)
+		    : sizeof (Elf64_External_Rela));
+	  }
+      }
+    else
+      gent->got.offset = (bfd_vma) -1;
 
   eh = (struct ppc_link_hash_entry *) h;
   if (eh->dyn_relocs == NULL)
@@ -4153,12 +5680,22 @@ ppc64_elf_size_dynamic_sections (output_
 	}
     }
 
+  if (htab->tlsld_got.refcount > 0)
+    {
+      htab->tlsld_got.offset = htab->sgot->_raw_size;
+      htab->sgot->_raw_size += 16;
+      if (info->shared)
+	htab->srelgot->_raw_size += sizeof (Elf64_External_Rela);
+    }
+  else
+    htab->tlsld_got.offset = (bfd_vma) -1;
+
   /* Set up .got offsets for local syms, and space for local dynamic
      relocs.  */
   for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
     {
-      bfd_signed_vma *local_got;
-      bfd_signed_vma *end_local_got;
+      struct got_entry **lgot_ents;
+      struct got_entry **end_lgot_ents;
       bfd_size_type locsymcount;
       Elf_Internal_Shdr *symtab_hdr;
       asection *srel;
@@ -4193,26 +5730,52 @@ ppc64_elf_size_dynamic_sections (output_
 	    }
 	}
 
-      local_got = elf_local_got_refcounts (ibfd);
-      if (!local_got)
+      lgot_ents = elf_local_got_ents (ibfd);
+      if (!lgot_ents)
 	continue;
 
       symtab_hdr = &elf_tdata (ibfd)->symtab_hdr;
       locsymcount = symtab_hdr->sh_info;
-      end_local_got = local_got + locsymcount;
+      end_lgot_ents = lgot_ents + locsymcount;
       s = htab->sgot;
       srel = htab->srelgot;
-      for (; local_got < end_local_got; ++local_got)
+      for (; lgot_ents < end_lgot_ents; ++lgot_ents)
 	{
-	  if (*local_got > 0)
-	    {
-	      *local_got = s->_raw_size;
-	      s->_raw_size += 8;
-	      if (info->shared)
-		srel->_raw_size += sizeof (Elf64_External_Rela);
-	    }
-	  else
-	    *local_got = (bfd_vma) -1;
+	  struct got_entry *ent;
+
+	  for (ent = *lgot_ents; ent != NULL; ent = ent->next)
+	    if (ent->got.refcount > 0)
+	      {
+		if ((ent->tls_type & TLS_LD) != 0)
+		  {
+		    if (htab->tlsld_got.offset == (bfd_vma) -1)
+		      {
+			htab->tlsld_got.offset = s->_raw_size;
+			s->_raw_size += 16;
+			if (info->shared)
+			  srel->_raw_size += sizeof (Elf64_External_Rela);
+		      }
+		    ent->got.offset = htab->tlsld_got.offset;
+		  }
+		else
+		  {
+		    ent->got.offset = s->_raw_size;
+		    if ((ent->tls_type & TLS_GD_LD) != 0)
+		      {
+			s->_raw_size += 16;
+			if (info->shared)
+			  srel->_raw_size += 2 * sizeof (Elf64_External_Rela);
+		      }
+		    else
+		      {
+			s->_raw_size += 8;
+			if (info->shared)
+			  srel->_raw_size += sizeof (Elf64_External_Rela);
+		      }
+		  }
+	      }
+	    else
+	      ent->got.offset = (bfd_vma) -1;
 	}
     }
 
@@ -4228,6 +5791,10 @@ ppc64_elf_size_dynamic_sections (output_
       if ((s->flags & SEC_LINKER_CREATED) == 0)
 	continue;
 
+      /* Reset _cooked_size since prelim layout will set it wrongly,
+	 and a non-zero _cooked_size sticks.  */
+      s->_cooked_size = 0;
+
       if (s == htab->sbrlt || s == htab->srelbrlt)
 	/* These haven't been allocated yet;  don't strip.  */
 	continue;
@@ -4281,8 +5848,10 @@ ppc64_elf_size_dynamic_sections (output_
       /* Allocate memory for the section contents.  We use bfd_zalloc
 	 here in case unused entries are not reclaimed before the
 	 section's contents are written out.  This should not happen,
-	 but this way if it does, we get a R_PPC64_NONE reloc instead
-	 of garbage.  */
+	 but this way if it does we get a R_PPC64_NONE reloc in .rela
+	 sections instead of garbage.
+	 We also rely on the section contents being zero when writing
+	 the GOT.  */
       s->contents = (bfd_byte *) bfd_zalloc (dynobj, s->_raw_size);
       if (s->contents == NULL)
 	return FALSE;
@@ -4364,11 +5933,16 @@ ppc_type_of_stub (input_sec, rel, hash, 
   if (h != NULL)
     {
       if (h->oh != NULL
-	  && h->oh->plt.offset != (bfd_vma) -1
 	  && h->oh->dynindx != -1)
 	{
-	  *hash = (struct ppc_link_hash_entry *) h->oh;
-	  return ppc_stub_plt_call;
+	  struct plt_entry *ent;
+	  for (ent = h->oh->plt.plist; ent != NULL; ent = ent->next)
+	    if (ent->addend == rel->r_addend
+		&& ent->plt.offset != (bfd_vma) -1)
+	      {
+		*hash = (struct ppc_link_hash_entry *) h->oh;
+		return ppc_stub_plt_call;
+	      }
 	}
 
       if (h->elf.root.type == bfd_link_hash_undefweak
@@ -4443,6 +6017,7 @@ ppc_build_one_stub (gen_entry, in_arg)
   bfd_byte *loc;
   bfd_byte *p;
   unsigned int indx;
+  struct plt_entry *ent;
   bfd_vma off;
   int size;
 
@@ -4554,7 +6129,13 @@ ppc_build_one_stub (gen_entry, in_arg)
 	}
 
       /* Now build the stub.  */
-      off = stub_entry->h->elf.plt.offset;
+      off = (bfd_vma) -1;
+      for (ent = stub_entry->h->elf.plt.plist; ent != NULL; ent = ent->next)
+	if (ent->addend == stub_entry->addend)
+	  {
+	    off = ent->plt.offset;
+	    break;
+	  }
       if (off >= (bfd_vma) -2)
 	abort ();
 
@@ -4607,7 +6188,15 @@ ppc_size_one_stub (gen_entry, in_arg)
 
   if (stub_entry->stub_type == ppc_stub_plt_call)
     {
-      off = stub_entry->h->elf.plt.offset & ~(bfd_vma) 1;
+      struct plt_entry *ent;
+      for (ent = stub_entry->h->elf.plt.plist; ent != NULL; ent = ent->next)
+	if (ent->addend == stub_entry->addend)
+	  {
+	    off = ent->plt.offset & ~(bfd_vma) 1;
+	    break;
+	  }
+      if (ent == NULL)
+	abort ();
       off += (htab->splt->output_offset
 	      + htab->splt->output_section->vma
 	      - elf_gp (htab->splt->output_section->owner)
@@ -4938,6 +6527,8 @@ ppc64_elf_size_stubs (output_bfd, stub_b
 		  bfd_vma sym_value;
 		  bfd_vma destination;
 		  struct ppc_link_hash_entry *hash;
+		  struct elf_link_hash_entry *h;
+		  Elf_Internal_Sym *sym;
 		  char *stub_name;
 		  const asection *id_sec;
 
@@ -4959,33 +6550,16 @@ ppc64_elf_size_stubs (output_bfd, stub_b
 
 		  /* Now determine the call target, its name, value,
 		     section.  */
-		  sym_sec = NULL;
-		  sym_value = 0;
 		  destination = 0;
-		  hash = NULL;
-		  if (r_indx < symtab_hdr->sh_info)
+		  if (!get_sym_h (&h, &sym, &sym_sec, NULL, &local_syms,
+				  r_indx, input_bfd))
+		    goto error_ret_free_internal;
+		  hash = (struct ppc_link_hash_entry *) h;
+
+		  if (hash == NULL)
 		    {
 		      /* It's a local symbol.  */
-		      Elf_Internal_Sym *sym;
-		      Elf_Internal_Shdr *hdr;
-
-		      if (local_syms == NULL)
-			{
-			  local_syms
-			    = (Elf_Internal_Sym *) symtab_hdr->contents;
-			  if (local_syms == NULL)
-			    local_syms
-			      = bfd_elf_get_elf_syms (input_bfd, symtab_hdr,
-						      symtab_hdr->sh_info, 0,
-						      NULL, NULL, NULL);
-			  if (local_syms == NULL)
-			    goto error_ret_free_internal;
-			}
-		      sym = local_syms + r_indx;
-		      hdr = elf_elfsections (input_bfd)[sym->st_shndx];
-		      sym_sec = hdr->bfd_section;
-		      if (ELF_ST_TYPE (sym->st_info) != STT_SECTION)
-			sym_value = sym->st_value;
+		      sym_value = sym->st_value;
 		      destination = (sym_value + irela->r_addend
 				     + sym_sec->output_offset
 				     + sym_sec->output_section->vma);
@@ -4993,21 +6567,10 @@ ppc64_elf_size_stubs (output_bfd, stub_b
 		  else
 		    {
 		      /* It's an external symbol.  */
-		      int e_indx;
-
-		      e_indx = r_indx - symtab_hdr->sh_info;
-		      hash = ((struct ppc_link_hash_entry *)
-			      elf_sym_hashes (input_bfd)[e_indx]);
-
-		      while (hash->elf.root.type == bfd_link_hash_indirect
-			     || hash->elf.root.type == bfd_link_hash_warning)
-			hash = ((struct ppc_link_hash_entry *)
-				hash->elf.root.u.i.link);
-
+		      sym_value = 0;
 		      if (hash->elf.root.type == bfd_link_hash_defined
 			  || hash->elf.root.type == bfd_link_hash_defweak)
 			{
-			  sym_sec = hash->elf.root.u.def.section;
 			  sym_value = hash->elf.root.u.def.value;
 			  if (sym_sec->output_section != NULL)
 			    destination = (sym_value + irela->r_addend
@@ -5031,6 +6594,24 @@ ppc64_elf_size_stubs (output_bfd, stub_b
 		  if (stub_type == ppc_stub_none)
 		    continue;
 
+		  /* __tls_get_addr calls might be eliminated.  */
+		  if (stub_type != ppc_stub_plt_call
+		      && hash != NULL
+		      && &hash->elf == htab->tls_get_addr
+		      && section->has_tls_reloc
+		      && irela != internal_relocs)
+		    {
+		      /* Get tls info.  */
+		      char *tls_type;
+
+		      if (!get_tls_type (&tls_type, &local_syms,
+					 irela - 1, input_bfd))
+			goto error_ret_free_internal;
+		      if (tls_type != NULL
+			  && (*tls_type & (TLS_TLS | TLS_GD_LD)) == TLS_TLS)
+			continue;
+		    }
+
 		  /* Support for grouping stub sections.  */
 		  id_sec = htab->stub_group[section->id].link_sec;
 
@@ -5067,6 +6648,7 @@ ppc64_elf_size_stubs (output_bfd, stub_b
 		  stub_entry->target_section = sym_sec;
 		  stub_entry->stub_type = stub_type;
 		  stub_entry->h = hash;
+		  stub_entry->addend = irela->r_addend;
 		  stub_changed = TRUE;
 		}
 
@@ -5317,7 +6899,10 @@ ppc64_elf_relocate_section (output_bfd, 
   struct elf_link_hash_entry **sym_hashes;
   Elf_Internal_Rela *rel;
   Elf_Internal_Rela *relend;
-  bfd_vma *local_got_offsets;
+  Elf_Internal_Rela outrel;
+  bfd_byte *loc;
+  unsigned int tls_get_addr_type;
+  struct got_entry **local_got_ents;
   bfd_vma TOCstart;
   bfd_boolean ret = TRUE;
   bfd_boolean is_opd;
@@ -5332,18 +6917,32 @@ ppc64_elf_relocate_section (output_bfd, 
     ppc_howto_init ();
 
   htab = ppc_hash_table (info);
-  local_got_offsets = elf_local_got_offsets (input_bfd);
+  if (info->shared && (htab->tlsld_got.offset & 1) == 0)
+    {
+      outrel.r_offset = (htab->sgot->output_section->vma
+			 + htab->sgot->output_offset
+			 + htab->tlsld_got.offset);
+      outrel.r_info = ELF64_R_INFO (0, R_PPC64_DTPMOD64);
+      outrel.r_addend = 0;
+
+      loc = htab->srelgot->contents;
+      loc += htab->srelgot->reloc_count++ * sizeof (Elf64_External_Rela);
+      bfd_elf64_swap_reloca_out (output_bfd, &outrel, loc);
+      htab->tlsld_got.offset |= 1;
+    }
+
+  local_got_ents = elf_local_got_ents (input_bfd);
   TOCstart = elf_gp (output_bfd);
   symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
   sym_hashes = elf_sym_hashes (input_bfd);
   is_opd = ppc64_elf_section_data (input_section)->opd.adjust != NULL;
 
+  tls_get_addr_type = 0;
   rel = relocs;
   relend = relocs + input_section->reloc_count;
   for (; rel < relend; rel++)
     {
       enum elf_ppc64_reloc_type r_type;
-      bfd_vma offset;
       bfd_vma addend;
       bfd_reloc_status_type r;
       Elf_Internal_Sym *sym;
@@ -5352,6 +6951,7 @@ ppc64_elf_relocate_section (output_bfd, 
       struct elf_link_hash_entry *fdh;
       const char *sym_name;
       unsigned long r_symndx;
+      char tls_type;
       bfd_vma relocation;
       bfd_boolean unresolved_reloc;
       bfd_boolean warned;
@@ -5362,8 +6962,6 @@ ppc64_elf_relocate_section (output_bfd, 
 
       r_type = (enum elf_ppc64_reloc_type) ELF64_R_TYPE (rel->r_info);
       r_symndx = ELF64_R_SYM (rel->r_info);
-      offset = rel->r_offset;
-      addend = rel->r_addend;
       r = bfd_reloc_other;
       sym = (Elf_Internal_Sym *) 0;
       sec = (asection *) 0;
@@ -5382,12 +6980,8 @@ ppc64_elf_relocate_section (output_bfd, 
 	  /* It's a local symbol.  */
 	  sym = local_syms + r_symndx;
 	  sec = local_sections[r_symndx];
-	  sym_name = "<local symbol>";
-
+	  sym_name = bfd_elf_local_sym_name (input_bfd, sym);
 	  relocation = _bfd_elf_rela_local_sym (output_bfd, sym, sec, rel);
-	  /* rel may have changed, update our copy of addend.  */
-	  addend = rel->r_addend;
-
 	  if (elf_section_data (sec) != NULL)
 	    {
 	      long *opd_sym_adjust;
@@ -5432,15 +7026,275 @@ ppc64_elf_relocate_section (output_bfd, 
 	    {
 	      if (! ((*info->callbacks->undefined_symbol)
 		     (info, h->root.root.string, input_bfd, input_section,
-		      offset, (!info->shared
-			       || info->no_undefined
-			       || ELF_ST_VISIBILITY (h->other)))))
+		      rel->r_offset, (!info->shared
+				      || info->no_undefined
+				      || ELF_ST_VISIBILITY (h->other)))))
 		return FALSE;
 	      warned = TRUE;
 	    }
 	}
 
-      /* First handle relocations that tweak non-addend part of insn.  */
+      /* TLS optimizations.  */
+      tls_type = 0;
+      if (IS_TLS_RELOC (r_type))
+	{
+	  if (h != NULL)
+	    tls_type = ((struct ppc_link_hash_entry *) h)->tls_type;
+	  else if (local_got_ents != NULL)
+	    {
+	      char *lgot_types;
+	      lgot_types = (char *) (local_got_ents + symtab_hdr->sh_info);
+	      tls_type = lgot_types[r_symndx];
+	    }
+	}
+
+      /* Ensure reloc mapping code below stays sane.  */
+      if (R_PPC64_TOC16_LO_DS != R_PPC64_TOC16_DS + 1
+	  || R_PPC64_TOC16_LO != R_PPC64_TOC16 + 1
+	  || (R_PPC64_GOT_TLSLD16 & 3)    != (R_PPC64_GOT_TLSGD16 & 3)
+	  || (R_PPC64_GOT_TLSLD16_LO & 3) != (R_PPC64_GOT_TLSGD16_LO & 3)
+	  || (R_PPC64_GOT_TLSLD16_HI & 3) != (R_PPC64_GOT_TLSGD16_HI & 3)
+	  || (R_PPC64_GOT_TLSLD16_HA & 3) != (R_PPC64_GOT_TLSGD16_HA & 3)
+	  || (R_PPC64_GOT_TLSLD16 & 3)    != (R_PPC64_GOT_TPREL16_DS & 3)
+	  || (R_PPC64_GOT_TLSLD16_LO & 3) != (R_PPC64_GOT_TPREL16_LO_DS & 3)
+	  || (R_PPC64_GOT_TLSLD16_HI & 3) != (R_PPC64_GOT_TPREL16_HI & 3)
+	  || (R_PPC64_GOT_TLSLD16_HA & 3) != (R_PPC64_GOT_TPREL16_HA & 3))
+	abort ();
+      switch (r_type)
+	{
+	default:
+	  tls_get_addr_type = 0;
+	  break;
+
+	case R_PPC64_TOC16:
+	case R_PPC64_TOC16_LO:
+	case R_PPC64_TOC16_DS:
+	case R_PPC64_TOC16_LO_DS:
+	  tls_get_addr_type = 0;
+	  {
+	    /* Check for toc tls entries.  */
+	    char *toc_tls;
+
+	    if (!get_tls_type (&toc_tls, &local_syms, rel, input_bfd))
+	      return FALSE;
+
+	    if (toc_tls)
+	      {
+		tls_type = *toc_tls;
+		if (r_type == R_PPC64_TOC16_DS
+		    || r_type == R_PPC64_TOC16_LO_DS)
+		  goto toctprel;
+		else
+		  tls_get_addr_type = tls_type;
+	      }
+	  }
+	  break;
+
+	case R_PPC64_GOT_TPREL16_DS:
+	case R_PPC64_GOT_TPREL16_LO_DS:
+	  tls_get_addr_type = 0;
+	toctprel:
+	  if (tls_type != 0
+	      && (tls_type & TLS_TPREL) == 0)
+	    {
+	      bfd_vma insn;
+	      insn = bfd_get_32 (output_bfd, contents + rel->r_offset - 2);
+	      insn &= 31 << 21;
+	      insn |= 0x3c0d0000;	/* addis 0,13,0 */
+	      bfd_put_32 (output_bfd, insn, contents + rel->r_offset - 2);
+	      r_type = R_PPC64_TPREL16_HA;
+	      rel->r_info = ELF64_R_INFO (r_symndx, r_type);
+	    }
+	  break;
+
+	case R_PPC64_TLS:
+	  tls_get_addr_type = 0;
+	  if (tls_type == 0)
+	    {
+	      /* Check for toc tls entries.  */
+	      char *toc_tls;
+
+	      if (!get_tls_type (&toc_tls, &local_syms, rel, input_bfd))
+		return FALSE;
+
+	      if (toc_tls)
+		tls_type = *toc_tls;
+	    }
+	  if (tls_type != 0
+	      && (tls_type & TLS_TPREL) == 0)
+	    {
+	      bfd_vma insn, rtra;
+	      insn = bfd_get_32 (output_bfd, contents + rel->r_offset);
+	      if ((insn & ((31 << 26) | (31 << 11)))
+		  == ((31 << 26) | (13 << 11)))
+		rtra = insn & ((1 << 26) - (1 << 16));
+	      else if ((insn & ((31 << 26) | (31 << 16)))
+		       == ((31 << 26) | (13 << 16)))
+		rtra = (insn & (31 << 21)) | ((insn & (31 << 11)) << 5);
+	      else
+		abort ();
+	      if ((insn & ((1 << 11) - (1 << 1))) == 266 << 1)
+		/* add -> addi.  */
+		insn = 14 << 26;
+	      else if ((insn & (31 << 1)) == 23 << 1
+		       && ((insn & (31 << 6)) < 14 << 6
+			   || ((insn & (31 << 6)) >= 16 << 6
+			       && (insn & (31 << 6)) < 24 << 6)))
+		/* load and store indexed -> dform.  */
+		insn = (32 | ((insn >> 6) & 31)) << 26;
+	      else if ((insn & (31 << 1)) == 21 << 1
+		       && (insn & (0x1a << 6)) == 0)
+		/* ldx, ldux, stdx, stdux -> ld, ldu, std, stdu.  */
+		insn = (((58 | ((insn >> 6) & 4)) << 26)
+			| ((insn >> 6) & 1));
+	      else if ((insn & (31 << 1)) == 21 << 1
+		       && (insn & ((1 << 11) - (1 << 1))) == 341 << 1)
+		/* lwax -> lwa.  */
+		insn = (58 << 26) | 2;
+	      else
+		abort ();
+	      insn |= rtra;
+	      bfd_put_32 (output_bfd, insn, contents + rel->r_offset);
+	      r_type = R_PPC64_TPREL16_LO;
+	      rel->r_info = ELF64_R_INFO (r_symndx, r_type);
+	      /* Was PPC64_TLS which sits on insn boundary, now
+		 PPC64_TPREL16_LO which is at insn+2.  */
+	      rel->r_offset += 2;
+	    }
+	  break;
+
+	case R_PPC64_GOT_TLSGD16:
+	case R_PPC64_GOT_TLSGD16_LO:
+	case R_PPC64_GOT_TLSGD16_HI:
+	case R_PPC64_GOT_TLSGD16_HA:
+	case R_PPC64_GOT_TLSLD16:
+	case R_PPC64_GOT_TLSLD16_LO:
+	case R_PPC64_GOT_TLSLD16_HI:
+	case R_PPC64_GOT_TLSLD16_HA:
+	  tls_get_addr_type = 0;
+	  if (tls_type != 0 && (tls_type & TLS_GD_LD) == 0)
+	    {
+	      if (r_type == R_PPC64_GOT_TLSGD16_HI
+		  || r_type == R_PPC64_GOT_TLSGD16_HA
+		  || r_type == R_PPC64_GOT_TLSLD16_HI
+		  || r_type == R_PPC64_GOT_TLSLD16_HA)
+		{
+		  if ((tls_type & TLS_LD) != 0)
+		    {
+		      bfd_put_32 (output_bfd, NOP, contents + rel->r_offset);
+		      r_type = R_PPC64_NONE;
+		      rel->r_offset -= 2;
+		    }
+		  else
+		    r_type = (((r_type - (R_PPC64_GOT_TLSGD16 & 3)) & 3)
+			      + R_PPC64_GOT_TPREL16_DS);
+		  rel->r_info = ELF64_R_INFO (r_symndx, r_type);
+		  break;
+		}
+
+	      /* This reloc and its instruction will be replaced so there's
+		 not much point in doing anything more here.  We know the
+		 next reloc will be a REL24 to __tls_get_addr, and will
+		 be handled below.  */
+	      tls_get_addr_type = tls_type;
+	      continue;
+	    }
+	  break;
+
+	case R_PPC64_REL14:
+	case R_PPC64_REL14_BRTAKEN:
+	case R_PPC64_REL14_BRNTAKEN:
+	case R_PPC64_REL24:
+	  if (h != NULL
+	      && h == htab->tls_get_addr
+	      && tls_get_addr_type != 0
+	      && (tls_get_addr_type & TLS_GD_LD) == 0)
+	    {
+	      /* Replace the call.  */
+	      bfd_vma insn1, insn2, insn3;
+	      bfd_vma offset = rel->r_offset;
+
+	      insn1 = bfd_get_32 (output_bfd, contents + rel[-1].r_offset - 2);
+	      insn3 = bfd_get_32 (output_bfd, contents + offset + 4);
+	      if (tls_get_addr_type & TLS_TPREL)
+		{
+		  /* IE */
+		  insn1 &= (1 << 26) - (1 << 2);
+		  insn1 |= 58 << 26;	/* ld */
+		  insn2 = 0x7c636a14;	/* add 3,3,13 */
+		  /* Fix the relocs for --emit-relocs.  */
+		  r_type = ELF64_R_TYPE (rel[-1].r_info);
+		  if (tls_get_addr_type & TLS_EXPLICIT)
+		    r_type += R_PPC64_TOC16_DS - R_PPC64_TOC16;
+		  else
+		    r_type = (((r_type - (R_PPC64_GOT_TLSGD16 & 3)) & 3)
+			      + R_PPC64_GOT_TPREL16_DS);
+		  rel[-1].r_info
+		    = ELF64_R_INFO (ELF64_R_SYM (rel[-1].r_info), r_type);
+		  rel->r_info = 0;
+		}
+	      else
+		{
+		  /* LE */
+		  insn1 = 0x3c6d0000;	/* addis 3,13,0 */
+		  insn2 = 0x38630000;	/* addi 3,3,0 */
+		  if (tls_get_addr_type & TLS_LD)
+		    {
+		      r_symndx = 0;
+		      rel[-1].r_addend = htab->tls_sec->vma + DTP_OFFSET;
+		      rel->r_addend = htab->tls_sec->vma + DTP_OFFSET;
+		    }
+		  else
+		    r_symndx = ELF64_R_SYM (rel[-1].r_info);
+		  rel[-1].r_info = ELF64_R_INFO (r_symndx, R_PPC64_TPREL16_HA);
+		  rel->r_info = ELF64_R_INFO (r_symndx, R_PPC64_TPREL16_LO);
+		  rel->r_offset += 2;
+		}
+	      if (insn3 == NOP
+		  || insn3 == CROR_151515 || insn3 == CROR_313131)
+		{
+		  insn3 = insn2;
+		  insn2 = NOP;
+		  rel->r_offset += 4;
+		}
+	      bfd_put_32 (output_bfd, insn1, contents + rel[-1].r_offset - 2);
+	      bfd_put_32 (output_bfd, insn2, contents + offset);
+	      bfd_put_32 (output_bfd, insn3, contents + offset + 4);
+	      /* Do the relocs again.  */
+	      rel -= 2;
+	      tls_get_addr_type = 0;
+	      continue;
+	    }
+	  tls_get_addr_type = 0;
+	  break;
+
+	case R_PPC64_DTPMOD64:
+	  if ((tls_type & TLS_GD_LD) == 0)
+	    {
+	      if ((tls_type & TLS_TPREL) != 0)
+		r_type = R_PPC64_TPREL64;
+	      else
+		{
+		  bfd_put_64 (output_bfd, (bfd_vma) 1,
+			      contents + rel->r_offset);
+		  r_type = R_PPC64_NONE;
+		}
+	      rel->r_info = ELF64_R_INFO (r_symndx, r_type);
+	      if ((tls_type & TLS_LD) == 0)
+		rel[1].r_info = 0;
+	    }
+	  break;
+
+	case R_PPC64_TPREL64:
+	  if ((tls_type & TLS_TPREL) == 0)
+	    {
+	      r_type = R_PPC64_NONE;
+	      rel->r_info = ELF64_R_INFO (r_symndx, r_type);
+	    }
+	  break;
+	}
+
+      /* Handle other relocations that tweak non-addend part of insn.  */
       insn = 0;
       switch (r_type)
 	{
@@ -5456,7 +7310,8 @@ ppc64_elf_relocate_section (output_bfd, 
 	  /* Branch not taken prediction relocations.  */
 	case R_PPC64_ADDR14_BRNTAKEN:
 	case R_PPC64_REL14_BRNTAKEN:
-	  insn |= bfd_get_32 (output_bfd, contents + offset) & ~(0x01 << 21);
+	  insn |= bfd_get_32 (output_bfd,
+			      contents + rel->r_offset) & ~(0x01 << 21);
 	  if (is_power4)
 	    {
 	      /* Set 'a' bit.  This is 0b00010 in BO field for branch
@@ -5471,16 +7326,16 @@ ppc64_elf_relocate_section (output_bfd, 
 	    }
 	  else
 	    {
-	      from = (offset
+	      from = (rel->r_offset
 		      + input_section->output_offset
 		      + input_section->output_section->vma);
 
 	      /* Invert 'y' bit if not the default.  */
-	      if ((bfd_signed_vma) (relocation + addend - from) < 0)
+	      if ((bfd_signed_vma) (relocation + rel->r_addend - from) < 0)
 		insn ^= 0x01 << 21;
 	    }
 
-	  bfd_put_32 (output_bfd, (bfd_vma) insn, contents + offset);
+	  bfd_put_32 (output_bfd, (bfd_vma) insn, contents + rel->r_offset);
 	  break;
 
 	case R_PPC64_REL24:
@@ -5491,20 +7346,20 @@ ppc64_elf_relocate_section (output_bfd, 
 	     need for a PLT entry.  */
 	  if (h != NULL
 	      && (fdh = ((struct ppc_link_hash_entry *) h)->oh) != NULL
-	      && fdh->plt.offset != (bfd_vma) -1
+	      && fdh->plt.plist != NULL
 	      && (stub_entry = ppc_get_stub_entry (input_section, sec, fdh,
 						   rel, htab)) != NULL)
 	    {
 	      bfd_boolean can_plt_call = 0;
 
-	      if (offset + 8 <= input_section->_cooked_size)
+	      if (rel->r_offset + 8 <= input_section->_cooked_size)
 		{
-		  insn = bfd_get_32 (input_bfd, contents + offset + 4);
+		  insn = bfd_get_32 (input_bfd, contents + rel->r_offset + 4);
 		  if (insn == NOP
 		      || insn == CROR_151515 || insn == CROR_313131)
 		    {
 		      bfd_put_32 (input_bfd, (bfd_vma) LD_R2_40R1,
-				  contents + offset + 4);
+				  contents + rel->r_offset + 4);
 		      can_plt_call = 1;
 		    }
 		}
@@ -5513,7 +7368,7 @@ ppc64_elf_relocate_section (output_bfd, 
 		{
 		  /* If this is a plain branch rather than a branch
 		     and link, don't require a nop.  */
-		  insn = bfd_get_32 (input_bfd, contents + offset);
+		  insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
 		  if ((insn & 1) == 0)
 		    can_plt_call = 1;
 		}
@@ -5523,7 +7378,6 @@ ppc64_elf_relocate_section (output_bfd, 
 		  relocation = (stub_entry->stub_offset
 				+ stub_entry->stub_sec->output_offset
 				+ stub_entry->stub_sec->output_section->vma);
-		  addend = 0;
 		  unresolved_reloc = FALSE;
 		}
 	    }
@@ -5531,7 +7385,7 @@ ppc64_elf_relocate_section (output_bfd, 
 	  if (h != NULL
 	      && h->root.type == bfd_link_hash_undefweak
 	      && relocation == 0
-	      && addend == 0)
+	      && rel->r_addend == 0)
 	    {
 	      /* Tweak calls to undefined weak functions to point at a
 		 blr.  We can thus call a weak function without first
@@ -5541,7 +7395,7 @@ ppc64_elf_relocate_section (output_bfd, 
 	      relocation = (htab->sfpr->_raw_size - 4
 			    + htab->sfpr->output_offset
 			    + htab->sfpr->output_section->vma);
-	      from = (offset
+	      from = (rel->r_offset
 		      + input_section->output_offset
 		      + input_section->output_section->vma);
 
@@ -5555,6 +7409,8 @@ ppc64_elf_relocate_section (output_bfd, 
 	}
 
       /* Set `addend'.  */
+      tls_type = 0;
+      addend = rel->r_addend;
       switch (r_type)
 	{
 	default:
@@ -5567,34 +7423,81 @@ ppc64_elf_relocate_section (output_bfd, 
 	  continue;
 
 	case R_PPC64_NONE:
+	case R_PPC64_TLS:
 	case R_PPC64_GNU_VTINHERIT:
 	case R_PPC64_GNU_VTENTRY:
 	  continue;
 
 	  /* GOT16 relocations.  Like an ADDR16 using the symbol's
 	     address in the GOT as relocation value instead of the
-	     symbols value itself.  Also, create a GOT entry for the
+	     symbol's value itself.  Also, create a GOT entry for the
 	     symbol and put the symbol value there.  */
+	case R_PPC64_GOT_TLSGD16:
+	case R_PPC64_GOT_TLSGD16_LO:
+	case R_PPC64_GOT_TLSGD16_HI:
+	case R_PPC64_GOT_TLSGD16_HA:
+	  tls_type = TLS_TLS | TLS_GD_LD;
+	  goto dogot;
+
+	case R_PPC64_GOT_TLSLD16:
+	case R_PPC64_GOT_TLSLD16_LO:
+	case R_PPC64_GOT_TLSLD16_HI:
+	case R_PPC64_GOT_TLSLD16_HA:
+	  tls_type = TLS_TLS | TLS_GD_LD | TLS_LD;
+	  goto dogot;
+
+	case R_PPC64_GOT_TPREL16_DS:
+	case R_PPC64_GOT_TPREL16_LO_DS:
+	case R_PPC64_GOT_TPREL16_HI:
+	case R_PPC64_GOT_TPREL16_HA:
+	  tls_type = TLS_TLS | TLS_TPREL;
+	  goto dogot;
+
+	case R_PPC64_GOT_DTPREL16_DS:
+	case R_PPC64_GOT_DTPREL16_LO_DS:
+	case R_PPC64_GOT_DTPREL16_HI:
+	case R_PPC64_GOT_DTPREL16_HA:
+	  tls_type = TLS_TLS | TLS_DTPREL;
+	  goto dogot;
+
 	case R_PPC64_GOT16:
 	case R_PPC64_GOT16_LO:
 	case R_PPC64_GOT16_HI:
 	case R_PPC64_GOT16_HA:
 	case R_PPC64_GOT16_DS:
 	case R_PPC64_GOT16_LO_DS:
+	dogot:
 	  {
 	    /* Relocation is to the entry for this symbol in the global
 	       offset table.  */
+	    struct got_entry *ent;
 	    bfd_vma off;
+	    unsigned long indx;
 
 	    if (htab->sgot == NULL)
 	      abort ();
 
 	    if (h != NULL)
+	      ent = h->got.glist;
+	    else
 	      {
-		bfd_boolean dyn;
+		if (local_got_ents == NULL)
+		  abort ();
+		ent = local_got_ents[r_symndx];
+	      }
 
-		off = h->got.offset;
-		dyn = htab->elf.dynamic_sections_created;
+	    for (; ent != NULL; ent = ent->next)
+	      if (ent->addend == rel->r_addend
+		  && ent->tls_type == tls_type)
+		break;
+	    if (ent == NULL)
+	      abort ();
+
+	    off = ent->got.offset;
+	    indx = 0;
+	    if (h != NULL)
+	      {
+		bfd_boolean dyn = htab->elf.dynamic_sections_created;
 		if (! WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info, h)
 		    || (info->shared
 			&& (info->symbolic
@@ -5603,68 +7506,87 @@ ppc64_elf_relocate_section (output_bfd, 
 				& ELF_LINK_FORCED_LOCAL))
 			&& (h->elf_link_hash_flags
 			    & ELF_LINK_HASH_DEF_REGULAR)))
+		  /* This is actually a static link, or it is a
+		     -Bsymbolic link and the symbol is defined
+		     locally, or the symbol was forced to be local
+		     because of a version file.  */
+		  ;
+		else
 		  {
-		    /* This is actually a static link, or it is a
-		       -Bsymbolic link and the symbol is defined
-		       locally, or the symbol was forced to be local
-		       because of a version file.  We must initialize
-		       this entry in the global offset table.  Since the
-		       offset must always be a multiple of 8, we use the
-		       least significant bit to record whether we have
-		       initialized it already.
-
-		       When doing a dynamic link, we create a .rel.got
-		       relocation entry to initialize the value.  This
-		       is done in the finish_dynamic_symbol routine.  */
-		    if ((off & 1) != 0)
-		      off &= ~1;
-		    else
-		      {
-			bfd_put_64 (output_bfd, relocation,
-				    htab->sgot->contents + off);
-			h->got.offset |= 1;
-		      }
+		    indx = h->dynindx;
+		    unresolved_reloc = FALSE;
 		  }
-		else
-		  unresolved_reloc = FALSE;
 	      }
+
+	    /* The offset must always be a multiple of 8.  We use the
+	       least significant bit to record whether we have already
+	       processed this entry.  */
+	    if ((off & 1) != 0)
+	      off &= ~1;
 	    else
 	      {
-		if (local_got_offsets == NULL)
-		  abort ();
-
-		off = local_got_offsets[r_symndx];
-
-		/* The offset must always be a multiple of 8.  We use
-		   the least significant bit to record whether we have
-		   already processed this entry.  */
-		if ((off & 1) != 0)
-		  off &= ~1;
-		else
+		/* Generate relocs for the dynamic linker, except in
+		   the case of TLSLD where we'll use one entry per
+		   module.  */
+		if ((info->shared || indx != 0)
+		    && ent->tls_type != (TLS_TLS | TLS_GD_LD | TLS_LD))
 		  {
-		    bfd_put_64 (output_bfd, relocation,
-				htab->sgot->contents + off);
-
-		    if (info->shared)
+		    outrel.r_offset = (htab->sgot->output_section->vma
+				       + htab->sgot->output_offset
+				       + off);
+		    if (ent->tls_type == (TLS_TLS | TLS_GD_LD))
 		      {
-			Elf_Internal_Rela outrel;
-			bfd_byte *loc;
-
-			/* We need to generate a R_PPC64_RELATIVE reloc
-			   for the dynamic linker.  */
-			outrel.r_offset = (htab->sgot->output_section->vma
-					   + htab->sgot->output_offset
-					   + off);
-			outrel.r_info = ELF64_R_INFO (0, R_PPC64_RELATIVE);
-			outrel.r_addend = relocation;
+			outrel.r_info = ELF64_R_INFO (indx, R_PPC64_DTPMOD64);
+			outrel.r_addend = 0;
 			loc = htab->srelgot->contents;
 			loc += (htab->srelgot->reloc_count++
 				* sizeof (Elf64_External_Rela));
 			bfd_elf64_swap_reloca_out (output_bfd, &outrel, loc);
+			outrel.r_info = ELF64_R_INFO (indx, R_PPC64_DTPREL64);
+			outrel.r_offset += 8;
 		      }
+		    else if (ent->tls_type == (TLS_TLS | TLS_DTPREL))
+		      outrel.r_info = ELF64_R_INFO (indx, R_PPC64_DTPREL64);
+		    else if (ent->tls_type == (TLS_TLS | TLS_TPREL))
+		      outrel.r_info = ELF64_R_INFO (indx, R_PPC64_TPREL64);
+		    else if (indx == 0)
+		      outrel.r_info = ELF64_R_INFO (indx, R_PPC64_RELATIVE);
+		    else
+		      outrel.r_info = ELF64_R_INFO (indx, R_PPC64_GLOB_DAT);
+		    outrel.r_addend = ent->addend;
+		    if (indx == 0)
+		      outrel.r_addend += relocation;
+		    loc = htab->srelgot->contents;
+		    loc += (htab->srelgot->reloc_count++
+			    * sizeof (Elf64_External_Rela));
+		    bfd_elf64_swap_reloca_out (output_bfd, &outrel, loc);
+		  }
 
-		    local_got_offsets[r_symndx] |= 1;
+		/* Init the .got section contents if we're not
+		   emitting a reloc.  */
+		if (!(info->shared || indx != 0))
+		  {
+
+		    relocation += ent->addend;
+		    if ((tls_type & TLS_TLS) != 0)
+		      {
+			relocation -= htab->tls_sec->vma + DTP_OFFSET;
+			if ((tls_type & TLS_TPREL) != 0)
+			  relocation += DTP_OFFSET - TP_OFFSET;
+		      }
+
+		    if ((tls_type & TLS_GD_LD) != 0)
+		      {
+			if ((tls_type & TLS_LD) != 0)
+			  relocation = - DTP_OFFSET;
+			bfd_put_64 (output_bfd, relocation,
+				    htab->sgot->contents + off + 8);
+			relocation = 1;
+		      }
+		    bfd_put_64 (output_bfd, relocation,
+				htab->sgot->contents + off);
 		  }
+		ent->got.offset |= 1;
 	      }
 
 	    if (off >= (bfd_vma) -2)
@@ -5673,7 +7595,7 @@ ppc64_elf_relocate_section (output_bfd, 
 	    relocation = htab->sgot->output_offset + off;
 
 	    /* TOC base (r2) is TOC start plus 0x8000.  */
-	    addend -= TOC_BASE_OFF;
+	    addend = - TOC_BASE_OFF;
 	  }
 	  break;
 
@@ -5690,19 +7612,23 @@ ppc64_elf_relocate_section (output_bfd, 
 	  if (h == NULL)
 	    break;
 
-	  if (h->plt.offset == (bfd_vma) -1
-	      || htab->splt == NULL)
+	  /* It's possible that we didn't make a PLT entry for this
+	     symbol.  This happens when statically linking PIC code,
+	     or when using -Bsymbolic.  Go find a match if there is a
+	     PLT entry.  */
+	  if (htab->splt != NULL)
 	    {
-	      /* We didn't make a PLT entry for this symbol.  This
-		 happens when statically linking PIC code, or when
-		 using -Bsymbolic.  */
-	      break;
+	      struct plt_entry *ent;
+	      for (ent = h->plt.plist; ent != NULL; ent = ent->next)
+		if (ent->addend == rel->r_addend
+		    && ent->plt.offset != (bfd_vma) -1)
+		  {
+		    relocation = (htab->splt->output_section->vma
+				  + htab->splt->output_offset
+				  + ent->plt.offset);
+		    unresolved_reloc = FALSE;
+		  }
 	    }
-
-	  relocation = (htab->splt->output_section->vma
-			+ htab->splt->output_offset
-			+ h->plt.offset);
-	  unresolved_reloc = FALSE;
 	  break;
 
 	  /* TOC16 relocs.  We want the offset relative to the TOC base,
@@ -5735,8 +7661,48 @@ ppc64_elf_relocate_section (output_bfd, 
 	case R_PPC64_REL24:
 	  break;
 
+	case R_PPC64_TPREL16:
+	case R_PPC64_TPREL16_LO:
+	case R_PPC64_TPREL16_HI:
+	case R_PPC64_TPREL16_HA:
+	case R_PPC64_TPREL16_DS:
+	case R_PPC64_TPREL16_LO_DS:
+	case R_PPC64_TPREL16_HIGHER:
+	case R_PPC64_TPREL16_HIGHERA:
+	case R_PPC64_TPREL16_HIGHEST:
+	case R_PPC64_TPREL16_HIGHESTA:
+	  addend -= htab->tls_sec->vma + TP_OFFSET;
+	  if (info->shared)
+	    /* The TPREL16 relocs shouldn't really be used in shared
+	       libs as they will result in DT_TEXTREL being set, but
+	       support them anyway.  */
+	    goto dodyn;
+	  break;
+
+	case R_PPC64_DTPREL16:
+	case R_PPC64_DTPREL16_LO:
+	case R_PPC64_DTPREL16_HI:
+	case R_PPC64_DTPREL16_HA:
+	case R_PPC64_DTPREL16_DS:
+	case R_PPC64_DTPREL16_LO_DS:
+	case R_PPC64_DTPREL16_HIGHER:
+	case R_PPC64_DTPREL16_HIGHERA:
+	case R_PPC64_DTPREL16_HIGHEST:
+	case R_PPC64_DTPREL16_HIGHESTA:
+	  addend -= htab->tls_sec->vma + DTP_OFFSET;
+	  break;
+
+	case R_PPC64_TPREL64:
+	  addend -= htab->tls_sec->vma + TP_OFFSET;
+	  goto dodyn;
+
+	case R_PPC64_DTPREL64:
+	  addend -= htab->tls_sec->vma + DTP_OFFSET;
+	  /* Fall thru */
+
 	  /* Relocations that may need to be propagated if this is a
 	     dynamic object.  */
+	case R_PPC64_DTPMOD64:
 	case R_PPC64_REL30:
 	case R_PPC64_REL32:
 	case R_PPC64_REL64:
@@ -5762,6 +7728,7 @@ ppc64_elf_relocate_section (output_bfd, 
 	  /* r_symndx will be zero only for relocs against symbols
 	     from removed linkonce sections, or sections discarded by
 	     a linker script.  */
+	dodyn:
 	  if (r_symndx == 0)
 	    break;
 	  /* Fall thru.  */
@@ -5774,7 +7741,7 @@ ppc64_elf_relocate_section (output_bfd, 
 	    break;
 
 	  if ((info->shared
-	       && (IS_ABSOLUTE_RELOC (r_type)
+	       && (MUST_BE_DYN_RELOC (r_type)
 		   || (h != NULL
 		       && h->dynindx != -1
 		       && (! info->symbolic
@@ -5812,14 +7779,14 @@ ppc64_elf_relocate_section (output_bfd, 
 		skip = TRUE, relocate = TRUE;
 	      outrel.r_offset += (input_section->output_section->vma
 				  + input_section->output_offset);
-	      outrel.r_addend = addend;
+	      outrel.r_addend = rel->r_addend;
 
 	      if (skip)
 		memset (&outrel, 0, sizeof outrel);
 	      else if (h != NULL
 		       && h->dynindx != -1
 		       && !is_opd
-		       && (!IS_ABSOLUTE_RELOC (r_type)
+		       && (!MUST_BE_DYN_RELOC (r_type)
 			   || !info->shared
 			   || !info->symbolic
 			   || (h->elf_link_hash_flags
@@ -5831,6 +7798,7 @@ ppc64_elf_relocate_section (output_bfd, 
 		     or this is an opd section reloc which must point
 		     at a local function.  */
 		  outrel.r_addend += relocation;
+		  /* ??? why? */
 		  relocate = TRUE;
 		  if (r_type == R_PPC64_ADDR64 || r_type == R_PPC64_TOC)
 		    {
@@ -5938,6 +7906,20 @@ ppc64_elf_relocate_section (output_bfd, 
 	case R_PPC64_PLT16_HA:
 	case R_PPC64_TOC16_HA:
 	case R_PPC64_SECTOFF_HA:
+	case R_PPC64_TPREL16_HA:
+	case R_PPC64_DTPREL16_HA:
+	case R_PPC64_GOT_TLSGD16_HA:
+	case R_PPC64_GOT_TLSLD16_HA:
+	case R_PPC64_GOT_TPREL16_HA:
+	case R_PPC64_GOT_DTPREL16_HA:
+	case R_PPC64_TPREL16_HIGHER:
+	case R_PPC64_TPREL16_HIGHERA:
+	case R_PPC64_TPREL16_HIGHEST:
+	case R_PPC64_TPREL16_HIGHESTA:
+	case R_PPC64_DTPREL16_HIGHER:
+	case R_PPC64_DTPREL16_HIGHERA:
+	case R_PPC64_DTPREL16_HIGHEST:
+	case R_PPC64_DTPREL16_HIGHESTA:
 	  /* It's just possible that this symbol is a weak symbol
 	     that's not actually defined anywhere. In that case,
 	     'sec' would be NULL, and we should leave the symbol
@@ -5958,6 +7940,14 @@ ppc64_elf_relocate_section (output_bfd, 
 	case R_PPC64_TOC16_LO_DS:
 	case R_PPC64_PLTGOT16_DS:
 	case R_PPC64_PLTGOT16_LO_DS:
+	case R_PPC64_GOT_TPREL16_DS:
+	case R_PPC64_GOT_TPREL16_LO_DS:
+	case R_PPC64_GOT_DTPREL16_DS:
+	case R_PPC64_GOT_DTPREL16_LO_DS:
+	case R_PPC64_TPREL16_DS:
+	case R_PPC64_TPREL16_LO_DS:
+	case R_PPC64_DTPREL16_DS:
+	case R_PPC64_DTPREL16_LO_DS:
 	  if (((relocation + addend) & 3) != 0)
 	    {
 	      (*_bfd_error_handler)
@@ -5982,7 +7972,7 @@ ppc64_elf_relocate_section (output_bfd, 
 	branch_check:
 	  /* If the branch is out of reach, then redirect the
 	     call to the local stub for this function.  */
-	  from = (offset
+	  from = (rel->r_offset
 		  + input_section->output_offset
 		  + input_section->output_section->vma);
 	  if (relocation + addend - from + max_br_offset >= 2 * max_br_offset
@@ -6019,7 +8009,7 @@ ppc64_elf_relocate_section (output_bfd, 
 				    input_bfd,
 				    input_section,
 				    contents,
-				    offset,
+				    rel->r_offset,
 				    relocation,
 				    addend);
 
@@ -6045,13 +8035,9 @@ ppc64_elf_relocate_section (output_bfd, 
 	    }
 	  else
 	    {
-	      name = bfd_elf_string_from_elf_section (input_bfd,
-						      symtab_hdr->sh_link,
-						      sym->st_name);
+	      name = bfd_elf_local_sym_name (input_bfd, sym);
 	      if (name == NULL)
 		continue;
-	      if (*name == '\0')
-		name = bfd_section_name (input_bfd, sec);
 	    }
 
 	  if (r == bfd_reloc_overflow)
@@ -6060,7 +8046,7 @@ ppc64_elf_relocate_section (output_bfd, 
 		continue;
 	      if (!((*info->callbacks->reloc_overflow)
 		    (info, name, ppc64_elf_howto_table[(int) r_type]->name,
-		     rel->r_addend, input_bfd, input_section, offset)))
+		     rel->r_addend, input_bfd, input_section, rel->r_offset)))
 		return FALSE;
 	    }
 	  else
@@ -6094,79 +8080,37 @@ ppc64_elf_finish_dynamic_symbol (output_
   htab = ppc_hash_table (info);
   dynobj = htab->elf.dynobj;
 
-  if (h->plt.offset != (bfd_vma) -1
-      && ((struct ppc_link_hash_entry *) h)->is_func_descriptor)
-    {
-      Elf_Internal_Rela rela;
-      bfd_byte *loc;
-
-      /* This symbol has an entry in the procedure linkage table.  Set
-	 it up.  */
-
-      if (htab->splt == NULL
-	  || htab->srelplt == NULL
-	  || htab->sglink == NULL)
-	abort ();
-
-      /* Create a JMP_SLOT reloc to inform the dynamic linker to
-	 fill in the PLT entry.  */
-
-      rela.r_offset = (htab->splt->output_section->vma
-		       + htab->splt->output_offset
-		       + h->plt.offset);
-      rela.r_info = ELF64_R_INFO (h->dynindx, R_PPC64_JMP_SLOT);
-      rela.r_addend = 0;
-
-      loc = htab->srelplt->contents;
-      loc += ((h->plt.offset - PLT_INITIAL_ENTRY_SIZE) / PLT_ENTRY_SIZE
-	      * sizeof (Elf64_External_Rela));
-      bfd_elf64_swap_reloca_out (output_bfd, &rela, loc);
-    }
-
-  if (h->got.offset != (bfd_vma) -1)
+  if (((struct ppc_link_hash_entry *) h)->is_func_descriptor)
     {
+      struct plt_entry *ent;
       Elf_Internal_Rela rela;
       bfd_byte *loc;
 
-      /* This symbol has an entry in the global offset table.  Set it
-	 up.  */
+      for (ent = h->plt.plist; ent != NULL; ent = ent->next)
+	if (ent->plt.offset != (bfd_vma) -1)
+	  {
+	    /* This symbol has an entry in the procedure linkage
+	       table.  Set it up.  */
 
-      if (htab->sgot == NULL || htab->srelgot == NULL)
-	abort ();
+	    if (htab->splt == NULL
+		|| htab->srelplt == NULL
+		|| htab->sglink == NULL)
+	      abort ();
 
-      rela.r_offset = (htab->sgot->output_section->vma
-		       + htab->sgot->output_offset
-		       + (h->got.offset &~ (bfd_vma) 1));
+	    /* Create a JMP_SLOT reloc to inform the dynamic linker to
+	       fill in the PLT entry.  */
 
-      /* If this is a static link, or it is a -Bsymbolic link and the
-	 symbol is defined locally or was forced to be local because
-	 of a version file, we just want to emit a RELATIVE reloc.
-	 The entry in the global offset table will already have been
-	 initialized in the relocate_section function.  */
-      if (info->shared
-	  && (info->symbolic
-	      || h->dynindx == -1
-	      || (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL))
-	  && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR))
-	{
-	  BFD_ASSERT((h->got.offset & 1) != 0);
-	  rela.r_info = ELF64_R_INFO (0, R_PPC64_RELATIVE);
-	  rela.r_addend = (h->root.u.def.value
-			   + h->root.u.def.section->output_section->vma
-			   + h->root.u.def.section->output_offset);
-	}
-      else
-	{
-	  BFD_ASSERT ((h->got.offset & 1) == 0);
-	  bfd_put_64 (output_bfd, (bfd_vma) 0,
-		      htab->sgot->contents + h->got.offset);
-	  rela.r_info = ELF64_R_INFO (h->dynindx, R_PPC64_GLOB_DAT);
-	  rela.r_addend = 0;
-	}
+	    rela.r_offset = (htab->splt->output_section->vma
+			     + htab->splt->output_offset
+			     + ent->plt.offset);
+	    rela.r_info = ELF64_R_INFO (h->dynindx, R_PPC64_JMP_SLOT);
+	    rela.r_addend = ent->addend;
 
-      loc = htab->srelgot->contents;
-      loc += htab->srelgot->reloc_count++ * sizeof (Elf64_External_Rela);
-      bfd_elf64_swap_reloca_out (output_bfd, &rela, loc);
+	    loc = htab->srelplt->contents;
+	    loc += ((ent->plt.offset - PLT_INITIAL_ENTRY_SIZE) / PLT_ENTRY_SIZE
+		    * sizeof (Elf64_External_Rela));
+	    bfd_elf64_swap_reloca_out (output_bfd, &rela, loc);
+	  }
     }
 
   if ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_COPY) != 0)
Index: bfd/elf64-ppc.h
===================================================================
RCS file: /cvs/src/src/bfd/elf64-ppc.h,v
retrieving revision 1.6
diff -u -p -d -r1.6 elf64-ppc.h
--- bfd/elf64-ppc.h	30 Nov 2002 08:39:39 -0000	1.6
+++ bfd/elf64-ppc.h	4 Feb 2003 14:02:14 -0000
@@ -1,5 +1,5 @@
 /* PowerPC64-specific support for 64-bit ELF.
-   Copyright 2002 Free Software Foundation, Inc.
+   Copyright 2002, 2003 Free Software Foundation, Inc.
 
 This file is part of BFD, the Binary File Descriptor library.
 
@@ -20,6 +20,8 @@ Foundation, Inc., 59 Temple Place - Suit
 bfd_boolean ppc64_elf_mark_entry_syms
   PARAMS ((struct bfd_link_info *));
 bfd_boolean ppc64_elf_edit_opd
+  PARAMS ((bfd *, struct bfd_link_info *));
+bfd_boolean ppc64_elf_tls_optimize
   PARAMS ((bfd *, struct bfd_link_info *));
 bfd_vma ppc64_elf_toc
   PARAMS ((bfd *));
Index: bfd/reloc.c
===================================================================
RCS file: /cvs/src/src/bfd/reloc.c,v
retrieving revision 1.78
diff -u -p -d -r1.78 reloc.c
--- bfd/reloc.c	24 Jan 2003 23:44:44 -0000	1.78
+++ bfd/reloc.c	4 Feb 2003 14:02:17 -0000
@@ -2393,6 +2393,89 @@ ENUMDOC
   Power(rs6000) and PowerPC relocations.
 
 ENUM
+  BFD_RELOC_PPC_TLS
+ENUMX
+  BFD_RELOC_PPC_DTPMOD
+ENUMX
+  BFD_RELOC_PPC_TPREL16
+ENUMX
+  BFD_RELOC_PPC_TPREL16_LO
+ENUMX
+  BFD_RELOC_PPC_TPREL16_HI
+ENUMX
+  BFD_RELOC_PPC_TPREL16_HA
+ENUMX
+  BFD_RELOC_PPC_TPREL
+ENUMX
+  BFD_RELOC_PPC_DTPREL16
+ENUMX
+  BFD_RELOC_PPC_DTPREL16_LO
+ENUMX
+  BFD_RELOC_PPC_DTPREL16_HI
+ENUMX
+  BFD_RELOC_PPC_DTPREL16_HA
+ENUMX
+  BFD_RELOC_PPC_DTPREL
+ENUMX
+  BFD_RELOC_PPC_GOT_TLSGD16
+ENUMX
+  BFD_RELOC_PPC_GOT_TLSGD16_LO
+ENUMX
+  BFD_RELOC_PPC_GOT_TLSGD16_HI
+ENUMX
+  BFD_RELOC_PPC_GOT_TLSGD16_HA
+ENUMX
+  BFD_RELOC_PPC_GOT_TLSLD16
+ENUMX
+  BFD_RELOC_PPC_GOT_TLSLD16_LO
+ENUMX
+  BFD_RELOC_PPC_GOT_TLSLD16_HI
+ENUMX
+  BFD_RELOC_PPC_GOT_TLSLD16_HA
+ENUMX
+  BFD_RELOC_PPC_GOT_TPREL16
+ENUMX
+  BFD_RELOC_PPC_GOT_TPREL16_LO
+ENUMX
+  BFD_RELOC_PPC_GOT_TPREL16_HI
+ENUMX
+  BFD_RELOC_PPC_GOT_TPREL16_HA
+ENUMX
+  BFD_RELOC_PPC_GOT_DTPREL16
+ENUMX
+  BFD_RELOC_PPC_GOT_DTPREL16_LO
+ENUMX
+  BFD_RELOC_PPC_GOT_DTPREL16_HI
+ENUMX
+  BFD_RELOC_PPC_GOT_DTPREL16_HA
+ENUMX
+  BFD_RELOC_PPC64_TPREL16_DS
+ENUMX
+  BFD_RELOC_PPC64_TPREL16_LO_DS
+ENUMX
+  BFD_RELOC_PPC64_TPREL16_HIGHER
+ENUMX
+  BFD_RELOC_PPC64_TPREL16_HIGHERA
+ENUMX
+  BFD_RELOC_PPC64_TPREL16_HIGHEST
+ENUMX
+  BFD_RELOC_PPC64_TPREL16_HIGHESTA
+ENUMX
+  BFD_RELOC_PPC64_DTPREL16_DS
+ENUMX
+  BFD_RELOC_PPC64_DTPREL16_LO_DS
+ENUMX
+  BFD_RELOC_PPC64_DTPREL16_HIGHER
+ENUMX
+  BFD_RELOC_PPC64_DTPREL16_HIGHERA
+ENUMX
+  BFD_RELOC_PPC64_DTPREL16_HIGHEST
+ENUMX
+  BFD_RELOC_PPC64_DTPREL16_HIGHESTA
+ENUMDOC
+  PowerPC and PowerPC64 thread-local storage relocations.
+
+ENUM
   BFD_RELOC_I370_D12
 ENUMDOC
   IBM 370/390 relocations
Index: gas/config/tc-ppc.c
===================================================================
RCS file: /cvs/src/src/gas/config/tc-ppc.c,v
retrieving revision 1.64
diff -u -p -d -r1.64 tc-ppc.c
--- gas/config/tc-ppc.c	23 Jan 2003 12:51:05 -0000	1.64
+++ gas/config/tc-ppc.c	4 Feb 2003 14:02:25 -0000
@@ -1460,60 +1460,94 @@ ppc_elf_suffix (str_p, exp_p)
 #define MAP(str,reloc) { str, sizeof (str)-1, reloc }
 
   static const struct map_bfd mapping[] = {
-    MAP ("l",		(int) BFD_RELOC_LO16),
-    MAP ("h",		(int) BFD_RELOC_HI16),
-    MAP ("ha",		(int) BFD_RELOC_HI16_S),
-    MAP ("brtaken",	(int) BFD_RELOC_PPC_B16_BRTAKEN),
-    MAP ("brntaken",	(int) BFD_RELOC_PPC_B16_BRNTAKEN),
-    MAP ("got",		(int) BFD_RELOC_16_GOTOFF),
-    MAP ("got@l",	(int) BFD_RELOC_LO16_GOTOFF),
-    MAP ("got@h",	(int) BFD_RELOC_HI16_GOTOFF),
-    MAP ("got@ha",	(int) BFD_RELOC_HI16_S_GOTOFF),
-    MAP ("fixup",	(int) BFD_RELOC_CTOR), /* warning with -mrelocatable */
-    MAP ("plt",		(int) BFD_RELOC_24_PLT_PCREL),
-    MAP ("pltrel24",	(int) BFD_RELOC_24_PLT_PCREL),
-    MAP ("copy",	(int) BFD_RELOC_PPC_COPY),
-    MAP ("globdat",	(int) BFD_RELOC_PPC_GLOB_DAT),
-    MAP ("local24pc",	(int) BFD_RELOC_PPC_LOCAL24PC),
-    MAP ("local",	(int) BFD_RELOC_PPC_LOCAL24PC),
-    MAP ("pltrel",	(int) BFD_RELOC_32_PLT_PCREL),
-    MAP ("plt@l",	(int) BFD_RELOC_LO16_PLTOFF),
-    MAP ("plt@h",	(int) BFD_RELOC_HI16_PLTOFF),
-    MAP ("plt@ha",	(int) BFD_RELOC_HI16_S_PLTOFF),
-    MAP ("sdarel",	(int) BFD_RELOC_GPREL16),
-    MAP ("sectoff",	(int) BFD_RELOC_16_BASEREL),
-    MAP ("sectoff@l",	(int) BFD_RELOC_LO16_BASEREL),
-    MAP ("sectoff@h",	(int) BFD_RELOC_HI16_BASEREL),
-    MAP ("sectoff@ha",	(int) BFD_RELOC_HI16_S_BASEREL),
-    MAP ("naddr",	(int) BFD_RELOC_PPC_EMB_NADDR32),
-    MAP ("naddr16",	(int) BFD_RELOC_PPC_EMB_NADDR16),
-    MAP ("naddr@l",	(int) BFD_RELOC_PPC_EMB_NADDR16_LO),
-    MAP ("naddr@h",	(int) BFD_RELOC_PPC_EMB_NADDR16_HI),
-    MAP ("naddr@ha",	(int) BFD_RELOC_PPC_EMB_NADDR16_HA),
-    MAP ("sdai16",	(int) BFD_RELOC_PPC_EMB_SDAI16),
-    MAP ("sda2rel",	(int) BFD_RELOC_PPC_EMB_SDA2REL),
-    MAP ("sda2i16",	(int) BFD_RELOC_PPC_EMB_SDA2I16),
-    MAP ("sda21",	(int) BFD_RELOC_PPC_EMB_SDA21),
-    MAP ("mrkref",	(int) BFD_RELOC_PPC_EMB_MRKREF),
-    MAP ("relsect",	(int) BFD_RELOC_PPC_EMB_RELSEC16),
-    MAP ("relsect@l",	(int) BFD_RELOC_PPC_EMB_RELST_LO),
-    MAP ("relsect@h",	(int) BFD_RELOC_PPC_EMB_RELST_HI),
-    MAP ("relsect@ha",	(int) BFD_RELOC_PPC_EMB_RELST_HA),
-    MAP ("bitfld",	(int) BFD_RELOC_PPC_EMB_BIT_FLD),
-    MAP ("relsda",	(int) BFD_RELOC_PPC_EMB_RELSDA),
-    MAP ("xgot",	(int) BFD_RELOC_PPC_TOC16),
+    MAP ("l",			(int) BFD_RELOC_LO16),
+    MAP ("h",			(int) BFD_RELOC_HI16),
+    MAP ("ha",			(int) BFD_RELOC_HI16_S),
+    MAP ("brtaken",		(int) BFD_RELOC_PPC_B16_BRTAKEN),
+    MAP ("brntaken",		(int) BFD_RELOC_PPC_B16_BRNTAKEN),
+    MAP ("got",			(int) BFD_RELOC_16_GOTOFF),
+    MAP ("got@l",		(int) BFD_RELOC_LO16_GOTOFF),
+    MAP ("got@h",		(int) BFD_RELOC_HI16_GOTOFF),
+    MAP ("got@ha",		(int) BFD_RELOC_HI16_S_GOTOFF),
+    MAP ("fixup",		(int) BFD_RELOC_CTOR),
+    MAP ("plt",			(int) BFD_RELOC_24_PLT_PCREL),
+    MAP ("pltrel24",		(int) BFD_RELOC_24_PLT_PCREL),
+    MAP ("copy",		(int) BFD_RELOC_PPC_COPY),
+    MAP ("globdat",		(int) BFD_RELOC_PPC_GLOB_DAT),
+    MAP ("local24pc",		(int) BFD_RELOC_PPC_LOCAL24PC),
+    MAP ("local",		(int) BFD_RELOC_PPC_LOCAL24PC),
+    MAP ("pltrel",		(int) BFD_RELOC_32_PLT_PCREL),
+    MAP ("plt@l",		(int) BFD_RELOC_LO16_PLTOFF),
+    MAP ("plt@h",		(int) BFD_RELOC_HI16_PLTOFF),
+    MAP ("plt@ha",		(int) BFD_RELOC_HI16_S_PLTOFF),
+    MAP ("sdarel",		(int) BFD_RELOC_GPREL16),
+    MAP ("sectoff",		(int) BFD_RELOC_16_BASEREL),
+    MAP ("sectoff@l",		(int) BFD_RELOC_LO16_BASEREL),
+    MAP ("sectoff@h",		(int) BFD_RELOC_HI16_BASEREL),
+    MAP ("sectoff@ha",		(int) BFD_RELOC_HI16_S_BASEREL),
+    MAP ("naddr",		(int) BFD_RELOC_PPC_EMB_NADDR32),
+    MAP ("naddr16",		(int) BFD_RELOC_PPC_EMB_NADDR16),
+    MAP ("naddr@l",		(int) BFD_RELOC_PPC_EMB_NADDR16_LO),
+    MAP ("naddr@h",		(int) BFD_RELOC_PPC_EMB_NADDR16_HI),
+    MAP ("naddr@ha",		(int) BFD_RELOC_PPC_EMB_NADDR16_HA),
+    MAP ("sdai16",		(int) BFD_RELOC_PPC_EMB_SDAI16),
+    MAP ("sda2rel",		(int) BFD_RELOC_PPC_EMB_SDA2REL),
+    MAP ("sda2i16",		(int) BFD_RELOC_PPC_EMB_SDA2I16),
+    MAP ("sda21",		(int) BFD_RELOC_PPC_EMB_SDA21),
+    MAP ("mrkref",		(int) BFD_RELOC_PPC_EMB_MRKREF),
+    MAP ("relsect",		(int) BFD_RELOC_PPC_EMB_RELSEC16),
+    MAP ("relsect@l",		(int) BFD_RELOC_PPC_EMB_RELST_LO),
+    MAP ("relsect@h",		(int) BFD_RELOC_PPC_EMB_RELST_HI),
+    MAP ("relsect@ha",		(int) BFD_RELOC_PPC_EMB_RELST_HA),
+    MAP ("bitfld",		(int) BFD_RELOC_PPC_EMB_BIT_FLD),
+    MAP ("relsda",		(int) BFD_RELOC_PPC_EMB_RELSDA),
+    MAP ("xgot",		(int) BFD_RELOC_PPC_TOC16),
+    MAP ("tls",			(int) BFD_RELOC_PPC_TLS),
+    MAP ("dtpmod",		(int) BFD_RELOC_PPC_DTPMOD),
+    MAP ("dtprel",		(int) BFD_RELOC_PPC_DTPREL),
+    MAP ("dtprel@l",		(int) BFD_RELOC_PPC_DTPREL16_LO),
+    MAP ("dtprel@h",		(int) BFD_RELOC_PPC_DTPREL16_HI),
+    MAP ("dtprel@ha",		(int) BFD_RELOC_PPC_DTPREL16_HA),
+    MAP ("tprel",		(int) BFD_RELOC_PPC_TPREL),
+    MAP ("tprel@l",		(int) BFD_RELOC_PPC_TPREL16_LO),
+    MAP ("tprel@h",		(int) BFD_RELOC_PPC_TPREL16_HI),
+    MAP ("tprel@ha",		(int) BFD_RELOC_PPC_TPREL16_HA),
+    MAP ("got@tlsgd",		(int) BFD_RELOC_PPC_GOT_TLSGD16),
+    MAP ("got@tlsgd@l",		(int) BFD_RELOC_PPC_GOT_TLSGD16_LO),
+    MAP ("got@tlsgd@h",		(int) BFD_RELOC_PPC_GOT_TLSGD16_HI),
+    MAP ("got@tlsgd@ha",	(int) BFD_RELOC_PPC_GOT_TLSGD16_HA),
+    MAP ("got@tlsld",		(int) BFD_RELOC_PPC_GOT_TLSLD16),
+    MAP ("got@tlsld@l",		(int) BFD_RELOC_PPC_GOT_TLSLD16_LO),
+    MAP ("got@tlsld@h",		(int) BFD_RELOC_PPC_GOT_TLSLD16_HI),
+    MAP ("got@tlsld@ha",	(int) BFD_RELOC_PPC_GOT_TLSLD16_HA),
+    MAP ("got@dtprel",		(int) BFD_RELOC_PPC_GOT_DTPREL16),
+    MAP ("got@dtprel@l",	(int) BFD_RELOC_PPC_GOT_DTPREL16_LO),
+    MAP ("got@dtprel@h",	(int) BFD_RELOC_PPC_GOT_DTPREL16_HI),
+    MAP ("got@dtprel@ha",	(int) BFD_RELOC_PPC_GOT_DTPREL16_HA),
+    MAP ("got@tprel",		(int) BFD_RELOC_PPC_GOT_TPREL16),
+    MAP ("got@tprel@l",		(int) BFD_RELOC_PPC_GOT_TPREL16_LO),
+    MAP ("got@tprel@h",		(int) BFD_RELOC_PPC_GOT_TPREL16_HI),
+    MAP ("got@tprel@ha",	(int) BFD_RELOC_PPC_GOT_TPREL16_HA),
     /* The following are only valid for ppc64.  Negative values are
        used instead of a flag.  */
-    MAP ("higher",	- (int) BFD_RELOC_PPC64_HIGHER),
-    MAP ("highera",	- (int) BFD_RELOC_PPC64_HIGHER_S),
-    MAP ("highest",	- (int) BFD_RELOC_PPC64_HIGHEST),
-    MAP ("highesta",	- (int) BFD_RELOC_PPC64_HIGHEST_S),
-    MAP ("tocbase",	- (int) BFD_RELOC_PPC64_TOC),
-    MAP ("toc",		- (int) BFD_RELOC_PPC_TOC16),
-    MAP ("toc@l",	- (int) BFD_RELOC_PPC64_TOC16_LO),
-    MAP ("toc@h",	- (int) BFD_RELOC_PPC64_TOC16_HI),
-    MAP ("toc@ha",	- (int) BFD_RELOC_PPC64_TOC16_HA),
-    { (char *) 0, 0,	(int) BFD_RELOC_UNUSED }
+    MAP ("higher",		- (int) BFD_RELOC_PPC64_HIGHER),
+    MAP ("highera",		- (int) BFD_RELOC_PPC64_HIGHER_S),
+    MAP ("highest",		- (int) BFD_RELOC_PPC64_HIGHEST),
+    MAP ("highesta",		- (int) BFD_RELOC_PPC64_HIGHEST_S),
+    MAP ("tocbase",		- (int) BFD_RELOC_PPC64_TOC),
+    MAP ("toc",			- (int) BFD_RELOC_PPC_TOC16),
+    MAP ("toc@l",		- (int) BFD_RELOC_PPC64_TOC16_LO),
+    MAP ("toc@h",		- (int) BFD_RELOC_PPC64_TOC16_HI),
+    MAP ("toc@ha",		- (int) BFD_RELOC_PPC64_TOC16_HA),
+    MAP ("dtprel@higher",	- (int) BFD_RELOC_PPC64_DTPREL16_HIGHER),
+    MAP ("dtprel@highera",	- (int) BFD_RELOC_PPC64_DTPREL16_HIGHERA),
+    MAP ("dtprel@highest",	- (int) BFD_RELOC_PPC64_DTPREL16_HIGHEST),
+    MAP ("dtprel@highesta",	- (int) BFD_RELOC_PPC64_DTPREL16_HIGHESTA),
+    MAP ("tprel@higher",	- (int) BFD_RELOC_PPC64_TPREL16_HIGHER),
+    MAP ("tprel@highera",	- (int) BFD_RELOC_PPC64_TPREL16_HIGHERA),
+    MAP ("tprel@highest",	- (int) BFD_RELOC_PPC64_TPREL16_HIGHEST),
+    MAP ("tprel@highesta",	- (int) BFD_RELOC_PPC64_TPREL16_HIGHESTA),
+    { (char *) 0, 0,		(int) BFD_RELOC_UNUSED }
   };
 
   if (*str++ != '@')
@@ -1545,29 +1579,32 @@ ppc_elf_suffix (str_p, exp_p)
 	    reloc = -reloc;
 	  }
 
-	if (exp_p->X_add_number != 0
-	    && (reloc == (int) BFD_RELOC_16_GOTOFF
-		|| reloc == (int) BFD_RELOC_LO16_GOTOFF
-		|| reloc == (int) BFD_RELOC_HI16_GOTOFF
-		|| reloc == (int) BFD_RELOC_HI16_S_GOTOFF))
-	  as_warn (_("identifier+constant@got means identifier@got+constant"));
-
-	/* Now check for identifier@suffix+constant.  */
-	if (*str == '-' || *str == '+')
+	if (!ppc_obj64)
 	  {
-	    char *orig_line = input_line_pointer;
-	    expressionS new_exp;
+	    if (exp_p->X_add_number != 0
+		&& (reloc == (int) BFD_RELOC_16_GOTOFF
+		    || reloc == (int) BFD_RELOC_LO16_GOTOFF
+		    || reloc == (int) BFD_RELOC_HI16_GOTOFF
+		    || reloc == (int) BFD_RELOC_HI16_S_GOTOFF))
+	      as_warn (_("identifier+constant@got means identifier@got+constant"));
 
-	    input_line_pointer = str;
-	    expression (&new_exp);
-	    if (new_exp.X_op == O_constant)
+	    /* Now check for identifier@suffix+constant.  */
+	    if (*str == '-' || *str == '+')
 	      {
-		exp_p->X_add_number += new_exp.X_add_number;
-		str = input_line_pointer;
-	      }
+		char *orig_line = input_line_pointer;
+		expressionS new_exp;
 
-	    if (&input_line_pointer != str_p)
-	      input_line_pointer = orig_line;
+		input_line_pointer = str;
+		expression (&new_exp);
+		if (new_exp.X_op == O_constant)
+		  {
+		    exp_p->X_add_number += new_exp.X_add_number;
+		    str = input_line_pointer;
+		  }
+
+		if (&input_line_pointer != str_p)
+		  input_line_pointer = orig_line;
+	      }
 	  }
 	*str_p = str;
 
@@ -2363,6 +2400,25 @@ md_assemble (str)
 #ifdef OBJ_ELF
       else if ((reloc = ppc_elf_suffix (&str, &ex)) != BFD_RELOC_UNUSED)
 	{
+	  /* Some TLS tweaks.  */
+	  switch (reloc)
+	    {
+	    default:
+	      break;
+	    case BFD_RELOC_PPC_TLS:
+	      insn = ppc_insert_operand (insn, operand, ppc_obj64 ? 13 : 2,
+					 (char *) NULL, 0);
+	      break;
+	  /* We'll only use the 32 (or 64) bit form of these relocations
+	     in constants.  Instructions get the 16 bit form.  */
+	    case BFD_RELOC_PPC_DTPREL:
+	      reloc = BFD_RELOC_PPC_DTPREL16;
+	      break;
+	    case BFD_RELOC_PPC_TPREL:
+	      reloc = BFD_RELOC_PPC_TPREL16;
+	      break;
+	    }
+
 	  /* For the absolute forms of branches, convert the PC
 	     relative form back into the absolute.  */
 	  if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0)
@@ -2424,6 +2480,23 @@ md_assemble (str)
 		case BFD_RELOC_PPC64_PLTGOT16_LO:
 		  reloc = BFD_RELOC_PPC64_PLTGOT16_LO_DS;
 		  break;
+		case BFD_RELOC_PPC_DTPREL16:
+		  reloc = BFD_RELOC_PPC64_DTPREL16_DS;
+		  break;
+		case BFD_RELOC_PPC_DTPREL16_LO:
+		  reloc = BFD_RELOC_PPC64_DTPREL16_LO_DS;
+		  break;
+		case BFD_RELOC_PPC_TPREL16:
+		  reloc = BFD_RELOC_PPC64_TPREL16_DS;
+		  break;
+		case BFD_RELOC_PPC_TPREL16_LO:
+		  reloc = BFD_RELOC_PPC64_TPREL16_LO_DS;
+		  break;
+		case BFD_RELOC_PPC_GOT_DTPREL16:
+		case BFD_RELOC_PPC_GOT_DTPREL16_LO:
+		case BFD_RELOC_PPC_GOT_TPREL16:
+		case BFD_RELOC_PPC_GOT_TPREL16_LO:
+		  break;
 		default:
 		  as_bad (_("unsupported relocation for DS offset field"));
 		  break;
@@ -5283,6 +5356,10 @@ ppc_force_relocation (fix)
       break;
     }
 
+  if (fix->fx_r_type >= BFD_RELOC_PPC_TLS
+      && fix->fx_r_type <= BFD_RELOC_PPC64_DTPREL16_HIGHESTA)
+    return 1;
+
   return generic_force_reloc (fix);
 }
 
@@ -5297,6 +5374,8 @@ ppc_fix_adjustable (fix)
 	  && fix->fx_r_type != BFD_RELOC_GPREL16
 	  && fix->fx_r_type != BFD_RELOC_VTABLE_INHERIT
 	  && fix->fx_r_type != BFD_RELOC_VTABLE_ENTRY
+	  && !(fix->fx_r_type >= BFD_RELOC_PPC_TLS
+	       && fix->fx_r_type <= BFD_RELOC_PPC64_DTPREL16_HIGHESTA)
 	  && (fix->fx_pcrel
 	      || (fix->fx_subsy != NULL
 		  && (S_GET_SEGMENT (fix->fx_subsy)
@@ -5632,6 +5711,48 @@ md_apply_fix3 (fixP, valP, seg)
 	    else
 	      bfd_putl16 ((bfd_vma) val, where);
 	  }
+	  break;
+
+	case BFD_RELOC_PPC_TLS:
+	case BFD_RELOC_PPC_DTPMOD:
+	case BFD_RELOC_PPC_TPREL16:
+	case BFD_RELOC_PPC_TPREL16_LO:
+	case BFD_RELOC_PPC_TPREL16_HI:
+	case BFD_RELOC_PPC_TPREL16_HA:
+	case BFD_RELOC_PPC_TPREL:
+	case BFD_RELOC_PPC_DTPREL16:
+	case BFD_RELOC_PPC_DTPREL16_LO:
+	case BFD_RELOC_PPC_DTPREL16_HI:
+	case BFD_RELOC_PPC_DTPREL16_HA:
+	case BFD_RELOC_PPC_DTPREL:
+	case BFD_RELOC_PPC_GOT_TLSGD16:
+	case BFD_RELOC_PPC_GOT_TLSGD16_LO:
+	case BFD_RELOC_PPC_GOT_TLSGD16_HI:
+	case BFD_RELOC_PPC_GOT_TLSGD16_HA:
+	case BFD_RELOC_PPC_GOT_TLSLD16:
+	case BFD_RELOC_PPC_GOT_TLSLD16_LO:
+	case BFD_RELOC_PPC_GOT_TLSLD16_HI:
+	case BFD_RELOC_PPC_GOT_TLSLD16_HA:
+	case BFD_RELOC_PPC_GOT_TPREL16:
+	case BFD_RELOC_PPC_GOT_TPREL16_LO:
+	case BFD_RELOC_PPC_GOT_TPREL16_HI:
+	case BFD_RELOC_PPC_GOT_TPREL16_HA:
+	case BFD_RELOC_PPC_GOT_DTPREL16:
+	case BFD_RELOC_PPC_GOT_DTPREL16_LO:
+	case BFD_RELOC_PPC_GOT_DTPREL16_HI:
+	case BFD_RELOC_PPC_GOT_DTPREL16_HA:
+	case BFD_RELOC_PPC64_TPREL16_DS:
+	case BFD_RELOC_PPC64_TPREL16_LO_DS:
+	case BFD_RELOC_PPC64_TPREL16_HIGHER:
+	case BFD_RELOC_PPC64_TPREL16_HIGHERA:
+	case BFD_RELOC_PPC64_TPREL16_HIGHEST:
+	case BFD_RELOC_PPC64_TPREL16_HIGHESTA:
+	case BFD_RELOC_PPC64_DTPREL16_DS:
+	case BFD_RELOC_PPC64_DTPREL16_LO_DS:
+	case BFD_RELOC_PPC64_DTPREL16_HIGHER:
+	case BFD_RELOC_PPC64_DTPREL16_HIGHERA:
+	case BFD_RELOC_PPC64_DTPREL16_HIGHEST:
+	case BFD_RELOC_PPC64_DTPREL16_HIGHESTA:
 	  break;
 #endif
 	  /* Because SDA21 modifies the register field, the size is set to 4
Index: ld/emultempl/ppc64elf.em
===================================================================
RCS file: /cvs/src/src/ld/emultempl/ppc64elf.em,v
retrieving revision 1.11
diff -u -p -d -r1.11 ppc64elf.em
--- ld/emultempl/ppc64elf.em	30 Nov 2002 08:39:46 -0000	1.11
+++ ld/emultempl/ppc64elf.em	4 Feb 2003 14:02:37 -0000
@@ -1,5 +1,5 @@
 # This shell script emits a C file. -*- C -*-
-#   Copyright 2002 Free Software Foundation, Inc.
+#   Copyright 2002, 2003 Free Software Foundation, Inc.
 #
 # This file is part of GLD, the Gnu Linker.
 #
@@ -101,7 +101,20 @@ ppc_before_allocation ()
       return;
     }
 
+  /* Size the sections.  This is premature, but we want to know the
+     TLS segment layout so that certain optimizations can be done.  */
+  lang_size_sections (stat_ptr->head, abs_output_section,
+		      &stat_ptr->head, 0, (bfd_vma) 0, NULL);
+
+  if (!ppc64_elf_tls_optimize (output_bfd, &link_info))
+    {
+      einfo ("%X%P: TLS problem %E\n");
+      return;
+    }
+
   gld${EMULATION_NAME}_before_allocation ();
+
+  lang_reset_memory_regions ();
 }
 
 struct hook_stub_info
Index: ld/testsuite/ld-powerpc/powerpc.exp
===================================================================
RCS file: /cvs/src/src/ld/testsuite/ld-powerpc/powerpc.exp,v
retrieving revision 1.4
diff -u -p -d -r1.4 powerpc.exp
--- ld/testsuite/ld-powerpc/powerpc.exp	3 Dec 2002 18:24:33 -0000	1.4
+++ ld/testsuite/ld-powerpc/powerpc.exp	4 Feb 2003 14:02:37 -0000
@@ -1,5 +1,5 @@
 # Expect script for ld-powerpc tests
-#   Copyright (C) 2002 Free Software Foundation
+#   Copyright 2002, 2003 Free Software Foundation
 #
 # This file is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -20,15 +20,26 @@ if { ![istarget "powerpc*-*-*"]	} {
     return
 }
 
-# powerpc 32 bit ELF only at the moment.
+# powerpc ELF only at the moment.
 
 if { [istarget "*-*-macos*"] || [istarget "*-*-netware*"]
      || [istarget "*-*-pe"] || [istarget "*-*-winnt*"]
      || [istarget "*-*-cygwin*"] || [istarget "*-*-aix*"]
-     || [istarget "*-*-beos*"] || [istarget "powerpc64*-*-*"] } {
+     || [istarget "*-*-beos*"] } {
     return
 }
 
+proc supports_ppc64 { } {
+    global ld
+
+    catch "exec $ld --help | grep emulations" tmp
+    if [ string match "*elf64ppc*" $tmp ] then {
+	return 1
+    } else {
+	return 0
+    }
+}
+
 # List contains test-items with 3 items followed by 2 lists:
 # 0:name 1:ld options 2:assembler options
 # 3:filenames of assembler files 4: action and options. 5: name of output file
@@ -39,10 +50,45 @@ if { [istarget "*-*-macos*"] || [istarge
 # readelf: Apply readelf options on result.  Compare with regex (last arg).
 
 set ppcelftests {
-    {"Reloc section order" "-shared -z nocombreloc" "" {reloc.s}
+    {"Reloc section order" "-melf32ppc -shared -z nocombreloc" "-a32" {reloc.s}
      {{objdump -hw reloc.d}} "reloc.so"}
-    {"APUinfo section processing" "" "-me500" {apuinfo1.s apuinfo2.s}
+    {"APUinfo section processing" "-melf32ppc"
+     "-a32 -me500" {apuinfo1.s apuinfo2.s}
    {{readelf -x5 apuinfo.rd}} "apuinfo"}
 }
 
+set ppc64elftests {
+    {"TLS static exec" "-melf64ppc" "-a64"  {tls.s tlslib.s}
+     {{objdump -dr tls.d} {objdump -sj.got tls.g} {objdump -sj.tdata tls.t}}
+      "tls"}
+    {"TLS helper shared library" "-shared -melf64ppc tmpdir/tlslib.o" "" {}
+     {} "libtlslib.so"}
+    {"TLS dynamic exec" "-melf64ppc tmpdir/tls.o tmpdir/libtlslib.so" "" {}
+     {{readelf -WSsrl tlsexe.r} {objdump -dr tlsexe.d}
+      {objdump -sj.got tlsexe.g} {objdump -sj.tdata tlsexe.t}}
+      "tlsexe"}
+    {"TLS shared" "-shared -melf64ppc tmpdir/tls.o" "" {}
+     {{readelf -WSsrl tlsso.r} {objdump -dr tlsso.d}
+      {objdump -sj.got tlsso.g} {objdump -sj.tdata tlsso.t}}
+      "tls.so"}
+    {"TLSTOC static exec" "-melf64ppc tmpdir/tlslib.o " "-a64"  {tlstoc.s}
+     {{objdump -dr tlstoc.d} {objdump -sj.toc tlstoc.g}
+      {objdump -sj.tdata tlstoc.t}}
+      "tlstoc"}
+    {"TLSTOC dynamic exec" "-melf64ppc tmpdir/tlstoc.o tmpdir/libtlslib.so"
+     "" {}
+     {{readelf -WSsrl tlsexetoc.r} {objdump -dr tlsexetoc.d}
+      {objdump -sj.toc tlsexetoc.g} {objdump -sj.tdata tlsexetoc.t}}
+      "tlsexetoc"}
+    {"TLSTOC shared" "-shared -melf64ppc tmpdir/tlstoc.o" "" {}
+     {{readelf -WSsrl tlstocso.r} {objdump -dr tlstocso.d}
+      {objdump -sj.toc tlstocso.g} {objdump -sj.tdata tlstocso.t}}
+      "tlstoc.so"}
+}
+
+
 run_ld_link_tests $ppcelftests
+
+if [ supports_ppc64 ] then {
+    run_ld_link_tests $ppc64elftests
+}
Index: ld/testsuite/ld-powerpc/tls.d
===================================================================
RCS file: ld/testsuite/ld-powerpc/tls.d
diff -N ld/testsuite/ld-powerpc/tls.d
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ ld/testsuite/ld-powerpc/tls.d	4 Feb 2003 14:12:04 -0000
@@ -0,0 +1,53 @@
+#source: tls.s
+#source: tlslib.s
+#as: -a64
+#ld: -melf64ppc
+#objdump: -dr
+#target: powerpc64*-*-*
+
+.*: +file format elf64-powerpc
+
+Disassembly of section \.text:
+
+0+100000e8 <_start>:
+    100000e8:	3c 6d 00 00 	addis	r3,r13,0
+    100000ec:	60 00 00 00 	nop
+    100000f0:	38 63 90 78 	addi	r3,r3,-28552
+    100000f4:	3c 6d 00 00 	addis	r3,r13,0
+    100000f8:	60 00 00 00 	nop
+    100000fc:	38 63 10 00 	addi	r3,r3,4096
+    10000100:	3c 6d 00 00 	addis	r3,r13,0
+    10000104:	60 00 00 00 	nop
+    10000108:	38 63 90 40 	addi	r3,r3,-28608
+    1000010c:	3c 6d 00 00 	addis	r3,r13,0
+    10000110:	60 00 00 00 	nop
+    10000114:	38 63 10 00 	addi	r3,r3,4096
+    10000118:	39 23 80 48 	addi	r9,r3,-32696
+    1000011c:	3d 23 00 00 	addis	r9,r3,0
+    10000120:	81 49 80 50 	lwz	r10,-32688\(r9\)
+    10000124:	e9 22 80 10 	ld	r9,-32752\(r2\)
+    10000128:	7d 49 18 2a 	ldx	r10,r9,r3
+    1000012c:	3d 2d 00 00 	addis	r9,r13,0
+    10000130:	a1 49 90 60 	lhz	r10,-28576\(r9\)
+    10000134:	89 4d 90 68 	lbz	r10,-28568\(r13\)
+    10000138:	3d 2d 00 00 	addis	r9,r13,0
+    1000013c:	99 49 90 70 	stb	r10,-28560\(r9\)
+    10000140:	3c 6d 00 00 	addis	r3,r13,0
+    10000144:	60 00 00 00 	nop
+    10000148:	38 63 90 00 	addi	r3,r3,-28672
+    1000014c:	3c 6d 00 00 	addis	r3,r13,0
+    10000150:	60 00 00 00 	nop
+    10000154:	38 63 10 00 	addi	r3,r3,4096
+    10000158:	f9 43 80 08 	std	r10,-32760\(r3\)
+    1000015c:	3d 23 00 00 	addis	r9,r3,0
+    10000160:	91 49 80 10 	stw	r10,-32752\(r9\)
+    10000164:	e9 22 80 08 	ld	r9,-32760\(r2\)
+    10000168:	7d 49 19 2a 	stdx	r10,r9,r3
+    1000016c:	3d 2d 00 00 	addis	r9,r13,0
+    10000170:	b1 49 90 60 	sth	r10,-28576\(r9\)
+    10000174:	e9 4d 90 2a 	lwa	r10,-28632\(r13\)
+    10000178:	3d 2d 00 00 	addis	r9,r13,0
+    1000017c:	a9 49 90 30 	lha	r10,-28624\(r9\)
+
+0+10000180 <\.__tls_get_addr>:
+    10000180:	4e 80 00 20 	blr
Index: ld/testsuite/ld-powerpc/tls.g
===================================================================
RCS file: ld/testsuite/ld-powerpc/tls.g
diff -N ld/testsuite/ld-powerpc/tls.g
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ ld/testsuite/ld-powerpc/tls.g	4 Feb 2003 14:12:04 -0000
@@ -0,0 +1,12 @@
+#source: tls.s
+#source: tlslib.s
+#as: -a64
+#ld: -melf64ppc
+#objdump: -sj.got
+#target: powerpc64*-*-*
+
+.*: +file format elf64-powerpc
+
+Contents of section \.got:
+ 100101e0 00000000 100181e0 ffffffff ffff8018  .*
+ 100101f0 ffffffff ffff8058                    .*
Index: ld/testsuite/ld-powerpc/tls.s
===================================================================
RCS file: ld/testsuite/ld-powerpc/tls.s
diff -N ld/testsuite/ld-powerpc/tls.s
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ ld/testsuite/ld-powerpc/tls.s	4 Feb 2003 14:12:04 -0000
@@ -0,0 +1,92 @@
+	.section ".tbss","awT",@nobits
+	.global _start,gd0,ld0,ld1,ld2,ie0,le0,le1
+	.align 3
+gd0:	.space 8
+ld0:	.space 8
+ld1:	.space 8
+ld2:	.space 8
+ie0:	.space 8
+le0:	.space 8
+le1:	.space 8
+
+	.section ".tdata","awT",@progbits
+	.align 3
+gd4:	.quad 0x123456789abcdef0
+ld4:	.quad 0x23456789abcdef01
+ld5:	.quad 0x3456789abcdef012
+ld6:	.quad 0x456789abcdef0123
+ie4:	.quad 0x56789abcdef01234
+le4:	.quad 0x6789abcdef012345
+le5:	.quad 0x789abcdef0123456
+
+	.text
+_start:
+#extern syms
+#GD
+ addi 3,2,gd@got@tlsgd		#R_PPC64_GOT_TLSGD16	gd
+ bl .__tls_get_addr		#R_PPC64_REL24		.__tls_get_addr
+ nop
+
+#LD
+ addi 3,2,ld@got@tlsld		#R_PPC64_GOT_TLSLD16	ld
+ bl .__tls_get_addr		#R_PPC64_REL24		.__tls_get_addr
+ nop
+
+#global syms
+#GD
+ addi 3,2,gd0@got@tlsgd		#R_PPC64_GOT_TLSGD16	gd0
+ bl .__tls_get_addr		#R_PPC64_REL24		.__tls_get_addr
+ nop
+
+#LD
+ addi 3,2,ld0@got@tlsld		#R_PPC64_GOT_TLSLD16	ld0
+ bl .__tls_get_addr		#R_PPC64_REL24		.__tls_get_addr
+ nop
+
+ addi 9,3,ld0@dtprel		#R_PPC64_DTPREL16	ld0
+
+ addis 9,3,ld1@dtprel@ha	#R_PPC64_DTPREL16_HA	ld1
+ lwz 10,ld1@dtprel@l(9)		#R_PPC64_DTPREL16_LO	ld1
+
+ ld 9,ld2@got@dtprel(2)		#R_PPC64_GOT_DTPREL16_DS ld2
+ ldx 10,9,3
+
+#IE
+ ld 9,ie0@got@tprel(2)		#R_PPC64_GOT_TPREL16_DS	ie0
+ lhzx 10,9,ie0@tls		#R_PPC64_TLS		ie0
+
+#LE
+ lbz 10,le0@tprel(13)		#R_PPC64_TPREL16	le0
+
+ addis 9,13,le1@tprel@ha	#R_PPC64_TPREL16_HA	le1
+ stb 10,le1@tprel@l(9)		#R_PPC64_TPREL16_LO	le1
+
+#local syms
+#GD
+ addi 3,2,gd4@got@tlsgd		#R_PPC64_GOT_TLSGD16	gd4
+ bl .__tls_get_addr		#R_PPC64_REL24		.__tls_get_addr
+ nop
+
+#LD
+ addi 3,2,ld4@got@tlsld		#R_PPC64_GOT_TLSLD16	ld4
+ bl .__tls_get_addr		#R_PPC64_REL24		.__tls_get_addr
+ nop
+
+ std 10,ld4@dtprel(3)		#R_PPC64_DTPREL16_DS	ld4
+
+ addis 9,3,ld5@dtprel@ha	#R_PPC64_DTPREL16_HA	ld5
+ stw 10,ld5@dtprel@l(9)		#R_PPC64_DTPREL16_LO	ld5
+
+ ld 9,ld6@got@dtprel(2)		#R_PPC64_GOT_DTPREL16_DS ld6
+ stdx 10,9,3
+
+#IE
+ ld 9,ie0@got@tprel(2)		#R_PPC64_GOT_TPREL16_DS	ie4
+ sthx 10,9,ie0@tls		#R_PPC64_TLS		ie4
+
+#LE
+ lwa 10,le4@tprel(13)		#R_PPC64_TPREL16	le4
+
+ addis 9,13,le5@tprel@ha	#R_PPC64_TPREL16_HA	le5
+ lha 10,le5@tprel@l(9)		#R_PPC64_TPREL16_LO	le5
+
Index: ld/testsuite/ld-powerpc/tls.t
===================================================================
RCS file: ld/testsuite/ld-powerpc/tls.t
diff -N ld/testsuite/ld-powerpc/tls.t
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ ld/testsuite/ld-powerpc/tls.t	4 Feb 2003 14:12:04 -0000
@@ -0,0 +1,14 @@
+#source: tls.s
+#source: tlslib.s
+#as: -a64
+#ld: -melf64ppc
+#objdump: -sj.tdata
+#target: powerpc64*-*-*
+
+.*: +file format elf64-powerpc
+
+Contents of section \.tdata:
+ 10010188 12345678 9abcdef0 23456789 abcdef01  .*
+ 10010198 3456789a bcdef012 456789ab cdef0123  .*
+ 100101a8 56789abc def01234 6789abcd ef012345  .*
+ 100101b8 789abcde f0123456 00c0ffee           .*
Index: ld/testsuite/ld-powerpc/tlsexe.d
===================================================================
RCS file: ld/testsuite/ld-powerpc/tlsexe.d
diff -N ld/testsuite/ld-powerpc/tlsexe.d
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ ld/testsuite/ld-powerpc/tlsexe.d	4 Feb 2003 14:12:04 -0000
@@ -0,0 +1,49 @@
+#source: tls.s
+#as: -a64
+#ld: -melf64ppc tmpdir/libtlslib.so
+#objdump: -dr
+#target: powerpc64*-*-*
+
+.*: +file format elf64-powerpc
+
+Disassembly of section \.text:
+
+0+10000378 <_start>:
+    10000378:	e8 62 80 10 	ld	r3,-32752\(r2\)
+    1000037c:	60 00 00 00 	nop
+    10000380:	7c 63 6a 14 	add	r3,r3,r13
+    10000384:	e8 62 80 18 	ld	r3,-32744\(r2\)
+    10000388:	60 00 00 00 	nop
+    1000038c:	7c 63 6a 14 	add	r3,r3,r13
+    10000390:	3c 6d 00 00 	addis	r3,r13,0
+    10000394:	60 00 00 00 	nop
+    10000398:	38 63 90 38 	addi	r3,r3,-28616
+    1000039c:	3c 6d 00 00 	addis	r3,r13,0
+    100003a0:	60 00 00 00 	nop
+    100003a4:	38 63 10 00 	addi	r3,r3,4096
+    100003a8:	39 23 80 40 	addi	r9,r3,-32704
+    100003ac:	3d 23 00 00 	addis	r9,r3,0
+    100003b0:	81 49 80 48 	lwz	r10,-32696\(r9\)
+    100003b4:	e9 22 80 20 	ld	r9,-32736\(r2\)
+    100003b8:	7d 49 18 2a 	ldx	r10,r9,r3
+    100003bc:	3d 2d 00 00 	addis	r9,r13,0
+    100003c0:	a1 49 90 58 	lhz	r10,-28584\(r9\)
+    100003c4:	89 4d 90 60 	lbz	r10,-28576\(r13\)
+    100003c8:	3d 2d 00 00 	addis	r9,r13,0
+    100003cc:	99 49 90 68 	stb	r10,-28568\(r9\)
+    100003d0:	3c 6d 00 00 	addis	r3,r13,0
+    100003d4:	60 00 00 00 	nop
+    100003d8:	38 63 90 00 	addi	r3,r3,-28672
+    100003dc:	3c 6d 00 00 	addis	r3,r13,0
+    100003e0:	60 00 00 00 	nop
+    100003e4:	38 63 10 00 	addi	r3,r3,4096
+    100003e8:	f9 43 80 08 	std	r10,-32760\(r3\)
+    100003ec:	3d 23 00 00 	addis	r9,r3,0
+    100003f0:	91 49 80 10 	stw	r10,-32752\(r9\)
+    100003f4:	e9 22 80 08 	ld	r9,-32760\(r2\)
+    100003f8:	7d 49 19 2a 	stdx	r10,r9,r3
+    100003fc:	3d 2d 00 00 	addis	r9,r13,0
+    10000400:	b1 49 90 58 	sth	r10,-28584\(r9\)
+    10000404:	e9 4d 90 2a 	lwa	r10,-28632\(r13\)
+    10000408:	3d 2d 00 00 	addis	r9,r13,0
+    1000040c:	a9 49 90 30 	lha	r10,-28624\(r9\)
Index: ld/testsuite/ld-powerpc/tlsexe.g
===================================================================
RCS file: ld/testsuite/ld-powerpc/tlsexe.g
diff -N ld/testsuite/ld-powerpc/tlsexe.g
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ ld/testsuite/ld-powerpc/tlsexe.g	4 Feb 2003 14:12:04 -0000
@@ -0,0 +1,12 @@
+#source: tls.s
+#as: -a64
+#ld: -melf64ppc tmpdir/libtlslib.so
+#objdump: -sj.got
+#target: powerpc64*-*-*
+
+.*: +file format elf64-powerpc
+
+Contents of section \.got:
+ 10010548 00000000 10018548 ffffffff ffff8018  .*
+ 10010558 00000000 00000000 00000000 00000000  .*
+ 10010568 00000000 00000000                    .*
Index: ld/testsuite/ld-powerpc/tlsexe.r
===================================================================
RCS file: ld/testsuite/ld-powerpc/tlsexe.r
diff -N ld/testsuite/ld-powerpc/tlsexe.r
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ ld/testsuite/ld-powerpc/tlsexe.r	4 Feb 2003 14:12:04 -0000
@@ -0,0 +1,120 @@
+#source: tls.s
+#source: tlslib.s
+#as: -a64
+#ld: -shared -melf64ppc
+#readelf: -WSsrl
+#target: powerpc64*-*-*
+
+There are 20 section headers.*
+
+Section Headers:
+ +\[Nr\] Name +Type +Address +Off +Size +ES Flg Lk Inf Al
+ +\[ 0\] +NULL +0+ 0+ 0+ 0+ +0 +0 +0
+ +\[ 1\] \.interp +PROGBITS +0+10000190 0+190 0+11 0+ +A +0 +0 +1
+ +\[ 2\] \.hash +HASH +0+100001a8 0+1a8 0+3c 04 +A +3 +0 +8
+ +\[ 3\] \.dynsym +DYNSYM +0+100001e8 0+1e8 0+f0 18 +A +4 +1 +8
+ +\[ 4\] \.dynstr +STRTAB +0+100002d8 0+2d8 0+51 0+ +A +0 +0 +1
+ +\[ 5\] \.rela\.dyn +RELA +0+10000330 0+330 0+48 18 +A +3 +0 +8
+ +\[ 6\] \.text +PROGBITS +0+10000378 0+378 0+98 0+ +AX +0 +0 +4
+ +\[ 7\] \.data +PROGBITS +0+10010410 0+410 0+ 0+ +WA +0 +0 +1
+ +\[ 8\] \.branch_lt +PROGBITS +0+10010410 0+410 0+ 0+ +WA +0 +0 +8
+ +\[ 9\] \.tdata +PROGBITS +0+10010410 0+410 0+38 0+ WAT +0 +0 +8
+ +\[10\] \.tbss +NOBITS +0+10010448 0+448 0+38 0+ WAT +0 +0 +8
+ +\[11\] \.dynamic +DYNAMIC +0+10010448 0+448 0+100 10 +WA +4 +0 +8
+ +\[12\] \.ctors +PROGBITS +0+10010548 0+570 0+ 0+ +W +0 +0 +1
+ +\[13\] \.dtors +PROGBITS +0+10010548 0+570 0+ 0+ +W +0 +0 +1
+ +\[14\] \.got +PROGBITS +0+10010548 0+548 0+28 08 +WA +0 +0 +8
+ +\[15\] \.sbss +PROGBITS +0+10010570 0+570 0+ 0+ +W +0 +0 +1
+ +\[16\] \.bss +NOBITS +0+10010570 0+570 0+ 0+ +WA +0 +0 +1
+ +\[17\] \.shstrtab +STRTAB +0+ 0+570 0+8e 0+ +0 +0 +1
+ +\[18\] \.symtab +SYMTAB +0+ 0+b00 0+408 18 +19 +1b +8
+ +\[19\] \.strtab +STRTAB +0+ 0+f08 0+7d 0+ +0 +0 +1
+#...
+
+Elf file type is EXEC \(Executable file\)
+Entry point 0x10000378
+There are 6 program headers.*
+
+Program Headers:
+ +Type +Offset +VirtAddr +PhysAddr +FileSiz +MemSiz +Flg Align
+ +PHDR +0x0+40 0x0+10000040 0x0+10000040 0x0+150 0x0+150 R E 0x8
+ +INTERP +0x0+190 0x0+10000190 0x0+10000190 0x0+11 0x0+11 R +0x1
+ +\[Requesting program interpreter: .*\]
+ +LOAD +0x0+ 0x0+10000000 0x0+10000000 0x0+410 0x0+410 R E 0x10000
+ +LOAD +0x0+410 0x0+10010410 0x0+10010410 0x0+160 0x0+160 RW +0x10000
+ +DYNAMIC +0x0+448 0x0+10010448 0x0+10010448 0x0+100 0x0+100 RW +0x8
+ +TLS +0x0+410 0x0+10010410 0x0+10010410 0x0+38 0x0+70 R +0x8
+
+ Section to Segment mapping:
+ +Segment Sections\.\.\.
+ +00 +
+ +01 +\.interp 
+ +02 +\.interp \.hash \.dynsym \.dynstr \.rela\.dyn \.text 
+ +03 +\.tdata \.tbss \.dynamic \.got 
+ +04 +\.tbss \.dynamic 
+ +05 +\.tdata \.tbss 
+
+Relocation section '\.rela\.dyn' at offset .* contains 3 entries:
+ +Offset +Info +Type +Symbol's Value +Symbol's Name \+ Addend
+0+10010558 +0+200000049 R_PPC64_TPREL64 +0+ gd \+ 0
+0+10010560 +0+400000049 R_PPC64_TPREL64 +0+ ld \+ 0
+0+10010568 +0+60000004e R_PPC64_DTPREL64 +0+50 ld2 \+ 0
+
+Symbol table '\.dynsym' contains 10 entries:
+ +Num: +Value +Size Type +Bind +Vis +Ndx Name
+ +0: 0+ +0 NOTYPE +LOCAL +DEFAULT +UND 
+ +1: 0+10010448 +0 OBJECT +GLOBAL DEFAULT +ABS _DYNAMIC
+ +2: 0+ +0 TLS +GLOBAL DEFAULT +UND gd
+ +3: 0+ +0 NOTYPE +GLOBAL DEFAULT +UND \.__tls_get_addr
+ +4: 0+ +0 TLS +GLOBAL DEFAULT +UND ld
+ +5: 0+10010570 +0 NOTYPE +GLOBAL DEFAULT +ABS __end
+ +6: 0+50 +0 TLS +GLOBAL DEFAULT +10 ld2
+ +7: 0+10010570 +0 NOTYPE +GLOBAL DEFAULT +ABS __bss_start
+ +8: 0+10010570 +0 NOTYPE +GLOBAL DEFAULT +ABS _edata
+ +9: 0+10010570 +0 NOTYPE +GLOBAL DEFAULT +ABS _end
+
+Symbol table '\.symtab' contains 43 entries:
+ +Num: +Value +Size Type +Bind +Vis +Ndx Name
+ +0: 0+ +0 NOTYPE +LOCAL +DEFAULT +UND 
+ +1: 0+10000190 +0 SECTION LOCAL +DEFAULT +1 
+ +2: 0+100001a8 +0 SECTION LOCAL +DEFAULT +2 
+ +3: 0+100001e8 +0 SECTION LOCAL +DEFAULT +3 
+ +4: 0+100002d8 +0 SECTION LOCAL +DEFAULT +4 
+ +5: 0+10000330 +0 SECTION LOCAL +DEFAULT +5 
+ +6: 0+10000378 +0 SECTION LOCAL +DEFAULT +6 
+ +7: 0+10010410 +0 SECTION LOCAL +DEFAULT +7 
+ +8: 0+10010410 +0 SECTION LOCAL +DEFAULT +8 
+ +9: 0+10010410 +0 SECTION LOCAL +DEFAULT +9 
+ +10: 0+10010448 +0 SECTION LOCAL +DEFAULT +10 
+ +11: 0+10010448 +0 SECTION LOCAL +DEFAULT +11 
+ +12: 0+10010548 +0 SECTION LOCAL +DEFAULT +12 
+ +13: 0+10010548 +0 SECTION LOCAL +DEFAULT +13 
+ +14: 0+10010548 +0 SECTION LOCAL +DEFAULT +14 
+ +15: 0+10010570 +0 SECTION LOCAL +DEFAULT +15 
+ +16: 0+10010570 +0 SECTION LOCAL +DEFAULT +16 
+ +17: 0+ +0 SECTION LOCAL +DEFAULT +17 
+ +18: 0+ +0 SECTION LOCAL +DEFAULT +18 
+ +19: 0+ +0 SECTION LOCAL +DEFAULT +19 
+ +20: 0+ +0 TLS +LOCAL +DEFAULT +9 gd4
+ +21: 0+8 +0 TLS +LOCAL +DEFAULT +9 ld4
+ +22: 0+10 +0 TLS +LOCAL +DEFAULT +9 ld5
+ +23: 0+18 +0 TLS +LOCAL +DEFAULT +9 ld6
+ +24: 0+20 +0 TLS +LOCAL +DEFAULT +9 ie4
+ +25: 0+28 +0 TLS +LOCAL +DEFAULT +9 le4
+ +26: 0+30 +0 TLS +LOCAL +DEFAULT +9 le5
+ +27: 0+10010448 +0 OBJECT +GLOBAL DEFAULT +ABS _DYNAMIC
+ +28: 0+ +0 TLS +GLOBAL DEFAULT +UND gd
+ +29: 0+60 +0 TLS +GLOBAL DEFAULT +10 le0
+ +30: 0+ +0 NOTYPE +GLOBAL DEFAULT +UND \.__tls_get_addr
+ +31: 0+40 +0 TLS +GLOBAL DEFAULT +10 ld0
+ +32: 0+68 +0 TLS +GLOBAL DEFAULT +10 le1
+ +33: 0+ +0 TLS +GLOBAL DEFAULT +UND ld
+ +34: 0+10000378 +0 NOTYPE +GLOBAL DEFAULT +6 _start
+ +35: 0+10010570 +0 NOTYPE +GLOBAL DEFAULT +ABS __end
+ +36: 0+50 +0 TLS +GLOBAL DEFAULT +10 ld2
+ +37: 0+48 +0 TLS +GLOBAL DEFAULT +10 ld1
+ +38: 0+10010570 +0 NOTYPE +GLOBAL DEFAULT +ABS __bss_start
+ +39: 0+10010570 +0 NOTYPE +GLOBAL DEFAULT +ABS _edata
+ +40: 0+10010570 +0 NOTYPE +GLOBAL DEFAULT +ABS _end
+ +41: 0+38 +0 TLS +GLOBAL DEFAULT +10 gd0
+ +42: 0+58 +0 TLS +GLOBAL DEFAULT +10 ie0
Index: ld/testsuite/ld-powerpc/tlsexe.t
===================================================================
RCS file: ld/testsuite/ld-powerpc/tlsexe.t
diff -N ld/testsuite/ld-powerpc/tlsexe.t
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ ld/testsuite/ld-powerpc/tlsexe.t	4 Feb 2003 14:12:04 -0000
@@ -0,0 +1,13 @@
+#source: tls.s
+#as: -a64
+#ld: -melf64ppc tmpdir/libtlslib.so
+#objdump: -sj.tdata
+#target: powerpc64*-*-*
+
+.*: +file format elf64-powerpc
+
+Contents of section \.tdata:
+ 10010410 12345678 9abcdef0 23456789 abcdef01  .*
+ 10010420 3456789a bcdef012 456789ab cdef0123  .*
+ 10010430 56789abc def01234 6789abcd ef012345  .*
+ 10010440 789abcde f0123456                    .*
Index: ld/testsuite/ld-powerpc/tlsexetoc.d
===================================================================
RCS file: ld/testsuite/ld-powerpc/tlsexetoc.d
diff -N ld/testsuite/ld-powerpc/tlsexetoc.d
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ ld/testsuite/ld-powerpc/tlsexetoc.d	4 Feb 2003 14:12:04 -0000
@@ -0,0 +1,33 @@
+#source: tlstoc.s
+#as: -a64
+#ld: -melf64ppc tmpdir/libtlslib.so
+#objdump: -dr
+#target: powerpc64*-*-*
+
+.*: +file format elf64-powerpc
+
+Disassembly of section \.text:
+
+0+10000338 <_start>:
+    10000338:	e8 62 80 08 	ld	r3,-32760\(r2\)
+    1000033c:	60 00 00 00 	nop
+    10000340:	7c 63 6a 14 	add	r3,r3,r13
+    10000344:	e8 62 80 18 	ld	r3,-32744\(r2\)
+    10000348:	60 00 00 00 	nop
+    1000034c:	7c 63 6a 14 	add	r3,r3,r13
+    10000350:	3c 6d 00 00 	addis	r3,r13,0
+    10000354:	60 00 00 00 	nop
+    10000358:	38 63 91 40 	addi	r3,r3,-28352
+    1000035c:	3c 6d 00 00 	addis	r3,r13,0
+    10000360:	60 00 00 00 	nop
+    10000364:	38 63 10 00 	addi	r3,r3,4096
+    10000368:	39 23 80 40 	addi	r9,r3,-32704
+    1000036c:	3d 23 00 00 	addis	r9,r3,0
+    10000370:	81 49 80 48 	lwz	r10,-32696\(r9\)
+    10000374:	3d 2d 00 00 	addis	r9,r13,0
+    10000378:	7d 49 18 2a 	ldx	r10,r9,r3
+    1000037c:	3d 2d 00 00 	addis	r9,r13,0
+    10000380:	a1 49 91 88 	lhz	r10,-28280\(r9\)
+    10000384:	89 4d 90 60 	lbz	r10,-28576\(r13\)
+    10000388:	3d 2d 00 00 	addis	r9,r13,0
+    1000038c:	99 49 90 68 	stb	r10,-28568\(r9\)
Index: ld/testsuite/ld-powerpc/tlsexetoc.g
===================================================================
RCS file: ld/testsuite/ld-powerpc/tlsexetoc.g
diff -N ld/testsuite/ld-powerpc/tlsexetoc.g
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ ld/testsuite/ld-powerpc/tlsexetoc.g	4 Feb 2003 14:12:04 -0000
@@ -0,0 +1,14 @@
+#source: tlstoc.s
+#as: -a64
+#ld: -melf64ppc tmpdir/libtlslib.so
+#objdump: -sj.toc
+#target: powerpc64*-*-*
+
+.*: +file format elf64-powerpc
+
+Contents of section \.toc:
+ 100104d0 00000000 00000000 00000000 00000000  .*
+ 100104e0 00000000 00000000 00000000 00000000  .*
+ 100104f0 00000000 00000001 00000000 00000000  .*
+ 10010500 00000000 00000001 00000000 00000000  .*
+ 10010510 ffffffff ffff8050 00000000 00000000  .*
Index: ld/testsuite/ld-powerpc/tlsexetoc.r
===================================================================
RCS file: ld/testsuite/ld-powerpc/tlsexetoc.r
diff -N ld/testsuite/ld-powerpc/tlsexetoc.r
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ ld/testsuite/ld-powerpc/tlsexetoc.r	4 Feb 2003 14:12:04 -0000
@@ -0,0 +1,121 @@
+#source: tlslib.s
+#source: tlstoc.s
+#as: -a64
+#ld: -shared -melf64ppc
+#readelf: -WSsrl
+#target: powerpc64*-*-*
+
+There are 21 section headers.*
+
+Section Headers:
+ +\[Nr\] Name +Type +Address +Off +Size +ES Flg Lk Inf Al
+ +\[ 0\] +NULL +0+ 0+ 0+ 0+ +0 +0 +0
+ +\[ 1\] .interp +PROGBITS +0+10000190 0+190 0+11 0+ +A +0 +0 +1
+ +\[ 2\] .hash +HASH +0+100001a8 0+1a8 0+38 04 +A +3 +0 +8
+ +\[ 3\] .dynsym +DYNSYM +0+100001e0 0+1e0 0+d8 18 +A +4 +1 +8
+ +\[ 4\] .dynstr +STRTAB +0+100002b8 0+2b8 0+4d 0+ +A +0 +0 +1
+ +\[ 5\] .rela.dyn +RELA +0+10000308 0+308 0+30 18 +A +3 +0 +8
+ +\[ 6\] .text +PROGBITS +0+10000338 0+338 0+58 0+ +AX +0 +0 +4
+ +\[ 7\] .data +PROGBITS +0+10010390 0+390 0+ 0+ +WA +0 +0 +1
+ +\[ 8\] .branch_lt +PROGBITS +0+10010390 0+390 0+ 0+ +WA +0 +0 +8
+ +\[ 9\] .tdata +PROGBITS +0+10010390 0+390 0+38 0+ WAT +0 +0 +8
+ +\[10\] .tbss +NOBITS +0+100103c8 0+3c8 0+38 0+ WAT +0 +0 +8
+ +\[11\] .dynamic +DYNAMIC +0+100103c8 0+3c8 0+100 10 +WA +4 +0 +8
+ +\[12\] .ctors +PROGBITS +0+100104c8 0+520 0+ 0+ +W +0 +0 +1
+ +\[13\] .dtors +PROGBITS +0+100104c8 0+520 0+ 0+ +W +0 +0 +1
+ +\[14\] .got +PROGBITS +0+100104c8 0+4c8 0+8 08 +WA +0 +0 +8
+ +\[15\] .toc +PROGBITS +0+100104d0 0+4d0 0+50 0+ +WA +0 +0 +1
+ +\[16\] .sbss +PROGBITS +0+10010520 0+520 0+ 0+ +W +0 +0 +1
+ +\[17\] .bss +NOBITS +0+10010520 0+520 0+ 0+ +WA +0 +0 +1
+ +\[18\] .shstrtab +STRTAB +0+ 0+520 0+93 0+ +0 +0 +1
+ +\[19\] .symtab +SYMTAB +0+ 0+af8 0+438 18 +20 +1d +8
+ +\[20\] .strtab +STRTAB +0+ 0+f30 0+83 0+ +0 +0 +1
+#...
+
+Elf file type is EXEC \(Executable file\)
+Entry point 0x10000338
+There are 6 program headers.*
+
+Program Headers:
+ +Type +Offset +VirtAddr +PhysAddr +FileSiz +MemSiz +Flg Align
+ +PHDR +0x0+40 0x0+10000040 0x0+10000040 0x0+150 0x0+150 R E 0x8
+ +INTERP +0x0+190 0x0+10000190 0x0+10000190 0x0+11 0x0+11 R +0x1
+ +\[Requesting program interpreter: .*\]
+ +LOAD +0x0+ 0x0+10000000 0x0+10000000 0x0+390 0x0+390 R E 0x10000
+ +LOAD +0x0+390 0x0+10010390 0x0+10010390 0x0+190 0x0+190 RW +0x10000
+ +DYNAMIC +0x0+3c8 0x0+100103c8 0x0+100103c8 0x0+100 0x0+100 RW +0x8
+ +TLS +0x0+390 0x0+10010390 0x0+10010390 0x0+38 0x0+70 R +0x8
+
+ Section to Segment mapping:
+ +Segment Sections\.\.\.
+ +00 +
+ +01 +\.interp 
+ +02 +\.interp \.hash \.dynsym \.dynstr \.rela\.dyn \.text 
+ +03 +\.tdata \.tbss \.dynamic \.got \.toc 
+ +04 +\.tbss \.dynamic 
+ +05 +\.tdata \.tbss 
+
+Relocation section '\.rela\.dyn' at offset .* contains 2 entries:
+ +Offset +Info +Type +Symbol's Value +Symbol's Name \+ Addend
+0+100104d0 +0+200000049 R_PPC64_TPREL64 +0+ gd \+ 0
+0+100104e0 +0+400000049 R_PPC64_TPREL64 +0+ ld \+ 0
+
+Symbol table '\.dynsym' contains 9 entries:
+ +Num: +Value +Size Type +Bind +Vis +Ndx Name
+ +0: 0+ +0 NOTYPE +LOCAL +DEFAULT +UND 
+ +1: 0+100103c8 +0 OBJECT +GLOBAL DEFAULT +ABS _DYNAMIC
+ +2: 0+ +0 TLS +GLOBAL DEFAULT +UND gd
+ +3: 0+ +0 NOTYPE +GLOBAL DEFAULT +UND \.__tls_get_addr
+ +4: 0+ +0 TLS +GLOBAL DEFAULT +UND ld
+ +5: 0+10010520 +0 NOTYPE +GLOBAL DEFAULT +ABS __end
+ +6: 0+10010520 +0 NOTYPE +GLOBAL DEFAULT +ABS __bss_start
+ +7: 0+10010520 +0 NOTYPE +GLOBAL DEFAULT +ABS _edata
+ +8: 0+10010520 +0 NOTYPE +GLOBAL DEFAULT +ABS _end
+
+Symbol table '\.symtab' contains 45 entries:
+ +Num: +Value +Size Type +Bind +Vis +Ndx Name
+ +0: 0+ +0 NOTYPE +LOCAL +DEFAULT +UND 
+ +1: 0+10000190 +0 SECTION LOCAL +DEFAULT +1 
+ +2: 0+100001a8 +0 SECTION LOCAL +DEFAULT +2 
+ +3: 0+100001e0 +0 SECTION LOCAL +DEFAULT +3 
+ +4: 0+100002b8 +0 SECTION LOCAL +DEFAULT +4 
+ +5: 0+10000308 +0 SECTION LOCAL +DEFAULT +5 
+ +6: 0+10000338 +0 SECTION LOCAL +DEFAULT +6 
+ +7: 0+10010390 +0 SECTION LOCAL +DEFAULT +7 
+ +8: 0+10010390 +0 SECTION LOCAL +DEFAULT +8 
+ +9: 0+10010390 +0 SECTION LOCAL +DEFAULT +9 
+ +10: 0+100103c8 +0 SECTION LOCAL +DEFAULT +10 
+ +11: 0+100103c8 +0 SECTION LOCAL +DEFAULT +11 
+ +12: 0+100104c8 +0 SECTION LOCAL +DEFAULT +12 
+ +13: 0+100104c8 +0 SECTION LOCAL +DEFAULT +13 
+ +14: 0+100104c8 +0 SECTION LOCAL +DEFAULT +14 
+ +15: 0+100104d0 +0 SECTION LOCAL +DEFAULT +15 
+ +16: 0+10010520 +0 SECTION LOCAL +DEFAULT +16 
+ +17: 0+10010520 +0 SECTION LOCAL +DEFAULT +17 
+ +18: 0+ +0 SECTION LOCAL +DEFAULT +18 
+ +19: 0+ +0 SECTION LOCAL +DEFAULT +19 
+ +20: 0+ +0 SECTION LOCAL +DEFAULT +20 
+ +21: 0+ +0 TLS +LOCAL +DEFAULT +9 gd4
+ +22: 0+8 +0 TLS +LOCAL +DEFAULT +9 ld4
+ +23: 0+10 +0 TLS +LOCAL +DEFAULT +9 ld5
+ +24: 0+18 +0 TLS +LOCAL +DEFAULT +9 ld6
+ +25: 0+20 +0 TLS +LOCAL +DEFAULT +9 ie4
+ +26: 0+28 +0 TLS +LOCAL +DEFAULT +9 le4
+ +27: 0+30 +0 TLS +LOCAL +DEFAULT +9 le5
+ +28: 0+10010518 +0 NOTYPE +LOCAL +DEFAULT +15 \.Lie0
+ +29: 0+100103c8 +0 OBJECT +GLOBAL DEFAULT +ABS _DYNAMIC
+ +30: 0+ +0 TLS +GLOBAL DEFAULT +UND gd
+ +31: 0+60 +0 TLS +GLOBAL DEFAULT +10 le0
+ +32: 0+ +0 NOTYPE +GLOBAL DEFAULT +UND \.__tls_get_addr
+ +33: 0+40 +0 TLS +GLOBAL DEFAULT +10 ld0
+ +34: 0+68 +0 TLS +GLOBAL DEFAULT +10 le1
+ +35: 0+ +0 TLS +GLOBAL DEFAULT +UND ld
+ +36: 0+10000338 +0 NOTYPE +GLOBAL DEFAULT +6 _start
+ +37: 0+10010520 +0 NOTYPE +GLOBAL DEFAULT +ABS __end
+ +38: 0+50 +0 TLS +GLOBAL DEFAULT +10 ld2
+ +39: 0+48 +0 TLS +GLOBAL DEFAULT +10 ld1
+ +40: 0+10010520 +0 NOTYPE +GLOBAL DEFAULT +ABS __bss_start
+ +41: 0+10010520 +0 NOTYPE +GLOBAL DEFAULT +ABS _edata
+ +42: 0+10010520 +0 NOTYPE +GLOBAL DEFAULT +ABS _end
+ +43: 0+38 +0 TLS +GLOBAL DEFAULT +10 gd0
+ +44: 0+58 +0 TLS +GLOBAL DEFAULT +10 ie0
Index: ld/testsuite/ld-powerpc/tlsexetoc.t
===================================================================
RCS file: ld/testsuite/ld-powerpc/tlsexetoc.t
diff -N ld/testsuite/ld-powerpc/tlsexetoc.t
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ ld/testsuite/ld-powerpc/tlsexetoc.t	4 Feb 2003 14:12:04 -0000
@@ -0,0 +1,13 @@
+#source: tlstoc.s
+#as: -a64
+#ld: -melf64ppc tmpdir/libtlslib.so
+#objdump: -sj.tdata
+#target: powerpc64*-*-*
+
+.*: +file format elf64-powerpc
+
+Contents of section \.tdata:
+ 10010390 12345678 9abcdef0 23456789 abcdef01  .*
+ 100103a0 3456789a bcdef012 456789ab cdef0123  .*
+ 100103b0 56789abc def01234 6789abcd ef012345  .*
+ 100103c0 789abcde f0123456                    .*
Index: ld/testsuite/ld-powerpc/tlslib.s
===================================================================
RCS file: ld/testsuite/ld-powerpc/tlslib.s
diff -N ld/testsuite/ld-powerpc/tlslib.s
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ ld/testsuite/ld-powerpc/tlslib.s	4 Feb 2003 14:12:04 -0000
@@ -0,0 +1,20 @@
+	.global .__tls_get_addr,__tls_get_addr,gd,ld
+
+	.section ".opd","aw",@progbits
+__tls_get_addr:
+	.align 3
+	.quad	.__tls_get_addr
+	.quad	.TOC.@tocbase
+	.quad	0
+
+	.section ".tbss","awT",@nobits
+	.align 3
+gd:	.space 8
+
+	.section ".tdata","awT",@progbits
+	.align 2
+ld:	.long 0xc0ffee
+
+	.text
+.__tls_get_addr:
+	blr
Index: ld/testsuite/ld-powerpc/tlsso.d
===================================================================
RCS file: ld/testsuite/ld-powerpc/tlsso.d
diff -N ld/testsuite/ld-powerpc/tlsso.d
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ ld/testsuite/ld-powerpc/tlsso.d	4 Feb 2003 14:12:04 -0000
@@ -0,0 +1,68 @@
+#source: tls.s
+#as: -a64
+#ld: -shared -melf64ppc
+#objdump: -dr
+#target: powerpc64*-*-*
+
+.*: +file format elf64-powerpc
+
+Disassembly of section \.text:
+
+0+718 <\.__tls_get_addr>:
+ 718:	3d 82 00 00 	addis	r12,r2,0
+ 71c:	f8 41 00 28 	std	r2,40\(r1\)
+ 720:	e9 6c 80 78 	ld	r11,-32648\(r12\)
+ 724:	e8 4c 80 80 	ld	r2,-32640\(r12\)
+ 728:	7d 69 03 a6 	mtctr	r11
+ 72c:	e9 6c 80 88 	ld	r11,-32632\(r12\)
+ 730:	4e 80 04 20 	bctr
+
+0+734 <_start>:
+ 734:	38 62 80 30 	addi	r3,r2,-32720
+ 738:	4b ff ff e1 	bl	718 <\.__tls_get_addr>
+ 73c:	e8 41 00 28 	ld	r2,40\(r1\)
+ 740:	38 62 80 08 	addi	r3,r2,-32760
+ 744:	4b ff ff d5 	bl	718 <\.__tls_get_addr>
+ 748:	e8 41 00 28 	ld	r2,40\(r1\)
+ 74c:	38 62 80 48 	addi	r3,r2,-32696
+ 750:	4b ff ff c9 	bl	718 <\.__tls_get_addr>
+ 754:	e8 41 00 28 	ld	r2,40\(r1\)
+ 758:	38 62 80 08 	addi	r3,r2,-32760
+ 75c:	4b ff ff bd 	bl	718 <\.__tls_get_addr>
+ 760:	e8 41 00 28 	ld	r2,40\(r1\)
+ 764:	39 23 80 40 	addi	r9,r3,-32704
+ 768:	3d 23 00 00 	addis	r9,r3,0
+ 76c:	81 49 80 48 	lwz	r10,-32696\(r9\)
+ 770:	e9 22 80 40 	ld	r9,-32704\(r2\)
+ 774:	7d 49 18 2a 	ldx	r10,r9,r3
+ 778:	e9 22 80 58 	ld	r9,-32680\(r2\)
+ 77c:	7d 49 6a 2e 	lhzx	r10,r9,r13
+ 780:	89 4d 00 00 	lbz	r10,0\(r13\)
+ 784:	3d 2d 00 00 	addis	r9,r13,0
+ 788:	99 49 00 00 	stb	r10,0\(r9\)
+ 78c:	38 62 80 18 	addi	r3,r2,-32744
+ 790:	4b ff ff 89 	bl	718 <\.__tls_get_addr>
+ 794:	e8 41 00 28 	ld	r2,40\(r1\)
+ 798:	38 62 80 08 	addi	r3,r2,-32760
+ 79c:	4b ff ff 7d 	bl	718 <\.__tls_get_addr>
+ 7a0:	e8 41 00 28 	ld	r2,40\(r1\)
+ 7a4:	f9 43 80 08 	std	r10,-32760\(r3\)
+ 7a8:	3d 23 00 00 	addis	r9,r3,0
+ 7ac:	91 49 80 10 	stw	r10,-32752\(r9\)
+ 7b0:	e9 22 80 28 	ld	r9,-32728\(r2\)
+ 7b4:	7d 49 19 2a 	stdx	r10,r9,r3
+ 7b8:	e9 22 80 58 	ld	r9,-32680\(r2\)
+ 7bc:	7d 49 6b 2e 	sthx	r10,r9,r13
+ 7c0:	e9 4d 90 2a 	lwa	r10,-28632\(r13\)
+ 7c4:	3d 2d 00 00 	addis	r9,r13,0
+ 7c8:	a9 49 90 30 	lha	r10,-28624\(r9\)
+ 7cc:	e8 41 00 28 	ld	r2,40\(r1\)
+ 7d0:	3d 82 00 00 	addis	r12,r2,0
+ 7d4:	e9 6c 80 60 	ld	r11,-32672\(r12\)
+ 7d8:	e8 4c 80 68 	ld	r2,-32664\(r12\)
+ 7dc:	7d 69 03 a6 	mtctr	r11
+ 7e0:	e9 6c 80 70 	ld	r11,-32656\(r12\)
+ 7e4:	4e 80 04 20 	bctr
+ 7e8:	60 00 00 00 	nop
+ 7ec:	38 00 00 00 	li	r0,0
+ 7f0:	4b ff ff dc 	b	7cc <_start\+0x98>
Index: ld/testsuite/ld-powerpc/tlsso.g
===================================================================
RCS file: ld/testsuite/ld-powerpc/tlsso.g
diff -N ld/testsuite/ld-powerpc/tlsso.g
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ ld/testsuite/ld-powerpc/tlsso.g	4 Feb 2003 14:12:04 -0000
@@ -0,0 +1,15 @@
+#source: tls.s
+#as: -a64
+#ld: -shared -melf64ppc
+#objdump: -sj.got
+#target: powerpc64*-*-*
+
+.*: +file format elf64-powerpc
+
+Contents of section \.got:
+ 10980 00000000 00018980 00000000 00000000  .*
+ 10990 00000000 00000000 00000000 00000000  .*
+ 109a0 00000000 00000000 00000000 00000000  .*
+ 109b0 00000000 00000000 00000000 00000000  .*
+ 109c0 00000000 00000000 00000000 00000000  .*
+ 109d0 00000000 00000000 00000000 00000000  .*
Index: ld/testsuite/ld-powerpc/tlsso.r
===================================================================
RCS file: ld/testsuite/ld-powerpc/tlsso.r
diff -N ld/testsuite/ld-powerpc/tlsso.r
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ ld/testsuite/ld-powerpc/tlsso.r	4 Feb 2003 14:12:04 -0000
@@ -0,0 +1,158 @@
+#source: tls.s
+#as: -a64
+#ld: -shared -melf64ppc
+#readelf: -WSsrl
+#target: powerpc64*-*-*
+
+There are 21 section headers.*
+
+Section Headers:
+ +\[Nr\] Name +Type +Address +Off +Size +ES Flg Lk Inf Al
+ +\[ 0\] +NULL +0+ 0+ 0+ 0+ +0 +0 +0
+ +\[ 1\] \.hash +HASH +0+120 0+120 0+d4 04 +A +2 +0 +8
+ +\[ 2\] \.dynsym +DYNSYM +0+1f8 0+1f8 0+330 18 +A +3 +12 +8
+ +\[ 3\] \.dynstr +STRTAB +0+528 0+528 0+54 0+ +A +0 +0 +1
+ +\[ 4\] \.rela\.dyn +RELA +0+580 0+580 0+180 18 +A +2 +0 +8
+ +\[ 5\] \.rela\.plt +RELA +0+700 0+700 0+18 18 +A +2 +10 +8
+ +\[ 6\] \.text +PROGBITS +0+718 0+718 0+dc 0+ +AX +0 +0 +4
+ +\[ 7\] \.data +PROGBITS +0+107f8 0+7f8 0+ 0+ +WA +0 +0 +1
+ +\[ 8\] \.branch_lt +PROGBITS +0+107f8 0+7f8 0+ 0+ +WA +0 +0 +8
+ +\[ 9\] \.tdata +PROGBITS +0+107f8 0+7f8 0+38 0+ WAT +0 +0 +8
+ +\[10\] \.tbss +NOBITS +0+10830 0+830 0+38 0+ WAT +0 +0 +8
+ +\[11\] \.dynamic +DYNAMIC +0+10830 0+830 0+150 10 +WA +3 +0 +8
+ +\[12\] \.ctors +PROGBITS +0+10980 0+9e0 0+ 0+ +W +0 +0 +1
+ +\[13\] \.dtors +PROGBITS +0+10980 0+9e0 0+ 0+ +W +0 +0 +1
+ +\[14\] \.got +PROGBITS +0+10980 0+980 0+60 08 +WA +0 +0 +8
+ +\[15\] \.sbss +PROGBITS +0+109e0 0+9e0 0+ 0+ +W +0 +0 +1
+ +\[16\] \.plt +NOBITS +0+109e0 0+9e0 0+30 18 +WA +0 +0 +8
+ +\[17\] \.bss +NOBITS +0+10a10 0+9e0 0+ 0+ +WA +0 +0 +1
+ +\[18\] \.shstrtab +STRTAB +0+ 0+9e0 0+90 0+ +0 +0 +1
+ +\[19\] \.symtab +SYMTAB +0+ 0+fb0 0+438 18 +20 +1d +8
+ +\[20\] \.strtab +STRTAB +0+ 0+13e8 0+8c 0+ +0 +0 +1
+#...
+
+Elf file type is DYN \(Shared object file\)
+Entry point 0x734
+There are 4 program headers.*
+
+Program Headers:
+ +Type +Offset +VirtAddr +PhysAddr +FileSiz +MemSiz +Flg Align
+ +LOAD +0x0+ 0x0+ 0x0+ 0x0+7f4 0x0+7f4 R E 0x10000
+ +LOAD +0x0+7f8 0x0+107f8 0x0+107f8 0x0+1e8 0x0+218 RW +0x10000
+ +DYNAMIC +0x0+830 0x0+10830 0x0+10830 0x0+150 0x0+150 RW +0x8
+ +TLS +0x0+7f8 0x0+107f8 0x0+107f8 0x0+38 0x0+70 R +0x8
+
+ Section to Segment mapping:
+ +Segment Sections\.\.\.
+ +0+ +\.hash \.dynsym \.dynstr \.rela\.dyn \.rela\.plt \.text 
+ +01 +\.tdata \.tbss \.dynamic \.got \.plt 
+ +02 +\.tbss \.dynamic 
+ +03 +\.tdata \.tbss 
+
+Relocation section '\.rela\.dyn' at offset .* contains 16 entries:
+ +Offset +Info +Type +Symbol's Value +Symbol's Name \+ Addend
+0+782 +0+1400000045 R_PPC64_TPREL16 +0+60 le0 \+ 0
+0+786 +0+1700000048 R_PPC64_TPREL16_HA +0+68 le1 \+ 0
+0+78a +0+1700000046 R_PPC64_TPREL16_LO +0+68 le1 \+ 0
+0+7c2 +0+90000005f R_PPC64_TPREL16_DS +0+107f8 \.tdata \+ 28
+0+7c6 +0+900000048 R_PPC64_TPREL16_HA +0+107f8 \.tdata \+ 30
+0+7ca +0+900000046 R_PPC64_TPREL16_LO +0+107f8 \.tdata \+ 30
+0+10988 +0+44 R_PPC64_DTPMOD64 +0+
+0+10998 +0+44 R_PPC64_DTPMOD64 +0+
+0+109a0 +0+4e R_PPC64_DTPREL64 +0+107f8
+0+109a8 +0+4e R_PPC64_DTPREL64 +0+10810
+0+109b0 +0+1300000044 R_PPC64_DTPMOD64 +0+ gd \+ 0
+0+109b8 +0+130000004e R_PPC64_DTPREL64 +0+ gd \+ 0
+0+109c0 +0+1b0000004e R_PPC64_DTPREL64 +0+50 ld2 \+ 0
+0+109c8 +0+2000000044 R_PPC64_DTPMOD64 +0+38 gd0 \+ 0
+0+109d0 +0+200000004e R_PPC64_DTPREL64 +0+38 gd0 \+ 0
+0+109d8 +0+2100000049 R_PPC64_TPREL64 +0+58 ie0 \+ 0
+
+Relocation section '\.rela\.plt' at offset .* contains 1 entries:
+ +Offset +Info +Type +Symbol's Value +Symbol's Name \+ Addend
+0+109f8 +0+1500000015 R_PPC64_JMP_SLOT +0+ __tls_get_addr \+ 0
+
+Symbol table '\.dynsym' contains 34 entries:
+ +Num: +Value +Size Type +Bind +Vis +Ndx Name
+ +0: 0+ +0 NOTYPE +LOCAL +DEFAULT +UND 
+ +1: 0+120 +0 SECTION LOCAL +DEFAULT +1 
+ +2: 0+1f8 +0 SECTION LOCAL +DEFAULT +2 
+ +3: 0+528 +0 SECTION LOCAL +DEFAULT +3 
+ +4: 0+580 +0 SECTION LOCAL +DEFAULT +4 
+ +5: 0+700 +0 SECTION LOCAL +DEFAULT +5 
+ +6: 0+718 +0 SECTION LOCAL +DEFAULT +6 
+ +7: 0+107f8 +0 SECTION LOCAL +DEFAULT +7 
+ +8: 0+107f8 +0 SECTION LOCAL +DEFAULT +8 
+ +9: 0+107f8 +0 SECTION LOCAL +DEFAULT +9 
+ +10: 0+10830 +0 SECTION LOCAL +DEFAULT +10 
+ +11: 0+10830 +0 SECTION LOCAL +DEFAULT +11 
+ +12: 0+10980 +0 SECTION LOCAL +DEFAULT +12 
+ +13: 0+10980 +0 SECTION LOCAL +DEFAULT +13 
+ +14: 0+10980 +0 SECTION LOCAL +DEFAULT +14 
+ +15: 0+109e0 +0 SECTION LOCAL +DEFAULT +15 
+ +16: 0+109e0 +0 SECTION LOCAL +DEFAULT +16 
+ +17: 0+10a10 +0 SECTION LOCAL +DEFAULT +17 
+ +18: 0+10830 +0 OBJECT +GLOBAL DEFAULT +ABS _DYNAMIC
+ +19: 0+ +0 NOTYPE +GLOBAL DEFAULT +UND gd
+ +20: 0+60 +0 TLS +GLOBAL DEFAULT +10 le0
+ +21: 0+ +0 NOTYPE +GLOBAL DEFAULT +UND __tls_get_addr
+ +22: 0+40 +0 TLS +GLOBAL DEFAULT +10 ld0
+ +23: 0+68 +0 TLS +GLOBAL DEFAULT +10 le1
+ +24: 0+ +0 NOTYPE +GLOBAL DEFAULT +UND ld
+ +25: 0+734 +0 NOTYPE +GLOBAL DEFAULT +6 _start
+ +26: 0+10a10 +0 NOTYPE +GLOBAL DEFAULT +ABS __end
+ +27: 0+50 +0 TLS +GLOBAL DEFAULT +10 ld2
+ +28: 0+48 +0 TLS +GLOBAL DEFAULT +10 ld1
+ +29: 0+109e0 +0 NOTYPE +GLOBAL DEFAULT +ABS __bss_start
+ +30: 0+109e0 +0 NOTYPE +GLOBAL DEFAULT +ABS _edata
+ +31: 0+10a10 +0 NOTYPE +GLOBAL DEFAULT +ABS _end
+ +32: 0+38 +0 TLS +GLOBAL DEFAULT +10 gd0
+ +33: 0+58 +0 TLS +GLOBAL DEFAULT +10 ie0
+
+Symbol table '\.symtab' contains 45 entries:
+ +Num: +Value +Size Type +Bind +Vis +Ndx Name
+ +0: 0+ +0 NOTYPE +LOCAL +DEFAULT +UND 
+ +1: 0+120 +0 SECTION LOCAL +DEFAULT +1 
+ +2: 0+1f8 +0 SECTION LOCAL +DEFAULT +2 
+ +3: 0+528 +0 SECTION LOCAL +DEFAULT +3 
+ +4: 0+580 +0 SECTION LOCAL +DEFAULT +4 
+ +5: 0+700 +0 SECTION LOCAL +DEFAULT +5 
+ +6: 0+718 +0 SECTION LOCAL +DEFAULT +6 
+ +7: 0+107f8 +0 SECTION LOCAL +DEFAULT +7 
+ +8: 0+107f8 +0 SECTION LOCAL +DEFAULT +8 
+ +9: 0+107f8 +0 SECTION LOCAL +DEFAULT +9 
+ +10: 0+10830 +0 SECTION LOCAL +DEFAULT +10 
+ +11: 0+10830 +0 SECTION LOCAL +DEFAULT +11 
+ +12: 0+10980 +0 SECTION LOCAL +DEFAULT +12 
+ +13: 0+10980 +0 SECTION LOCAL +DEFAULT +13 
+ +14: 0+10980 +0 SECTION LOCAL +DEFAULT +14 
+ +15: 0+109e0 +0 SECTION LOCAL +DEFAULT +15 
+ +16: 0+109e0 +0 SECTION LOCAL +DEFAULT +16 
+ +17: 0+10a10 +0 SECTION LOCAL +DEFAULT +17 
+ +18: 0+ +0 SECTION LOCAL +DEFAULT +18 
+ +19: 0+ +0 SECTION LOCAL +DEFAULT +19 
+ +20: 0+ +0 SECTION LOCAL +DEFAULT +20 
+ +21: 0+ +0 TLS +LOCAL +DEFAULT +9 gd4
+ +22: 0+8 +0 TLS +LOCAL +DEFAULT +9 ld4
+ +23: 0+10 +0 TLS +LOCAL +DEFAULT +9 ld5
+ +24: 0+18 +0 TLS +LOCAL +DEFAULT +9 ld6
+ +25: 0+20 +0 TLS +LOCAL +DEFAULT +9 ie4
+ +26: 0+28 +0 TLS +LOCAL +DEFAULT +9 le4
+ +27: 0+30 +0 TLS +LOCAL +DEFAULT +9 le5
+ +28: 0+718 +0 NOTYPE +LOCAL +DEFAULT +6 \.__tls_get_addr
+ +29: 0+10830 +0 OBJECT +GLOBAL DEFAULT +ABS _DYNAMIC
+ +30: 0+ +0 NOTYPE +GLOBAL DEFAULT +UND gd
+ +31: 0+60 +0 TLS +GLOBAL DEFAULT +10 le0
+ +32: 0+ +0 NOTYPE +GLOBAL DEFAULT +UND __tls_get_addr
+ +33: 0+40 +0 TLS +GLOBAL DEFAULT +10 ld0
+ +34: 0+68 +0 TLS +GLOBAL DEFAULT +10 le1
+ +35: 0+ +0 NOTYPE +GLOBAL DEFAULT +UND ld
+ +36: 0+734 +0 NOTYPE +GLOBAL DEFAULT +6 _start
+ +37: 0+10a10 +0 NOTYPE +GLOBAL DEFAULT +ABS __end
+ +38: 0+50 +0 TLS +GLOBAL DEFAULT +10 ld2
+ +39: 0+48 +0 TLS +GLOBAL DEFAULT +10 ld1
+ +40: 0+109e0 +0 NOTYPE +GLOBAL DEFAULT +ABS __bss_start
+ +41: 0+109e0 +0 NOTYPE +GLOBAL DEFAULT +ABS _edata
+ +42: 0+10a10 +0 NOTYPE +GLOBAL DEFAULT +ABS _end
+ +43: 0+38 +0 TLS +GLOBAL DEFAULT +10 gd0
+ +44: 0+58 +0 TLS +GLOBAL DEFAULT +10 ie0
Index: ld/testsuite/ld-powerpc/tlsso.t
===================================================================
RCS file: ld/testsuite/ld-powerpc/tlsso.t
diff -N ld/testsuite/ld-powerpc/tlsso.t
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ ld/testsuite/ld-powerpc/tlsso.t	4 Feb 2003 14:12:04 -0000
@@ -0,0 +1,13 @@
+#source: tls.s
+#as: -a64
+#ld: -shared -melf64ppc
+#objdump: -sj.tdata
+#target: powerpc64*-*-*
+
+.*: +file format elf64-powerpc
+
+Contents of section \.tdata:
+ 107f8 12345678 9abcdef0 23456789 abcdef01  .*
+ 10808 3456789a bcdef012 456789ab cdef0123  .*
+ 10818 56789abc def01234 6789abcd ef012345  .*
+ 10828 789abcde f0123456                    .*
Index: ld/testsuite/ld-powerpc/tlstoc.d
===================================================================
RCS file: ld/testsuite/ld-powerpc/tlstoc.d
diff -N ld/testsuite/ld-powerpc/tlstoc.d
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ ld/testsuite/ld-powerpc/tlstoc.d	4 Feb 2003 14:12:04 -0000
@@ -0,0 +1,37 @@
+#source: tlslib.s
+#source: tlstoc.s
+#as: -a64
+#ld: -melf64ppc
+#objdump: -dr
+#target: powerpc64*-*-*
+
+.*: +file format elf64-powerpc
+
+Disassembly of section \.text:
+
+00000000100000e8 <\.__tls_get_addr>:
+    100000e8:	4e 80 00 20 	blr
+
+00000000100000ec <_start>:
+    100000ec:	3c 6d 00 00 	addis	r3,r13,0
+    100000f0:	60 00 00 00 	nop
+    100000f4:	38 63 90 58 	addi	r3,r3,-28584
+    100000f8:	3c 6d 00 00 	addis	r3,r13,0
+    100000fc:	60 00 00 00 	nop
+    10000100:	38 63 10 00 	addi	r3,r3,4096
+    10000104:	3c 6d 00 00 	addis	r3,r13,0
+    10000108:	60 00 00 00 	nop
+    1000010c:	38 63 90 58 	addi	r3,r3,-28584
+    10000110:	3c 6d 00 00 	addis	r3,r13,0
+    10000114:	60 00 00 00 	nop
+    10000118:	38 63 10 00 	addi	r3,r3,4096
+    1000011c:	39 23 80 50 	addi	r9,r3,-32688
+    10000120:	3d 23 00 00 	addis	r9,r3,0
+    10000124:	81 49 80 58 	lwz	r10,-32680\(r9\)
+    10000128:	3d 2d 00 00 	addis	r9,r13,0
+    1000012c:	7d 49 18 2a 	ldx	r10,r9,r3
+    10000130:	3d 2d 00 00 	addis	r9,r13,0
+    10000134:	a1 49 90 a0 	lhz	r10,-28512\(r9\)
+    10000138:	89 4d 90 70 	lbz	r10,-28560\(r13\)
+    1000013c:	3d 2d 00 00 	addis	r9,r13,0
+    10000140:	99 49 90 78 	stb	r10,-28552\(r9\)
Index: ld/testsuite/ld-powerpc/tlstoc.g
===================================================================
RCS file: ld/testsuite/ld-powerpc/tlstoc.g
diff -N ld/testsuite/ld-powerpc/tlstoc.g
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ ld/testsuite/ld-powerpc/tlstoc.g	4 Feb 2003 14:12:04 -0000
@@ -0,0 +1,15 @@
+#source: tlslib.s
+#source: tlstoc.s
+#as: -a64
+#ld: -melf64ppc
+#objdump: -sj.toc
+#target: powerpc64*-*-*
+
+.*: +file format elf64-powerpc
+
+Contents of section \.toc:
+ 100101a0 00000000 00000001 00000000 00000000  .*
+ 100101b0 00000000 00000001 00000000 00000000  .*
+ 100101c0 00000000 00000001 00000000 00000000  .*
+ 100101d0 00000000 00000001 00000000 00000000  .*
+ 100101e0 ffffffff ffff8060 00000000 00000000  .*
Index: ld/testsuite/ld-powerpc/tlstoc.s
===================================================================
RCS file: ld/testsuite/ld-powerpc/tlstoc.s
diff -N ld/testsuite/ld-powerpc/tlstoc.s
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ ld/testsuite/ld-powerpc/tlstoc.s	4 Feb 2003 14:12:04 -0000
@@ -0,0 +1,88 @@
+	.section ".tbss","awT",@nobits
+	.global _start,gd0,ld0,ld1,ld2,ie0,le0,le1
+	.align 3
+gd0:	.space 8
+ld0:	.space 8
+ld1:	.space 8
+ld2:	.space 8
+ie0:	.space 8
+le0:	.space 8
+le1:	.space 8
+
+	.section ".tdata","awT",@progbits
+	.align 3
+gd4:	.quad 0x123456789abcdef0
+ld4:	.quad 0x23456789abcdef01
+ld5:	.quad 0x3456789abcdef012
+ld6:	.quad 0x456789abcdef0123
+ie4:	.quad 0x56789abcdef01234
+le4:	.quad 0x6789abcdef012345
+le5:	.quad 0x789abcdef0123456
+
+	.text
+_start:
+#extern syms
+#GD
+ addi 3,2,.Lgd@toc
+ bl .__tls_get_addr
+ nop
+ .section .toc,"aw",@progbits
+.Lgd:
+ .quad gd@dtpmod
+ .quad gd@dtprel
+ .text
+#LD
+ addi 3,2,.Lld@toc
+ bl .__tls_get_addr
+ nop
+ .section .toc,"aw",@progbits
+.Lld:
+ .quad ld@dtpmod
+ .quad 0
+ .text
+
+#global syms
+#GD
+ addi 3,2,.Lgd0@toc
+ bl .__tls_get_addr
+ nop
+ .section .toc,"aw",@progbits
+.Lgd0:
+ .quad gd0@dtpmod
+ .quad gd0@dtprel
+ .text
+#LD
+ addi 3,2,.Lld0@toc
+ bl .__tls_get_addr
+ nop
+ .section .toc,"aw",@progbits
+.Lld0:
+ .quad ld0@dtpmod
+ .quad 0
+ .text
+
+ addi 9,3,ld0@dtprel
+
+ addis 9,3,ld1@dtprel@ha
+ lwz 10,ld1@dtprel@l(9)
+
+ ld 9,.Lld2@toc(2)
+ ldx 10,9,3
+ .section .toc,"aw",@progbits
+.Lld2:
+ .quad ld2@dtprel
+ .text
+
+#IE
+ ld 9,.Lie0@toc(2)
+ lhzx 10,9,.Lie0@tls
+ .section .toc,"aw",@progbits
+.Lie0:
+ .quad ie0@tprel
+ .text
+
+#LE
+ lbz 10,le0@tprel(13)		#R_PPC64_TPREL16	le0
+
+ addis 9,13,le1@tprel@ha	#R_PPC64_TPREL16_HA	le1
+ stb 10,le1@tprel@l(9)		#R_PPC64_TPREL16_LO	le1
Index: ld/testsuite/ld-powerpc/tlstoc.t
===================================================================
RCS file: ld/testsuite/ld-powerpc/tlstoc.t
diff -N ld/testsuite/ld-powerpc/tlstoc.t
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ ld/testsuite/ld-powerpc/tlstoc.t	4 Feb 2003 14:12:04 -0000
@@ -0,0 +1,14 @@
+#source: tlslib.s
+#source: tlstoc.s
+#as: -a64
+#ld: -melf64ppc
+#objdump: -sj.tdata
+#target: powerpc64*-*-*
+
+.*: +file format elf64-powerpc
+
+Contents of section \.tdata:
+ 10010148 00c0ffee 00000000 12345678 9abcdef0  .*
+ 10010158 23456789 abcdef01 3456789a bcdef012  .*
+ 10010168 456789ab cdef0123 56789abc def01234  .*
+ 10010178 6789abcd ef012345 789abcde f0123456  .*
Index: ld/testsuite/ld-powerpc/tlstocso.d
===================================================================
RCS file: ld/testsuite/ld-powerpc/tlstocso.d
diff -N ld/testsuite/ld-powerpc/tlstocso.d
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ ld/testsuite/ld-powerpc/tlstocso.d	4 Feb 2003 14:12:04 -0000
@@ -0,0 +1,52 @@
+#source: tlstoc.s
+#as: -a64
+#ld: -shared -melf64ppc
+#objdump: -dr
+#target: powerpc64*-*-*
+
+.*: +file format elf64-powerpc
+
+Disassembly of section \.text:
+
+0+6b8 <\.__tls_get_addr>:
+ 6b8:	3d 82 00 00 	addis	r12,r2,0
+ 6bc:	f8 41 00 28 	std	r2,40\(r1\)
+ 6c0:	e9 6c 80 70 	ld	r11,-32656\(r12\)
+ 6c4:	e8 4c 80 78 	ld	r2,-32648\(r12\)
+ 6c8:	7d 69 03 a6 	mtctr	r11
+ 6cc:	e9 6c 80 80 	ld	r11,-32640\(r12\)
+ 6d0:	4e 80 04 20 	bctr
+
+0+6d4 <_start>:
+ 6d4:	38 62 80 08 	addi	r3,r2,-32760
+ 6d8:	4b ff ff e1 	bl	6b8 <\.__tls_get_addr>
+ 6dc:	e8 41 00 28 	ld	r2,40\(r1\)
+ 6e0:	38 62 80 18 	addi	r3,r2,-32744
+ 6e4:	4b ff ff d5 	bl	6b8 <\.__tls_get_addr>
+ 6e8:	e8 41 00 28 	ld	r2,40\(r1\)
+ 6ec:	38 62 80 28 	addi	r3,r2,-32728
+ 6f0:	4b ff ff c9 	bl	6b8 <\.__tls_get_addr>
+ 6f4:	e8 41 00 28 	ld	r2,40\(r1\)
+ 6f8:	38 62 80 38 	addi	r3,r2,-32712
+ 6fc:	4b ff ff bd 	bl	6b8 <\.__tls_get_addr>
+ 700:	e8 41 00 28 	ld	r2,40\(r1\)
+ 704:	39 23 80 40 	addi	r9,r3,-32704
+ 708:	3d 23 00 00 	addis	r9,r3,0
+ 70c:	81 49 80 48 	lwz	r10,-32696\(r9\)
+ 710:	3d 2d 00 00 	addis	r9,r13,0
+ 714:	7d 49 18 2a 	ldx	r10,r9,r3
+ 718:	e9 22 80 50 	ld	r9,-32688\(r2\)
+ 71c:	7d 49 6a 2e 	lhzx	r10,r9,r13
+ 720:	89 4d 00 00 	lbz	r10,0\(r13\)
+ 724:	3d 2d 00 00 	addis	r9,r13,0
+ 728:	99 49 00 00 	stb	r10,0\(r9\)
+ 72c:	e8 41 00 28 	ld	r2,40\(r1\)
+ 730:	3d 82 00 00 	addis	r12,r2,0
+ 734:	e9 6c 80 58 	ld	r11,-32680\(r12\)
+ 738:	e8 4c 80 60 	ld	r2,-32672\(r12\)
+ 73c:	7d 69 03 a6 	mtctr	r11
+ 740:	e9 6c 80 68 	ld	r11,-32664\(r12\)
+ 744:	4e 80 04 20 	bctr
+ 748:	60 00 00 00 	nop
+ 74c:	38 00 00 00 	li	r0,0
+ 750:	4b ff ff dc 	b	72c <_start\+0x58>
Index: ld/testsuite/ld-powerpc/tlstocso.g
===================================================================
RCS file: ld/testsuite/ld-powerpc/tlstocso.g
diff -N ld/testsuite/ld-powerpc/tlstocso.g
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ ld/testsuite/ld-powerpc/tlstocso.g	4 Feb 2003 14:12:04 -0000
@@ -0,0 +1,14 @@
+#source: tlstoc.s
+#as: -a64
+#ld: -shared -melf64ppc
+#objdump: -sj.toc
+#target: powerpc64*-*-*
+
+.*: +file format elf64-powerpc
+
+Contents of section \.toc:
+ 108e8 00000000 00000000 00000000 00000000  .*
+ 108f8 00000000 00000000 00000000 00000000  .*
+ 10908 00000000 00000000 00000000 00000000  .*
+ 10918 00000000 00000000 00000000 00000000  .*
+ 10928 00000000 00000000 00000000 00000000  .*
Index: ld/testsuite/ld-powerpc/tlstocso.r
===================================================================
RCS file: ld/testsuite/ld-powerpc/tlstocso.r
diff -N ld/testsuite/ld-powerpc/tlstocso.r
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ ld/testsuite/ld-powerpc/tlstocso.r	4 Feb 2003 14:12:04 -0000
@@ -0,0 +1,157 @@
+#source: tlstoc.s
+#as: -a64
+#ld: -shared -melf64ppc
+#readelf: -WSsrl
+#target: powerpc64*-*-*
+
+There are 22 section headers.*
+
+Section Headers:
+ +\[Nr\] Name +Type +Address +Off +Size +ES Flg Lk Inf Al
+ +\[ 0\] +NULL +0+ 0+ 0+ 0+ +0 +0 +0
+ +\[ 1\] \.hash +HASH +0+120 0+120 0+d8 04 +A +2 +0 +8
+ +\[ 2\] \.dynsym +DYNSYM +0+1f8 0+1f8 0+348 18 +A +3 +13 +8
+ +\[ 3\] \.dynstr +STRTAB +0+540 0+540 0+54 0+ +A +0 +0 +1
+ +\[ 4\] \.rela\.dyn +RELA +0+598 0+598 0+108 18 +A +2 +0 +8
+ +\[ 5\] \.rela\.plt +RELA +0+6a0 0+6a0 0+18 18 +A +2 +11 +8
+ +\[ 6\] \.text +PROGBITS +0+6b8 0+6b8 0+9c 0+ +AX +0 +0 +4
+ +\[ 7\] \.data +PROGBITS +0+10758 0+758 0+ 0+ +WA +0 +0 +1
+ +\[ 8\] \.branch_lt +PROGBITS +0+10758 0+758 0+ 0+ +WA +0 +0 +8
+ +\[ 9\] \.tdata +PROGBITS +0+10758 0+758 0+38 0+ WAT +0 +0 +8
+ +\[10\] \.tbss +NOBITS +0+10790 0+790 0+38 0+ WAT +0 +0 +8
+ +\[11\] \.dynamic +DYNAMIC +0+10790 0+790 0+150 10 +WA +3 +0 +8
+ +\[12\] \.ctors +PROGBITS +0+108e0 0+938 0+ 0+ +W +0 +0 +1
+ +\[13\] \.dtors +PROGBITS +0+108e0 0+938 0+ 0+ +W +0 +0 +1
+ +\[14\] \.got +PROGBITS +0+108e0 0+8e0 0+8 08 +WA +0 +0 +8
+ +\[15\] \.toc +PROGBITS +0+108e8 0+8e8 0+50 0+ +WA +0 +0 +1
+ +\[16\] \.sbss +PROGBITS +0+10938 0+938 0+ 0+ +W +0 +0 +1
+ +\[17\] \.plt +NOBITS +0+10938 0+938 0+30 18 +WA +0 +0 +8
+ +\[18\] \.bss +NOBITS +0+10968 0+938 0+ 0+ +WA +0 +0 +1
+ +\[19\] \.shstrtab +STRTAB +0+ 0+938 0+95 0+ +0 +0 +1
+ +\[20\] \.symtab +SYMTAB +0+ 0+f50 0+468 18 +21 +1f +8
+ +\[21\] \.strtab +STRTAB +0+ 0+13b8 0+92 0+ +0 +0 +1
+#...
+
+Elf file type is DYN \(Shared object file\)
+Entry point 0x6d4
+There are 4 program headers.*
+
+Program Headers:
+ +Type +Offset +VirtAddr +PhysAddr +FileSiz +MemSiz +Flg Align
+ +LOAD +0x0+ 0x0+ 0x0+ 0x0+754 0x0+754 R E 0x10000
+ +LOAD +0x0+758 0x0+10758 0x0+10758 0x0+1e0 0x0+210 RW +0x10000
+ +DYNAMIC +0x0+790 0x0+10790 0x0+10790 0x0+150 0x0+150 RW +0x8
+ +TLS +0x0+758 0x0+10758 0x0+10758 0x0+38 0x0+70 R +0x8
+
+ Section to Segment mapping:
+ +Segment Sections\.\.\.
+ +0+ +\.hash \.dynsym \.dynstr \.rela\.dyn \.rela\.plt \.text 
+ +01 +\.tdata \.tbss \.dynamic \.got \.toc \.plt 
+ +02 +\.tbss \.dynamic 
+ +03 +\.tdata \.tbss 
+
+Relocation section '\.rela\.dyn' at offset .* contains 11 entries:
+ +Offset +Info +Type +Symbol's Value +Symbol's Name \+ Addend
+0+712 +0+f00000048 R_PPC64_TPREL16_HA +0+108e8 \.toc \+ 40
+0+722 +0+1500000045 R_PPC64_TPREL16 +0+60 le0 \+ 0
+0+726 +0+1800000048 R_PPC64_TPREL16_HA +0+68 le1 \+ 0
+0+108e8 +0+1400000044 R_PPC64_DTPMOD64 +0+ gd \+ 0
+0+108f0 +0+140000004e R_PPC64_DTPREL64 +0+ gd \+ 0
+0+108f8 +0+1900000044 R_PPC64_DTPMOD64 +0+ ld \+ 0
+0+10908 +0+2100000044 R_PPC64_DTPMOD64 +0+38 gd0 \+ 0
+0+10910 +0+210000004e R_PPC64_DTPREL64 +0+38 gd0 \+ 0
+0+10918 +0+1700000044 R_PPC64_DTPMOD64 +0+40 ld0 \+ 0
+0+10928 +0+1c0000004e R_PPC64_DTPREL64 +0+50 ld2 \+ 0
+0+10930 +0+2200000049 R_PPC64_TPREL64 +0+58 ie0 \+ 0
+
+Relocation section '\.rela\.plt' at offset 0x6a0 contains 1 entries:
+ +Offset +Info +Type +Symbol's Value +Symbol's Name \+ Addend
+0+10950 +0+1600000015 R_PPC64_JMP_SLOT +0+ __tls_get_addr \+ 0
+
+Symbol table '\.dynsym' contains 35 entries:
+ +Num: +Value +Size Type +Bind +Vis +Ndx Name
+ +0: 0+ +0 NOTYPE +LOCAL +DEFAULT +UND 
+ +1: 0+120 +0 SECTION LOCAL +DEFAULT +1 
+ +2: 0+1f8 +0 SECTION LOCAL +DEFAULT +2 
+ +3: 0+540 +0 SECTION LOCAL +DEFAULT +3 
+ +4: 0+598 +0 SECTION LOCAL +DEFAULT +4 
+ +5: 0+6a0 +0 SECTION LOCAL +DEFAULT +5 
+ +6: 0+6b8 +0 SECTION LOCAL +DEFAULT +6 
+ +7: 0+10758 +0 SECTION LOCAL +DEFAULT +7 
+ +8: 0+10758 +0 SECTION LOCAL +DEFAULT +8 
+ +9: 0+10758 +0 SECTION LOCAL +DEFAULT +9 
+ +10: 0+10790 +0 SECTION LOCAL +DEFAULT +10 
+ +11: 0+10790 +0 SECTION LOCAL +DEFAULT +11 
+ +12: 0+108e0 +0 SECTION LOCAL +DEFAULT +12 
+ +13: 0+108e0 +0 SECTION LOCAL +DEFAULT +13 
+ +14: 0+108e0 +0 SECTION LOCAL +DEFAULT +14 
+ +15: 0+108e8 +0 SECTION LOCAL +DEFAULT +15 
+ +16: 0+10938 +0 SECTION LOCAL +DEFAULT +16 
+ +17: 0+10938 +0 SECTION LOCAL +DEFAULT +17 
+ +18: 0+10968 +0 SECTION LOCAL +DEFAULT +18 
+ +19: 0+10790 +0 OBJECT +GLOBAL DEFAULT +ABS _DYNAMIC
+ +20: 0+ +0 NOTYPE +GLOBAL DEFAULT +UND gd
+ +21: 0+60 +0 TLS +GLOBAL DEFAULT +10 le0
+ +22: 0+ +0 NOTYPE +GLOBAL DEFAULT +UND __tls_get_addr
+ +23: 0+40 +0 TLS +GLOBAL DEFAULT +10 ld0
+ +24: 0+68 +0 TLS +GLOBAL DEFAULT +10 le1
+ +25: 0+ +0 NOTYPE +GLOBAL DEFAULT +UND ld
+ +26: 0+6d4 +0 NOTYPE +GLOBAL DEFAULT +6 _start
+ +27: 0+10968 +0 NOTYPE +GLOBAL DEFAULT +ABS __end
+ +28: 0+50 +0 TLS +GLOBAL DEFAULT +10 ld2
+ +29: 0+48 +0 TLS +GLOBAL DEFAULT +10 ld1
+ +30: 0+10938 +0 NOTYPE +GLOBAL DEFAULT +ABS __bss_start
+ +31: 0+10938 +0 NOTYPE +GLOBAL DEFAULT +ABS _edata
+ +32: 0+10968 +0 NOTYPE +GLOBAL DEFAULT +ABS _end
+ +33: 0+38 +0 TLS +GLOBAL DEFAULT +10 gd0
+ +34: 0+58 +0 TLS +GLOBAL DEFAULT +10 ie0
+
+Symbol table '\.symtab' contains 47 entries:
+ +Num: +Value +Size Type +Bind +Vis +Ndx Name
+ +0: 0+ +0 NOTYPE +LOCAL +DEFAULT +UND 
+ +1: 0+120 +0 SECTION LOCAL +DEFAULT +1 
+ +2: 0+1f8 +0 SECTION LOCAL +DEFAULT +2 
+ +3: 0+540 +0 SECTION LOCAL +DEFAULT +3 
+ +4: 0+598 +0 SECTION LOCAL +DEFAULT +4 
+ +5: 0+6a0 +0 SECTION LOCAL +DEFAULT +5 
+ +6: 0+6b8 +0 SECTION LOCAL +DEFAULT +6 
+ +7: 0+10758 +0 SECTION LOCAL +DEFAULT +7 
+ +8: 0+10758 +0 SECTION LOCAL +DEFAULT +8 
+ +9: 0+10758 +0 SECTION LOCAL +DEFAULT +9 
+ +10: 0+10790 +0 SECTION LOCAL +DEFAULT +10 
+ +11: 0+10790 +0 SECTION LOCAL +DEFAULT +11 
+ +12: 0+108e0 +0 SECTION LOCAL +DEFAULT +12 
+ +13: 0+108e0 +0 SECTION LOCAL +DEFAULT +13 
+ +14: 0+108e0 +0 SECTION LOCAL +DEFAULT +14 
+ +15: 0+108e8 +0 SECTION LOCAL +DEFAULT +15 
+ +16: 0+10938 +0 SECTION LOCAL +DEFAULT +16 
+ +17: 0+10938 +0 SECTION LOCAL +DEFAULT +17 
+ +18: 0+10968 +0 SECTION LOCAL +DEFAULT +18 
+ +19: 0+ +0 SECTION LOCAL +DEFAULT +19 
+ +20: 0+ +0 SECTION LOCAL +DEFAULT +20 
+ +21: 0+ +0 SECTION LOCAL +DEFAULT +21 
+ +22: 0+ +0 TLS +LOCAL +DEFAULT +9 gd4
+ +23: 0+8 +0 TLS +LOCAL +DEFAULT +9 ld4
+ +24: 0+10 +0 TLS +LOCAL +DEFAULT +9 ld5
+ +25: 0+18 +0 TLS +LOCAL +DEFAULT +9 ld6
+ +26: 0+20 +0 TLS +LOCAL +DEFAULT +9 ie4
+ +27: 0+28 +0 TLS +LOCAL +DEFAULT +9 le4
+ +28: 0+30 +0 TLS +LOCAL +DEFAULT +9 le5
+ +29: 0+10930 +0 NOTYPE +LOCAL +DEFAULT +15 \.Lie0
+ +30: 0+6b8 +0 NOTYPE +LOCAL +DEFAULT +6 \.__tls_get_addr
+ +31: 0+10790 +0 OBJECT +GLOBAL DEFAULT +ABS _DYNAMIC
+ +32: 0+ +0 NOTYPE +GLOBAL DEFAULT +UND gd
+ +33: 0+60 +0 TLS +GLOBAL DEFAULT +10 le0
+ +34: 0+ +0 NOTYPE +GLOBAL DEFAULT +UND __tls_get_addr
+ +35: 0+40 +0 TLS +GLOBAL DEFAULT +10 ld0
+ +36: 0+68 +0 TLS +GLOBAL DEFAULT +10 le1
+ +37: 0+ +0 NOTYPE +GLOBAL DEFAULT +UND ld
+ +38: 0+6d4 +0 NOTYPE +GLOBAL DEFAULT +6 _start
+ +39: 0+10968 +0 NOTYPE +GLOBAL DEFAULT +ABS __end
+ +40: 0+50 +0 TLS +GLOBAL DEFAULT +10 ld2
+ +41: 0+48 +0 TLS +GLOBAL DEFAULT +10 ld1
+ +42: 0+10938 +0 NOTYPE +GLOBAL DEFAULT +ABS __bss_start
+ +43: 0+10938 +0 NOTYPE +GLOBAL DEFAULT +ABS _edata
+ +44: 0+10968 +0 NOTYPE +GLOBAL DEFAULT +ABS _end
+ +45: 0+38 +0 TLS +GLOBAL DEFAULT +10 gd0
+ +46: 0+58 +0 TLS +GLOBAL DEFAULT +10 ie0
Index: ld/testsuite/ld-powerpc/tlstocso.t
===================================================================
RCS file: ld/testsuite/ld-powerpc/tlstocso.t
diff -N ld/testsuite/ld-powerpc/tlstocso.t
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ ld/testsuite/ld-powerpc/tlstocso.t	4 Feb 2003 14:12:04 -0000
@@ -0,0 +1,13 @@
+#source: tlstoc.s
+#as: -a64
+#ld: -shared -melf64ppc
+#objdump: -sj.tdata
+#target: powerpc64*-*-*
+
+.*: +file format elf64-powerpc
+
+Contents of section \.tdata:
+ 10758 12345678 9abcdef0 23456789 abcdef01  .*
+ 10768 3456789a bcdef012 456789ab cdef0123  .*
+ 10778 56789abc def01234 6789abcd ef012345  .*
+ 10788 789abcde f0123456                    .*


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