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) { @@ -1389,6 +1403,9 @@ // by Clang for -march=armv7. F->addFnAttr("target-cpu", "cortex-a8"); } + // When -mbranch-protection= is used, the inline asm adds a BTI. Suppress BTI + // for the function to avoid double BTI. This is a no-op without + // -mbranch-protection=. if (JumpTableArch == Triple::aarch64) { F->addFnAttr("branch-target-enforcement", "false"); F->addFnAttr("sign-return-address", "none"); @@ -1398,6 +1415,11 @@ // the linker. F->addFnAttr("target-features", "-c,-relax"); } + // When -fcf-protection= is used, the inline asm adds an ENDBR. Suppress ENDBR + // for the function to avoid double ENDBR. This is a no-op without + // -fcf-protection=. + 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/function.ll b/llvm/test/Transforms/LowerTypeTests/function.ll --- a/llvm/test/Transforms/LowerTypeTests/function.ll +++ b/llvm/test/Transforms/LowerTypeTests/function.ll @@ -77,8 +77,8 @@ ; NATIVE-SAME: "s,s"(ptr @f.cfi, ptr @g.cfi) -; X86-LINUX: attributes #[[ATTR]] = { naked nounwind } -; X86-WIN32: attributes #[[ATTR]] = { nounwind } +; X86-LINUX: attributes #[[ATTR]] = { naked nocf_check nounwind } +; X86-WIN32: attributes #[[ATTR]] = { nocf_check nounwind } ; ARM: attributes #[[ATTR]] = { naked nounwind ; THUMB: attributes #[[ATTR]] = { naked nounwind "target-cpu"="cortex-a8" "target-features"="+thumb-mode" } ; RISCV: attributes #[[ATTR]] = { naked nounwind "target-features"="-c,-relax" } 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 }