PowerPC64 GOT_PCREL relocs

Alan Modra amodra@gmail.com
Thu Sep 5 06:21:00 GMT 2019


PC-relative relocs typically use the addend in adjusting what they are
relative to.  For example:
	bcl 20,31,1f
1:	mflr 12
	addi 12,12,xxx-1b
generates "R_PPC64_REL16 xxx+0x4" for the addi (when little-endian).
The addend reflects the fact that you want the offset relative to the
previous insn not the current one in this case.

So the question is, will we ever want to do something like that for an
instruction using R_PPC64_GOT_PCREL34?  I thought so at the time I
first implemented support in ld but at the time I think the hardware
was possibly going to support pcrel+offset+reg addressing.  In which
case you might want something like:
	load_big_offset_into_r2
	pld 3,sym-big_offset@got@pcrel(2)
which would be a way of supporting more than 8G offsets from code to
the GOT.  We could do the same with
	load_big_offset_into_r2
	pla 9,sym-big_offset@got@pcrel
	ldx 3,9,2
However, this is really a poor version of TOC-pointer relative code.

So let's go with an addend on R_PPC64_GOT_PCREL34 meaning that
sym+addend should be put in a GOT entry, and the relocation calculate
the pc-relative offset to that GOT entry.

Note that this is an extension to the ABI, which says (by the
expression given for GOT relocs) that non-zero addends on GOT and PLT
relocs are ignored.  This is true for all GOT/PLT relocs, not just the
pcrel ones.

	* elf64-ppc.c (ppc64_elf_check_relocs): Interpret an addend in
	GOT_PCREL and PLT_PCREL relocs as affecting the value stored
	in the GOT/PLT entry rather than affecting the offset to that
	GOI/PLT entry.
	(ppc64_elf_edit_toc, ppc64_elf_relocate_section): Likewise.

diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c
index e39b6faf17..88ace7e6fe 100644
--- a/bfd/elf64-ppc.c
+++ b/bfd/elf64-ppc.c
@@ -4524,7 +4524,6 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
       int tls_type;
       struct _ppc64_elf_section_data *ppc64_sec;
       struct plt_entry **ifunc, **plt_list;
-      bfd_vma sym_addend;
 
       r_symndx = ELF64_R_SYM (rel->r_info);
       if (r_symndx < symtab_hdr->sh_info)
@@ -4550,18 +4549,6 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
 	case R_PPC64_D28:
 	case R_PPC64_TPREL34:
 	case R_PPC64_DTPREL34:
-	  htab->powerxx_stubs = 1;
-	  /* Fall through.  */
-	default:
-	  /* Somewhat foolishly, because the ABIs don't specifically
-	     allow it, ppc64 gas and ld support GOT and PLT relocs
-	     with non-zero addends where the addend results in
-	     sym+addend being stored in the GOT or PLT entry.  This
-	     can't be supported for pcrel relocs because the addend is
-	     used to specify the pcrel offset.  */
-	  sym_addend = rel->r_addend;
-	  break;
-
 	case R_PPC64_PCREL34:
 	case R_PPC64_GOT_PCREL34:
 	case R_PPC64_GOT_TLSGD34:
@@ -4572,7 +4559,8 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
 	case R_PPC64_PLT_PCREL34_NOTOC:
 	case R_PPC64_PCREL28:
 	  htab->powerxx_stubs = 1;
-	  sym_addend = 0;
+	  break;
+	default:
 	  break;
 	}
 
