[lld] 4f38ab2 - [LLD][ELF][ARM] Do not insert interworking thunks for non STT_FUNC symbols

Peter Smith via llvm-commits llvm-commits at lists.llvm.org
Tue Jan 28 03:54:48 PST 2020


Author: Peter Smith
Date: 2020-01-28T11:54:18Z
New Revision: 4f38ab250ff4680375c4c01db0a88c157093c665

URL: https://github.com/llvm/llvm-project/commit/4f38ab250ff4680375c4c01db0a88c157093c665
DIFF: https://github.com/llvm/llvm-project/commit/4f38ab250ff4680375c4c01db0a88c157093c665.diff

LOG: [LLD][ELF][ARM] Do not insert interworking thunks for non STT_FUNC symbols

ELF for the ARM architecture requires linkers to provide
interworking for symbols that are of type STT_FUNC. Interworking for
other symbols must be encoded directly in the object file. LLD was always
providing interworking, regardless of the symbol type, this breaks some
programs that have branches from Thumb state targeting STT_NOTYPE symbols
that have bit 0 clear, but they are in fact internal labels in a Thumb
function. LLD treats these symbols as ARM and inserts a transition to Arm.

This fixes the problem for in range branches, R_ARM_JUMP24,
R_ARM_THM_JUMP24 and R_ARM_THM_JUMP19. This is expected to be the vast
majority of problem cases as branching to an internal label close to the
function.

There is at least one follow up patch required.
- R_ARM_CALL and R_ARM_THM_CALL may do interworking via BL/BLX
  substitution.

In theory range-extension thunks can be altered to not change state when
the symbol type is not STT_FUNC. I will need to check with ld.bfd to see if
this is the case in practice.

Fixes (part of) https://github.com/ClangBuiltLinux/linux/issues/773

Differential Revision: https://reviews.llvm.org/D73474

Added: 
    lld/test/ELF/arm-thumb-interwork-ifunc.s
    lld/test/ELF/arm-thumb-interwork-notfunc.s

Modified: 
    lld/ELF/Arch/ARM.cpp
    lld/test/ELF/arm-thunk-edgecase.s

Removed: 
    


