This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
[AArch64] PR18668, Generate long branch veneer if call to plt stub is out of range
- From: Jiong Wang <jiong dot wang at arm dot com>
- To: "binutils\ at sourceware dot org" <binutils at sourceware dot org>
- Date: Thu, 16 Jul 2015 15:29:50 +0100
- Subject: [AArch64] PR18668, Generate long branch veneer if call to plt stub is out of range
- Authentication-results: sourceware.org; auth=none
- References: <n99pp3sgori dot fsf at arm dot com>
(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