Blob Blame History Raw
--- binutils-2.23.52.0.1.orig/bfd/elf64-aarch64.c	2015-07-29 15:17:32.056365096 +0100
+++ binutils-2.23.52.0.1/bfd/elf64-aarch64.c	2015-07-29 16:37:17.550432586 +0100
@@ -3932,10 +3932,11 @@ elf64_aarch64_final_link_relocate (reloc
   unsigned int r_type = howto->type;
   unsigned long r_symndx;
   bfd_byte *hit_data = contents + rel->r_offset;
-  bfd_vma place;
+  bfd_vma place, off;
   bfd_signed_vma signed_addend;
   struct elf64_aarch64_link_hash_table *globals;
   bfd_boolean weak_undef_p;
+  asection *base_got;
 
   globals = elf64_aarch64_hash_table (info);
 
@@ -3971,8 +3972,6 @@ elf64_aarch64_final_link_relocate (reloc
     {
       asection *plt;
       const char *name;
-      asection *base_got;
-      bfd_vma off;
 
       if ((input_section->flags & SEC_ALLOC) == 0
 	  || h->plt.offset == (bfd_vma) -1)
@@ -4326,6 +4325,58 @@ elf64_aarch64_final_link_relocate (reloc
 	  value = aarch64_resolve_relocation (r_type, place, value,
 					      0, weak_undef_p);
 	}
+      else
+	{
+	  struct elf_aarch64_local_symbol *locals
+	    = elf64_aarch64_locals (input_bfd);
+
+	  if (locals == NULL)
+	    {
+	      (*_bfd_error_handler)
+		(_("%B: Local symbol descriptor table be NULL when applying "
+		   "relocation against local symbol"),
+		 input_bfd);
+	      abort ();
+	    }
+
+	  off = symbol_got_offset (input_bfd, h, r_symndx);
+	  base_got = globals->root.sgot;
+	  bfd_vma got_entry_addr = (base_got->output_section->vma
+				    + base_got->output_offset + off);
+
+	  if (!symbol_got_offset_mark_p (input_bfd, h, r_symndx))
+	    {
+	      bfd_put_64 (output_bfd, value, base_got->contents + off);
+
+	      if (info->shared)
+		{
+		  asection *s;
+		  Elf_Internal_Rela outrel;
+
+		  /* For local symbol, we have done absolute relocation in static
+		     linking stageh. While for share library, we need to update
+		     the content of GOT entry according to the share objects
+		     loading base address. So we need to generate a
+		     R_AARCH64_RELATIVE reloc for dynamic linker.  */
+		  s = globals->root.srelgot;
+		  if (s == NULL)
+		    abort ();
+
+		  outrel.r_offset = got_entry_addr;
+		  outrel.r_info = ELF64_R_INFO (0, R_AARCH64_RELATIVE);
+		  outrel.r_addend = value;
+		  elf_append_rela (output_bfd, s, &outrel);
+		}
+
+	      symbol_got_offset_mark (input_bfd, h, r_symndx);
+	    }
+
+	  /* Update the relocation value to GOT entry addr as we have transformed
+	     the direct data access into indirect data access through GOT.  */
+	  value = got_entry_addr;
+	  value = aarch64_resolve_relocation (r_type, place, value,
+					      0, weak_undef_p);
+	}
       break;
 
     case R_AARCH64_TLSGD_ADR_PAGE21:
@@ -7032,7 +7083,8 @@ elf64_aarch64_size_dynamic_sections (bfd
 		  htab->root.sgot->size += GOT_ENTRY_SIZE * 2;
 		}
 
-	      if (got_type & GOT_TLS_IE)
+	      if (got_type & GOT_TLS_IE
+		  || got_type & GOT_NORMAL)
 		{
 		  locals[i].got_offset = htab->root.sgot->size;
 		  htab->root.sgot->size += GOT_ENTRY_SIZE;
@@ -7042,10 +7094,6 @@ elf64_aarch64_size_dynamic_sections (bfd
 		{
 		}
 
-	      if (got_type == GOT_NORMAL)
-		{
-		}
-
 	      if (info->shared)
 		{
 		  if (got_type & GOT_TLSDESC_GD)
@@ -7058,7 +7106,8 @@ elf64_aarch64_size_dynamic_sections (bfd
 		  if (got_type & GOT_TLS_GD)
 		    htab->root.srelgot->size += RELOC_SIZE (htab) * 2;
 
-		  if (got_type & GOT_TLS_IE)
+		  if (got_type & GOT_TLS_IE
+		      || got_type & GOT_NORMAL)
 		    htab->root.srelgot->size += RELOC_SIZE (htab);
 		}
 	    }