diff options
author | Omair Javaid <omair.javaid@linaro.org> | 2025-06-12 19:38:42 +0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-06-12 19:38:42 +0500 |
commit | e1e1836bbd70e4f30bd0be97b9d81eabfd6b45c8 (patch) | |
tree | 161853a2d8cb724fdc46c3fabac05f2c4c2201df /llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp | |
parent | cc17f68e566ab7db4ac8e95dc857e49e10d8366c (diff) | |
download | llvm-e1e1836bbd70e4f30bd0be97b9d81eabfd6b45c8.zip llvm-e1e1836bbd70e4f30bd0be97b9d81eabfd6b45c8.tar.gz llvm-e1e1836bbd70e4f30bd0be97b9d81eabfd6b45c8.tar.bz2 |
[CodeGen] Inline stack guard check on Windows (#136290)
This patch optimizes the Windows security cookie check mechanism by
moving the comparison inline and only calling __security_check_cookie
when the check fails. This reduces the overhead of making a DLL call
for every function return.
Previously, we implemented this optimization through a machine pass
(X86WinFixupBufferSecurityCheckPass) in PR #95904 submitted by
@mahesh-attarde. We have reverted that pass in favor of this new
approach. Also we have abandoned the AArch64 specific implementation
of same pass in PR #121938 in favor of this more general solution.
The old machine instruction pass approach:
- Scanned the generated code to find __security_check_cookie calls
- Modified these calls by splitting basic blocks
- Added comparison logic and conditional branching
- Required complex block management and live register computation
The new approach:
- Implements the same optimization during instruction selection
- Directly emits the comparison and conditional branching
- No need for post-processing or basic block manipulation
- Disables optimization at -Oz.
Thanks @tamaspetz, @efriedma-quic and @arsenm for their help.
Diffstat (limited to 'llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp')
-rw-r--r-- | llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp | 95 |
1 files changed, 78 insertions, 17 deletions
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp index e6a1dc9..c63eb7f 100644 --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -3037,8 +3037,9 @@ void SelectionDAGBuilder::visitSPDescriptorParent(StackProtectorDescriptor &SPD, // First create the loads to the guard/stack slot for the comparison. const TargetLowering &TLI = DAG.getTargetLoweringInfo(); - EVT PtrTy = TLI.getPointerTy(DAG.getDataLayout()); - EVT PtrMemTy = TLI.getPointerMemTy(DAG.getDataLayout()); + auto &DL = DAG.getDataLayout(); + EVT PtrTy = TLI.getFrameIndexTy(DL); + EVT PtrMemTy = TLI.getPointerMemTy(DL, DL.getAllocaAddrSpace()); MachineFrameInfo &MFI = ParentBB->getParent()->getFrameInfo(); int FI = MFI.getStackProtectorIndex(); @@ -3047,8 +3048,8 @@ void SelectionDAGBuilder::visitSPDescriptorParent(StackProtectorDescriptor &SPD, SDLoc dl = getCurSDLoc(); SDValue StackSlotPtr = DAG.getFrameIndex(FI, PtrTy); const Module &M = *ParentBB->getParent()->getFunction().getParent(); - Align Align = - DAG.getDataLayout().getPrefTypeAlign(PointerType::get(M.getContext(), 0)); + Align Align = DL.getPrefTypeAlign( + PointerType::get(M.getContext(), DL.getAllocaAddrSpace())); // Generate code to load the content of the guard slot. SDValue GuardVal = DAG.getLoad( @@ -3059,8 +3060,14 @@ void SelectionDAGBuilder::visitSPDescriptorParent(StackProtectorDescriptor &SPD, if (TLI.useStackGuardXorFP()) GuardVal = TLI.emitStackGuardXorFP(DAG, GuardVal, dl); - // Retrieve guard check function, nullptr if instrumentation is inlined. - if (const Function *GuardCheckFn = TLI.getSSPStackGuardCheck(M)) { + // If we're using function-based instrumentation, call the guard check + // function + if (SPD.shouldEmitFunctionBasedCheckStackProtector()) { + // Get the guard check function from the target and verify it exists since + // we're using function-based instrumentation + const Function *GuardCheckFn = TLI.getSSPStackGuardCheck(M); + assert(GuardCheckFn && "Guard check function is null"); + // The target provides a guard check function to validate the guard value. // Generate a call to that function with the content of the guard slot as // argument. @@ -3101,10 +3108,9 @@ void SelectionDAGBuilder::visitSPDescriptorParent(StackProtectorDescriptor &SPD, } // Perform the comparison via a getsetcc. - SDValue Cmp = DAG.getSetCC(dl, TLI.getSetCCResultType(DAG.getDataLayout(), - *DAG.getContext(), - Guard.getValueType()), - Guard, GuardVal, ISD::SETNE); + SDValue Cmp = DAG.getSetCC( + dl, TLI.getSetCCResultType(DL, *DAG.getContext(), Guard.getValueType()), + Guard, GuardVal, ISD::SETNE); // If the guard/stackslot do not equal, branch to failure MBB. SDValue BrCond = DAG.getNode(ISD::BRCOND, dl, @@ -3126,14 +3132,69 @@ void SelectionDAGBuilder::visitSPDescriptorParent(StackProtectorDescriptor &SPD, /// For a high level explanation of how this fits into the stack protector /// generation see the comment on the declaration of class /// StackProtectorDescriptor. -void -SelectionDAGBuilder::visitSPDescriptorFailure(StackProtectorDescriptor &SPD) { +void SelectionDAGBuilder::visitSPDescriptorFailure( + StackProtectorDescriptor &SPD) { + const TargetLowering &TLI = DAG.getTargetLoweringInfo(); - TargetLowering::MakeLibCallOptions CallOptions; - CallOptions.setDiscardResult(true); - SDValue Chain = TLI.makeLibCall(DAG, RTLIB::STACKPROTECTOR_CHECK_FAIL, - MVT::isVoid, {}, CallOptions, getCurSDLoc()) - .second; + MachineBasicBlock *ParentBB = SPD.getParentMBB(); + const Module &M = *ParentBB->getParent()->getFunction().getParent(); + SDValue Chain; + + // For -Oz builds with a guard check function, we use function-based + // instrumentation. Otherwise, if we have a guard check function, we call it + // in the failure block. + auto *GuardCheckFn = TLI.getSSPStackGuardCheck(M); + if (GuardCheckFn && !SPD.shouldEmitFunctionBasedCheckStackProtector()) { + // First create the loads to the guard/stack slot for the comparison. + auto &DL = DAG.getDataLayout(); + EVT PtrTy = TLI.getFrameIndexTy(DL); + EVT PtrMemTy = TLI.getPointerMemTy(DL, DL.getAllocaAddrSpace()); + + MachineFrameInfo &MFI = ParentBB->getParent()->getFrameInfo(); + int FI = MFI.getStackProtectorIndex(); + + SDLoc dl = getCurSDLoc(); + SDValue StackSlotPtr = DAG.getFrameIndex(FI, PtrTy); + Align Align = DL.getPrefTypeAlign( + PointerType::get(M.getContext(), DL.getAllocaAddrSpace())); + + // Generate code to load the content of the guard slot. + SDValue GuardVal = DAG.getLoad( + PtrMemTy, dl, DAG.getEntryNode(), StackSlotPtr, + MachinePointerInfo::getFixedStack(DAG.getMachineFunction(), FI), Align, + MachineMemOperand::MOVolatile); + + if (TLI.useStackGuardXorFP()) + GuardVal = TLI.emitStackGuardXorFP(DAG, GuardVal, dl); + + // The target provides a guard check function to validate the guard value. + // Generate a call to that function with the content of the guard slot as + // argument. + FunctionType *FnTy = GuardCheckFn->getFunctionType(); + assert(FnTy->getNumParams() == 1 && "Invalid function signature"); + + TargetLowering::ArgListTy Args; + TargetLowering::ArgListEntry Entry; + Entry.Node = GuardVal; + Entry.Ty = FnTy->getParamType(0); + if (GuardCheckFn->hasParamAttribute(0, Attribute::AttrKind::InReg)) + Entry.IsInReg = true; + Args.push_back(Entry); + + TargetLowering::CallLoweringInfo CLI(DAG); + CLI.setDebugLoc(getCurSDLoc()) + .setChain(DAG.getEntryNode()) + .setCallee(GuardCheckFn->getCallingConv(), FnTy->getReturnType(), + getValue(GuardCheckFn), std::move(Args)); + + Chain = TLI.LowerCallTo(CLI).second; + } else { + TargetLowering::MakeLibCallOptions CallOptions; + CallOptions.setDiscardResult(true); + Chain = TLI.makeLibCall(DAG, RTLIB::STACKPROTECTOR_CHECK_FAIL, MVT::isVoid, + {}, CallOptions, getCurSDLoc()) + .second; + } // Emit a trap instruction if we are required to do so. const TargetOptions &TargetOpts = DAG.getTarget().Options; |