[llvm] f8aa5f6 - [Hexagon] Add KCFI support for forward-edge control flow integrity (#191746)

via llvm-commits llvm-commits at lists.llvm.org
Tue Jun 23 07:32:05 PDT 2026


Author: Brian Cain
Date: 2026-06-23T09:32:00-05:00
New Revision: f8aa5f66209d69c2c1f033317a4b4be961f4a78c

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

LOG: [Hexagon] Add KCFI support for forward-edge control flow integrity (#191746)

Add KCFI support for Hexagon. KCFI provides lightweight forward-edge CFI
for indirect calls by embedding a type hash before each function and
checking it before indirect calls, without requiring LTO.

Added: 
    llvm/test/CodeGen/Hexagon/kcfi.ll

Modified: 
    llvm/lib/Target/Hexagon/HexagonAsmPrinter.cpp
    llvm/lib/Target/Hexagon/HexagonAsmPrinter.h
    llvm/lib/Target/Hexagon/HexagonISelLowering.cpp
    llvm/lib/Target/Hexagon/HexagonISelLowering.h
    llvm/lib/Target/Hexagon/HexagonMCInstLower.cpp
    llvm/lib/Target/Hexagon/HexagonPseudo.td
    llvm/lib/Target/Hexagon/HexagonTargetMachine.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/Hexagon/HexagonAsmPrinter.cpp b/llvm/lib/Target/Hexagon/HexagonAsmPrinter.cpp
index 2a1427b38142c..61ca9020bb689 100644
--- a/llvm/lib/Target/Hexagon/HexagonAsmPrinter.cpp
+++ b/llvm/lib/Target/Hexagon/HexagonAsmPrinter.cpp
@@ -976,6 +976,115 @@ void HexagonAsmPrinter::LowerPATCHABLE_EVENT_CALL(const MachineInstr &MI,
              Typed ? SledKind::TYPED_EVENT : SledKind::CUSTOM_EVENT, 2);
 }
 
+void HexagonAsmPrinter::LowerKCFI_CHECK(const MachineInstr &MI) {
+  Register AddrReg = MI.getOperand(0).getReg();
+  const int64_t Type = MI.getOperand(1).getImm();
+  MachineBasicBlock::const_instr_iterator NextI = std::next(MI.getIterator());
+  assert(NextI != MI.getParent()->instr_end() && NextI->isCall() &&
+         "KCFI_CHECK not followed by a call instruction");
+  assert(NextI->getOperand(0).getReg() == AddrReg &&
+         "KCFI_CHECK call target doesn't match call operand");
+
+  // Scratch registers for the compare. Default to R6/R7 (caller-saved,
+  // in GeneralSubRegs for potential compounding). If AddrReg conflicts,
+  // fall back through other caller-saved registers.
+  unsigned ScratchRegs[] = {Hexagon::R6, Hexagon::R7};
+  unsigned NextReg = Hexagon::R8;
+  for (auto &Reg : ScratchRegs) {
+    if (Reg != AddrReg)
+      continue;
+    if (NextReg == AddrReg)
+      ++NextReg;
+    Reg = NextReg++;
+  }
+  unsigned LoadReg = ScratchRegs[0];
+  unsigned TypeReg = ScratchRegs[1];
+  unsigned PredReg = Hexagon::P0;
+
+  // Adjust for patchable-function-prefix (nop padding before the function).
+  int64_t PrefixNops = MI.getMF()->getFunction().getFnAttributeAsParsedInteger(
+      "patchable-function-prefix");
+  int64_t Offset = -(PrefixNops * 4 + 4);
+
+  // Emit the KCFI check sequence.
+  //
+  // Packet 1: Load the type hash and materialize the expected hash together.
+  // The load offset fits in the native instruction field for any
+  // patchable-function-prefix count, so it never requires a constant
+  // extender.  This lets the extender for ##hash share the same packet,
+  // saving one packet compared to emitting them separately.
+  //   { r_load = memw(r_addr + #offset); r_type = ##expected_hash }
+  MCInst *LoadInst = OutContext.createMCInst();
+  LoadInst->setOpcode(Hexagon::L2_loadri_io);
+  LoadInst->addOperand(MCOperand::createReg(LoadReg));
+  LoadInst->addOperand(MCOperand::createReg(AddrReg));
+  LoadInst->addOperand(MCOperand::createExpr(HexagonMCExpr::create(
+      MCConstantExpr::create(Offset, OutContext), OutContext)));
+
+  MCInst *TypeInst = OutContext.createMCInst();
+  TypeInst->setOpcode(Hexagon::A2_tfrsi);
+  TypeInst->addOperand(MCOperand::createReg(TypeReg));
+  auto *TypeExpr = HexagonMCExpr::create(
+      MCConstantExpr::create(Type, OutContext), OutContext);
+  HexagonMCInstrInfo::setMustExtend(*TypeExpr, true);
+  TypeInst->addOperand(MCOperand::createExpr(TypeExpr));
+
+  MCInst LoadTypePacket;
+  LoadTypePacket.setOpcode(Hexagon::BUNDLE);
+  LoadTypePacket.addOperand(MCOperand::createImm(0));
+  LoadTypePacket.addOperand(MCOperand::createInst(LoadInst));
+  LoadTypePacket.addOperand(MCOperand::createInst(TypeInst));
+  EmitToStreamer(*OutStreamer, LoadTypePacket);
+
+  // Packet 3: Compare and branch if equal.
+  //   { p0 = cmp.eq(r_load, r_type); if (p0.new) jump:t .Lpass }
+  MCSymbol *Pass = OutContext.createTempSymbol();
+
+  MCInst *CmpInst = OutContext.createMCInst();
+  CmpInst->setOpcode(Hexagon::C2_cmpeq);
+  CmpInst->addOperand(MCOperand::createReg(PredReg));
+  CmpInst->addOperand(MCOperand::createReg(LoadReg));
+  CmpInst->addOperand(MCOperand::createReg(TypeReg));
+
+  MCInst *JumpInst = OutContext.createMCInst();
+  JumpInst->setOpcode(Hexagon::J2_jumptnewpt);
+  JumpInst->addOperand(MCOperand::createReg(PredReg));
+  JumpInst->addOperand(MCOperand::createExpr(HexagonMCExpr::create(
+      MCSymbolRefExpr::create(Pass, OutContext), OutContext)));
+
+  MCInst CmpJmpPacket;
+  CmpJmpPacket.setOpcode(Hexagon::BUNDLE);
+  CmpJmpPacket.addOperand(MCOperand::createImm(0));
+  CmpJmpPacket.addOperand(MCOperand::createInst(CmpInst));
+  CmpJmpPacket.addOperand(MCOperand::createInst(JumpInst));
+  EmitToStreamer(*OutStreamer, CmpJmpPacket);
+
+  // Packet 4: Crash on mismatch via misaligned load.
+  // Use the same mechanism as llvm.trap (PS_crash): a doubleword load from
+  // a misaligned address is guaranteed to fault in all execution modes,
+  // including kernel/monitor mode where trap0 may not generate a useful
+  // exception.
+  MCSymbol *TrapLabel = OutContext.createTempSymbol();
+  OutStreamer->emitLabel(TrapLabel);
+
+  MCInst *CrashInst = OutContext.createMCInst();
+  CrashInst->setOpcode(Hexagon::PS_loadrdabs);
+  CrashInst->addOperand(MCOperand::createReg(Hexagon::D13));
+  auto *CrashExpr = HexagonMCExpr::create(
+      MCConstantExpr::create(0xBADC0FEE, OutContext), OutContext);
+  HexagonMCInstrInfo::setMustExtend(*CrashExpr, true);
+  CrashInst->addOperand(MCOperand::createExpr(CrashExpr));
+
+  MCInst CrashPacket;
+  CrashPacket.setOpcode(Hexagon::BUNDLE);
+  CrashPacket.addOperand(MCOperand::createImm(0));
+  CrashPacket.addOperand(MCOperand::createInst(CrashInst));
+  EmitToStreamer(*OutStreamer, CrashPacket);
+
+  emitKCFITrapEntry(*MI.getMF(), TrapLabel);
+  OutStreamer->emitLabel(Pass);
+}
+
 void HexagonAsmPrinter::EmitSled(const MachineInstr &MI, SledKind Kind) {
   static const int8_t NoopsInSledCount = 6;
   // We want to emit the following pattern:

diff  --git a/llvm/lib/Target/Hexagon/HexagonAsmPrinter.h b/llvm/lib/Target/Hexagon/HexagonAsmPrinter.h
index 83621142ca5b5..1c71a2739bd49 100644
--- a/llvm/lib/Target/Hexagon/HexagonAsmPrinter.h
+++ b/llvm/lib/Target/Hexagon/HexagonAsmPrinter.h
@@ -68,6 +68,9 @@ class TargetMachine;
     void LowerPATCHABLE_EVENT_CALL(const MachineInstr &MI, bool Typed);
     void EmitSled(const MachineInstr &MI, SledKind Kind);
 
+    // KCFI check lowering.
+    void LowerKCFI_CHECK(const MachineInstr &MI);
+
     void HexagonProcessInstruction(MCInst &Inst, const MachineInstr &MBB);
 
     void printOperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O);

diff  --git a/llvm/lib/Target/Hexagon/HexagonISelLowering.cpp b/llvm/lib/Target/Hexagon/HexagonISelLowering.cpp
index b369bdff477d6..acafd754969d7 100644
--- a/llvm/lib/Target/Hexagon/HexagonISelLowering.cpp
+++ b/llvm/lib/Target/Hexagon/HexagonISelLowering.cpp
@@ -644,6 +644,8 @@ HexagonTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
 
   unsigned OpCode = DoesNotReturn ? HexagonISD::CALLnr : HexagonISD::CALL;
   Chain = DAG.getNode(OpCode, dl, {MVT::Other, MVT::Glue}, Ops);
+  if (CLI.CFIType)
+    Chain.getNode()->setCFIType(CLI.CFIType->getZExtValue());
   Glue = Chain.getValue(1);
 
   // Create the CALLSEQ_END node.
@@ -3971,6 +3973,31 @@ MachineBasicBlock *HexagonTargetLowering::EmitInstrWithCustomInserter(
   }
 }
 
