Blame SOURCES/gdb-rhbz1125820-ppc64le-enablement-10of37.patch

2c2fa1
commit b9e5796b0d6ebc355e4a6d06791b7366939d10f2
2c2fa1
Author: Alan Modra <amodra@gmail.com>
2c2fa1
Date:   Tue Oct 29 15:58:05 2013 +1030
2c2fa1
2c2fa1
    ELFv2 stub, plt and glink changes
2c2fa1
    
2c2fa1
    An ELFv2 PLT entry is simply the address of the target function rather
2c2fa1
    than three (or two) words to specify entry, toc and static chain.  PLT
2c2fa1
    call stubs are correspondingly simpler and need no thread safety
2c2fa1
    barrier.  The glink resolver stub and branch table also is simplified,
2c2fa1
    a change that could be applied to ELFv1 too, but isn't as yet.
2c2fa1
    
2c2fa1
    	* elf64-ppc.c (PLT_ENTRY_SIZE, PLT_INITIAL_ENTRY_SIZE): Add htab
2c2fa1
    	parameter and adjust for ELFv2.  Update all uses.
2c2fa1
    	(PLT_CALL_STUB_SIZE): Delete.
2c2fa1
    	(ppc64_elf_get_synthetic_symtab): Support new glink layout.
2c2fa1
    	(allocate_dynrelocs): Likewise.
2c2fa1
    	(plt_stub_size, build_plt_stub): Adjust for ELFv2.
2c2fa1
    	(get_r2off): Return 0 for ELFv2 -R.
2c2fa1
    	(ppc_build_one_stub, ppc_size_one_stub): Adjust for ELFv2.
2c2fa1
    	(ppc64_elf_size_stubs): Likewise.
2c2fa1
    	(ppc64_elf_build_stubs): Add new ELFv2 glink.
2c2fa1
2c2fa1
Index: gdb-7.6.1/bfd/elf64-ppc.c
2c2fa1
===================================================================
2c2fa1
--- gdb-7.6.1.orig/bfd/elf64-ppc.c
2c2fa1
+++ gdb-7.6.1/bfd/elf64-ppc.c
2c2fa1
@@ -125,10 +125,10 @@ static bfd_vma opd_entry_value
2c2fa1
 #define ELF_DYNAMIC_INTERPRETER "/usr/lib/ld.so.1"
2c2fa1
 
2c2fa1
 /* The size in bytes of an entry in the procedure linkage table.  */
2c2fa1
-#define PLT_ENTRY_SIZE 24
2c2fa1
+#define PLT_ENTRY_SIZE(htab) (htab->opd_abi ? 24 : 8)
2c2fa1
 
2c2fa1
 /* The initial size of the plt reserved for the dynamic linker.  */
2c2fa1
-#define PLT_INITIAL_ENTRY_SIZE PLT_ENTRY_SIZE
2c2fa1
+#define PLT_INITIAL_ENTRY_SIZE(htab) (htab->opd_abi ? 24 : 16)
2c2fa1
 
2c2fa1
 /* TOC base pointers offset from start of TOC.  */
2c2fa1
 #define TOC_BASE_OFF	0x8000
2c2fa1
@@ -140,7 +140,6 @@ static bfd_vma opd_entry_value
2c2fa1
 /* .plt call stub instructions.  The normal stub is like this, but
2c2fa1
    sometimes the .plt entry crosses a 64k boundary and we need to
2c2fa1
    insert an addi to adjust r11.  */
2c2fa1
-#define PLT_CALL_STUB_SIZE (7*4)
2c2fa1
 #define STD_R2_40R1	0xf8410028	/* std	 %r2,40(%r1)	     */
2c2fa1
 #define ADDIS_R11_R2	0x3d620000	/* addis %r11,%r2,xxx@ha     */
2c2fa1
 #define LD_R12_0R11	0xe98b0000	/* ld	 %r12,xxx+0@l(%r11)  */
2c2fa1
@@ -184,6 +183,11 @@ static bfd_vma opd_entry_value
2c2fa1
 					/*  mtctr %12			*/
2c2fa1
 					/*  ld %11,16(%11)		*/
2c2fa1
 					/*  bctr			*/
2c2fa1
+#define MFLR_R0		0x7c0802a6	/*  mflr %r0			*/
2c2fa1
+#define MTLR_R0		0x7c0803a6	/*  mtlr %r0			*/
2c2fa1
+#define SUB_R12_R12_R11	0x7d8b6050	/*  subf %r12,%r11,%r12		*/
2c2fa1
+#define ADDI_R0_R12	0x380c0000	/*  addi %r0,%r12,0		*/
2c2fa1
+#define SRDI_R0_R0_2	0x7800f082	/*  rldicl %r0,%r0,62,2		*/
2c2fa1
 
2c2fa1
 /* Pad with this.  */
2c2fa1
 #define NOP		0x60000000
