This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[AArch64] PR18668, Generate long branch veneer if call to plt stub is out of range


(add the patch)

If text section size is really big, when the linker redirect function
call to plt stub, the branch offset may be out of range.

Currently, AArch64 BFD has long branch veneer infrastructure ready, but
it's not enabled for call to plt stub. Only absolute call long branch
implemented while for PIC/.so, call to PLT stub is the common case and
we need to support this.

This patch copied some code from ARM32, and cleaned up code logic in
final_link code where BFD_RELOC_AARCH64_JUMP26/CALL26 handled.

The code logic for handling CALL26/JUMP26 is simplied into:

  * if it call via plt stub, then update relocation value to plt stub address.
  * use the updated relocation value to check whether it's fit into range.
    And if the offset don't fit into the range then check whether any
    long branch veneer register for it.
  * if long branch veneer register, then udpate final relocation value
    to the address of veneer, otherwise don't touch relocation value.

test done
===
  native ld check OK.
  linking the huge OpenLoop reported on PR 18668 successfully which
  failed on the old bfd linker.
  

OK for trunk?

2015-07-15  Jiong Wang  <jiong.wang@arm.com>
bfd/
  PR ld/18668
  * elfnn-aarch64.c (aarch64_type_of_stub): Update destination for
  calls go through plt stub.
  (elfNN_aarch64_final_link_relocate): Adjust code logic for CALL26,
  JUMP26 relocation to support inserting veneer for call to plt stub.

ld/testsuite/
  * ld-aarch64/farcall-b-gsym.s: New test.
  * ld-aarch64/farcall-b-plt.s: Ditto.
  * ld-aarch64/farcall-bl-plt.s: Ditto.
  * ld-aarch64/farcall-b-gsym.d: New expect file.
  * ld-aarch64/farcall-b-plt.d: Ditto.
  * ld-aarch64/farcall-bl-plt.d: Ditto.

OK for trunk?
-- 
Regards,
Jiong

commit 8d3fa62f5ab58a7e30968422dd3238470f7f067d
Author: Jiong Wang <jiong.wang@arm.com>
Date:   Wed Jul 15 14:26:40 2015 +0000

    1