@@ -4621,7 +4609,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
 	  if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC)
 	    {
 	      ifunc = update_local_sym_info (abfd, symtab_hdr, r_symndx,
-					     sym_addend,
+					     rel->r_addend,
 					     NON_GOT | PLT_IFUNC);
 	      if (ifunc == NULL)
 		return FALSE;
@@ -4638,7 +4626,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
 	    ((struct ppc_link_hash_entry *) h)->tls_mask |= TLS_TLS | TLS_MARK;
 	  else
 	    if (!update_local_sym_info (abfd, symtab_hdr, r_symndx,
-					sym_addend,
+					rel->r_addend,
 					NON_GOT | TLS_TLS | TLS_MARK))
 	      return FALSE;
 	  sec->has_tls_reloc = 1;
@@ -4712,7 +4700,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
 
 	      eh = (struct ppc_link_hash_entry *) h;
 	      for (ent = eh->elf.got.glist; ent != NULL; ent = ent->next)
-		if (ent->addend == sym_addend
+		if (ent->addend == rel->r_addend
 		    && ent->owner == abfd
 		    && ent->tls_type == tls_type)
 		  break;
@@ -4723,7 +4711,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
 		  if (ent == NULL)
 		    return FALSE;
 		  ent->next = eh->elf.got.glist;
-		  ent->addend = sym_addend;
+		  ent->addend = rel->r_addend;
 		  ent->owner = abfd;
 		  ent->tls_type = tls_type;
 		  ent->is_indirect = FALSE;
@@ -4736,14 +4724,14 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
 	  else
 	    /* This is a global offset table entry for a local symbol.  */
 	    if (!update_local_sym_info (abfd, symtab_hdr, r_symndx,
-					sym_addend, tls_type))
+					rel->r_addend, tls_type))
 	      return FALSE;
 
 	  /* We may also need a plt entry if the symbol turns out to be
 	     an ifunc.  */
 	  if (h != NULL && !bfd_link_pic (info) && abiversion (abfd) != 1)
 	    {
-	      if (!update_plt_info (abfd, &h->plt.plist, sym_addend))
+	      if (!update_plt_info (abfd, &h->plt.plist, rel->r_addend))
 		return FALSE;
 	    }
 	  break;
@@ -4769,9 +4757,9 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
 	    }
 	  if (plt_list == NULL)
 	    plt_list = update_local_sym_info (abfd, symtab_hdr, r_symndx,
-					      sym_addend,
+					      rel->r_addend,
 					      NON_GOT | PLT_KEEP);
-	  if (!update_plt_info (abfd, plt_list, sym_addend))
+	  if (!update_plt_info (abfd, plt_list, rel->r_addend))
 	    return FALSE;
 	  break;
 
@@ -4929,7 +4917,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
 	  /* We may need a .plt entry if the function this reloc
 	     refers to is in a shared lib.  */
 	  if (plt_list
-	      && !update_plt_info (abfd, plt_list, sym_addend))
+	      && !update_plt_info (abfd, plt_list, rel->r_addend))
 	    return FALSE;
 	  break;
 
@@ -4973,7 +4961,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
 	    }
 	  else
 	    if (!update_local_sym_info (abfd, symtab_hdr, r_symndx,
-					sym_addend, tls_type))
+					rel->r_addend, tls_type))
 	      return FALSE;
 
 	  ppc64_sec = ppc64_elf_section_data (sec);
@@ -4995,7 +4983,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
 	    }
 	  BFD_ASSERT (rel->r_offset % 8 == 0);
 	  ppc64_sec->u.toc.symndx[rel->r_offset / 8] = r_symndx;
-	  ppc64_sec->u.toc.add[rel->r_offset / 8] = sym_addend;
+	  ppc64_sec->u.toc.add[rel->r_offset / 8] = rel->r_addend;
 
 	  /* Mark the second slot of a GD or LD entry.
 	     -1 to indicate GD and -2 to indicate LD.  */
@@ -9044,7 +9032,7 @@ ppc64_elf_edit_toc (struct bfd_link_info *info)
 	      asection *sym_sec;
 	      struct elf_link_hash_entry *h;
 	      struct got_entry *ent;
-	      bfd_vma sym_addend, val, pc;
+	      bfd_vma val, pc;
 	      unsigned char buf[8];
 	      unsigned int insn;
 	      enum {no_check, check_lo, check_ha} insn_check;
@@ -9119,11 +9107,7 @@ ppc64_elf_edit_toc (struct bfd_link_info *info)
 
 		case R_PPC64_GOT16_HA:
 		case R_PPC64_GOT16_LO_DS:
-		  sym_addend = rel->r_addend;
-		  break;
-
 		case R_PPC64_GOT_PCREL34:
-		  sym_addend = 0;
 		  break;
 		}
 
@@ -9144,7 +9128,7 @@ ppc64_elf_edit_toc (struct bfd_link_info *info)
 		val = h->root.u.def.value;
 	      else
 		val = sym->st_value;
