Skip to content

[CodeGen] Inline stack guard check on Windows #136290

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Jun 12, 2025
Merged
95 changes: 78 additions & 17 deletions llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -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(
Expand All @@ -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.
Expand Down Expand Up @@ -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,
Expand All @@ -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;
Expand Down
8 changes: 3 additions & 5 deletions llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1877,7 +1877,7 @@ void SelectionDAGISel::SelectAllBasicBlocks(const Function &Fn) {

if (SP->shouldEmitSDCheck(*LLVMBB)) {
bool FunctionBasedInstrumentation =
TLI->getSSPStackGuardCheck(*Fn.getParent());
TLI->getSSPStackGuardCheck(*Fn.getParent()) && Fn.hasMinSize();
SDB->SPDescriptor.initialize(LLVMBB, FuncInfo->getMBB(LLVMBB),
FunctionBasedInstrumentation);
}
Expand Down Expand Up @@ -1950,8 +1950,7 @@ SelectionDAGISel::FinishBasicBlock() {

// Add load and check to the basicblock.
FuncInfo->MBB = ParentMBB;
FuncInfo->InsertPt =
findSplitPointForStackProtector(ParentMBB, *TII);
FuncInfo->InsertPt = findSplitPointForStackProtector(ParentMBB, *TII);
SDB->visitSPDescriptorParent(SDB->SPDescriptor, ParentMBB);
CurDAG->setRoot(SDB->getRoot());
SDB->clear();
Expand All @@ -1973,8 +1972,7 @@ SelectionDAGISel::FinishBasicBlock() {
findSplitPointForStackProtector(ParentMBB, *TII);

// Splice the terminator of ParentMBB into SuccessMBB.
SuccessMBB->splice(SuccessMBB->end(), ParentMBB,
SplitPoint,
SuccessMBB->splice(SuccessMBB->end(), ParentMBB, SplitPoint,
ParentMBB->end());

// Add compare/jump on neq/jump to the parent BB.
Expand Down
1 change: 0 additions & 1 deletion llvm/lib/Target/X86/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,6 @@ set(sources
X86VZeroUpper.cpp
X86WinEHState.cpp
X86WinEHUnwindV2.cpp
X86WinFixupBufferSecurityCheck.cpp
X86InsertWait.cpp
GISel/X86CallLowering.cpp
GISel/X86InstructionSelector.cpp
Expand Down
4 changes: 0 additions & 4 deletions llvm/lib/Target/X86/X86.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,6 @@ FunctionPass *createX86OptimizeLEAs();
/// Return a pass that transforms setcc + movzx pairs into xor + setcc.
FunctionPass *createX86FixupSetCC();

/// Return a pass that transform inline buffer security check into seperate bb
FunctionPass *createX86WinFixupBufferSecurityCheckPass();

/// Return a pass that avoids creating store forward block issues in the hardware.
FunctionPass *createX86AvoidStoreForwardingBlocks();

Expand Down Expand Up @@ -195,7 +192,6 @@ void initializeX86ExpandPseudoPass(PassRegistry &);
void initializeX86FastPreTileConfigPass(PassRegistry &);
void initializeX86FastTileConfigPass(PassRegistry &);
void initializeX86FixupSetCCPassPass(PassRegistry &);
void initializeX86WinFixupBufferSecurityCheckPassPass(PassRegistry &);
void initializeX86FlagsCopyLoweringPassPass(PassRegistry &);
void initializeX86LoadValueInjectionLoadHardeningPassPass(PassRegistry &);
void initializeX86LoadValueInjectionRetHardeningPassPass(PassRegistry &);
Expand Down
1 change: 0 additions & 1 deletion llvm/lib/Target/X86/X86TargetMachine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -554,7 +554,6 @@ bool X86PassConfig::addPreISel() {
void X86PassConfig::addPreRegAlloc() {
if (getOptLevel() != CodeGenOptLevel::None) {
addPass(&LiveRangeShrinkID);
addPass(createX86WinFixupBufferSecurityCheckPass());
addPass(createX86FixupSetCC());
addPass(createX86OptimizeLEAs());
addPass(createX86CallFrameOptimization());
Expand Down
Loading
Loading