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 @@ -1179,6 +1179,7 @@ } static const unsigned kX86JumpTableEntrySize = 8; +static const unsigned kX86IBTJumpTableEntrySize = 16; static const unsigned kARMJumpTableEntrySize = 4; static const unsigned kARMBTIJumpTableEntrySize = 8; static const unsigned kRISCVJumpTableEntrySize = 8; @@ -1187,6 +1188,10 @@ switch (Arch) { case Triple::x86: case Triple::x86_64: + if (const auto *MD = mdconst::extract_or_null( + M.getModuleFlag("cf-protection-branch"))) + if (MD->getZExtValue()) + return kX86IBTJumpTableEntrySize; return kX86JumpTableEntrySize; case Triple::arm: case Triple::thumb: @@ -1215,8 +1220,17 @@ unsigned ArgIndex = AsmArgs.size(); if (JumpTableArch == Triple::x86 || JumpTableArch == Triple::x86_64) { + bool Endbr = false; + if (const auto *MD = mdconst::extract_or_null( + Dest->getParent()->getModuleFlag("cf-protection-branch"))) + Endbr = MD->getZExtValue() != 0; + if (Endbr) + AsmOS << (JumpTableArch == Triple::x86 ? "endbr32\n" : "endbr64\n"); AsmOS << "jmp ${" << ArgIndex << ":c}@plt\n"; - AsmOS << "int3\nint3\nint3\n"; + if (Endbr) + AsmOS << ".balign 16, 0xcc\n"; + else + AsmOS << "int3\nint3\nint3\n"; } else if (JumpTableArch == Triple::arm) { AsmOS << "b $" << ArgIndex << "\n"; } else if (JumpTableArch == Triple::aarch64) { @@ -1398,6 +1412,8 @@ // the linker. F->addFnAttr("target-features", "-c,-relax"); } + if (JumpTableArch == Triple::x86 || JumpTableArch == Triple::x86_64) + F->addFnAttr(Attribute::NoCfCheck); // Make sure we don't emit .eh_frame for this function. F->addFnAttr(Attribute::NoUnwind); diff --git a/llvm/test/Transforms/LowerTypeTests/x86-jumptable.ll b/llvm/test/Transforms/LowerTypeTests/x86-jumptable.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/LowerTypeTests/x86-jumptable.ll @@ -0,0 +1,31 @@ +;; Test jump table generation with Indirect Branch Tracking on x86. +; RUN: opt -S -passes=lowertypetests -mtriple=i686 %s | FileCheck --check-prefixes=X86,X86_32 %s +; RUN: opt -S -passes=lowertypetests -mtriple=x86_64 %s | FileCheck --check-prefixes=X86,X86_64 %s + +@0 = private unnamed_addr constant [2 x ptr] [ptr @f, ptr @g], align 16 + +define void @f() !type !0 { + ret void +} + +define internal void @g() !type !0 { + ret void +} + +declare i1 @llvm.type.test(ptr %ptr, metadata %bitset) nounwind readnone + +define i1 @foo(ptr %p) { + %x = call i1 @llvm.type.test(ptr %p, metadata !"typeid1") + ret i1 %x +} + +!llvm.module.flags = !{!1} +!0 = !{i32 0, !"typeid1"} +!1 = !{i32 8, !"cf-protection-branch", i32 1} + +; X86: define private void @.cfi.jumptable() #[[#ATTR:]] align 16 { +; X86-NEXT: entry: +; X86_32-NEXT: call void asm sideeffect "endbr32\0Ajmp ${0:c}@plt\0A.balign 16, 0xcc\0Aendbr32\0Ajmp ${1:c}@plt\0A.balign 16, 0xcc\0A", "s,s"(ptr @f.cfi, ptr @g.cfi) +; X86_64-NEXT: call void asm sideeffect "endbr64\0Ajmp ${0:c}@plt\0A.balign 16, 0xcc\0Aendbr64\0Ajmp ${1:c}@plt\0A.balign 16, 0xcc\0A", "s,s"(ptr @f.cfi, ptr @g.cfi) + +; X86_64: attributes #[[#ATTR]] = { naked nocf_check nounwind }