2c2fa1
@@ -3238,9 +3242,9 @@ ppc64_elf_get_synthetic_symtab (bfd *abf
2c2fa1
 
2c2fa1
 	      if (dyn.d_tag == DT_PPC64_GLINK)
2c2fa1
 		{
2c2fa1
-		  /* The first glink stub starts at offset 32; see comment in
2c2fa1
-		     ppc64_elf_finish_dynamic_sections. */
2c2fa1
-		  glink_vma = dyn.d_un.d_val + 32;
2c2fa1
+		  /* The first glink stub starts at offset 32; see
2c2fa1
+		     comment in ppc64_elf_finish_dynamic_sections. */
2c2fa1
+		  glink_vma = dyn.d_un.d_val + GLINK_CALL_STUB_SIZE - 8 * 4;
2c2fa1
 		  /* The .glink section usually does not survive the final
2c2fa1
 		     link; search for the section (usually .text) where the
2c2fa1
 		     glink stubs now reside.  */
2c2fa1
@@ -3258,13 +3262,21 @@ ppc64_elf_get_synthetic_symtab (bfd *abf
2c2fa1
 	  /* Determine __glink trampoline by reading the relative branch
2c2fa1
 	     from the first glink stub.  */
2c2fa1
 	  bfd_byte buf[4];
2c2fa1
-	  if (bfd_get_section_contents (abfd, glink, buf,
2c2fa1
-					glink_vma + 4 - glink->vma, 4))
2c2fa1
+	  unsigned int off = 0;
2c2fa1
+
2c2fa1
+	  while (bfd_get_section_contents (abfd, glink, buf,
2c2fa1
+					   glink_vma + off - glink->vma, 4))
2c2fa1
 	    {
2c2fa1
 	      unsigned int insn = bfd_get_32 (abfd, buf);
2c2fa1
 	      insn ^= B_DOT;
2c2fa1
 	      if ((insn & ~0x3fffffc) == 0)
2c2fa1
-		resolv_vma = glink_vma + 4 + (insn ^ 0x2000000) - 0x2000000;
2c2fa1
+		{
2c2fa1
+		  resolv_vma = glink_vma + off + (insn ^ 0x2000000) - 0x2000000;
2c2fa1
+		  break;
2c2fa1
+		}
2c2fa1
+	      off += 4;
2c2fa1
+	      if (off > 4)
2c2fa1
+		break;
2c2fa1
 	    }
2c2fa1
 
2c2fa1
 	  if (resolv_vma)
2c2fa1
@@ -3417,8 +3429,13 @@ ppc64_elf_get_synthetic_symtab (bfd *abf
2c2fa1
 	      memcpy (names, "@plt", sizeof ("@plt"));
2c2fa1
 	      names += sizeof ("@plt");
2c2fa1
 	      s++;
2c2fa1
-	      glink_vma += 8;
2c2fa1
-	      if (i >= 0x8000)
2c2fa1
+	      if (abi < 2)
2c2fa1
+		{
2c2fa1
+		  glink_vma += 8;
2c2fa1
+		  if (i >= 0x8000)
2c2fa1
+		    glink_vma += 4;
2c2fa1
+		}
2c2fa1
+	      else
2c2fa1
 		glink_vma += 4;
2c2fa1
 	    }
2c2fa1
 	  count += plt_count;
2c2fa1
@@ -9021,7 +9038,7 @@ allocate_dynrelocs (struct elf_link_hash
2c2fa1
 	      {
2c2fa1
 		s = htab->iplt;
2c2fa1
 		pent->plt.offset = s->size;
2c2fa1
-		s->size += PLT_ENTRY_SIZE;
2c2fa1
+		s->size += PLT_ENTRY_SIZE (htab);
2c2fa1
 		s = htab->reliplt;
2c2fa1
 	      }
2c2fa1
 	    else
2c2fa1
@@ -9030,21 +9047,26 @@ allocate_dynrelocs (struct elf_link_hash
2c2fa1
 		   first entry.  */
2c2fa1
 		s = htab->plt;
2c2fa1
 		if (s->size == 0)
2c2fa1
-		  s->size += PLT_INITIAL_ENTRY_SIZE;
2c2fa1
+		  s->size += PLT_INITIAL_ENTRY_SIZE (htab);
2c2fa1
 
2c2fa1
 		pent->plt.offset = s->size;
2c2fa1
 
2c2fa1
 		/* Make room for this entry.  */
2c2fa1
-		s->size += PLT_ENTRY_SIZE;
2c2fa1
+		s->size += PLT_ENTRY_SIZE (htab);
2c2fa1
 
2c2fa1
 		/* Make room for the .glink code.  */
2c2fa1
 		s = htab->glink;
2c2fa1
 		if (s->size == 0)
2c2fa1
 		  s->size += GLINK_CALL_STUB_SIZE;
2c2fa1
-		/* We need bigger stubs past index 32767.  */
2c2fa1
-		if (s->size >= GLINK_CALL_STUB_SIZE + 32768*2*4)
2c2fa1
+		if (htab->opd_abi)
2c2fa1
+		  {
2c2fa1
+		    /* We need bigger stubs past index 32767.  */
2c2fa1
+		    if (s->size >= GLINK_CALL_STUB_SIZE + 32768*2*4)
2c2fa1
+		      s->size += 4;
2c2fa1
+		    s->size += 2*4;
2c2fa1
+		  }
2c2fa1
+		else
2c2fa1
 		  s->size += 4;
2c2fa1
-		s->size += 2*4;
2c2fa1
 
2c2fa1
 		/* We also need to make an entry in the .rela.plt section.  */
2c2fa1
 		s = htab->relplt;
2c2fa1
@@ -9393,7 +9415,7 @@ ppc64_elf_size_dynamic_sections (bfd *ou
2c2fa1
 	      {
2c2fa1
 		s = htab->iplt;
2c2fa1
 		ent->plt.offset = s->size;
2c2fa1
-		s->size += PLT_ENTRY_SIZE;
2c2fa1
+		s->size += PLT_ENTRY_SIZE (htab);
2c2fa1
 
2c2fa1
 		htab->reliplt->size += sizeof (Elf64_External_Rela);
2c2fa1
 	      }
2c2fa1
@@ -9727,19 +9749,23 @@ plt_stub_size (struct ppc_link_hash_tabl
2c2fa1
 	       struct ppc_stub_hash_entry *stub_entry,
2c2fa1
 	       bfd_vma off)
2c2fa1
 {
2c2fa1
-  unsigned size = PLT_CALL_STUB_SIZE;
2c2fa1
+  unsigned size = 12;
2c2fa1
 
2c2fa1
-  if (!(ALWAYS_EMIT_R2SAVE
2c2fa1
-	|| stub_entry->stub_type == ppc_stub_plt_call_r2save))
2c2fa1
-    size -= 4;
2c2fa1
-  if (!htab->plt_static_chain)
2c2fa1
-    size -= 4;
2c2fa1
-  if (htab->plt_thread_safe)
2c2fa1
-    size += 8;
2c2fa1
-  if (PPC_HA (off) == 0)
2c2fa1
-    size -= 4;
2c2fa1
-  if (PPC_HA (off + 8 + 8 * htab->plt_static_chain) != PPC_HA (off))
2c2fa1
+  if (ALWAYS_EMIT_R2SAVE
2c2fa1
+      || stub_entry->stub_type == ppc_stub_plt_call_r2save)
2c2fa1
     size += 4;
2c2fa1
+  if (PPC_HA (off) != 0)
2c2fa1
+    size += 4;
2c2fa1
+  if (htab->opd_abi)
2c2fa1
+    {
2c2fa1
+      size += 4;
2c2fa1
+      if (htab->plt_static_chain)
2c2fa1
+	size += 4;
2c2fa1
+      if (htab->plt_thread_safe)
2c2fa1
+	size += 8;
2c2fa1
+      if (PPC_HA (off + 8 + 8 * htab->plt_static_chain) != PPC_HA (off))
2c2fa1
+	size += 4;
2c2fa1
+    }
2c2fa1
   if (stub_entry->h != NULL
2c2fa1
       && (stub_entry->h == htab->tls_get_addr_fd
2c2fa1
 	  || stub_entry->h == htab->tls_get_addr)
2c2fa1
@@ -9773,12 +9799,14 @@ build_plt_stub (struct ppc_link_hash_tab
2c2fa1
 		bfd_byte *p, bfd_vma offset, Elf_Internal_Rela *r)
2c2fa1
 {
2c2fa1
   bfd *obfd = htab->stub_bfd;
2c2fa1
+  bfd_boolean plt_load_toc = htab->opd_abi;
2c2fa1
   bfd_boolean plt_static_chain = htab->plt_static_chain;
2c2fa1
   bfd_boolean plt_thread_safe = htab->plt_thread_safe;
2c2fa1
   bfd_boolean use_fake_dep = plt_thread_safe;
2c2fa1
   bfd_vma cmp_branch_off = 0;
2c2fa1
 
2c2fa1
   if (!ALWAYS_USE_FAKE_DEP
2c2fa1
+      && plt_load_toc
2c2fa1
       && plt_thread_safe
2c2fa1
       && !(stub_entry->h != NULL
2c2fa1
 	   && (stub_entry->h == htab->tls_get_addr_fd
2c2fa1
@@ -9786,7 +9814,8 @@ build_plt_stub (struct ppc_link_hash_tab
2c2fa1
 	   && !htab->no_tls_get_addr_opt))
2c2fa1
     {
2c2fa1
       bfd_vma pltoff = stub_entry->plt_ent->plt.offset & ~1;
2c2fa1
-      bfd_vma pltindex = (pltoff - PLT_INITIAL_ENTRY_SIZE) / PLT_ENTRY_SIZE;
2c2fa1
+      bfd_vma pltindex = ((pltoff - PLT_INITIAL_ENTRY_SIZE (htab))
2c2fa1
+			  / PLT_ENTRY_SIZE (htab));
2c2fa1
       bfd_vma glinkoff = GLINK_CALL_STUB_SIZE + pltindex * 8;
2c2fa1
       bfd_vma to, from;
2c2fa1
 
2c2fa1
@@ -9820,22 +9849,25 @@ build_plt_stub (struct ppc_link_hash_tab
2c2fa1
 	  r[1].r_offset = r[0].r_offset + 4;
2c2fa1
 	  r[1].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO_DS);
2c2fa1
 	  r[1].r_addend = r[0].r_addend;
2c2fa1
-	  if (PPC_HA (offset + 8 + 8 * plt_static_chain) != PPC_HA (offset))
2c2fa1
-	    {
2c2fa1
-	      r[2].r_offset = r[1].r_offset + 4;
2c2fa1
-	      r[2].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO);
2c2fa1
-	      r[2].r_addend = r[0].r_addend;
2c2fa1
-	    }
2c2fa1
-	  else
2c2fa1
+	  if (plt_load_toc)
2c2fa1
 	    {
2c2fa1
-	      r[2].r_offset = r[1].r_offset + 8 + 8 * use_fake_dep;
2c2fa1
-	      r[2].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO_DS);
2c2fa1
-	      r[2].r_addend = r[0].r_addend + 8;
2c2fa1
-	      if (plt_static_chain)
2c2fa1
-		{
2c2fa1
-		  r[3].r_offset = r[2].r_offset + 4;
2c2fa1
-		  r[3].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO_DS);
2c2fa1
-		  r[3].r_addend = r[0].r_addend + 16;
2c2fa1
+	      if (PPC_HA (offset + 8 + 8 * plt_static_chain) != PPC_HA (offset))
2c2fa1
+		{
2c2fa1
+		  r[2].r_offset = r[1].r_offset + 4;
2c2fa1
+		  r[2].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO);
2c2fa1
+		  r[2].r_addend = r[0].r_addend;
2c2fa1
+		}
2c2fa1
+	      else
2c2fa1
+		{
2c2fa1
+		  r[2].r_offset = r[1].r_offset + 8 + 8 * use_fake_dep;
2c2fa1
+		  r[2].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO_DS);
2c2fa1
+		  r[2].r_addend = r[0].r_addend + 8;
2c2fa1
+		  if (plt_static_chain)
2c2fa1
+		    {
2c2fa1
+		      r[3].r_offset = r[2].r_offset + 4;
2c2fa1
+		      r[3].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO_DS);
2c2fa1
+		      r[3].r_addend = r[0].r_addend + 16;
2c2fa1
+		    }
2c2fa1
 		}
2c2fa1
 	    }
2c2fa1
 	}
2c2fa1
@@ -9844,20 +9876,24 @@ build_plt_stub (struct ppc_link_hash_tab
2c2fa1
 	bfd_put_32 (obfd, STD_R2_40R1, p),			p += 4;
2c2fa1
       bfd_put_32 (obfd, ADDIS_R11_R2 | PPC_HA (offset), p),	p += 4;
2c2fa1
       bfd_put_32 (obfd, LD_R12_0R11 | PPC_LO (offset), p),	p += 4;
2c2fa1
-      if (PPC_HA (offset + 8 + 8 * plt_static_chain) != PPC_HA (offset))
2c2fa1
+      if (plt_load_toc
2c2fa1
+	  && PPC_HA (offset + 8 + 8 * plt_static_chain) != PPC_HA (offset))
2c2fa1
 	{
2c2fa1
 	  bfd_put_32 (obfd, ADDI_R11_R11 | PPC_LO (offset), p),	p += 4;
2c2fa1
 	  offset = 0;
2c2fa1
 	}
2c2fa1
       bfd_put_32 (obfd, MTCTR_R12, p),				p += 4;
2c2fa1
-      if (use_fake_dep)
2c2fa1
+      if (plt_load_toc)
2c2fa1
 	{
2c2fa1
-	  bfd_put_32 (obfd, XOR_R2_R12_R12, p),			p += 4;
2c2fa1
-	  bfd_put_32 (obfd, ADD_R11_R11_R2, p),			p += 4;
2c2fa1
+	  if (use_fake_dep)
2c2fa1
+	    {
2c2fa1
+	      bfd_put_32 (obfd, XOR_R2_R12_R12, p),		p += 4;
2c2fa1
+	      bfd_put_32 (obfd, ADD_R11_R11_R2, p),		p += 4;
2c2fa1
+	    }
2c2fa1
+	  bfd_put_32 (obfd, LD_R2_0R11 | PPC_LO (offset + 8), p), p += 4;
2c2fa1
+	  if (plt_static_chain)
2c2fa1
+	    bfd_put_32 (obfd, LD_R11_0R11 | PPC_LO (offset + 16), p), p += 4;
2c2fa1
 	}
2c2fa1
-      bfd_put_32 (obfd, LD_R2_0R11 | PPC_LO (offset + 8), p),	p += 4;
2c2fa1
-      if (plt_static_chain)
2c2fa1
-	bfd_put_32 (obfd, LD_R11_0R11 | PPC_LO (offset + 16), p), p += 4;
2c2fa1
     }
2c2fa1
   else
2c2fa1
     {
2c2fa1
@@ -9867,22 +9903,25 @@ build_plt_stub (struct ppc_link_hash_tab
2c2fa1
 	      || stub_entry->stub_type == ppc_stub_plt_call_r2save)
2c2fa1
 	    r[0].r_offset += 4;
2c2fa1
 	  r[0].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_DS);
2c2fa1
-	  if (PPC_HA (offset + 8 + 8 * plt_static_chain) != PPC_HA (offset))
2c2fa1
+	  if (plt_load_toc)
2c2fa1
 	    {
2c2fa1
-	      r[1].r_offset = r[0].r_offset + 4;
2c2fa1
-	      r[1].r_info = ELF64_R_INFO (0, R_PPC64_TOC16);
2c2fa1
-	      r[1].r_addend = r[0].r_addend;
2c2fa1
-	    }
2c2fa1
-	  else
2c2fa1
-	    {
2c2fa1
-	      r[1].r_offset = r[0].r_offset + 8 + 8 * use_fake_dep;
2c2fa1
-	      r[1].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_DS);
2c2fa1
-	      r[1].r_addend = r[0].r_addend + 8 + 8 * plt_static_chain;
2c2fa1
-	      if (plt_static_chain)
2c2fa1
+	      if (PPC_HA (offset + 8 + 8 * plt_static_chain) != PPC_HA (offset))
2c2fa1
 		{
2c2fa1
-		  r[2].r_offset = r[1].r_offset + 4;
2c2fa1
-		  r[2].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_DS);
2c2fa1
-		  r[2].r_addend = r[0].r_addend + 8;
2c2fa1
+		  r[1].r_offset = r[0].r_offset + 4;
2c2fa1
+		  r[1].r_info = ELF64_R_INFO (0, R_PPC64_TOC16);
2c2fa1
+		  r[1].r_addend = r[0].r_addend;
2c2fa1
+		}
2c2fa1
+	      else
2c2fa1
+		{
2c2fa1
+		  r[1].r_offset = r[0].r_offset + 8 + 8 * use_fake_dep;
2c2fa1
+		  r[1].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_DS);
2c2fa1
+		  r[1].r_addend = r[0].r_addend + 8 + 8 * plt_static_chain;
2c2fa1
+		  if (plt_static_chain)
2c2fa1
+		    {
2c2fa1
+		      r[2].r_offset = r[1].r_offset + 4;
2c2fa1
+		      r[2].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_DS);
2c2fa1
+		      r[2].r_addend = r[0].r_addend + 8;
2c2fa1
+		    }
2c2fa1
 		}
2c2fa1
 	    }
2c2fa1
 	}
2c2fa1
@@ -9890,22 +9929,26 @@ build_plt_stub (struct ppc_link_hash_tab
2c2fa1
 	  || stub_entry->stub_type == ppc_stub_plt_call_r2save)
2c2fa1
 	bfd_put_32 (obfd, STD_R2_40R1, p),			p += 4;
2c2fa1
       bfd_put_32 (obfd, LD_R12_0R2 | PPC_LO (offset), p),	p += 4;
2c2fa1
-      if (PPC_HA (offset + 8 + 8 * plt_static_chain) != PPC_HA (offset))
2c2fa1
+      if (plt_load_toc
2c2fa1
+	  && PPC_HA (offset + 8 + 8 * plt_static_chain) != PPC_HA (offset))
2c2fa1
 	{
2c2fa1
 	  bfd_put_32 (obfd, ADDI_R2_R2 | PPC_LO (offset), p),	p += 4;
2c2fa1
 	  offset = 0;
2c2fa1
 	}
2c2fa1
       bfd_put_32 (obfd, MTCTR_R12, p),				p += 4;
2c2fa1
-      if (use_fake_dep)
2c2fa1
+      if (plt_load_toc)
2c2fa1
 	{
2c2fa1
-	  bfd_put_32 (obfd, XOR_R11_R12_R12, p),		p += 4;
2c2fa1
-	  bfd_put_32 (obfd, ADD_R2_R2_R11, p),			p += 4;
2c2fa1
+	  if (use_fake_dep)
2c2fa1
+	    {
2c2fa1
+	      bfd_put_32 (obfd, XOR_R11_R12_R12, p),		p += 4;
2c2fa1
+	      bfd_put_32 (obfd, ADD_R2_R2_R11, p),		p += 4;
2c2fa1
+	    }
2c2fa1
+	  if (plt_static_chain)
2c2fa1
+	    bfd_put_32 (obfd, LD_R11_0R2 | PPC_LO (offset + 16), p), p += 4;
2c2fa1
+	  bfd_put_32 (obfd, LD_R2_0R2 | PPC_LO (offset + 8), p), p += 4;
2c2fa1
 	}
2c2fa1
-      if (plt_static_chain)
2c2fa1
-	bfd_put_32 (obfd, LD_R11_0R2 | PPC_LO (offset + 16), p), p += 4;
2c2fa1
-      bfd_put_32 (obfd, LD_R2_0R2 | PPC_LO (offset + 8), p),	p += 4;
2c2fa1
     }
