This is a conditional revert ofcca40aa8d8, which made LLVM's branch-target-enforcement mode generate BTI at the start of _every_ function, even in the case where the function has internal linkage and its address is never taken for use in an indirect call. The rationale was that it might turn out at link time that a direct call to the function spanned a larger distance than the range of a BL instruction (say, if the translation unit generated multiple code sections and the linker put them a very long way apart). Then the linker might insert a long-branch thunk using an indirect call instruction. SYSVABI64 has now clarified that in this situation the static linker may not assume that the target function is safe to call directly. If it needs to use this strategy, it's responsible for also generating a 'landing pad' near the target function, with a BTI followed by a direct branch, and using that as the target of the long-distance indirect call.606ce44fe4LLD complies with this spec as of commit098b0d18ad. So if we're compiling in a mode that respects SYSVABI64, such as targeting Linux, it's safe to leave out the BTI at the start of a function with internal linkage if we can prove that its address isn't either used in an indirect call in _this_ translation unit or passed out of the object. Therefore, this patch goes back to the behavior beforecca40aa8d8, leaving out BTIs in functions that can't be called indirectly, but only if the target triple is Linux. (I wasn't able to find a more precise query for "is this a SYSVABI64-compliant platform?", but Linux certainly is, and this check at least fails in the safe direction - if in doubt, we put in all the BTIs that might be necessary.)
113 lines
3.6 KiB
LLVM
113 lines
3.6 KiB
LLVM
; RUN: llc -mtriple=aarch64-linux-gnu -aarch64-min-jump-table-entries=4 %s -o - | FileCheck %s --check-prefixes=CHECK,SYSV
|
|
; RUN: llc -mtriple=aarch64-none-elf -aarch64-min-jump-table-entries=4 %s -o - | FileCheck %s --check-prefixes=CHECK,NONSYSV
|
|
|
|
define void @f0() "patchable-function-entry"="0" "branch-target-enforcement" {
|
|
; CHECK-LABEL: f0:
|
|
; CHECK-NEXT: .Lfunc_begin0:
|
|
; CHECK: // %bb.0:
|
|
; CHECK-NEXT: hint #34
|
|
; CHECK-NEXT: ret
|
|
; CHECK-NOT: .section __patchable_function_entries
|
|
ret void
|
|
}
|
|
|
|
;; -fpatchable-function-entry=1 -mbranch-protection=bti
|
|
;; For M=0, place the label .Lpatch0 after the initial BTI.
|
|
define void @f1() "patchable-function-entry"="1" "branch-target-enforcement" {
|
|
; CHECK-LABEL: f1:
|
|
; CHECK-NEXT: .Lfunc_begin1:
|
|
; CHECK-NEXT: .cfi_startproc
|
|
; CHECK-NEXT: // %bb.0:
|
|
; CHECK-NEXT: hint #34
|
|
; CHECK-NEXT: .Lpatch0:
|
|
; CHECK-NEXT: nop
|
|
; CHECK-NEXT: ret
|
|
; CHECK: .section __patchable_function_entries,"awo",@progbits,f1{{$}}
|
|
; CHECK-NEXT: .p2align 3
|
|
; CHECK-NEXT: .xword .Lpatch0
|
|
ret void
|
|
}
|
|
|
|
;; -fpatchable-function-entry=2,1 -mbranch-protection=bti
|
|
define void @f2_1() "patchable-function-entry"="1" "patchable-function-prefix"="1" "branch-target-enforcement" {
|
|
; CHECK-LABEL: .type f2_1,@function
|
|
; CHECK-NEXT: .Ltmp0:
|
|
; CHECK-NEXT: nop
|
|
; CHECK-NEXT: f2_1:
|
|
; CHECK-NEXT: .Lfunc_begin2:
|
|
; CHECK-NEXT: .cfi_startproc
|
|
; CHECK-NEXT: // %bb.0:
|
|
; CHECK-NEXT: hint #34
|
|
; CHECK-NEXT: nop
|
|
; CHECK-NEXT: ret
|
|
; CHECK: .Lfunc_end2:
|
|
; CHECK-NEXT: .size f2_1, .Lfunc_end2-f2_1
|
|
; CHECK: .section __patchable_function_entries,"awo",@progbits,f2_1{{$}}
|
|
; CHECK-NEXT: .p2align 3
|
|
; CHECK-NEXT: .xword .Ltmp0
|
|
ret void
|
|
}
|
|
|
|
;; -fpatchable-function-entry=1 -mbranch-protection=bti
|
|
;; For SysV compliant targets, we don't add BTI (or create the .Lpatch0 symbol)
|
|
;; because the function has internal linkage and isn't address-taken. For
|
|
;; non-SysV targets, we do add the BTI, because outside SYSVABI64 there's no
|
|
;; spec preventing the static linker from using an indirect call instruction in
|
|
;; a long-branch thunk inserted at link time.
|
|
define internal void @f1i(i64 %v) "patchable-function-entry"="1" "branch-target-enforcement" {
|
|
; CHECK-LABEL: f1i:
|
|
; CHECK-NEXT: .Lfunc_begin3:
|
|
; CHECK: // %bb.0:
|
|
; NONSYSV-NEXT: hint #34
|
|
; NONSYSV-NEXT: .Lpatch1:
|
|
; CHECK-NEXT: nop
|
|
;; Other basic blocks have BTI, but they don't affect our decision to not create .Lpatch0
|
|
; CHECK: .LBB{{.+}} // %sw.bb1
|
|
; CHECK-NEXT: hint #36
|
|
; CHECK: .section __patchable_function_entries,"awo",@progbits,f1i{{$}}
|
|
; CHECK-NEXT: .p2align 3
|
|
; NONSYSV-NEXT: .xword .Lpatch1
|
|
; SYSV-NEXT: .xword .Lfunc_begin3
|
|
entry:
|
|
switch i64 %v, label %sw.bb0 [
|
|
i64 1, label %sw.bb1
|
|
i64 2, label %sw.bb2
|
|
i64 3, label %sw.bb3
|
|
i64 4, label %sw.bb4
|
|
]
|
|
sw.bb0:
|
|
call void asm sideeffect "nop", ""()
|
|
ret void
|
|
sw.bb1:
|
|
call void asm sideeffect "", ""()
|
|
ret void
|
|
sw.bb2:
|
|
call void asm sideeffect "", ""()
|
|
ret void
|
|
sw.bb3:
|
|
call void asm sideeffect "", ""()
|
|
ret void
|
|
sw.bb4:
|
|
call void asm sideeffect "", ""()
|
|
ret void
|
|
}
|
|
|
|
;; Test the interaction with -fsanitize=function.
|
|
; CHECK: .type sanitize_function,@function
|
|
; CHECK-NEXT: .Ltmp{{.*}}:
|
|
; CHECK-NEXT: nop
|
|
; CHECK-NEXT: .word 3238382334 // 0xc105cafe
|
|
; CHECK-NEXT: .word 42
|
|
; CHECK-NEXT: sanitize_function:
|
|
; CHECK-NEXT: .Lfunc_begin{{.*}}:
|
|
; CHECK-NEXT: .cfi_startproc
|
|
; CHECK-NEXT: // %bb.0:
|
|
; CHECK-NEXT: hint #34
|
|
; CHECK-NEXT: nop
|
|
; CHECK-NEXT: ret
|
|
define void @sanitize_function(ptr noundef %x) "patchable-function-prefix"="1" "patchable-function-entry"="1" "branch-target-enforcement" !func_sanitize !0 {
|
|
ret void
|
|
}
|
|
|
|
!0 = !{i32 3238382334, i32 42}
|