diff --git a/bfd/elfnn-aarch64.c b/bfd/elfnn-aarch64.c
index c252b13..e05a5da 100644
--- a/bfd/elfnn-aarch64.c
+++ b/bfd/elfnn-aarch64.c
@@ -2222,9 +2222,11 @@ aarch64_type_of_stub (struct bfd_link_info *info,
   globals = elf_aarch64_hash_table (info);
   via_plt_p = (globals->root.splt != NULL && hash != NULL
 	       && hash->root.plt.offset != (bfd_vma) - 1);
-
+  /* Make sure call to plt stub can fit into the branch range.  */
   if (via_plt_p)
-    return stub_type;
+    destination = (globals->root.splt->output_section->vma
+		   + globals->root.splt->output_offset
+		   + hash->root.plt.offset);
 
   /* Determine where the call point is.  */
   location = (input_sec->output_offset
@@ -4766,38 +4768,25 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto,
 	/* If the call goes through a PLT entry, make sure to
 	   check distance to the right destination address.  */
 	if (via_plt_p)
-	  {
-	    value = (splt->output_section->vma
-		     + splt->output_offset + h->plt.offset);
-	    *unresolved_reloc_p = FALSE;
-	  }
-
-	/* If the target symbol is global and marked as a function the
-	   relocation applies a function call or a tail call.  In this
-	   situation we can veneer out of range branches.  The veneers
-	   use IP0 and IP1 hence cannot be used arbitrary out of range
-	   branches that occur within the body of a function.  */
-	if (h && h->type == STT_FUNC)
-	  {
-	    /* Check if a stub has to be inserted because the destination
-	       is too far away.  */
-	    if (! aarch64_valid_branch_p (value, place))
-	      {
-		/* The target is out of reach, so redirect the branch to
-		   the local stub for this function.  */
-		struct elf_aarch64_stub_hash_entry *stub_entry;
-		stub_entry = elfNN_aarch64_get_stub_entry (input_section,
-							   sym_sec, h,
-							   rel, globals);
-		if (stub_entry != NULL)
-		  value = (stub_entry->stub_offset
-			   + stub_entry->stub_sec->output_offset
-			   + stub_entry->stub_sec->output_section->vma);
-	      }
-	  }
+	  value = (splt->output_section->vma
+		   + splt->output_offset + h->plt.offset);
+
+	/* Check if a stub has to be inserted because the destination
+	   is too far away.  */
+	struct elf_aarch64_stub_hash_entry *stub_entry = NULL;
+	if (! aarch64_valid_branch_p (value, place))
+	  /* The target is out of reach, so redirect the branch to
+	     the local stub for this function.  */
+	stub_entry = elfNN_aarch64_get_stub_entry (input_section, sym_sec, h,
+						   rel, globals);
+	if (stub_entry != NULL)
+	  value = (stub_entry->stub_offset
+		   + stub_entry->stub_sec->output_offset
+		   + stub_entry->stub_sec->output_section->vma);
       }
       value = _bfd_aarch64_elf_resolve_relocation (bfd_r_type, place, value,
 						   signed_addend, weak_undef_p);
+      *unresolved_reloc_p = FALSE;
       break;
 
     case BFD_RELOC_AARCH64_ADR_LO21_PCREL:
diff --git a/ld/testsuite/ld-aarch64/aarch64-elf.exp b/ld/testsuite/ld-aarch64/aarch64-elf.exp
index bfbbe24..99f2f6f 100644
--- a/ld/testsuite/ld-aarch64/aarch64-elf.exp
+++ b/ld/testsuite/ld-aarch64/aarch64-elf.exp
@@ -113,6 +113,9 @@ run_dump_test "limit-b"
 run_dump_test "limit-bl"
 run_dump_test "farcall-section"
 run_dump_test "farcall-back"
+run_dump_test "farcall-b-gsym"
+run_dump_test "farcall-b-plt"
+run_dump_test "farcall-bl-plt"
 run_dump_test "farcall-bl"
 run_dump_test "farcall-b"
 run_dump_test "farcall-b-none-function"
diff --git a/ld/testsuite/ld-aarch64/farcall-b-gsym.d b/ld/testsuite/ld-aarch64/farcall-b-gsym.d
new file mode 100644
index 0000000..eced18e
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/farcall-b-gsym.d
@@ -0,0 +1,5 @@
+#name: aarch64-farcall-b-gsym
+#source: farcall-b-gsym.s
+#as:
+#ld: -Ttext 0x1000
+#error: .*\(.text\+0x0\): relocation truncated to fit: R_AARCH64_JUMP26 against symbol `bar_gsym'.*
diff --git a/ld/testsuite/ld-aarch64/farcall-b-gsym.s b/ld/testsuite/ld-aarch64/farcall-b-gsym.s
new file mode 100644
index 0000000..b7bfe23
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/farcall-b-gsym.s
@@ -0,0 +1,17 @@
+	.global _start
+	.global bar_gsym
+
+# We will place the section .text at 0x1000.
+
+	.text
+
+_start:
+# for long jump (JUMP26) to global symbol, we shouldn't insert veneer
+# as the veneer will clobber IP0/IP1 which is caller saved, gcc only
+# reserve them for function call relocation (CALL26).
+	b bar_gsym
+	# ((1 << 25) - 1) << 2
+	.skip 134217724, 0
+bar_gsym:
+	nop
+	ret
diff --git a/ld/testsuite/ld-aarch64/farcall-b-plt.d b/ld/testsuite/ld-aarch64/farcall-b-plt.d
new file mode 100644
index 0000000..9e2c891
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/farcall-b-plt.d
@@ -0,0 +1,38 @@
+#name: aarch64-farcall-b-plt
+#source: farcall-b-plt.s
+#as:
+#ld: -shared
+#objdump: -dr
+#...
+
+Disassembly of section .plt:
+
+.* <foo@plt-0x20>:
+.*:	a9bf7bf0 	stp	x16, x30, \[sp,#-16\]!
+.*:	90040090 	adrp	x16, 8010000 <__foo_veneer\+.*>
+.*:	f941f611 	ldr	x17, \[x16,#1000\]
+.*:	910fa210 	add	x16, x16, #0x3e8
+.*:	d61f0220 	br	x17
+.*:	d503201f 	nop
+.*:	d503201f 	nop
+.*:	d503201f 	nop
+
+.* <foo@plt>:
+.*:	90040090 	adrp	x16, 8010000 <__foo_veneer\+.*>
+.*:	f941fa11 	ldr	x17, \[x16,#1008\]
+.*:	910fc210 	add	x16, x16, #0x3f0
+.*:	d61f0220 	br	x17
+
+Disassembly of section .text:
+
+.* <_start>:
+	...
+.*:	14000003 	b	80002c8 <__foo_veneer>
+.*:	d65f03c0 	ret
+.*:	14000007 	b	80002e0 <__foo_veneer\+.*>
+
+.* <__foo_veneer>:
+.*:	90fc0010 	adrp	x16, 0 <foo@plt-0x2b0>
+.*:	910ac210 	add	x16, x16, #0x2b0
+.*:	d61f0200 	br	x16
+	...
diff --git a/ld/testsuite/ld-aarch64/farcall-b-plt.s b/ld/testsuite/ld-aarch64/farcall-b-plt.s
new file mode 100644
index 0000000..227f5f1
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/farcall-b-plt.s
@@ -0,0 +1,11 @@
+	.global _start
+	.global foo
+	.type foo, @function
+	.text
+_start:
+	# ((1 << 25) - 1) << 2
+	# jump26 relocation out of range to plt stub,
+	# we need long branch veneer.
+	.skip 134217724, 0
+	b foo
+	ret
diff --git a/ld/testsuite/ld-aarch64/farcall-bl-plt.d b/ld/testsuite/ld-aarch64/farcall-bl-plt.d
new file mode 100644
index 0000000..205a810
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/farcall-bl-plt.d
@@ -0,0 +1,38 @@
+#name: aarch64-farcall-bl-plt
+#source: farcall-bl-plt.s
+#as:
+#ld: -shared
+#objdump: -dr
+#...
+
+Disassembly of section .plt:
+
+.* <foo@plt-0x20>:
+.*:	a9bf7bf0 	stp	x16, x30, \[sp,#-16\]!
+.*:	90040090 	adrp	x16, 8010000 <__foo_veneer\+.*>
+.*:	f941f611 	ldr	x17, \[x16,#1000\]
+.*:	910fa210 	add	x16, x16, #0x3e8
+.*:	d61f0220 	br	x17
+.*:	d503201f 	nop
+.*:	d503201f 	nop
+.*:	d503201f 	nop
+
+.* <foo@plt>:
+.*:	90040090 	adrp	x16, 8010000 <__foo_veneer\+.*>
+.*:	f941fa11 	ldr	x17, \[x16,#1008\]
+.*:	910fc210 	add	x16, x16, #0x3f0
+.*:	d61f0220 	br	x17
+
+Disassembly of section .text:
+
+.* <_start>:
+	...
+.*:	94000003 	bl	80002c8 <__foo_veneer>
+.*:	d65f03c0 	ret
+.*:	14000007 	b	80002e0 <__foo_veneer\+.*>
+
+.* <__foo_veneer>:
+.*:	90fc0010 	adrp	x16, 0 <foo@plt-0x2b0>
+.*:	910ac210 	add	x16, x16, #0x2b0
+.*:	d61f0200 	br	x16
+	...
diff --git a/ld/testsuite/ld-aarch64/farcall-bl-plt.s b/ld/testsuite/ld-aarch64/farcall-bl-plt.s
new file mode 100644
index 0000000..2cb0dd0
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/farcall-bl-plt.s
@@ -0,0 +1,12 @@
+	.global _start
+	.global foo
+	.type foo, @function
+	.text
+
+_start:
+	# ((1 << 25) - 1) << 2
+	# call26 relocation out of range to plt stub,
+	# we need long branch veneer.
+	.skip 134217724, 0
+	bl foo
+	ret

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]