diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -138,6 +138,8 @@ X86 Support in Clang -------------------- +- Support ``-mindirect-branch-cs-prefix`` for call and jmp to indirect thunk. + DWARF Support in Clang ---------------------- diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def --- a/clang/include/clang/Basic/CodeGenOptions.def +++ b/clang/include/clang/Basic/CodeGenOptions.def @@ -108,6 +108,8 @@ ///< 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. diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -2025,6 +2025,10 @@ NormalizedValues<["Keep", "Extern"]>, NormalizedValuesScope<"llvm::FunctionReturnThunksKind">, MarshallingInfoEnum, "Keep">; +def mindirect_branch_cs_prefix : Flag<["-"], "mindirect-branch-cs-prefix">, + Group, Flags<[CoreOption, CC1Option]>, + HelpText<"Add cs prefix to call and jmp to indirect thunk">, + MarshallingInfoFlag>; defm xray_instrument : BoolFOption<"xray-instrument", LangOpts<"XRayInstrument">, DefaultFalse, diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -775,6 +775,9 @@ 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 diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -6359,6 +6359,8 @@ 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. diff --git a/clang/test/CodeGen/X86/indirect-branch-cs-prefix.c b/clang/test/CodeGen/X86/indirect-branch-cs-prefix.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/X86/indirect-branch-cs-prefix.c @@ -0,0 +1,4 @@ +// 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() {} diff --git a/clang/test/Driver/x86_features.c b/clang/test/Driver/x86_features.c --- a/clang/test/Driver/x86_features.c +++ b/clang/test/Driver/x86_features.c @@ -6,8 +6,11 @@ // 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" diff --git a/llvm/lib/Target/X86/X86MCInstLower.cpp b/llvm/lib/Target/X86/X86MCInstLower.cpp --- a/llvm/lib/Target/X86/X86MCInstLower.cpp +++ b/llvm/lib/Target/X86/X86MCInstLower.cpp @@ -2440,6 +2440,9 @@ 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"); @@ -2488,13 +2491,16 @@ 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: @@ -2668,6 +2674,10 @@ .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; diff --git a/llvm/lib/Target/X86/X86ReturnThunks.cpp b/llvm/lib/Target/X86/X86ReturnThunks.cpp --- a/llvm/lib/Target/X86/X86ReturnThunks.cpp +++ b/llvm/lib/Target/X86/X86ReturnThunks.cpp @@ -34,6 +34,7 @@ #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" @@ -73,9 +74,14 @@ 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(); diff --git a/llvm/test/CodeGen/X86/attr-function-return.ll b/llvm/test/CodeGen/X86/attr-function-return.ll --- a/llvm/test/CodeGen/X86/attr-function-return.ll +++ b/llvm/test/CodeGen/X86/attr-function-return.ll @@ -6,6 +6,11 @@ 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} diff --git a/llvm/test/CodeGen/X86/lvi-hardening-indirectbr.ll b/llvm/test/CodeGen/X86/lvi-hardening-indirectbr.ll --- a/llvm/test/CodeGen/X86/lvi-hardening-indirectbr.ll +++ b/llvm/test/CodeGen/X86/lvi-hardening-indirectbr.ll @@ -22,18 +22,22 @@ ; 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 @@ -50,16 +54,20 @@ ; 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 } @@ -79,14 +87,18 @@ ; 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() @@ -113,14 +125,18 @@ ; 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 @@ -278,3 +294,7 @@ ; X64-NEXT: jmpq *%r11 attributes #1 = { nonlazybind } + +!llvm.module.flags = !{!0} + +!0 = !{i32 4, !"indirect_branch_cs_prefix", i32 1}