From: Jiong Wang Date: Tue, 11 Aug 2015 20:44:31 +0000 (+0100) Subject: [AArch64] PR18668, repair long branch veneer for plt stub X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=07f9ddfeba5b572451471f905473f7ddbba1d472;p=binutils-gdb.git [AArch64] PR18668, repair long branch veneer for plt stub 2015-08-11 Jiong Wang 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: Likewise. * ld-aarch64/farcall-bl-plt.s: Likewise. * ld-aarch64/farcall-b-gsym.d: New expect file. * ld-aarch64/farcall-b-plt.d: Likewise. * ld-aarch64/farcall-bl-plt.d: Likewise. --- diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 97fffdd92a8..e2378fe3d0d 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,11 @@ +2015-08-11 Jiong Wang + + 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. + 2015-08-11 Jiong Wang * elfnn-aarch64.c (IS_AARCH64_TLS_RELOC): Recognize diff --git a/bfd/elfnn-aarch64.c b/bfd/elfnn-aarch64.c index c8ad42184fe..097a275990f 100644 --- a/bfd/elfnn-aarch64.c +++ b/bfd/elfnn-aarch64.c @@ -2333,9 +2333,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 @@ -4890,38 +4892,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_16_PCREL: diff --git a/ld/testsuite/ChangeLog b/ld/testsuite/ChangeLog index dae1cbb54da..9b16f251f68 100644 --- a/ld/testsuite/ChangeLog +++ b/ld/testsuite/ChangeLog @@ -1,3 +1,12 @@ +2015-08-11 Jiong Wang + + * ld-aarch64/farcall-b-gsym.s: New test. + * ld-aarch64/farcall-b-plt.s: Likewise. + * ld-aarch64/farcall-bl-plt.s: Likewise. + * ld-aarch64/farcall-b-gsym.d: New expect file. + * ld-aarch64/farcall-b-plt.d: Likewise. + * ld-aarch64/farcall-bl-plt.d: Likewise. + 2015-08-11 Jiong Wang * ld-aarch64/emit-relocs-529.s: New testcase. diff --git a/ld/testsuite/ld-aarch64/aarch64-elf.exp b/ld/testsuite/ld-aarch64/aarch64-elf.exp index c8a8aae227e..b87b198596a 100644 --- a/ld/testsuite/ld-aarch64/aarch64-elf.exp +++ b/ld/testsuite/ld-aarch64/aarch64-elf.exp @@ -127,6 +127,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 00000000000..eced18e2482 --- /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 00000000000..b7bfe230052 --- /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 00000000000..9e2c891f1c3 --- /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: + +.* : +.*: 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 + +.* : +.*: 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 +.*: 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 00000000000..227f5f1ef33 --- /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 00000000000..205a810989d --- /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: + +.* : +.*: 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 + +.* : +.*: 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 +.*: 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 00000000000..2cb0dd0011d --- /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