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

2c2fa1
commit 6911b7dcb8ea17f8b811578dd4ac1ab7bb675e7b
2c2fa1
Author: Alan Modra <amodra@gmail.com>
2c2fa1
Date:   Tue Oct 29 15:37:43 2013 +1030
2c2fa1
2c2fa1
    Add ELFv2 .localentry support.
2c2fa1
    
2c2fa1
    This defines the ELF symbol st_other field used to encode the number
2c2fa1
    of instructions between a function "global entry" and its "local entry",
2c2fa1
    and adds support related to the local entry offset.
2c2fa1
    
2c2fa1
    include/elf/
2c2fa1
    	* ppc64.h (STO_PPC64_LOCAL_BIT, STO_PPC64_LOCAL_MASK): Define.
2c2fa1
    	(ppc64_decode_local_entry, ppc64_encode_local_entry): New functions.
2c2fa1
    	(PPC64_LOCAL_ENTRY_OFFSET, PPC64_SET_LOCAL_ENTRY_OFFSET): Define.
2c2fa1
    bfd/
2c2fa1
    	* elf64-ppc.c (struct ppc_stub_hash_entry): Add "other".
2c2fa1
    	(stub_hash_newfunc): Init new ppc_stub_hash_entry field, and one
2c2fa1
    	we forgot, "plt_ent".
2c2fa1
    	(ppc64_elf_add_symbol_hook): Check ELFv1 objects don't have
2c2fa1
    	st_other bits only valid in ELFv2.
2c2fa1
    	(ppc64_elf_merge_symbol_attribute): New function.
2c2fa1
    	(ppc_type_of_stub): Add local_off param to test branch range.
2c2fa1
    	(ppc_build_one_stub): Adjust destinations for ELFv2 locals.
2c2fa1
    	(ppc_size_one_stub, toc_adjusting_stub_needed): Similarly.
2c2fa1
    	(ppc64_elf_size_stubs): Pass local_off to ppc_type_of_stub.
2c2fa1
    	Set "other" field.
2c2fa1
    	(ppc64_elf_relocate_section): Adjust destination for ELFv2 local
2c2fa1
    	calls.
2c2fa1
    gas/
2c2fa1
    	* config/tc-ppc.c (md_pseudo_table): Add .localentry.
2c2fa1
    	(ppc_elf_localentry): New function.
2c2fa1
    	(ppc_force_relocation): Force relocs on all branches to localenty
2c2fa1
    	symbols.
2c2fa1
    	(ppc_fix_adjustable): Don't reduce such symbols to section+offset.
2c2fa1
    binutils/
2c2fa1
    	* readelf.c (get_ppc64_symbol_other): New function.
2c2fa1
    	(get_symbol_other): Use it for EM_PPC64.
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
@@ -118,6 +118,7 @@ static bfd_vma opd_entry_value
2c2fa1
 #define elf_backend_link_output_symbol_hook   ppc64_elf_output_symbol_hook
2c2fa1
 #define elf_backend_special_sections	      ppc64_elf_special_sections
2c2fa1
 #define elf_backend_post_process_headers      _bfd_elf_set_osabi
2c2fa1
+#define elf_backend_merge_symbol_attribute    ppc64_elf_merge_symbol_attribute
2c2fa1
 
2c2fa1
 /* The name of the dynamic interpreter.  This is put in the .interp
2c2fa1
    section.  */
2c2fa1
@@ -3640,6 +3641,9 @@ struct ppc_stub_hash_entry {
2c2fa1
   /* Where this stub is being called from, or, in the case of combined
2c2fa1
      stub sections, the first input section in the group.  */
2c2fa1
   asection *id_sec;
2c2fa1
+
2c2fa1
+  /* Symbol st_other.  */
2c2fa1
+  unsigned char other;
2c2fa1
 };
2c2fa1
 