+MachineInstr *
+HexagonTargetLowering::EmitKCFICheck(MachineBasicBlock &MBB,
+                                     MachineBasicBlock::instr_iterator &MBBI,
+                                     const TargetInstrInfo *TII) const {
+  assert(MBBI->isCall() && MBBI->getCFIType() &&
+         "Invalid call instruction for a KCFI check");
+
+  switch (MBBI->getOpcode()) {
+  case Hexagon::J2_callr:
+  case Hexagon::PS_callr_nr:
+    break;
+  default:
+    llvm_unreachable("Unexpected CFI call opcode");
+  }
+
+  MachineOperand &Target = MBBI->getOperand(0);
+  assert(Target.isReg() && "Invalid target operand for an indirect call");
+  Target.setIsRenamable(false);
+
+  return BuildMI(MBB, MBBI, MBBI->getDebugLoc(), TII->get(Hexagon::KCFI_CHECK))
+      .addReg(Target.getReg())
+      .addImm(MBBI->getCFIType())
+      .getInstr();
+}
+
 bool HexagonTargetLowering::isMaskAndCmp0FoldingBeneficial(
     const Instruction &AndI) const {
   // Only sink 'and' mask to cmp use block if it is masking a single bit since

diff  --git a/llvm/lib/Target/Hexagon/HexagonISelLowering.h b/llvm/lib/Target/Hexagon/HexagonISelLowering.h
index 00152d7615769..87041e696f0f4 100644
--- a/llvm/lib/Target/Hexagon/HexagonISelLowering.h
+++ b/llvm/lib/Target/Hexagon/HexagonISelLowering.h
@@ -291,6 +291,12 @@ class HexagonTargetLowering : public TargetLowering {
   EmitInstrWithCustomInserter(MachineInstr &MI,
                               MachineBasicBlock *BB) const override;
 
+  bool supportKCFIBundles() const override { return true; }
+
+  MachineInstr *EmitKCFICheck(MachineBasicBlock &MBB,
+                              MachineBasicBlock::instr_iterator &MBBI,
+                              const TargetInstrInfo *TII) const override;
+
 private:
   void initializeHVXLowering();
   unsigned getPreferredHvxVectorAction(MVT VecTy) const;

diff  --git a/llvm/lib/Target/Hexagon/HexagonMCInstLower.cpp b/llvm/lib/Target/Hexagon/HexagonMCInstLower.cpp
index c592a55615859..668c5e436e5ff 100644
--- a/llvm/lib/Target/Hexagon/HexagonMCInstLower.cpp
+++ b/llvm/lib/Target/Hexagon/HexagonMCInstLower.cpp
@@ -123,6 +123,10 @@ void llvm::HexagonLowerToMC(const MCInstrInfo &MCII, const MachineInstr *MI,
     AP.LowerPATCHABLE_EVENT_CALL(*MI, true);
     return;
   }
+  if (MI->getOpcode() == Hexagon::KCFI_CHECK) {
+    AP.LowerKCFI_CHECK(*MI);
+    return;
+  }
 
   MCInst *MCI = AP.OutContext.createMCInst();
   MCI->setOpcode(MI->getOpcode());

diff  --git a/llvm/lib/Target/Hexagon/HexagonPseudo.td b/llvm/lib/Target/Hexagon/HexagonPseudo.td
index 4e5e8c3d26f00..d75a5c0e51ce8 100644
--- a/llvm/lib/Target/Hexagon/HexagonPseudo.td
+++ b/llvm/lib/Target/Hexagon/HexagonPseudo.td
@@ -621,6 +621,16 @@ defm PS_storerd : NewCircularStore<DoubleRegs, WordAccess>;
 let hasSideEffects = 1, isPseudo = 1, isCodeGenOnly = 1, isSolo = 1 in
 def PS_crash: InstHexagon<(outs), (ins), "", [], "", PSEUDO, TypePSEUDO>;
 
+// KCFI type check pseudo -- lowered in the AsmPrinter to a
+// load-compare-trap sequence before indirect calls. On mismatch, a
+// misaligned load faults.
+// Defs: R6/R7 default scratch (R8 fallback if AddrReg conflicts), P0 for
+// compare, D13 for the crash load.
+let hasSideEffects = 1, mayLoad = 1, isPseudo = 1, isCodeGenOnly = 1,
+    Defs = [R6, R7, R8, P0, D13], Size = 28 in
+def KCFI_CHECK : InstHexagon<(outs), (ins IntRegs:$ptr, i32imm:$type),
+                              "", [], "", PSEUDO, TypePSEUDO>;
+
 // This is actual trap1 instruction from before v65. It's here since it is
 // no longer included in DepInstrInfo.td.
 def PS_trap1 : HInst<(outs), (ins u8_0Imm:$Ii), "trap1(#$Ii)", tc_53c851ab,

diff  --git a/llvm/lib/Target/Hexagon/HexagonTargetMachine.cpp b/llvm/lib/Target/Hexagon/HexagonTargetMachine.cpp
index 5c72b6cb20883..5d835c9c6e71c 100644
--- a/llvm/lib/Target/Hexagon/HexagonTargetMachine.cpp
+++ b/llvm/lib/Target/Hexagon/HexagonTargetMachine.cpp
@@ -508,6 +508,10 @@ void HexagonPassConfig::addPreEmitPass() {
       addPass(&HexagonLiveVariablesID);
   }
 
+  // Emit KCFI checks for indirect calls. Must run before packetization so
+  // the check and call can be bundled together into a VLIW packet.
+  addPass(createKCFIPass());
+
   // Packetization is mandatory: it handles gather/scatter at all opt levels.
   addPass(createHexagonPacketizer(NoOpt));
 

diff  --git a/llvm/test/CodeGen/Hexagon/kcfi.ll b/llvm/test/CodeGen/Hexagon/kcfi.ll
new file mode 100644
index 0000000000000..7fd2ee4a9e16d
--- /dev/null
+++ b/llvm/test/CodeGen/Hexagon/kcfi.ll
@@ -0,0 +1,191 @@
+; RUN: llc -mtriple=hexagon -verify-machineinstrs < %s | FileCheck %s --check-prefix=ASM
+; RUN: llc -mtriple=hexagon -verify-machineinstrs -stop-after=finalize-isel < %s \
+; RUN:   | FileCheck %s --check-prefix=ISEL
+; RUN: llc -mtriple=hexagon -verify-machineinstrs -stop-after=kcfi < %s \
+; RUN:   | FileCheck %s --check-prefix=KCFI
+
+; Verify KCFI type hash is emitted before the function.
+; ASM:       .word 12345678
+; ASM-LABEL: f1:
+
+define void @f1(ptr noundef %x) !kcfi_type !1 {
+; Load and type-hash materialization are combined in one packet.
+; ASM:       r{{[0-9]+}} = memw(r0+#-4)
+; ASM-NEXT:  r{{[0-9]+}} = ##12345678
+; ASM-NEXT:  }
+; ASM-NEXT:  {
+; ASM-NEXT:    p0 = cmp.eq(r{{[0-9]+}},r{{[0-9]+}})
+; ASM-NEXT:    if (p0.new) jump:t
+; ASM-NEXT:  }
+; ASM:       r{{[0-9]+}}:{{[0-9]+}} = memd(##3134984174)
+
+; After ISel, the call should carry a cfi-type.
+; ISEL-LABEL: name: f1
+; ISEL:       J2_callr %0,{{.*}} cfi-type 12345678
+
+; After the KCFI pass, the check and call are bundled.
+; KCFI-LABEL: name: f1
+; KCFI:       BUNDLE{{.*}} {
+; KCFI-NEXT:    KCFI_CHECK $r0, 12345678
+; KCFI-NEXT:    J2_callr killed $r0
+; KCFI-NEXT:  }
+
+  call void %x() [ "kcfi"(i32 12345678) ]
+  ret void
+}
+
+; Test with a second call using a 
diff erent type hash.
+define void @f2(ptr noundef %x) !kcfi_type !2 {
+; ASM-LABEL: f2:
+; ASM:       r{{[0-9]+}} = memw(r0+#-4)
+; ASM-NEXT:  r{{[0-9]+}} = ##1234
+; ASM-NEXT:  }
+; ASM-NEXT:  {
+; ASM-NEXT:    p0 = cmp.eq(r{{[0-9]+}},r{{[0-9]+}})
+; ASM-NEXT:    if (p0.new) jump:t
+; ASM-NEXT:  }
+; ASM:       r{{[0-9]+}}:{{[0-9]+}} = memd(##3134984174)
+
+  call void %x() [ "kcfi"(i32 1234) ]
+  ret void
+}
+
+; Test with patchable-function-entry (nops placed after the label,
+; so the KCFI offset is still -4).
+define void @f3(ptr noundef %x) #0 {
+; ASM-LABEL: f3:
+; ASM:       nop
+; ASM:       nop
+; ASM:       r{{[0-9]+}} = memw(r0+#-4)
+; ASM-NEXT:  r{{[0-9]+}} = ##12345678
+; ASM-NEXT:  }
+; ASM-NEXT:  {
+; ASM-NEXT:    p0 = cmp.eq(r{{[0-9]+}},r{{[0-9]+}})
+; ASM-NEXT:    if (p0.new) jump:t
+; ASM-NEXT:  }
+; ASM:       r{{[0-9]+}}:{{[0-9]+}} = memd(##3134984174)
+
+  call void %x() [ "kcfi"(i32 12345678) ]
+  ret void
+}
+
+;; Test patchable-function-prefix: nops are placed before the function entry
+;; (after the type hash), so the KCFI load offset is adjusted from -4 to
+;; -(PrefixNops*4 + 4).
+define void @f4_prefix(ptr noundef %x) #1 !kcfi_type !1 {
+; ASM-LABEL: f4_prefix:
+; ASM:       r{{[0-9]+}} = memw(r0+#-12)
+; ASM-NEXT:  r{{[0-9]+}} = ##12345678
+; ASM-NEXT:  }
+; ASM-NEXT:  {
+; ASM-NEXT:    p0 = cmp.eq(r{{[0-9]+}},r{{[0-9]+}})
+; ASM-NEXT:    if (p0.new) jump:t
+; ASM-NEXT:  }
+; ASM:       r{{[0-9]+}}:{{[0-9]+}} = memd(##3134984174)
+
+  call void %x() [ "kcfi"(i32 12345678) ]
+  ret void
+}
+
+;; Test patchable-function-prefix with 3 nops: offset = -(3*4+4) = -16.
+define void @f5_prefix3(ptr noundef %x) #2 !kcfi_type !1 {
+; ASM-LABEL: f5_prefix3:
+; ASM:       r{{[0-9]+}} = memw(r0+#-16)
+; ASM-NEXT:  r{{[0-9]+}} = ##12345678
+; ASM-NEXT:  }
+; ASM-NEXT:  {
+; ASM-NEXT:    p0 = cmp.eq(r{{[0-9]+}},r{{[0-9]+}})
+; ASM-NEXT:    if (p0.new) jump:t
+; ASM-NEXT:  }
+; ASM:       r{{[0-9]+}}:{{[0-9]+}} = memd(##3134984174)
+
+  call void %x() [ "kcfi"(i32 12345678) ]
+  ret void
+}
+
+;; Test scratch register conflict: call target is R6. The default scratch
+;; registers are R6/R7, so when the target occupies R6, the load scratch
+;; must use R8 instead.
+define void @f6_target_r6() {
+; ASM-LABEL: f6_target_r6:
+; ASM:       r8 = memw(r6+#-4)
+; ASM-NEXT:  r7 = ##12345678
+; ASM-NEXT:  }
+; ASM-NEXT:  {
+; ASM-NEXT:    p0 = cmp.eq(r8,r7)
+; ASM-NEXT:    if (p0.new) jump:t
+; ASM-NEXT:  }
+; ASM:       r{{[0-9]+}}:{{[0-9]+}} = memd(##3134984174)
+
+; KCFI-LABEL: name: f6_target_r6
+; KCFI:       BUNDLE{{.*}} {
+; KCFI-NEXT:    KCFI_CHECK $r6, 12345678
+; KCFI-NEXT:    J2_callr{{.*}}killed $r6
+; KCFI-NEXT:  }
+
+  %target = call ptr asm sideeffect "", "={r6}"()
+  call void %target() [ "kcfi"(i32 12345678) ]
+  ret void
+}
+
+;; Test scratch register conflict: call target is R7. The type-hash scratch
+;; must use R8 instead.
+define void @f7_target_r7() {
+; ASM-LABEL: f7_target_r7:
+; ASM:       r6 = memw(r7+#-4)
+; ASM-NEXT:  r8 = ##12345678
+; ASM-NEXT:  }
+; ASM-NEXT:  {
+; ASM-NEXT:    p0 = cmp.eq(r6,r8)
+; ASM-NEXT:    if (p0.new) jump:t
+; ASM-NEXT:  }
+; ASM:       r{{[0-9]+}}:{{[0-9]+}} = memd(##3134984174)
+
+; KCFI-LABEL: name: f7_target_r7
+; KCFI:       BUNDLE{{.*}} {
+; KCFI-NEXT:    KCFI_CHECK $r7, 12345678
+; KCFI-NEXT:    J2_callr{{.*}}killed $r7
+; KCFI-NEXT:  }
+
+  %target = call ptr asm sideeffect "", "={r7}"()
+  call void %target() [ "kcfi"(i32 12345678) ]
+  ret void
+}
+
+;; Test noreturn indirect call with KCFI (uses PS_callr_nr opcode).
+define void @f8_noreturn(ptr noundef %x) {
+; ASM-LABEL: f8_noreturn:
+; ASM:       r{{[0-9]+}} = memw(r0+#-4)
+; ASM-NEXT:  r{{[0-9]+}} = ##12345678
+; ASM-NEXT:  }
+; ASM-NEXT:  {
+; ASM-NEXT:    p0 = cmp.eq(r{{[0-9]+}},r{{[0-9]+}})
+; ASM-NEXT:    if (p0.new) jump:t
+; ASM-NEXT:  }
+; ASM:       r{{[0-9]+}}:{{[0-9]+}} = memd(##3134984174)
+
+; ISEL-LABEL: name: f8_noreturn
+; ISEL:       PS_callr_nr %0,{{.*}} cfi-type 12345678
+
+; KCFI-LABEL: name: f8_noreturn
+; KCFI:       BUNDLE{{.*}} {
+; KCFI-NEXT:    KCFI_CHECK $r0, 12345678
+; KCFI-NEXT:    PS_callr_nr killed $r0
+; KCFI-NEXT:  }
+
+  call void %x() #3 [ "kcfi"(i32 12345678) ]
+  unreachable
+}
+
+; Verify the .kcfi_traps section is emitted.
+; ASM:       .section .kcfi_traps
+
+attributes #0 = { "patchable-function-entry"="2" }
+attributes #1 = { "patchable-function-prefix"="2" }
+attributes #2 = { "patchable-function-prefix"="3" }
+attributes #3 = { noreturn }
+
+!llvm.module.flags = !{!0}
+!0 = !{i32 4, !"kcfi", i32 1}
+!1 = !{i32 12345678}
+!2 = !{i32 1234}


        


More information about the llvm-commits mailing list