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

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