[llvm] afd2058 - MachineFunction: -fsanitize={function, kcfi}: ensure 4-byte alignment

Fangrui Song via llvm-commits llvm-commits at lists.llvm.org
Fri Jun 30 09:13:24 PDT 2023


Author: Fangrui Song
Date: 2023-06-30T09:13:19-07:00
New Revision: afd20587f9952654a9a9ec427052220b5e3a6982

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

LOG: MachineFunction: -fsanitize={function,kcfi}: ensure 4-byte alignment

Fix https://github.com/llvm/llvm-project/issues/63579
```
% cat a.c
void foo() {}
% clang --target=arm-none-eabi -mthumb -mno-unaligned-access -fsanitize=kcfi a.c -S -o - | grep p2align
        .p2align        1
% clang --target=armv6m-none-eabi -fsanitize=function a.c -S -o - | grep p2align
        .p2align        1
```

Ensure that -fsanitize={function,kcfi} instrumented functions are aligned by at
least 4, so that loading the type hash before the function label will not cause
a misaligned access. This is especially important for -mno-unaligned-access
configurations that don't set `setMinFunctionAlignment` to 4 or greater.

With this patch, the generated assembly for the examples above will contain `.p2align 2`
before the type hash.

If `__attribute__((aligned(N)))` or `-falign-functions=N` is specified, the
larger alignment will be used.

Reviewed By: simon_tatham, samitolvanen

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

Added: 
    llvm/test/CodeGen/ARM/func-sanitizer.ll
    llvm/test/CodeGen/ARM/kcfi.ll

Modified: 
    llvm/lib/CodeGen/MachineFunction.cpp
    llvm/test/CodeGen/RISCV/kcfi-patchable-function-prefix.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/CodeGen/MachineFunction.cpp b/llvm/lib/CodeGen/MachineFunction.cpp
