From 6f867f9102838ebe314c1f3661fdf95700386e5a Mon Sep 17 00:00:00 2001 From: Phoebe Wang Date: Fri, 29 Jul 2022 17:47:49 +0800 Subject: [PATCH] [X86] Support ``-mindirect-branch-cs-prefix`` for call and jmp to indirect thunk This is to address feature request from https://github.com/ClangBuiltLinux/linux/issues/1665 Reviewed By: nickdesaulniers, MaskRay Differential Revision: https://reviews.llvm.org/D130754 --- clang/docs/ReleaseNotes.rst | 2 + clang/include/clang/Basic/CodeGenOptions.def | 2 + clang/include/clang/Driver/Options.td | 4 ++ clang/lib/CodeGen/CodeGenModule.cpp | 3 ++ clang/lib/Driver/ToolChains/Clang.cpp | 2 + clang/test/CodeGen/X86/indirect-branch-cs-prefix.c | 4 ++ clang/test/Driver/x86_features.c | 7 ++- llvm/lib/Target/X86/X86MCInstLower.cpp | 12 ++++- llvm/lib/Target/X86/X86ReturnThunks.cpp | 6 +++ llvm/test/CodeGen/X86/attr-function-return.ll | 5 +++ llvm/test/CodeGen/X86/lvi-hardening-indirectbr.ll | 52 +++++++++++++++------- 11 files changed, 80 insertions(+), 19 deletions(-) create mode 100644 clang/test/CodeGen/X86/indirect-branch-cs-prefix.c diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index dd0d802..7d90b08 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -138,6 +138,8 @@ CUDA Support in Clang 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 index ef79579..1d32281 100644 --- a/clang/include/clang/Basic/CodeGenOptions.def +++ b/clang/include/clang/Basic/CodeGenOptions.def @@ -108,6 +108,8 @@ CODEGENOPT(CFProtectionBranch , 1, 0) ///< if -fcf-protection is ///< 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 index 709dbfd..be84975 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -2025,6 +2025,10 @@ def mfunction_return_EQ : Joined<["-"], "mfunction-return=">, 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 index dc1122f..537cb78 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -775,6 +775,9 @@ void CodeGenModule::Release() { 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 index 231eed2..7e88a20 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -6359,6 +6359,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, 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 index 0000000..369db26 --- /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 index e657dbf..7900b15 100644 --- 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 index 0972e80..76ddb3d 100644 --- a/llvm/lib/Target/X86/X86MCInstLower.cpp +++ b/llvm/lib/Target/X86/X86MCInstLower.cpp @@ -2440,6 +2440,9 @@ void X86AsmPrinter::emitInstruction(const MachineInstr *MI) { 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 @@ void X86AsmPrinter::emitInstruction(const MachineInstr *MI) { 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 @@ void X86AsmPrinter::emitInstruction(const MachineInstr *MI) { .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 index 4b20322..0107fab 100644 --- 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 @@ bool X86ReturnThunks::runOnMachineFunction(MachineFunction &MF) { 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 index f40d971..091a8ea 100644 --- 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 index 7bc0fe7..b6e6e61 100644 --- a/llvm/test/CodeGen/X86/lvi-hardening-indirectbr.ll +++ b/llvm/test/CodeGen/X86/lvi-hardening-indirectbr.ll @@ -22,18 +22,22 @@ entry: ; 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 @@ define void @icall_global_fp(i32 %x, ptr %fpp) #0 { ; 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 @@ define void @vcall(ptr %obj) #0 { ; 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 @@ define void @nonlazybind_caller() #0 { ; 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 @@ latch: ; X64-NEXT: jmpq *%r11 attributes #1 = { nonlazybind } + +!llvm.module.flags = !{!0} + +!0 = !{i32 4, !"indirect_branch_cs_prefix", i32 1} -- 2.7.4