X86 Support in Clang
--------------------
+- Support ``-mindirect-branch-cs-prefix`` for call and jmp to indirect thunk.
+
DWARF Support in Clang
----------------------
///< set to full or branch.
CODEGENOPT(IBTSeal, 1, 0) ///< set to optimize CFProtectionBranch.
CODEGENOPT(FunctionReturnThunks, 1, 0) ///< -mfunction-return={keep|thunk-extern}
+CODEGENOPT(IndirectBranchCSPrefix, 1, 0) ///< if -mindirect-branch-cs-prefix
+ ///< is set.
CODEGENOPT(XRayInstrumentFunctions , 1, 0) ///< Set when -fxray-instrument is
///< enabled.
NormalizedValues<["Keep", "Extern"]>,
NormalizedValuesScope<"llvm::FunctionReturnThunksKind">,
MarshallingInfoEnum<CodeGenOpts<"FunctionReturnThunks">, "Keep">;
+def mindirect_branch_cs_prefix : Flag<["-"], "mindirect-branch-cs-prefix">,
+ Group<m_Group>, Flags<[CoreOption, CC1Option]>,
+ HelpText<"Add cs prefix to call and jmp to indirect thunk">,
+ MarshallingInfoFlag<CodeGenOpts<"IndirectBranchCSPrefix">>;
defm xray_instrument : BoolFOption<"xray-instrument",
LangOpts<"XRayInstrument">, DefaultFalse,
if (CodeGenOpts.FunctionReturnThunks)
getModule().addModuleFlag(llvm::Module::Override, "function_return_thunk_extern", 1);
+ if (CodeGenOpts.IndirectBranchCSPrefix)
+ getModule().addModuleFlag(llvm::Module::Override, "indirect_branch_cs_prefix", 1);
+
// Add module metadata for return address signing (ignoring
// non-leaf/all) and stack tagging. These are actually turned on by function
// attributes, but we use module metadata to emit build attributes. This is
CmdArgs.push_back(
Args.MakeArgString(Twine("-mfunction-return=") + A->getValue()));
+ Args.AddLastArg(CmdArgs, options::OPT_mindirect_branch_cs_prefix);
+
// Forward -f options with positive and negative forms; we translate these by
// hand. Do not propagate PGO options to the GPU-side compilations as the
// profile info is for the host-side compilation only.
--- /dev/null
+// RUN: %clang -target i386-unknown-unknown -o - -emit-llvm -S -mindirect-branch-cs-prefix %s | FileCheck %s
+
+// CHECK: !{i32 4, !"indirect_branch_cs_prefix", i32 1}
+void foo() {}
// RUN: %clang -### %s -mieee-fp -S 2>&1 | FileCheck --check-prefix=IEEE %s
// IEEE-NOT: error: unknown argument
-// RUN: %clang -target i386-unknown-unknown -### %s -mskip-rax-setup -S 2>&1 | FileCheck --check-prefix=SRS %s
+// RUN: %clang --target=i386 -### %s -mskip-rax-setup -S 2>&1 | FileCheck --check-prefix=SRS %s
// SRS: "-mskip-rax-setup"
-// RUN: %clang -target i386-unknown-unknown -### %s -mno-skip-rax-setup -S 2>&1 | FileCheck --check-prefix=NO-SRS %s
+// RUN: %clang --target=i386 -### %s -mno-skip-rax-setup -S 2>&1 | FileCheck --check-prefix=NO-SRS %s
// NO-SRS-NOT: "-mskip-rax-setup"
+
+// RUN: %clang --target=i386 -### %s -mindirect-branch-cs-prefix -S 2>&1 | FileCheck --check-prefix=IND-CS %s
+// IND-CS: "-mindirect-branch-cs-prefix"
if (OutStreamer->isVerboseAsm())
addConstantComments(MI, *OutStreamer);
+ bool IndCS =
+ MF->getMMI().getModule()->getModuleFlag("indirect_branch_cs_prefix");
+
switch (MI->getOpcode()) {
case TargetOpcode::DBG_VALUE:
llvm_unreachable("Should be handled target independently");
break;
}
+ case X86::TAILJMPd64:
+ if (IndCS && MI->hasRegisterImplicitUseOperand(X86::R11))
+ EmitAndCountInstruction(MCInstBuilder(X86::CS_PREFIX));
+ LLVM_FALLTHROUGH;
case X86::TAILJMPr:
case X86::TAILJMPm:
case X86::TAILJMPd:
case X86::TAILJMPd_CC:
case X86::TAILJMPr64:
case X86::TAILJMPm64:
- case X86::TAILJMPd64:
case X86::TAILJMPd64_CC:
case X86::TAILJMPr64_REX:
case X86::TAILJMPm64_REX:
.addImm(MI->getOperand(0).getImm())
.addReg(X86::NoRegister));
return;
+ case X86::CALL64pcrel32:
+ if (IndCS && MI->hasRegisterImplicitUseOperand(X86::R11))
+ EmitAndCountInstruction(MCInstBuilder(X86::CS_PREFIX));
+ break;
}
MCInst TmpInst;
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/MC/MCInstrDesc.h"
#include "llvm/Support/Debug.h"
if (Term.getOpcode() == RetOpc)
Rets.push_back(&Term);
+ bool IndCS =
+ MF.getMMI().getModule()->getModuleFlag("indirect_branch_cs_prefix");
+ const MCInstrDesc &CS = ST.getInstrInfo()->get(X86::CS_PREFIX);
const MCInstrDesc &JMP = ST.getInstrInfo()->get(X86::TAILJMPd);
for (MachineInstr *Ret : Rets) {
+ if (IndCS)
+ BuildMI(Ret->getParent(), Ret->getDebugLoc(), CS);
BuildMI(Ret->getParent(), Ret->getDebugLoc(), JMP)
.addExternalSymbol(ThunkName.data());
Ret->eraseFromParent();
define void @x() fn_ret_thunk_extern {
; CHECK-LABEL: x:
; CHECK: # %bb.0:
+; CHECK-NEXT: cs
; CHECK-NEXT: jmp __x86_return_thunk
ret void
}
+
+!llvm.module.flags = !{!0}
+
+!0 = !{i32 4, !"indirect_branch_cs_prefix", i32 1}
; X64: callq bar
; X64-DAG: movl %[[x]], %edi
; X64-DAG: movq %[[fp]], %r11
-; X64: callq __llvm_lvi_thunk_r11
+; X64: cs
+; X64-NEXT: callq __llvm_lvi_thunk_r11
; X64: movl %[[x]], %edi
; X64: callq bar
; X64-DAG: movl %[[x]], %edi
; X64-DAG: movq %[[fp]], %r11
-; X64: jmp __llvm_lvi_thunk_r11 # TAILCALL
+; X64: cs
+; X64-NEXT: jmp __llvm_lvi_thunk_r11 # TAILCALL
; X64FAST-LABEL: icall_reg:
; X64FAST: callq bar
-; X64FAST: callq __llvm_lvi_thunk_r11
+; X64FAST: cs
+; X64FAST-NEXT: callq __llvm_lvi_thunk_r11
; X64FAST: callq bar
-; X64FAST: jmp __llvm_lvi_thunk_r11 # TAILCALL
+; X64FAST: cs
+; X64FAST-NEXT: jmp __llvm_lvi_thunk_r11 # TAILCALL
@global_fp = external dso_local global ptr
; X64-LABEL: icall_global_fp:
; X64-DAG: movl %edi, %[[x:[^ ]*]]
; X64-DAG: movq global_fp(%rip), %r11
-; X64: callq __llvm_lvi_thunk_r11
+; X64: cs
+; X64-NEXT: callq __llvm_lvi_thunk_r11
; X64-DAG: movl %[[x]], %edi
; X64-DAG: movq global_fp(%rip), %r11
-; X64: jmp __llvm_lvi_thunk_r11 # TAILCALL
+; X64: cs
+; X64-NEXT: jmp __llvm_lvi_thunk_r11 # TAILCALL
; X64FAST-LABEL: icall_global_fp:
; X64FAST: movq global_fp(%rip), %r11
-; X64FAST: callq __llvm_lvi_thunk_r11
+; X64FAST: cs
+; X64FAST-NEXT: callq __llvm_lvi_thunk_r11
; X64FAST: movq global_fp(%rip), %r11
-; X64FAST: jmp __llvm_lvi_thunk_r11 # TAILCALL
+; X64FAST: cs
+; X64FAST-NEXT: jmp __llvm_lvi_thunk_r11 # TAILCALL
%struct.Foo = type { ptr }
; X64: movq (%rdi), %[[vptr:[^ ]*]]
; X64: movq 8(%[[vptr]]), %[[fp:[^ ]*]]
; X64: movq %[[fp]], %r11
-; X64: callq __llvm_lvi_thunk_r11
+; X64: cs
+; X64-NEXT: callq __llvm_lvi_thunk_r11
; X64-DAG: movq %[[obj]], %rdi
; X64-DAG: movq %[[fp]], %r11
-; X64: jmp __llvm_lvi_thunk_r11 # TAILCALL
+; X64: cs
+; X64-NEXT: jmp __llvm_lvi_thunk_r11 # TAILCALL
; X64FAST-LABEL: vcall:
-; X64FAST: callq __llvm_lvi_thunk_r11
-; X64FAST: jmp __llvm_lvi_thunk_r11 # TAILCALL
+; X64FAST: cs
+; X64FAST-NEXT: callq __llvm_lvi_thunk_r11
+; X64FAST: cs
+; X64FAST-NEXT: jmp __llvm_lvi_thunk_r11 # TAILCALL
declare dso_local void @direct_callee()
; X64-LABEL: nonlazybind_caller:
; X64: movq nonlazybind_callee@GOTPCREL(%rip), %[[REG:.*]]
; X64: movq %[[REG]], %r11
-; X64: callq __llvm_lvi_thunk_r11
+; X64: cs
+; X64-NEXT: callq __llvm_lvi_thunk_r11
; X64: movq %[[REG]], %r11
-; X64: jmp __llvm_lvi_thunk_r11 # TAILCALL
+; X64: cs
+; X64-NEXT: jmp __llvm_lvi_thunk_r11 # TAILCALL
; X64FAST-LABEL: nonlazybind_caller:
; X64FAST: movq nonlazybind_callee@GOTPCREL(%rip), %r11
-; X64FAST: callq __llvm_lvi_thunk_r11
+; X64FAST: cs
+; X64FAST-NEXT: callq __llvm_lvi_thunk_r11
; X64FAST: movq nonlazybind_callee@GOTPCREL(%rip), %r11
-; X64FAST: jmp __llvm_lvi_thunk_r11 # TAILCALL
+; X64FAST: cs
+; X64FAST-NEXT: jmp __llvm_lvi_thunk_r11 # TAILCALL
; Check that a switch gets lowered using a jump table
; X64-NEXT: jmpq *%r11
attributes #1 = { nonlazybind }
+
+!llvm.module.flags = !{!0}
+
+!0 = !{i32 4, !"indirect_branch_cs_prefix", i32 1}