+2015-08-11 Jiong Wang <jiong.wang@arm.com>
+
+ 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 <jiong.wang@arm.com>
* elfnn-aarch64.c (IS_AARCH64_TLS_RELOC): Recognize
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
/* 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:
+2015-08-11 Jiong Wang <jiong.wang@arm.com>
+
+ * 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 <jiong.wang@arm.com>
* ld-aarch64/emit-relocs-529.s: New testcase.
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"
--- /dev/null
+#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'.*
--- /dev/null
+ .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
--- /dev/null
+#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
+ ...
--- /dev/null
+ .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
--- /dev/null
+#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
+ ...
--- /dev/null
+ .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