2c2fa1
-  if (plt_thread_safe && !use_fake_dep)
2c2fa1
+  if (plt_load_toc && plt_thread_safe && !use_fake_dep)
2c2fa1
     {
2c2fa1
       bfd_put_32 (obfd, CMPLDI_R2_0, p),			p += 4;
2c2fa1
       bfd_put_32 (obfd, BNECTR_P4, p),				p += 4;
2c2fa1
@@ -10004,6 +10047,8 @@ get_r2off (struct bfd_link_info *info,
2c2fa1
       /* Support linking -R objects.  Get the toc pointer from the
2c2fa1
 	 opd entry.  */
2c2fa1
       char buf[8];
2c2fa1
+      if (!htab->opd_abi)
2c2fa1
+	return r2off;
2c2fa1
       asection *opd = stub_entry->h->elf.root.u.def.section;
2c2fa1
       bfd_vma opd_off = stub_entry->h->elf.root.u.def.value;
2c2fa1
 
2c2fa1
@@ -10233,7 +10278,8 @@ ppc_build_one_stub (struct bfd_hash_entr
2c2fa1
 	  r[0].r_offset = loc - stub_entry->stub_sec->contents;
2c2fa1
 	  if (bfd_big_endian (info->output_bfd))
2c2fa1
 	    r[0].r_offset += 2;
2c2fa1
-	  if (stub_entry->stub_type == ppc_stub_plt_branch_r2off)
2c2fa1
+	  if (stub_entry->stub_type == ppc_stub_plt_branch_r2off
2c2fa1
+	      && htab->opd_abi)
2c2fa1
 	    r[0].r_offset += 4;
2c2fa1
 	  r[0].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_DS);
2c2fa1
 	  r[0].r_addend = dest;
2c2fa1
@@ -10246,7 +10292,8 @@ ppc_build_one_stub (struct bfd_hash_entr
2c2fa1
 	    }
2c2fa1
 	}
2c2fa1
 
2c2fa1
-      if (stub_entry->stub_type != ppc_stub_plt_branch_r2off)
2c2fa1
+      if (stub_entry->stub_type != ppc_stub_plt_branch_r2off
2c2fa1
+	  || !htab->opd_abi)
2c2fa1
 	{
2c2fa1
 	  if (PPC_HA (off) != 0)
2c2fa1
 	    {
2c2fa1
@@ -10497,10 +10544,11 @@ ppc_size_one_stub (struct bfd_hash_entry
2c2fa1
       if (info->emitrelocations)
2c2fa1
 	{
2c2fa1
 	  stub_entry->stub_sec->reloc_count
2c2fa1
-	    += (2
2c2fa1
-		+ (PPC_HA (off) != 0)
2c2fa1
-		+ (htab->plt_static_chain
2c2fa1
-		   && PPC_HA (off + 16) == PPC_HA (off)));
2c2fa1
+	    += ((PPC_HA (off) != 0)
2c2fa1
+		+ (htab->opd_abi
2c2fa1
+		   ? 2 + (htab->plt_static_chain
2c2fa1
+			  && PPC_HA (off + 16) == PPC_HA (off))
2c2fa1
+		   : 1));
2c2fa1
 	  stub_entry->stub_sec->flags |= SEC_RELOC;
2c2fa1
 	}
2c2fa1
     }
2c2fa1
@@ -10527,7 +10575,7 @@ ppc_size_one_stub (struct bfd_hash_entry
2c2fa1
       if (stub_entry->stub_type == ppc_stub_long_branch_r2off)
2c2fa1
 	{
2c2fa1
 	  r2off = get_r2off (info, stub_entry);
2c2fa1
-	  if (r2off == 0)
2c2fa1
+	  if (r2off == 0 && htab->opd_abi)
2c2fa1
 	    {
2c2fa1
 	      htab->stub_error = TRUE;
2c2fa1
 	      return FALSE;
2c2fa1
@@ -10540,8 +10588,11 @@ ppc_size_one_stub (struct bfd_hash_entry
2c2fa1
 
2c2fa1
       local_off = PPC64_LOCAL_ENTRY_OFFSET (stub_entry->other);
2c2fa1
 
2c2fa1
-      /* If the branch offset if too big, use a ppc_stub_plt_branch.  */
2c2fa1
-      if (off + (1 << 25) >= (bfd_vma) (1 << 26) - local_off)
2c2fa1
+      /* If the branch offset if too big, use a ppc_stub_plt_branch.
2c2fa1
+	 Do the same for -R objects without function descriptors.  */
2c2fa1
+      if (off + (1 << 25) >= (bfd_vma) (1 << 26) - local_off
2c2fa1
+	  || (stub_entry->stub_type == ppc_stub_long_branch_r2off
2c2fa1
+	      && r2off == 0))
2c2fa1
 	{
2c2fa1
 	  struct ppc_branch_hash_entry *br_entry;
2c2fa1
 
2c2fa1
@@ -10584,7 +10635,8 @@ ppc_size_one_stub (struct bfd_hash_entry
2c2fa1
 	      stub_entry->stub_sec->flags |= SEC_RELOC;
2c2fa1
 	    }
2c2fa1
 
2c2fa1
-	  if (stub_entry->stub_type != ppc_stub_plt_branch_r2off)
2c2fa1
+	  if (stub_entry->stub_type != ppc_stub_plt_branch_r2off
2c2fa1
+	      || !htab->opd_abi)
2c2fa1
 	    {
2c2fa1
 	      size = 12;
2c2fa1
 	      if (PPC_HA (off) != 0)
2c2fa1
@@ -11487,7 +11539,9 @@ ppc64_elf_size_stubs (struct bfd_link_in
2c2fa1
   htab->plt_stub_align = plt_stub_align;
2c2fa1
   if (plt_thread_safe == -1 && !info->executable)
2c2fa1
     plt_thread_safe = 1;
2c2fa1
-  if (plt_thread_safe == -1)
2c2fa1
+  if (!htab->opd_abi)
2c2fa1
+    plt_thread_safe = 0;
2c2fa1
+  else if (plt_thread_safe == -1)
2c2fa1
     {
2c2fa1
       static const char *const thread_starter[] =
2c2fa1
 	{
2c2fa1
@@ -12059,26 +12113,56 @@ ppc64_elf_build_stubs (bfd_boolean emit_
2c2fa1
       plt0 -= htab->glink->output_section->vma + htab->glink->output_offset;
2c2fa1
       bfd_put_64 (htab->glink->owner, plt0, p);
2c2fa1
       p += 8;
2c2fa1
-      bfd_put_32 (htab->glink->owner, MFLR_R12, p);
2c2fa1
-      p += 4;
2c2fa1
-      bfd_put_32 (htab->glink->owner, BCL_20_31, p);
2c2fa1
-      p += 4;
2c2fa1
-      bfd_put_32 (htab->glink->owner, MFLR_R11, p);
2c2fa1
-      p += 4;
2c2fa1
-      bfd_put_32 (htab->glink->owner, LD_R2_0R11 | (-16 & 0xfffc), p);
2c2fa1
-      p += 4;
2c2fa1
-      bfd_put_32 (htab->glink->owner, MTLR_R12, p);
2c2fa1
-      p += 4;
2c2fa1
-      bfd_put_32 (htab->glink->owner, ADD_R11_R2_R11, p);
2c2fa1
-      p += 4;
2c2fa1
-      bfd_put_32 (htab->glink->owner, LD_R12_0R11, p);
2c2fa1
-      p += 4;
2c2fa1
-      bfd_put_32 (htab->glink->owner, LD_R2_0R11 | 8, p);
2c2fa1
-      p += 4;
2c2fa1
-      bfd_put_32 (htab->glink->owner, MTCTR_R12, p);
2c2fa1
-      p += 4;
2c2fa1
-      bfd_put_32 (htab->glink->owner, LD_R11_0R11 | 16, p);
2c2fa1
-      p += 4;
2c2fa1
+      if (htab->opd_abi)
2c2fa1
+	{
2c2fa1
+	  bfd_put_32 (htab->glink->owner, MFLR_R12, p);
2c2fa1
+	  p += 4;
2c2fa1
+	  bfd_put_32 (htab->glink->owner, BCL_20_31, p);
2c2fa1
+	  p += 4;
2c2fa1
+	  bfd_put_32 (htab->glink->owner, MFLR_R11, p);
2c2fa1
+	  p += 4;
2c2fa1
+	  bfd_put_32 (htab->glink->owner, LD_R2_0R11 | (-16 & 0xfffc), p);
2c2fa1
+	  p += 4;
2c2fa1
+	  bfd_put_32 (htab->glink->owner, MTLR_R12, p);
2c2fa1
+	  p += 4;
2c2fa1
+	  bfd_put_32 (htab->glink->owner, ADD_R11_R2_R11, p);
2c2fa1
+	  p += 4;
2c2fa1
+	  bfd_put_32 (htab->glink->owner, LD_R12_0R11, p);
2c2fa1
+	  p += 4;
2c2fa1
+	  bfd_put_32 (htab->glink->owner, LD_R2_0R11 | 8, p);
2c2fa1
+	  p += 4;
2c2fa1
+	  bfd_put_32 (htab->glink->owner, MTCTR_R12, p);
2c2fa1
+	  p += 4;
2c2fa1
+	  bfd_put_32 (htab->glink->owner, LD_R11_0R11 | 16, p);
2c2fa1
+	  p += 4;
2c2fa1
+	}
2c2fa1
+      else
2c2fa1
+	{
2c2fa1
+	  bfd_put_32 (htab->glink->owner, MFLR_R0, p);
2c2fa1
+	  p += 4;
2c2fa1
+	  bfd_put_32 (htab->glink->owner, BCL_20_31, p);
2c2fa1
+	  p += 4;
2c2fa1
+	  bfd_put_32 (htab->glink->owner, MFLR_R11, p);
2c2fa1
+	  p += 4;
2c2fa1
+	  bfd_put_32 (htab->glink->owner, LD_R2_0R11 | (-16 & 0xfffc), p);
2c2fa1
+	  p += 4;
2c2fa1
+	  bfd_put_32 (htab->glink->owner, MTLR_R0, p);
2c2fa1
+	  p += 4;
2c2fa1
+	  bfd_put_32 (htab->glink->owner, SUB_R12_R12_R11, p);
2c2fa1
+	  p += 4;
2c2fa1
+	  bfd_put_32 (htab->glink->owner, ADD_R11_R2_R11, p);
2c2fa1
+	  p += 4;
2c2fa1
+	  bfd_put_32 (htab->glink->owner, ADDI_R0_R12 | (-48 & 0xffff), p);
2c2fa1
+	  p += 4;
2c2fa1
+	  bfd_put_32 (htab->glink->owner, LD_R12_0R11, p);
2c2fa1
+	  p += 4;
2c2fa1
+	  bfd_put_32 (htab->glink->owner, SRDI_R0_R0_2, p);
2c2fa1
+	  p += 4;
2c2fa1
+	  bfd_put_32 (htab->glink->owner, MTCTR_R12, p);
2c2fa1
+	  p += 4;
2c2fa1
+	  bfd_put_32 (htab->glink->owner, LD_R11_0R11 | 8, p);
2c2fa1
+	  p += 4;
2c2fa1
+	}
2c2fa1
       bfd_put_32 (htab->glink->owner, BCTR, p);
2c2fa1
       p += 4;
2c2fa1
       while (p - htab->glink->contents < GLINK_CALL_STUB_SIZE)
2c2fa1
@@ -12091,17 +12175,21 @@ ppc64_elf_build_stubs (bfd_boolean emit_
2c2fa1
       indx = 0;
2c2fa1
       while (p < htab->glink->contents + htab->glink->size)
2c2fa1
 	{
2c2fa1
-	  if (indx < 0x8000)
2c2fa1
-	    {
2c2fa1
-	      bfd_put_32 (htab->glink->owner, LI_R0_0 | indx, p);
2c2fa1
-	      p += 4;
2c2fa1
-	    }
2c2fa1
-	  else
2c2fa1
+	  if (htab->opd_abi)
2c2fa1
 	    {
2c2fa1
-	      bfd_put_32 (htab->glink->owner, LIS_R0_0 | PPC_HI (indx), p);
2c2fa1
-	      p += 4;
2c2fa1
-	      bfd_put_32 (htab->glink->owner, ORI_R0_R0_0 | PPC_LO (indx), p);
2c2fa1
-	      p += 4;
2c2fa1
+	      if (indx < 0x8000)
2c2fa1
+		{
2c2fa1
+		  bfd_put_32 (htab->glink->owner, LI_R0_0 | indx, p);
2c2fa1
+		  p += 4;
2c2fa1
+		}
2c2fa1
+	      else
2c2fa1
+		{
2c2fa1
+		  bfd_put_32 (htab->glink->owner, LIS_R0_0 | PPC_HI (indx), p);
2c2fa1
+		  p += 4;
2c2fa1
+		  bfd_put_32 (htab->glink->owner, ORI_R0_R0_0 | PPC_LO (indx),
2c2fa1
+			      p);
2c2fa1
+		  p += 4;
2c2fa1
+		}
2c2fa1
 	    }
2c2fa1
 	  bfd_put_32 (htab->glink->owner,
2c2fa1
 		      B_DOT | ((htab->glink->contents - p + 8) & 0x3fffffc), p);
2c2fa1
@@ -14192,8 +14280,8 @@ ppc64_elf_finish_dynamic_symbol (bfd *ou
2c2fa1
 	    rela.r_info = ELF64_R_INFO (h->dynindx, R_PPC64_JMP_SLOT);
2c2fa1
 	    rela.r_addend = ent->addend;
2c2fa1
 	    loc = (htab->relplt->contents
2c2fa1
-		   + ((ent->plt.offset - PLT_INITIAL_ENTRY_SIZE)
2c2fa1
-		      / (PLT_ENTRY_SIZE / sizeof (Elf64_External_Rela))));
2c2fa1
+		   + ((ent->plt.offset - PLT_INITIAL_ENTRY_SIZE (htab))
2c2fa1
+		      / PLT_ENTRY_SIZE (htab) * sizeof (Elf64_External_Rela)));
2c2fa1
 	  }
2c2fa1
 	bfd_elf64_swap_reloca_out (output_bfd, &rela, loc);
2c2fa1
       }
2c2fa1
@@ -14288,7 +14376,7 @@ ppc64_elf_finish_dynamic_sections (bfd *
2c2fa1
 		 of glink rather than the first entry point, which is
2c2fa1
 		 what ld.so needs, and now have a bigger stub to
2c2fa1
 		 support automatic multiple TOCs.  */
2c2fa1
-	      dyn.d_un.d_ptr += GLINK_CALL_STUB_SIZE - 32;
2c2fa1
+	      dyn.d_un.d_ptr += GLINK_CALL_STUB_SIZE - 8 * 4;
2c2fa1
 	      break;
2c2fa1
 
2c2fa1
 	    case DT_PPC64_OPD:
2c2fa1
@@ -14361,7 +14449,7 @@ ppc64_elf_finish_dynamic_sections (bfd *
2c2fa1
     {
2c2fa1
       /* Set .plt entry size.  */
2c2fa1
       elf_section_data (htab->plt->output_section)->this_hdr.sh_entsize
2c2fa1
-	= PLT_ENTRY_SIZE;
2c2fa1
+	= PLT_ENTRY_SIZE (htab);
2c2fa1
     }
2c2fa1
 
2c2fa1
   /* brlt is SEC_LINKER_CREATED, so we need to write out relocs for