From 99ad26cb0d4f9152dbe5ed03b74020cc52d84d94 Mon Sep 17 00:00:00 2001
From: Jiong Wang <jiong.wang@arm.com>
Date: Mon, 1 Jun 2015 10:26:00 +0100
Subject: [PATCH] [AArch64] BFD Support BFD_RELOC_AARCH64_LD64_GOTPAGE_LO15

2015-06-01  Jiong Wang  <jiong.wang@arm.com>
bfd/
	* elfnn-aarch64.c (aarch64_reloc_got_type): Support
	BFD_RELOC_AARCH64_LD64_GOTPAGE_LO15.
	(elfNN_aarch64_final_link_relocate): Ditto.
	(elfNN_aarch64_gc_swap_hook): Ditto.
	(elfNN_aarch64_check_relocs): Ditto.
	* elfxx-aarch64.c (_bfd_aarch64_elf_put_addend): Ditto.

ld/testsuite/
	* ld-aarch64/emit-relocs-313.s: New test file.
	* ld-aarch64/emit-relocs-313.d: Ditto.
	* ld-aarch64/aarch64-elf.exp: Run new test.
---
 bfd/ChangeLog                             |  9 ++++++++
 bfd/elfnn-aarch64.c                       | 25 +++++++++++++++++++++--
 bfd/elfxx-aarch64.c                       |  6 ++++++
 ld/testsuite/ChangeLog                    |  6 ++++++
 ld/testsuite/ld-aarch64/aarch64-elf.exp   |  1 +
 ld/testsuite/ld-aarch64/emit-relocs-313.d | 18 ++++++++++++++++
 ld/testsuite/ld-aarch64/emit-relocs-313.s |  5 +++++
 7 files changed, 68 insertions(+), 2 deletions(-)
 create mode 100644 ld/testsuite/ld-aarch64/emit-relocs-313.d
 create mode 100644 ld/testsuite/ld-aarch64/emit-relocs-313.s

diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index ccb2928c3fa..5ae71b2ea9b 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,3 +1,12 @@
+2015-06-01  Jiong Wang  <jiong.wang@arm.com>
+
+	* elfnn-aarch64.c (aarch64_reloc_got_type): Support
+	BFD_RELOC_AARCH64_LD64_GOTPAGE_LO15.
+	(elfNN_aarch64_final_link_relocate): Ditto.
+	(elfNN_aarch64_gc_swap_hook): Ditto.
+	(elfNN_aarch64_check_relocs): Ditto.
+	* elfxx-aarch64.c (_bfd_aarch64_elf_put_addend): Ditto.
+
 2015-06-01  Jiong Wang  <jiong.wang@arm.com>
 
 	* reloc.c (BFD_RELOC_AARCH64_LD64_GOTPAGE_LO15): New entry.
diff --git a/bfd/elfnn-aarch64.c b/bfd/elfnn-aarch64.c
index 2615f248f70..bcb25fd905b 100644
--- a/bfd/elfnn-aarch64.c
+++ b/bfd/elfnn-aarch64.c
@@ -4052,6 +4052,7 @@ aarch64_reloc_got_type (bfd_reloc_code_real_type r_type)
     case BFD_RELOC_AARCH64_ADR_GOT_PAGE:
     case BFD_RELOC_AARCH64_GOT_LD_PREL19:
     case BFD_RELOC_AARCH64_LD32_GOT_LO12_NC:
+    case BFD_RELOC_AARCH64_LD64_GOTPAGE_LO15:
     case BFD_RELOC_AARCH64_LD64_GOT_LO12_NC:
       return GOT_NORMAL;
 
@@ -4507,6 +4508,7 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto,
     {
       asection *plt;
       const char *name;
+      bfd_vma addend = 0;
 
       if ((input_section->flags & SEC_ALLOC) == 0
 	  || h->plt.offset == (bfd_vma) -1)
@@ -4604,6 +4606,7 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto,
 	case BFD_RELOC_AARCH64_ADR_GOT_PAGE:
 	case BFD_RELOC_AARCH64_GOT_LD_PREL19:
 	case BFD_RELOC_AARCH64_LD32_GOT_LO12_NC:
+	case BFD_RELOC_AARCH64_LD64_GOTPAGE_LO15:
 	case BFD_RELOC_AARCH64_LD64_GOT_LO12_NC:
 	  base_got = globals->root.sgot;
 	  off = h->got.offset;
@@ -4663,8 +4666,11 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto,
 	    value = aarch64_calculate_got_entry_vma (h, globals, info,
 						     value, output_bfd,
 						     unresolved_reloc_p);
+	  if (bfd_r_type == BFD_RELOC_AARCH64_LD64_GOTPAGE_LO15)
+	    addend = (globals->root.sgot->output_section->vma
+		      + globals->root.sgot->output_offset);
 	  value = _bfd_aarch64_elf_resolve_relocation (bfd_r_type, place, value,
-						       0, weak_undef_p);
+						       addend, weak_undef_p);
 	  return _bfd_aarch64_elf_put_addend (input_bfd, hit_data, bfd_r_type, howto, value);
 	case BFD_RELOC_AARCH64_ADD_LO12:
 	case BFD_RELOC_AARCH64_ADR_HI21_PCREL:
