diff --git a/llvm/lib/Transforms/Instrumentation/KCFI.cpp b/llvm/lib/Transforms/Instrumentation/KCFI.cpp --- a/llvm/lib/Transforms/Instrumentation/KCFI.cpp +++ b/llvm/lib/Transforms/Instrumentation/KCFI.cpp @@ -73,6 +73,7 @@ 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 @@ // 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 --- 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:]]