Files
llvm-project/llvm/test/CodeGen/ARM/kcfi-patchable-function-prefix.ll
Kees Cook d130f40264 [ARM][KCFI] Add backend support for Kernel Control-Flow Integrity (#163698)
Implement KCFI (Kernel Control Flow Integrity) backend support for
ARM32, Thumb2, and Thumb1. The Linux kernel has supported ARM KCFI via
Clang's generic KCFI implementation, but this has finally started to
[cause problems](https://github.com/ClangBuiltLinux/linux/issues/2124)
so it's time to get the KCFI operand bundle lowering working on ARM.

Supports patchable-function-prefix with adjusted load offsets. Provides
an instruction size worst case estimate of how large the KCFI bundle is
so that range-limited instructions (e.g. cbz) know how big the indirect
calls can become.

ARM implementation notes:
- Four-instruction EOR sequence builds the 32-bit type ID byte-by-byte
  to work within ARM's modified immediate encoding constraints.
- Scratch register selection: r12 (IP) is preferred, r3 used as fallback
  when r12 holds the call target. r3 gets spilled/reloaded if it is
  being used as a call argument.
- UDF trap encoding: 0x8000 | (0x1F << 5) | target_reg_index, similar
  to aarch64's trap encoding.

Thumb2 implementation notes:
- Logically the same as ARM
- UDF trap encoding: 0x80 | target_reg_index

Thumb1 implementation notes:
- Due to register pressure, 2 scratch registers are needed: r3 and r2,
  which get spilled/reloaded if they are being used as call args.
- Instead of EOR, add/lsl sequence to load immediate, followed by
  a compare.
- No trap encoding.

Update tests to validate all three sub targets.
2025-10-23 08:27:13 -07:00

100 lines
2.8 KiB
LLVM

; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
; RUN: llc -mtriple=armv7-linux-gnueabi -verify-machineinstrs < %s | FileCheck %s
; CHECK: .p2align 2
; CHECK-NOT: nop
; CHECK: .long 12345678
define void @f1(ptr noundef %x) !kcfi_type !1 {
; CHECK-LABEL: f1:
; CHECK: @ %bb.0:
; CHECK-NEXT: .save {r11, lr}
; CHECK-NEXT: push {r11, lr}
; CHECK-NEXT: bic r12, r0, #1
; CHECK-NEXT: ldr r12, [r12, #-4]
; CHECK-NEXT: eor r12, r12, #78
; CHECK-NEXT: eor r12, r12, #24832
; CHECK-NEXT: eor r12, r12, #12320768
; CHECK-NEXT: eors r12, r12, #0
; CHECK-NEXT: beq .Ltmp0
; CHECK-NEXT: udf #33760
; CHECK-NEXT: .Ltmp0:
; CHECK-NEXT: blx r0
; CHECK-NEXT: pop {r11, pc}
call void %x() [ "kcfi"(i32 12345678) ]
ret void
}
; CHECK: .p2align 2
; CHECK-NOT: .long
; CHECK-NOT: nop
define void @f2(ptr noundef %x) {
; CHECK-LABEL: f2:
; CHECK: @ %bb.0:
; CHECK-NEXT: .save {r11, lr}
; CHECK-NEXT: push {r11, lr}
; CHECK-NEXT: bic r12, r0, #1
; CHECK-NEXT: ldr r12, [r12, #-4]
; CHECK-NEXT: eor r12, r12, #78
; CHECK-NEXT: eor r12, r12, #24832
; CHECK-NEXT: eor r12, r12, #12320768
; CHECK-NEXT: eors r12, r12, #0
; CHECK-NEXT: beq .Ltmp1
; CHECK-NEXT: udf #33760
; CHECK-NEXT: .Ltmp1:
; CHECK-NEXT: blx r0
; CHECK-NEXT: pop {r11, pc}
call void %x() [ "kcfi"(i32 12345678) ]
ret void
}
; CHECK: .p2align 2
; CHECK: .long 12345678
; CHECK-COUNT-11: nop
define void @f3(ptr noundef %x) #0 !kcfi_type !1 {
; CHECK-LABEL: f3:
; CHECK: @ %bb.0:
; CHECK-NEXT: .save {r11, lr}
; CHECK-NEXT: push {r11, lr}
; CHECK-NEXT: bic r12, r0, #1
; CHECK-NEXT: ldr r12, [r12, #-48]
; CHECK-NEXT: eor r12, r12, #78
; CHECK-NEXT: eor r12, r12, #24832
; CHECK-NEXT: eor r12, r12, #12320768
; CHECK-NEXT: eors r12, r12, #0
; CHECK-NEXT: beq .Ltmp3
; CHECK-NEXT: udf #33760
; CHECK-NEXT: .Ltmp3:
; CHECK-NEXT: blx r0
; CHECK-NEXT: pop {r11, pc}
call void %x() [ "kcfi"(i32 12345678) ]
ret void
}
; CHECK: .p2align 2
; CHECK-COUNT-11: nop
define void @f4(ptr noundef %x) #0 {
; CHECK-LABEL: f4:
; CHECK: @ %bb.0:
; CHECK-NEXT: .save {r11, lr}
; CHECK-NEXT: push {r11, lr}
; CHECK-NEXT: bic r12, r0, #1
; CHECK-NEXT: ldr r12, [r12, #-48]
; CHECK-NEXT: eor r12, r12, #78
; CHECK-NEXT: eor r12, r12, #24832
; CHECK-NEXT: eor r12, r12, #12320768
; CHECK-NEXT: eors r12, r12, #0
; CHECK-NEXT: beq .Ltmp5
; CHECK-NEXT: udf #33760
; CHECK-NEXT: .Ltmp5:
; CHECK-NEXT: blx r0
; CHECK-NEXT: pop {r11, pc}
call void %x() [ "kcfi"(i32 12345678) ]
ret void
}
attributes #0 = { "patchable-function-prefix"="11" }
!llvm.module.flags = !{!0}
!0 = !{i32 4, !"kcfi", i32 1}
!1 = !{i32 12345678}