@@ -4869,20 +4875,26 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto,
     case BFD_RELOC_AARCH64_ADR_GOT_PAGE:
     case BFD_RELOC_AARCH64_GOT_LD_PREL19:
     case BFD_RELOC_AARCH64_LD32_GOT_LO12_NC:
+    case BFD_RELOC_AARCH64_LD64_GOTPAGE_LO15:
     case BFD_RELOC_AARCH64_LD64_GOT_LO12_NC:
       if (globals->root.sgot == NULL)
 	BFD_ASSERT (h != NULL);
 
       if (h != NULL)
 	{
+	  bfd_vma addend = 0;
 	  value = aarch64_calculate_got_entry_vma (h, globals, info, value,
 						   output_bfd,
 						   unresolved_reloc_p);
+	  if (bfd_r_type == BFD_RELOC_AARCH64_LD64_GOTPAGE_LO15)
+	    addend = (globals->root.sgot->output_section->vma
+		      + globals->root.sgot->output_offset);
 	  value = _bfd_aarch64_elf_resolve_relocation (bfd_r_type, place, value,
-						       0, weak_undef_p);
+						       addend, weak_undef_p);
 	}
       else
       {
+	bfd_vma addend = 0;
 	struct elf_aarch64_local_symbol *locals
 	  = elf_aarch64_locals (input_bfd);
 
@@ -4931,6 +4943,12 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto,
 	/* 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;
+
+	if (bfd_r_type == BFD_RELOC_AARCH64_LD64_GOTPAGE_LO15)
+	  addend = base_got->output_section->vma + base_got->output_offset;
+
+	value = _bfd_aarch64_elf_resolve_relocation (bfd_r_type, place, value,
+						     addend, weak_undef_p);
       }
 
       break;
@@ -5926,6 +5944,7 @@ elfNN_aarch64_gc_sweep_hook (bfd *abfd,
 	case BFD_RELOC_AARCH64_ADR_GOT_PAGE:
 	case BFD_RELOC_AARCH64_GOT_LD_PREL19:
 	case BFD_RELOC_AARCH64_LD32_GOT_LO12_NC:
+	case BFD_RELOC_AARCH64_LD64_GOTPAGE_LO15:
 	case BFD_RELOC_AARCH64_LD64_GOT_LO12_NC:
 	case BFD_RELOC_AARCH64_TLSDESC_ADD_LO12_NC:
 	case BFD_RELOC_AARCH64_TLSDESC_ADR_PAGE21:
@@ -6283,6 +6302,7 @@ elfNN_aarch64_check_relocs (bfd *abfd, struct bfd_link_info *info,
 	    case BFD_RELOC_AARCH64_GOT_LD_PREL19:
 	    case BFD_RELOC_AARCH64_JUMP26:
 	    case BFD_RELOC_AARCH64_LD32_GOT_LO12_NC:
+	    case BFD_RELOC_AARCH64_LD64_GOTPAGE_LO15:
 	    case BFD_RELOC_AARCH64_LD64_GOT_LO12_NC:
 	    case BFD_RELOC_AARCH64_NN:
 	      if (htab->root.dynobj == NULL)
@@ -6394,6 +6414,7 @@ elfNN_aarch64_check_relocs (bfd *abfd, struct bfd_link_info *info,
 	case BFD_RELOC_AARCH64_ADR_GOT_PAGE:
 	case BFD_RELOC_AARCH64_GOT_LD_PREL19:
 	case BFD_RELOC_AARCH64_LD32_GOT_LO12_NC:
+	case BFD_RELOC_AARCH64_LD64_GOTPAGE_LO15:
 	case BFD_RELOC_AARCH64_LD64_GOT_LO12_NC:
 	case BFD_RELOC_AARCH64_TLSDESC_ADD_LO12_NC:
 	case BFD_RELOC_AARCH64_TLSDESC_ADR_PAGE21:
diff --git a/bfd/elfxx-aarch64.c b/bfd/elfxx-aarch64.c
index 576df78b9f9..889b0d0e59d 100644
--- a/bfd/elfxx-aarch64.c
+++ b/bfd/elfxx-aarch64.c
@@ -258,6 +258,7 @@ _bfd_aarch64_elf_put_addend (bfd *abfd,
       break;
 
     case BFD_RELOC_AARCH64_LD32_GOT_LO12_NC:
+    case BFD_RELOC_AARCH64_LD64_GOTPAGE_LO15:
     case BFD_RELOC_AARCH64_LD64_GOT_LO12_NC:
     case BFD_RELOC_AARCH64_LDST128_LO12:
     case BFD_RELOC_AARCH64_LDST16_LO12:
@@ -413,6 +414,11 @@ _bfd_aarch64_elf_resolve_relocation (bfd_reloc_code_real_type r_type,
       value = PG (value + addend) - PG (place);
       break;
 
+    case BFD_RELOC_AARCH64_LD64_GOTPAGE_LO15:
+      /* Caller must make sure addend is the base address of .got section.  */
+      value = value - PG (addend);
+      break;
+
     case BFD_RELOC_AARCH64_ADD_LO12:
     case BFD_RELOC_AARCH64_LD32_GOT_LO12_NC:
     case BFD_RELOC_AARCH64_LD64_GOT_LO12_NC:
diff --git a/ld/testsuite/ChangeLog b/ld/testsuite/ChangeLog
index 483baa78065..985704003c2 100644
--- a/ld/testsuite/ChangeLog
+++ b/ld/testsuite/ChangeLog
@@ -1,3 +1,9 @@
+2015-06-01  Jiong Wang  <jiong.wang@arm.com>
+
+	* ld-aarch64/emit-relocs-313.s: New test file.
+	* ld-aarch64/emit-relocs-313.d: Ditto.
+	* ld-aarch64/aarch64-elf.exp: Run new test.
+
 2015-05-29  Stephen Kitt  <steve@sk2.org>
 
 	* ld-pe/pe-run2.exp (test_direct2_link_dll): Add $CFLAGS to the
diff --git a/ld/testsuite/ld-aarch64/aarch64-elf.exp b/ld/testsuite/ld-aarch64/aarch64-elf.exp
index bfbbe2425ae..79b5a3eb9cb 100644
--- a/ld/testsuite/ld-aarch64/aarch64-elf.exp
+++ b/ld/testsuite/ld-aarch64/aarch64-elf.exp
@@ -99,6 +99,7 @@ run_dump_test "emit-relocs-309-low-bad"
 # 310 not done yet
 run_dump_test "emit-relocs-311"
 run_dump_test "emit-relocs-312"
+run_dump_test "emit-relocs-313"
 
 # test addend correctness when --emit-relocs specified for non-relocatable obj.
 run_dump_test "emit-relocs-local-addend"
diff --git a/ld/testsuite/ld-aarch64/emit-relocs-313.d b/ld/testsuite/ld-aarch64/emit-relocs-313.d
new file mode 100644
index 00000000000..0a7b5d151bc
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/emit-relocs-313.d
@@ -0,0 +1,18 @@
+#source: emit-relocs-313.s
+#ld: -T relocs.ld --defsym globala=0x11000 --defsym globalb=0x45000 --defsym globalc=0x1234  -e0 --emit-relocs
+#objdump: -dr
+
+.*: +file format .*
+
+
+Disassembly of section .text:
+
+0000000000010000 <\.text>:
+   10000:	90000082 	adrp	x2, 20000 <_GLOBAL_OFFSET_TABLE_>
+			10000: R_AARCH64_ADR_PREL_PG_HI21	_GLOBAL_OFFSET_TABLE_
+   10004:	f9400840 	ldr	x0, \[x2,#16\]
+			10004: R_AARCH64_LD64_GOTPAGE_LO15	globala
+   10008:	f9400c40 	ldr	x0, \[x2,#24\]
+			10008: R_AARCH64_LD64_GOTPAGE_LO15	globalb
+   1000c:	f9400440 	ldr	x0, \[x2,#8\]
+			1000c: R_AARCH64_LD64_GOTPAGE_LO15	globalc
diff --git a/ld/testsuite/ld-aarch64/emit-relocs-313.s b/ld/testsuite/ld-aarch64/emit-relocs-313.s
new file mode 100644
index 00000000000..b13a0e5262b
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/emit-relocs-313.s
@@ -0,0 +1,5 @@
+	.text
+	adrp  x2, _GLOBAL_OFFSET_TABLE_
+	ldr	x0, [x2, #:gotpage_lo14:globala]
+	ldr	x0, [x2, #:gotpage_lo14:globalb]
+	ldr	x0, [x2, #:gotpage_lo14:globalc]