################################################################################
diff  --git a/lld/ELF/Arch/ARM.cpp b/lld/ELF/Arch/ARM.cpp
index 487bbd5d512a..7f18effa096f 100644
--- a/lld/ELF/Arch/ARM.cpp
+++ b/lld/ELF/Arch/ARM.cpp
@@ -277,8 +277,8 @@ bool ARM::needsThunk(RelExpr expr, RelType type, const InputFile *file,
   case R_ARM_PLT32:
   case R_ARM_JUMP24:
     // Source is ARM, all PLT entries are ARM so no interworking required.
-    // Otherwise we need to interwork if Symbol has bit 0 set (Thumb).
-    if (expr == R_PC && ((s.getVA() & 1) == 1))
+    // Otherwise we need to interwork if STT_FUNC Symbol has bit 0 set (Thumb).
+    if (s.isFunc() && expr == R_PC && (s.getVA() & 1))
       return true;
     LLVM_FALLTHROUGH;
   case R_ARM_CALL: {
@@ -288,8 +288,8 @@ bool ARM::needsThunk(RelExpr expr, RelType type, const InputFile *file,
   case R_ARM_THM_JUMP19:
   case R_ARM_THM_JUMP24:
     // Source is Thumb, all PLT entries are ARM so interworking is required.
-    // Otherwise we need to interwork if Symbol has bit 0 clear (ARM).
-    if (expr == R_PLT_PC || ((s.getVA() & 1) == 0))
+    // Otherwise we need to interwork if STT_FUNC Symbol has bit 0 clear (ARM).
+    if (expr == R_PLT_PC || (s.isFunc() && (s.getVA() & 1) == 0))
       return true;
     LLVM_FALLTHROUGH;
   case R_ARM_THM_CALL: {

diff  --git a/lld/test/ELF/arm-thumb-interwork-ifunc.s b/lld/test/ELF/arm-thumb-interwork-ifunc.s
new file mode 100644
index 000000000000..a0e4239ff3f3
--- /dev/null
+++ b/lld/test/ELF/arm-thumb-interwork-ifunc.s
@@ -0,0 +1,52 @@
+// REQUIRES: arm
+// RUN: llvm-mc --triple=armv7a-linux-gnueabihf -arm-add-build-attributes -filetype=obj -o %t.o %s
+// RUN: ld.lld %t.o -o %t
+// RUN: llvm-objdump -triple armv7a-none-linux-gnueabi -d --no-show-raw-insn %t
+
+/// Non-preemptible ifuncs are called via a PLT entry which is always Arm
+/// state, expect the ARM callers to go direct to the PLT entry, Thumb
+/// branches are indirected via state change thunks, the bl is changed to blx.
+
+ .syntax unified
+ .text
+ .balign 0x1000
+ .type foo STT_GNU_IFUNC
+ .globl foo
+foo:
+ bx lr
+
+ .section .text.1, "ax", %progbits
+ .arm
+ .global _start
+_start:
+ b foo
+ bl foo
+
+ .section .text.2, "ax", %progbits
+ .thumb
+ .global thumb_caller
+thumb_caller:
+ b foo
+ b.w foo
+ bl foo
+
+// CHECK: 00012004 _start:
+// CHECK-NEXT: b       #36
+// CHECK-NEXT: bl      #32
+
+// CHECK: 0001200c thumb_caller:
+// CHECK-NEXT: b.w     #8
+// CHECK-NEXT: b.w     #4
+// CHECK-NEXT: blx     #24
+
+// CHECK: 00012018 __Thumbv7ABSLongThunk_foo:
+// CHECK-NEXT: movw    r12, #8240
+// CHECK-NEXT: movt    r12, #1
+// CHECK-NEXT: bx      r12
+
+// CHECK: Disassembly of section .iplt:
+
+// CHECK: 00012030 $a:
+// CHECK-NEXT: add     r12, pc, #0, #12
+// CHECK-NEXT: add     r12, r12, #4096
+// CHECK-NEXT: ldr     pc, [r12, #8]!

diff  --git a/lld/test/ELF/arm-thumb-interwork-notfunc.s b/lld/test/ELF/arm-thumb-interwork-notfunc.s
new file mode 100644
index 000000000000..4f29fdf541fb
--- /dev/null
+++ b/lld/test/ELF/arm-thumb-interwork-notfunc.s
@@ -0,0 +1,73 @@
+// REQUIRES: arm
+// RUN: llvm-mc --triple=armv7a-linux-gnueabihf -arm-add-build-attributes -filetype=obj -o %t.o %s
+// RUN: ld.lld %t.o -o %t
+// RUN: llvm-objdump --no-show-raw-insn -d %t | FileCheck %s
+
+.syntax unified
+.section .arm_target, "ax", %progbits
+.balign 0x1000
+.arm
+arm_func_with_notype:
+.type arm_func_with_explicit_notype, %notype
+arm_func_with_explicit_notype:
+ bx lr
+
+.section .thumb_target, "ax", %progbits
+.balign 4
+.thumb
+thumb_func_with_notype:
+.type thumb_func_with_explicit_notype, %notype
+thumb_func_with_explicit_notype:
+ bx lr
+
+/// All the symbols that are targets of the branch relocations do not have
+/// type STT_FUNC. LLD should not insert interworking thunks as non STT_FUNC
+/// symbols have no state information, the ABI assumes the user has manually
+/// done the interworking.
+.section .arm_caller, "ax", %progbits
+.balign 4
+.arm
+.global _start
+_start:
+ b .arm_target
+ b arm_func_with_notype
+ b arm_func_with_explicit_notype
+ b .thumb_target
+ b thumb_func_with_notype
+ b thumb_func_with_explicit_notype
+
+ .section .thumb_caller, "ax", %progbits
+ .thumb
+ .balign 4
+ b.w .arm_target
+ b.w arm_func_with_notype
+ b.w arm_func_with_explicit_notype
+ b.w .thumb_target
+ b.w thumb_func_with_notype
+ b.w thumb_func_with_explicit_notype
+ beq.w .arm_target
+ beq.w arm_func_with_notype
+ beq.w arm_func_with_explicit_notype
+ beq.w .thumb_target
+ beq.w thumb_func_with_notype
+ beq.w thumb_func_with_explicit_notype
+
+// CHECK: 00012008 _start:
+// CHECK-NEXT: 12008: b       #-16
+// CHECK-NEXT: 1200c: b       #-20
+// CHECK-NEXT: 12010: b       #-24
+// CHECK-NEXT: 12014: b       #-24
+// CHECK-NEXT: 12018: b       #-28
+// CHECK-NEXT: 1201c: b       #-32
+// CHECK:      12020: b.w     #-36
+// CHECK-NEXT: 12024: b.w     #-40
+// CHECK-NEXT: 12028: b.w     #-44
+// CHECK-NEXT: 1202c: b.w     #-44
+// CHECK-NEXT: 12030: b.w     #-48
+// CHECK-NEXT: 12034: b.w     #-52
+// CHECK-NEXT: 12038: beq.w   #-60
+// CHECK-NEXT: 1203c: beq.w   #-64
+// CHECK-NEXT: 12040: beq.w   #-68
+// CHECK-NEXT: 12044: beq.w   #-68
+// CHECK-NEXT: 12048: beq.w   #-72
+// CHECK-NEXT: 1204c: beq.w   #-76

diff  --git a/lld/test/ELF/arm-thunk-edgecase.s b/lld/test/ELF/arm-thunk-edgecase.s
index 356687668399..b7414cafddef 100644
--- a/lld/test/ELF/arm-thunk-edgecase.s
+++ b/lld/test/ELF/arm-thunk-edgecase.s
@@ -18,6 +18,7 @@
 .arm
 .section .text_armfunc, "ax", %progbits
 .globl armfunc
+.type armfunc, %function
 armfunc:
 	b	thumbfunc
 


        


More information about the llvm-commits mailing list