2c2fa1
 struct ppc_branch_hash_entry {
2c2fa1
@@ -3886,7 +3890,9 @@ stub_hash_newfunc (struct bfd_hash_entry
2c2fa1
       eh->target_value = 0;
2c2fa1
       eh->target_section = NULL;
2c2fa1
       eh->h = NULL;
2c2fa1
+      eh->plt_ent = NULL;
2c2fa1
       eh->id_sec = NULL;
2c2fa1
+      eh->other = 0;
2c2fa1
     }
2c2fa1
 
2c2fa1
   return entry;
2c2fa1
@@ -4629,7 +4635,7 @@ static bfd_boolean
2c2fa1
 ppc64_elf_add_symbol_hook (bfd *ibfd,
2c2fa1
 			   struct bfd_link_info *info,
2c2fa1
 			   Elf_Internal_Sym *isym,
2c2fa1
-			   const char **name ATTRIBUTE_UNUSED,
2c2fa1
+			   const char **name,
2c2fa1
 			   flagword *flags ATTRIBUTE_UNUSED,
2c2fa1
 			   asection **sec,
2c2fa1
 			   bfd_vma *value ATTRIBUTE_UNUSED)
2c2fa1
@@ -4649,9 +4655,35 @@ ppc64_elf_add_symbol_hook (bfd *ibfd,
2c2fa1
 	   && strcmp ((*sec)->name, ".opd") == 0)
2c2fa1
     isym->st_info = ELF_ST_INFO (ELF_ST_BIND (isym->st_info), STT_FUNC);
2c2fa1
 
2c2fa1
+  if ((STO_PPC64_LOCAL_MASK & isym->st_other) != 0)
2c2fa1
+    {
2c2fa1
+      if (abiversion (ibfd) == 0)
2c2fa1
+	set_abiversion (ibfd, 2);
2c2fa1
+      else if (abiversion (ibfd) == 1)
2c2fa1
+	{
2c2fa1
+	  info->callbacks->einfo (_("%P: symbol '%s' has invalid st_other"
2c2fa1
+				    " for ABI version 1\n"), name);
2c2fa1
+	  bfd_set_error (bfd_error_bad_value);
2c2fa1
+	  return FALSE;
2c2fa1
+	}
2c2fa1
+    }
2c2fa1
+
2c2fa1
   return TRUE;
2c2fa1
 }
2c2fa1
 
2c2fa1
+/* Merge non-visibility st_other attributes: local entry point.  */
2c2fa1
+
2c2fa1
+static void
2c2fa1
+ppc64_elf_merge_symbol_attribute (struct elf_link_hash_entry *h,
2c2fa1
+				  const Elf_Internal_Sym *isym,
2c2fa1
+				  bfd_boolean definition,
2c2fa1
+				  bfd_boolean dynamic)
2c2fa1
+{
2c2fa1
+  if (definition && !dynamic)
2c2fa1
+    h->other = ((isym->st_other & ~ELF_ST_VISIBILITY (-1))
2c2fa1
+		| ELF_ST_VISIBILITY (h->other));
2c2fa1
+}
2c2fa1
+
2c2fa1
 /* This function makes an old ABI object reference to ".bar" cause the
2c2fa1
    inclusion of a new ABI object archive that defines "bar".
2c2fa1
    NAME is a symbol defined in an archive.  Return a symbol in the hash
2c2fa1
@@ -9586,7 +9618,8 @@ ppc_type_of_stub (asection *input_sec,
2c2fa1
 		  const Elf_Internal_Rela *rel,
2c2fa1
 		  struct ppc_link_hash_entry **hash,
2c2fa1
 		  struct plt_entry **plt_ent,
2c2fa1
-		  bfd_vma destination)
2c2fa1
+		  bfd_vma destination,
2c2fa1
+		  unsigned long local_off)
2c2fa1
 {
2c2fa1
   struct ppc_link_hash_entry *h = *hash;
2c2fa1
   bfd_vma location;
2c2fa1
@@ -9655,7 +9688,7 @@ ppc_type_of_stub (asection *input_sec,
2c2fa1
   if (r_type != R_PPC64_REL24)
2c2fa1
     max_branch_offset = 1 << 15;
2c2fa1
 
2c2fa1
-  if (branch_offset + max_branch_offset >= 2 * max_branch_offset)
2c2fa1
+  if (branch_offset + max_branch_offset >= 2 * max_branch_offset - local_off)
2c2fa1
     /* We need a stub.  Figure out whether a long_branch or plt_branch
2c2fa1
        is needed later.  */
2c2fa1
     return ppc_stub_long_branch;