-	      val += sym_addend;
+	      val += rel->r_addend;
 	      val += sym_sec->output_section->vma + sym_sec->output_offset;
 
 /* Fudge factor to allow for the fact that the preliminary layout
@@ -9209,7 +9193,7 @@ ppc64_elf_edit_toc (struct bfd_link_info *info)
 		  ent = local_got_ents[r_symndx];
 		}
 	      for (; ent != NULL; ent = ent->next)
-		if (ent->addend == sym_addend
+		if (ent->addend == rel->r_addend
 		    && ent->owner == ibfd
 		    && ent->tls_type == 0)
 		  break;
@@ -15535,14 +15519,6 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 	    bfd_vma off;
 	    unsigned long indx = 0;
 	    struct got_entry *ent;
-	    bfd_vma sym_addend = orig_rel.r_addend;
-
-	    if (r_type == R_PPC64_GOT_PCREL34
-		|| r_type == R_PPC64_GOT_TLSGD34
-		|| r_type == R_PPC64_GOT_TLSLD34
-		|| r_type == R_PPC64_GOT_TPREL34
-		|| r_type == R_PPC64_GOT_DTPREL34)
-	      sym_addend = 0;
 
 	    if (tls_type == (TLS_TLS | TLS_LD)
 		&& (h == NULL
@@ -15576,7 +15552,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 		  }
 
 		for (; ent != NULL; ent = ent->next)
-		  if (ent->addend == sym_addend
+		  if (ent->addend == orig_rel.r_addend
 		      && ent->owner == input_bfd
 		      && ent->tls_type == tls_type)
 		    break;
@@ -15633,7 +15609,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 		    outrel.r_offset = (got->output_section->vma
 				       + got->output_offset
 				       + off);
-		    outrel.r_addend = sym_addend;
+		    outrel.r_addend = orig_rel.r_addend;
 		    if (tls_type & (TLS_LD | TLS_GD))
 		      {
 			outrel.r_addend = 0;
@@ -15646,7 +15622,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 			    bfd_elf64_swap_reloca_out (output_bfd,
 						       &outrel, loc);
 			    outrel.r_offset += 8;
-			    outrel.r_addend = sym_addend;
+			    outrel.r_addend = orig_rel.r_addend;
 			    outrel.r_info
 			      = ELF64_R_INFO (indx, R_PPC64_DTPREL64);
 			  }
@@ -15692,7 +15668,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 		   emitting a reloc.  */
 		else
 		  {
-		    relocation += sym_addend;
+		    relocation += orig_rel.r_addend;
 		    if (tls_type != 0)
 		      {
 			if (htab->elf.tls_sec == NULL)
@@ -15723,6 +15699,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 	      abort ();
 
 	    relocation = got->output_section->vma + got->output_offset + off;
+	    addend = 0;
 	    if (!(r_type == R_PPC64_GOT_PCREL34
 		  || r_type == R_PPC64_GOT_TLSGD34
 		  || r_type == R_PPC64_GOT_TLSLD34
@@ -15760,15 +15737,10 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 	    if (plt_list)
 	      {
 		struct plt_entry *ent;
-		bfd_vma sym_addend = orig_rel.r_addend;
-
-		if (r_type == R_PPC64_PLT_PCREL34
-		    || r_type == R_PPC64_PLT_PCREL34_NOTOC)
-		  sym_addend = 0;
 
 		for (ent = *plt_list; ent != NULL; ent = ent->next)
 		  if (ent->plt.offset != (bfd_vma) -1
-		      && ent->addend == sym_addend)
+		      && ent->addend == orig_rel.r_addend)
 		    {
 		      asection *plt;
 		      bfd_vma got;
@@ -15797,9 +15769,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 				 + htab->sec_info[input_section->id].toc_off);
 			  relocation -= got;
 			}
-		      if (r_type != R_PPC64_PLT_PCREL34
-			  && r_type != R_PPC64_PLT_PCREL34_NOTOC)
-			addend = 0;
+		      addend = 0;
 		      unresolved_reloc = FALSE;
 		      break;
 		    }

-- 
Alan Modra
Australia Development Lab, IBM



More information about the Binutils mailing list