Index: lib/CodeGen/StackProtector.cpp =================================================================== --- lib/CodeGen/StackProtector.cpp +++ lib/CodeGen/StackProtector.cpp @@ -349,6 +349,43 @@ StackGuardVar = M->getOrInsertGlobal("__guard_local", PtrTy); cast(StackGuardVar) ->setVisibility(GlobalValue::HiddenVisibility); + } else if (TT.isOSMSVCRT()) { + LLVMContext &Context = RI->getContext(); + Type *ArgTy = Type::getInt32Ty(Context); + MDString *SPReg = MDString::get(Context, "esp"); + Function *RRTy = + Intrinsic::getDeclaration(M, Intrinsic::read_register, ArgTy); + + switch (TT.getArch()) { + default: + report_fatal_error("unsupported arch for Windows stack protection"); + case Triple::x86_64: + ArgTy = Type::getInt64Ty(Context); + SPReg = MDString::get(Context, "rsp"); + RRTy = Intrinsic::getDeclaration(M, Intrinsic::read_register, ArgTy); + /* fallthrough */ + case Triple::x86: { + Value *Cookie = M->getOrInsertGlobal("__security_cookie", ArgTy); + + IRBuilder<> IRB(&F->getEntryBlock().front()); + + /// %StackGuardSlot = alloca [i32|i64] + /// %SecurityCookie = load [i32|i64]* @__security_cookie + /// %StackPointer = call [i32|i64]* @llvm.read_register.[i32|i64](metadata !0) + /// %Canary = xor [i32|i64] %SecurityCookie, %StackPointer + /// store [i32|i64] %Canary, [i32|i64]* %StackGuardSlot + AI = IRB.CreateAlloca(ArgTy, nullptr, "StackGuardSlot"); + LoadInst *SecurityCookie = IRB.CreateLoad(Cookie, "SecurityCookie"); + Value *R = MetadataAsValue::get(Context, MDNode::get(Context, SPReg)); + CallInst *StackPointer = IRB.CreateCall(RRTy, R, "StackPointer"); + Value *Canary = IRB.CreateXor(SecurityCookie, StackPointer, "Canary"); + IRB.CreateStore(Canary, AI); + + break; + } + } + + return false; } else { SupportsSelectionDAGSP = true; StackGuardVar = M->getOrInsertGlobal("__stack_chk_guard", PtrTy); @@ -389,6 +426,8 @@ } if (SupportsSelectionDAGSP) { + assert(!Trip.isOSMSVCRT() && "MSVCRT SSP cannot be lowered via SelDAG"); + // Since we have a potential tail call, insert the special stack check // intrinsic. Instruction *InsertionPt = nullptr; @@ -406,6 +445,51 @@ Intrinsic::getDeclaration(M, Intrinsic::stackprotectorcheck); CallInst::Create(Intrinsic, StackGuardVar, "", InsertionPt); } else { + LLVMContext &Context = RI->getContext(); + Type *ArgTy = Type::getInt32Ty(Context); + MDString *SPReg = MDString::get(Context, "esp"); + Function *RRTy = + Intrinsic::getDeclaration(M, Intrinsic::read_register, ArgTy); + + if (Trip.isOSMSVCRT()) { + switch (Trip.getArch()) { + default: + report_fatal_error("unsupported arch for Windows stack protection"); + case Triple::x86_64: + ArgTy = Type::getInt64Ty(RI->getContext()); + SPReg = MDString::get(Context, "rsp"); + RRTy = Intrinsic::getDeclaration(M, Intrinsic::read_register, ArgTy); + /* fallthrough */ + case Triple::x86: { + Constant *SecurityCheckCookie = + M->getOrInsertFunction("__security_check_cookie", + Type::getVoidTy(Context), ArgTy, nullptr); + if (Trip.getArch() == Triple::x86) { + Function *F = cast(SecurityCheckCookie); + F->setCallingConv(CallingConv::X86_FastCall); + F->addAttribute(1, Attribute::InReg); + } + + IRBuilder<> IRB(RI); + + /// %SavedCanary = load [i32|i64]* %StackGuardSlot + /// %StackPointer = call [i32|i64] @llvm.read_register.[i32|o64](metadata !0) + /// %Cookie = xor [i32|i64] %SavedCanary, %StackPointer + /// call void @__security_check_cookie([i32|i64] %Cookie) + LoadInst *SavedCanary = IRB.CreateLoad(AI, "SavedCanary"); + Value *R = MetadataAsValue::get(Context, MDNode::get(Context, SPReg)); + CallInst *StackPointer = IRB.CreateCall(RRTy, R, "StackPointer"); + Value *Cookie = IRB.CreateXor(SavedCanary, StackPointer, "Cookie"); + CallInst *Check = IRB.CreateCall(SecurityCheckCookie, Cookie); + if (Trip.getArch() == Triple::x86) { + Check->setCallingConv(CallingConv::X86_FastCall); + Check->addAttribute(1, Attribute::InReg); + } + } + } + continue; + } + // If we do not support SelectionDAG based tail calls, generate IR level // tail calls. // Index: test/CodeGen/X86/windows-ssp-x64.ll =================================================================== --- /dev/null +++ test/CodeGen/X86/windows-ssp-x64.ll @@ -0,0 +1,49 @@ +; RUN: llc -mtriple x86_64-windows-msvc -filetype asm -o - %s | FileCheck %s + +target triple = "x86_64--windows-msvc" + +@__security_cookie = external global i64 + +declare i64 @llvm.read_register.i64(metadata) +declare void @__security_check_cookie(i64) +declare void @memset(i8*, i32, i64) + +define void @function() { + %StackGuardSlot = alloca i64 + %SecurityCookie = load i64* @__security_cookie + %StackPointer = call i64 @llvm.read_register.i64(metadata !0) + %Canary = xor i64 %SecurityCookie, %StackPointer + store i64 %Canary, i64* %StackGuardSlot + + %buffer = alloca [8 x i8], align 1 + %arraydecay = bitcast [8 x i8]* %buffer to i8* + call void @memset(i8* %arraydecay, i32 0, i64 9) + + %SavedCanary = load i64* %StackGuardSlot + %StackPointer1 = call i64 @llvm.read_register.i64(metadata !0) + %Cookie = xor i64 %SavedCanary, %StackPointer1 + call void @__security_check_cookie(i64 %Cookie) + + ret void +} + +; CHECK-LABEL: function + +; CHECK: movq %rsp, %[[RSI:r..]] +; CHECK-NEXT: movq __security_cookie(%rip), %[[RAX:r..]] +; CHECK-NEXT: xorq %[[RSI]], %[[RAX]] +; CHECK-NEXT: movq %[[RAX]], [[OFFSET:[0-9]+]](%rsp) + +; CHECK: callq memset + +; CHECK: xorq [[OFFSET]](%rsp), %[[RSI]] +; CHECK-NEXT: movq %[[RSI]], %rcx +; CHECK-NEXT: callq __security_check_cookie + +define i32 @main() { + call void @function() + ret i32 0 +} + +!0 = !{!"rsp\00"} + Index: test/CodeGen/X86/windows-ssp-x86.ll =================================================================== --- /dev/null +++ test/CodeGen/X86/windows-ssp-x86.ll @@ -0,0 +1,47 @@ +; RUN: llc -mtriple i686-windows-msvc -filetype asm -o - %s | FileCheck %s + +target triple = "i686--windows-msvc" + +@__security_cookie = external global i32 + +declare i32 @llvm.read_register.i32(metadata) +declare x86_fastcallcc void @__security_check_cookie(i32 inreg) +declare void @memset(i8*, i32, i32) + +define void @function() { + %StackGuardSlot = alloca i32 + %SecurityCookie = load i32* @__security_cookie + %StackPointer = call i32 @llvm.read_register.i32(metadata !0) + %Canary = xor i32 %SecurityCookie, %StackPointer + store i32 %Canary, i32* %StackGuardSlot + + %buffer = alloca [8 x i8], align 1 + %arraydecay = bitcast [8 x i8]* %buffer to i8* + call void @memset(i8* %arraydecay, i32 0, i32 9) + + %SavedCanary = load i32* %StackGuardSlot + %StackPointer1 = call i32 @llvm.read_register.i32(metadata !0) + %Cookie = xor i32 %SavedCanary, %StackPointer1 + call x86_fastcallcc void @__security_check_cookie(i32 inreg %Cookie) + + ret void +} + +; CHECK-LABEL: _function +; CHECK: movl ___security_cookie, %[[EAX:e..]] +; CHECK-NEXT: xorl %[[SP:e..]], %[[EAX]] +; CHECK-NEXT: movl %[[EAX]], [[OFFSET:[0-9]+]](%esp) + +; CHECK: calll _memset + +; CHECK: xorl [[OFFSET]](%esp), %[[SP]] +; CHECK-NEXT: movl %[[SP]], %ecx +; CHECK-NEXT: calll @__security_check_cookie@4 + +define i32 @main() { + call void @function() + ret i32 0 +} + +!0 = !{!"esp\00"} +