2c2fa1
@@ -10023,9 +10056,11 @@ ppc_build_one_stub (struct bfd_hash_entr
2c2fa1
     case ppc_stub_long_branch:
2c2fa1
     case ppc_stub_long_branch_r2off:
2c2fa1
       /* Branches are relative.  This is where we are going to.  */
2c2fa1
-      off = dest = (stub_entry->target_value
2c2fa1
-		    + stub_entry->target_section->output_offset
2c2fa1
-		    + stub_entry->target_section->output_section->vma);
2c2fa1
+      dest = (stub_entry->target_value
2c2fa1
+	      + stub_entry->target_section->output_offset
2c2fa1
+	      + stub_entry->target_section->output_section->vma);
2c2fa1
+      dest += PPC64_LOCAL_ENTRY_OFFSET (stub_entry->other);
2c2fa1
+      off = dest;
2c2fa1
 
2c2fa1
       /* And this is where we are coming from.  */
2c2fa1
       off -= (stub_entry->stub_offset
2c2fa1
@@ -10128,6 +10163,8 @@ ppc_build_one_stub (struct bfd_hash_entr
2c2fa1
       dest = (stub_entry->target_value
2c2fa1
 	      + stub_entry->target_section->output_offset
2c2fa1
 	      + stub_entry->target_section->output_section->vma);
2c2fa1
+      if (stub_entry->stub_type != ppc_stub_plt_branch_r2off)
2c2fa1
+	dest += PPC64_LOCAL_ENTRY_OFFSET (stub_entry->other);
2c2fa1
 
2c2fa1
       bfd_put_64 (htab->brlt->owner, dest,
2c2fa1
 		  htab->brlt->contents + br_entry->offset);
2c2fa1
@@ -10472,6 +10509,7 @@ ppc_size_one_stub (struct bfd_hash_entry
2c2fa1
       /* ppc_stub_long_branch or ppc_stub_plt_branch, or their r2off
2c2fa1
 	 variants.  */
2c2fa1
       bfd_vma r2off = 0;
2c2fa1
+      bfd_vma local_off = 0;
2c2fa1
 
2c2fa1
       off = (stub_entry->target_value
2c2fa1
 	     + stub_entry->target_section->output_offset
2c2fa1
@@ -10500,8 +10538,10 @@ ppc_size_one_stub (struct bfd_hash_entry
2c2fa1
 	  off -= size - 4;
2c2fa1
 	}
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))
2c2fa1
+      if (off + (1 << 25) >= (bfd_vma) (1 << 26) - local_off)
2c2fa1
 	{
2c2fa1
 	  struct ppc_branch_hash_entry *br_entry;
2c2fa1
 
2c2fa1
@@ -11097,7 +11137,10 @@ toc_adjusting_stub_needed (struct bfd_li
2c2fa1
 	     need a plt_branch stub.  A plt_branch stub uses r2.  */
2c2fa1
 	  else if (dest - (isec->output_offset
2c2fa1
 			   + isec->output_section->vma
2c2fa1
-			   + rel->r_offset) + (1 << 25) >= (2 << 25))
2c2fa1
+			   + rel->r_offset) + (1 << 25)
2c2fa1
+		   >= (2u << 25) - PPC64_LOCAL_ENTRY_OFFSET (h
2c2fa1
+							     ? h->other
2c2fa1
+							     : sym->st_other))
2c2fa1
 	    {
2c2fa1
 	      ret = 1;
2c2fa1
 	      break;
2c2fa1
@@ -11553,6 +11596,7 @@ ppc64_elf_size_stubs (struct bfd_link_in
2c2fa1
 		  asection *sym_sec, *code_sec;
2c2fa1
 		  bfd_vma sym_value, code_value;
2c2fa1
 		  bfd_vma destination;
2c2fa1
+		  unsigned long local_off;
2c2fa1
 		  bfd_boolean ok_dest;
2c2fa1
 		  struct ppc_link_hash_entry *hash;
2c2fa1
 		  struct ppc_link_hash_entry *fdh;
2c2fa1
@@ -11629,12 +11673,16 @@ ppc64_elf_size_stubs (struct bfd_link_in
2c2fa1
 		    }
2c2fa1
 
2c2fa1
 		  destination = 0;
2c2fa1
+		  local_off = 0;
2c2fa1
 		  if (ok_dest)
2c2fa1
 		    {
2c2fa1
 		      sym_value += irela->r_addend;
2c2fa1
 		      destination = (sym_value
2c2fa1
 				     + sym_sec->output_offset
2c2fa1
 				     + sym_sec->output_section->vma);
2c2fa1
+		      local_off = PPC64_LOCAL_ENTRY_OFFSET (hash
2c2fa1
+							    ? hash->elf.other
2c2fa1
+							    : sym->st_other);
2c2fa1
 		    }
2c2fa1
 
2c2fa1
 		  code_sec = sym_sec;
2c2fa1
@@ -11671,7 +11719,8 @@ ppc64_elf_size_stubs (struct bfd_link_in
2c2fa1
 		  /* Determine what (if any) linker stub is needed.  */
2c2fa1
 		  plt_ent = NULL;
2c2fa1
 		  stub_type = ppc_type_of_stub (section, irela, &hash,
2c2fa1
-						&plt_ent, destination);
2c2fa1
+						&plt_ent, destination,
2c2fa1
+						local_off);
2c2fa1
 
2c2fa1
 		  if (stub_type != ppc_stub_plt_call)
2c2fa1
 		    {
2c2fa1
@@ -11771,6 +11820,7 @@ ppc64_elf_size_stubs (struct bfd_link_in
2c2fa1
 		    }
2c2fa1
 		  stub_entry->h = hash;
2c2fa1
 		  stub_entry->plt_ent = plt_ent;
2c2fa1
+		  stub_entry->other = hash ? hash->elf.other : sym->st_other;
2c2fa1
 		  stub_entry->addend = irela->r_addend;
2c2fa1
 
2c2fa1
 		  if (stub_entry->h != NULL)
2c2fa1
@@ -13105,6 +13155,10 @@ ppc64_elf_relocate_section (bfd *output_
2c2fa1
 		  + input_section->output_offset
2c2fa1
 		  + input_section->output_section->vma);
2c2fa1
 
2c2fa1
+	  relocation += PPC64_LOCAL_ENTRY_OFFSET (fdh
2c2fa1
+						  ? fdh->elf.other
2c2fa1
+						  : sym->st_other);
2c2fa1
+
2c2fa1
 	  if (stub_entry != NULL
2c2fa1
 	      && (stub_entry->stub_type == ppc_stub_long_branch
2c2fa1
 		  || stub_entry->stub_type == ppc_stub_plt_branch)
2c2fa1
Index: gdb-7.6.1/include/elf/ppc64.h
2c2fa1
===================================================================
2c2fa1
--- gdb-7.6.1.orig/include/elf/ppc64.h
2c2fa1
+++ gdb-7.6.1/include/elf/ppc64.h
2c2fa1
@@ -171,6 +171,53 @@ END_RELOC_NUMBERS (R_PPC64_max)
2c2fa1
    0 for unspecified or not using any features affected by the differences.  */
2c2fa1
 #define EF_PPC64_ABI	3
2c2fa1
 
2c2fa1
+/* The ELFv2 ABI uses three bits in the symbol st_other field of a
2c2fa1
+   function definition to specify the number of instructions between a
2c2fa1
+   function's global entry point and local entry point.
2c2fa1
+   The global entry point is used when it is necessary to set up the
2c2fa1
+   toc pointer (r2) for the function.  Callers must enter the global
2c2fa1
+   entry point with r12 set to the global entry point address.  On
2c2fa1
+   return from the function, r2 may have a different value to that
2c2fa1
+   which it had on entry.
2c2fa1
+   The local entry point is used when r2 is known to already be valid
2c2fa1
+   for the function.  There is no requirement on r12 when using the
2c2fa1
+   local entry point, and on return r2 will contain the same value as
2c2fa1
+   at entry.
2c2fa1
+   A value of zero in these bits means that the function has a single
2c2fa1
+   entry point with no requirement on r12 or r2, and that on return r2
2c2fa1
+   will contain the same value as at entry.
2c2fa1
+   Values of one and seven are reserved.  */
2c2fa1
+#define STO_PPC64_LOCAL_BIT		5
2c2fa1
+#define STO_PPC64_LOCAL_MASK		(7 << STO_PPC64_LOCAL_BIT)
2c2fa1
+
2c2fa1
+// 3 bit other field to bytes.
2c2fa1
+static inline unsigned int
2c2fa1
+ppc64_decode_local_entry(unsigned int other)
2c2fa1
+{
2c2fa1
+  return ((1 << other) >> 2) << 2;
2c2fa1
+}
2c2fa1
+
2c2fa1
+// bytes to field value.
2c2fa1
+static inline unsigned int
2c2fa1
+ppc64_encode_local_entry(unsigned int val)
2c2fa1
+{
2c2fa1
+  return (val >= 4 * 4
2c2fa1
+	  ? (val >= 8 * 4
2c2fa1
+	     ? (val >= 16 * 4 ? 6 : 5)
2c2fa1
+	     : 4)
2c2fa1
+	  : (val >= 2 * 4
2c2fa1
+	     ? 3
2c2fa1
+	     : (val >= 1 * 4 ? 2 : 0)));
2c2fa1
+}
2c2fa1
+
2c2fa1
+/* st_other to number of bytes.  */
2c2fa1
+#define PPC64_LOCAL_ENTRY_OFFSET(other)				\
2c2fa1
+  ppc64_decode_local_entry (((other) & STO_PPC64_LOCAL_MASK)	\
2c2fa1
+			    >> STO_PPC64_LOCAL_BIT)
2c2fa1
+/* number of bytes to st_other.  */
2c2fa1
+#define PPC64_SET_LOCAL_ENTRY_OFFSET(val)		\
2c2fa1
+  ppc64_encode_local_entry (val) << STO_PPC64_LOCAL_BIT
2c2fa1
+
2c2fa1
 /* Specify the start of the .glink section.  */
2c2fa1
 #define DT_PPC64_GLINK		DT_LOPROC
2c2fa1