[llvm] ce4bb08 - [KCFI] Fix hash offset calculation in Thumb mode

Sami Tolvanen via llvm-commits llvm-commits at lists.llvm.org
Mon Jun 12 12:44:27 PDT 2023


Author: Sami Tolvanen
Date: 2023-06-12T19:43:34Z
New Revision: ce4bb083c043d42474cd071bd5149dc5fd4430f6

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

LOG: [KCFI] Fix hash offset calculation in Thumb mode

ARM stores the Thumb state in the least significant bit of the
function pointers. When compiling for ARM or Thumb, as all
instructions are at least 16-bit aligned, ignore the LSB when
computing the prefix hash location, so we can support both
pure Thumb and mixed ARM/Thumb binaries.

Fixes #62936

Reviewed By: MaskRay, simon_tatham

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

Added: 
    

Modified: 
    llvm/lib/Transforms/Instrumentation/KCFI.cpp
    llvm/test/Transforms/KCFI/kcfi.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/Instrumentation/KCFI.cpp b/llvm/lib/Transforms/Instrumentation/KCFI.cpp
index eacbb02828658..b1a26880c7010 100644
--- a/llvm/lib/Transforms/Instrumentation/KCFI.cpp
+++ b/llvm/lib/Transforms/Instrumentation/KCFI.cpp
@@ -73,6 +73,7 @@ PreservedAnalyses KCFIPass::run(Function &F, FunctionAnalysisManager &AM) {
   IntegerType *Int32Ty = Type::getInt32Ty(Ctx);
   MDNode *VeryUnlikelyWeights =
       MDBuilder(Ctx).createBranchWeights(1, (1U << 20) - 1);
+  Triple T(M.getTargetTriple());
 
   for (CallInst *CI : KCFICalls) {
     // Get the expected hash value.
@@ -93,8 +94,18 @@ PreservedAnalyses KCFIPass::run(Function &F, FunctionAnalysisManager &AM) {
 
     // Emit a check and trap if the target hash doesn't match.
     IRBuilder<> Builder(Call);
-    Value *HashPtr = Builder.CreateConstInBoundsGEP1_32(
-        Int32Ty, Call->getCalledOperand(), -1);
+    Value *FuncPtr = Call->getCalledOperand();
+    // ARM uses the least significant bit of the function pointer to select
+    // between ARM and Thumb modes for the callee. Instructions are always
+    // at least 16-bit aligned, so clear the LSB before we compute the hash
+    // location.
+    if (T.isARM() || T.isThumb()) {
+      FuncPtr = Builder.CreateIntToPtr(
+          Builder.CreateAnd(Builder.CreatePtrToInt(FuncPtr, Int32Ty),
+                            ConstantInt::get(Int32Ty, -2)),
+          FuncPtr->getType());
+    }
+    Value *HashPtr = Builder.CreateConstInBoundsGEP1_32(Int32Ty, FuncPtr, -1);
     Value *Test = Builder.CreateICmpNE(Builder.CreateLoad(Int32Ty, HashPtr),
                                        ConstantInt::get(Int32Ty, ExpectedHash));
     Instruction *ThenTerm =

diff  --git a/llvm/test/Transforms/KCFI/kcfi.ll b/llvm/test/Transforms/KCFI/kcfi.ll
index f6028ae782193..41ef9140358cd 100644
--- a/llvm/test/Transforms/KCFI/kcfi.ll
+++ b/llvm/test/Transforms/KCFI/kcfi.ll
@@ -1,8 +1,13 @@
-; RUN: opt -S -passes=kcfi %s | FileCheck %s
+; RUN: opt -S -passes=kcfi %s | FileCheck --check-prefixes=CHECK,NOARM %s
+; RUN: %if arm-registered-target %{ opt -S -passes=kcfi -mtriple=thumbv7m-unknown-linux-gnu %s | FileCheck --check-prefixes=CHECK,ARM %s %}
 
 ; CHECK-LABEL: define void @f1(
 define void @f1(ptr noundef %x) {
-  ; CHECK:      %[[#GEPI:]] = getelementptr inbounds i32, ptr %x, i32 -1
+  ; ARM:        %[[#FINT:]] = ptrtoint ptr %x to i32
+  ; ARM-NEXT:   %[[#FAND:]] = and i32 %[[#FINT]], -2
+  ; ARM-NEXT:   %[[#FPTR:]] = inttoptr i32 %[[#FAND]] to ptr
+  ; ARM-NEXT:   %[[#GEPI:]] = getelementptr inbounds i32, ptr %[[#FPTR]], i32 -1
+  ; NOARM:      %[[#GEPI:]] = getelementptr inbounds i32, ptr %x, i32 -1
   ; CHECK-NEXT: %[[#LOAD:]] = load i32, ptr %[[#GEPI]], align 4
   ; CHECK-NEXT: %[[#ICMP:]] = icmp ne i32 %[[#LOAD]], 12345678
   ; CHECK-NEXT: br i1 %[[#ICMP]], label %[[#TRAP:]], label %[[#CALL:]], !prof ![[#WEIGHTS:]]


        


More information about the llvm-commits mailing list