diff --git a/llvm/lib/Transforms/IPO/LowerTypeTests.cpp b/llvm/lib/Transforms/IPO/LowerTypeTests.cpp --- a/llvm/lib/Transforms/IPO/LowerTypeTests.cpp +++ b/llvm/lib/Transforms/IPO/LowerTypeTests.cpp @@ -1205,6 +1205,7 @@ static const unsigned kX86JumpTableEntrySize = 8; static const unsigned kARMJumpTableEntrySize = 4; +static const unsigned kARMBTIJumpTableEntrySize = 8; unsigned LowerTypeTestsModule::getJumpTableEntrySize() { switch (Arch) { @@ -1213,7 +1214,12 @@ return kX86JumpTableEntrySize; case Triple::arm: case Triple::thumb: + return kARMJumpTableEntrySize; case Triple::aarch64: + if (const auto *BTE = mdconst::extract_or_null( + M.getModuleFlag("branch-target-enforcement"))) + if (BTE->getZExtValue()) + return kARMBTIJumpTableEntrySize; return kARMJumpTableEntrySize; default: report_fatal_error("Unsupported architecture for jump tables"); @@ -1232,7 +1238,13 @@ if (JumpTableArch == Triple::x86 || JumpTableArch == Triple::x86_64) { AsmOS << "jmp ${" << ArgIndex << ":c}@plt\n"; AsmOS << "int3\nint3\nint3\n"; - } else if (JumpTableArch == Triple::arm || JumpTableArch == Triple::aarch64) { + } else if (JumpTableArch == Triple::arm) { + AsmOS << "b $" << ArgIndex << "\n"; + } else if (JumpTableArch == Triple::aarch64) { + if (const auto *BTE = mdconst::extract_or_null( + Dest->getParent()->getModuleFlag("branch-target-enforcement"))) + if (BTE->getZExtValue()) + AsmOS << "bti c\n"; AsmOS << "b $" << ArgIndex << "\n"; } else if (JumpTableArch == Triple::thumb) { AsmOS << "b.w $" << ArgIndex << "\n"; @@ -1394,6 +1406,10 @@ // by Clang for -march=armv7. F->addFnAttr("target-cpu", "cortex-a8"); } + if (JumpTableArch == Triple::aarch64) { + F->addFnAttr("branch-target-enforcement", "false"); + F->addFnAttr("sign-return-address", "none"); + } // Make sure we don't emit .eh_frame for this function. F->addFnAttr(Attribute::NoUnwind); diff --git a/llvm/test/Transforms/LowerTypeTests/aarch64-jumptable.ll b/llvm/test/Transforms/LowerTypeTests/aarch64-jumptable.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/LowerTypeTests/aarch64-jumptable.ll @@ -0,0 +1,39 @@ +; RUN: opt -S -lowertypetests -mtriple=aarch64-unknown-linux-gnu < %s | FileCheck --check-prefixes=AARCH64 %s + +; Test for the jump table generation with branch protection on AArch64 + +target datalayout = "e-p:64:64" + +@0 = private unnamed_addr constant [2 x void (...)*] [void (...)* bitcast (void ()* @f to void (...)*), void (...)* bitcast (void ()* @g to void (...)*)], align 16 + +; AARCH64: @f = alias void (), void ()* @[[JT:.*]] + +define void @f() !type !0 { + ret void +} + +define internal void @g() !type !0 { + ret void +} + +!0 = !{i32 0, !"typeid1"} + +declare i1 @llvm.type.test(i8* %ptr, metadata %bitset) nounwind readnone + +define i1 @foo(i8* %p) { + %x = call i1 @llvm.type.test(i8* %p, metadata !"typeid1") + ret i1 %x +} + +!llvm.module.flags = !{!1} + +!1 = !{i32 4, !"branch-target-enforcement", i32 1} + +; AARCH64: define private void @[[JT]]() #[[ATTR:.*]] align 8 { + +; AARCH64: bti c +; AARCH64-SAME: b $0 +; AARCH64-SAME: bti c +; AARCH64-SAME: b $1 + +; AARCH64: attributes #[[ATTR]] = { naked nounwind "branch-target-enforcement"="false" "sign-return-address"="none"