index a934a5cd24ff6..88939e96e07f5 100644
--- a/llvm/lib/CodeGen/MachineFunction.cpp
+++ b/llvm/lib/CodeGen/MachineFunction.cpp
@@ -212,6 +212,14 @@ void MachineFunction::init() {
     Alignment = std::max(Alignment,
                          STI->getTargetLowering()->getPrefFunctionAlignment());
 
+  // -fsanitize=function and -fsanitize=kcfi instrument indirect function calls
+  // to load a type hash before the function label. Ensure functions are aligned
+  // by a least 4 to avoid unaligned access, which is especially important for
+  // -mno-unaligned-access.
+  if (F.hasMetadata(LLVMContext::MD_func_sanitize) ||
+      F.getMetadata(LLVMContext::MD_kcfi_type))
+    Alignment = std::max(Alignment, Align(4));
+
   if (AlignAllFunctions)
     Alignment = Align(1ULL << AlignAllFunctions);
 

diff  --git a/llvm/test/CodeGen/ARM/func-sanitizer.ll b/llvm/test/CodeGen/ARM/func-sanitizer.ll
new file mode 100644
index 0000000000000..b52707a035ca2
--- /dev/null
+++ b/llvm/test/CodeGen/ARM/func-sanitizer.ll
@@ -0,0 +1,41 @@
+; RUN: llc -mtriple=thumbv6m-none-eabi < %s | FileCheck %s
+
+; CHECK-LABEL: .globl nosan
+; CHECK-NEXT:  .p2align 1
+; CHECK-NEXT:  .type nosan,%function
+; CHECK-NEXT:  .code 16
+; CHECK-NEXT:  .thumb_func
+; CHECK-NEXT:  nosan:
+define dso_local void @nosan() nounwind {
+  ret void
+}
+
+;; The alignment is at least 4 to avoid unaligned type hash loads when this
+;; instrumented function is indirectly called.
+; CHECK-LABEL: .globl foo
+; CHECK-NEXT:  .p2align 2
+; CHECK-NEXT:  .type foo,%function
+; CHECK-NEXT:  .long 3238382334
+; CHECK-NEXT:  .long 3170468932
+; CHECK-NEXT:  .code 16
+; CHECK-NEXT:  .thumb_func
+; CHECK-NEXT:  foo:
+define dso_local void @foo() nounwind !func_sanitize !0 {
+  ret void
+}
+
+;; If "align" is smaller than 4 (required alignment from !func_sanitize), use 4.
+; CHECK-LABEL: .globl align2
+; CHECK-NEXT:  .p2align 2
+define dso_local void @align2() nounwind align 2 !func_sanitize !0 {
+  ret void
+}
+
+;; If "align" is larger than 4, use its value.
+; CHECK-LABEL: .globl align8
+; CHECK-NEXT:  .p2align 3
+define dso_local void @align8() nounwind align 8 !func_sanitize !0 {
+  ret void
+}
+
+!0 = !{i32 -1056584962, i32 -1124498364}

diff  --git a/llvm/test/CodeGen/ARM/kcfi.ll b/llvm/test/CodeGen/ARM/kcfi.ll
new file mode 100644
index 0000000000000..9e16468c9347b
--- /dev/null
+++ b/llvm/test/CodeGen/ARM/kcfi.ll
@@ -0,0 +1,28 @@
+; RUN: llc -mtriple=thumbv6m-none-eabi < %s | FileCheck %s
+
+; CHECK-LABEL: .globl nosan
+; CHECK-NEXT:  .p2align 1
+; CHECK-NEXT:  .type nosan,%function
+; CHECK-NEXT:  .code 16
+; CHECK-NEXT:  .thumb_func
+; CHECK-NEXT:  nosan:
+define dso_local void @nosan() nounwind {
+  ret void
+}
+
+;; The alignment is at least 4 to avoid unaligned type hash loads when this
+;; instrumented function is indirectly called.
+; CHECK-LABEL: .globl f1
+; CHECK-NEXT:  .p2align 2
+; CHECK-NEXT:  .type f1,%function
+; CHECK-NEXT:  .long 3170468932
+; CHECK-NEXT:  .code 16
+; CHECK-NEXT:  .thumb_func
+; CHECK-NEXT:  f1:
+define void @f1(ptr noundef %x) !kcfi_type !1 {
+  ret void
+}
+
+!llvm.module.flags = !{!0}
+!0 = !{i32 4, !"kcfi", i32 1}
+!1 = !{i32 -1124498364}

diff  --git a/llvm/test/CodeGen/RISCV/kcfi-patchable-function-prefix.ll b/llvm/test/CodeGen/RISCV/kcfi-patchable-function-prefix.ll
index 778a4215b430c..8e13bb769ea50 100644
--- a/llvm/test/CodeGen/RISCV/kcfi-patchable-function-prefix.ll
+++ b/llvm/test/CodeGen/RISCV/kcfi-patchable-function-prefix.ll
@@ -1,8 +1,10 @@
 ; RUN: llc -mtriple=riscv64 -verify-machineinstrs < %s | FileCheck %s --check-prefixes=CHECK,NOC
 ; RUN: llc -mtriple=riscv64 -mattr=+c -verify-machineinstrs < %s | FileCheck %s --check-prefixes=CHECK,C
 
-; NOC:            .p2align 2
-; C:              .p2align 1
+;; The alignment is at least 4 to avoid unaligned type hash loads when this
+;; instrumented function is indirectly called.
+; CHECK-LABEL:    .globl f1
+; CHECK:          .p2align 2
 ; CHECK-NOT:        nop
 ; CHECK:          .word   12345678
 ; CHECK-LABEL:    f1:
@@ -12,6 +14,7 @@ define void @f1(ptr noundef %x) !kcfi_type !1 {
   ret void
 }
 
+; CHECK-LABEL:    .globl f2
 ; NOC:            .p2align 2
 ; C:              .p2align 1
 ; CHECK-NOT:       .word
@@ -23,8 +26,8 @@ define void @f2(ptr noundef %x) {
   ret void
 }
 
-; NOC:            .p2align 2
-; C:              .p2align 1
+; CHECK-LABEL:    .globl f3
+; CHECK:          .p2align 2
 ; CHECK:          .word   12345678
 ; CHECK-COUNT-11:   nop
 ; CHECK-LABEL:    f3:
@@ -35,6 +38,7 @@ define void @f3(ptr noundef %x) #0 !kcfi_type !1 {
   ret void
 }
 
+; CHECK-LABEL:    .globl f4
 ; NOC:            .p2align 2
 ; C:              .p2align 1
 ; CHECK-NOT:      .word


        


More information about the llvm-commits mailing list