[AArch64] PR18668, repair long branch veneer for plt stub
authorJiong Wang <jiong.wang@arm.com>
Tue, 11 Aug 2015 20:44:31 +0000 (21:44 +0100)
committerJiong Wang <jiong.wang@arm.com>
Tue, 11 Aug 2015 20:44:31 +0000 (21:44 +0100)
2015-08-11  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: 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.

bfd/ChangeLog
bfd/elfnn-aarch64.c
ld/testsuite/ChangeLog
ld/testsuite/ld-aarch64/aarch64-elf.exp
ld/testsuite/ld-aarch64/farcall-b-gsym.d [new file with mode: 0644]
ld/testsuite/ld-aarch64/farcall-b-gsym.s [new file with mode: 0644]
ld/testsuite/ld-aarch64/farcall-b-plt.d [new file with mode: 0644]
ld/testsuite/ld-aarch64/farcall-b-plt.s [new file with mode: 0644]
ld/testsuite/ld-aarch64/farcall-bl-plt.d [new file with mode: 0644]
ld/testsuite/ld-aarch64/farcall-bl-plt.s [new file with mode: 0644]

index 97fffdd92a850739746c27d0f351286473411b42..e2378fe3d0d5c0b8ac5379842b01d1e6c7345889 100644 (file)
@@ -1,3 +1,11 @@
+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
index c8ad42184fe59fa584b191f63ae3e59e4524ca8f..097a275990f1d350be8f68943093926a5c66157a 100644 (file)
@@ -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:
index dae1cbb54daaa8e48251db766d0ef2e7ddc00fab..9b16f251f68bc94fb61204c1a7dbe34d82c79728 100644 (file)
@@ -1,3 +1,12 @@
+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.
index c8a8aae227e78dbe2bf6d69a6bbd3bfa14aeff44..b87b198596a5cf140744dfea473892a06a977420 100644 (file)
@@ -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 (file)
index 0000000..eced18e
--- /dev/null
@@ -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 (file)
index 0000000..b7bfe23
--- /dev/null
@@ -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 (file)
index 0000000..9e2c891
--- /dev/null
@@ -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 (file)
index 0000000..227f5f1
--- /dev/null
@@ -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 (file)
index 0000000..205a810
--- /dev/null
@@ -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 (file)
index 0000000..2cb0dd0
--- /dev/null
@@ -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