Index: include/llvm/Analysis/EHPersonalities.h =================================================================== --- include/llvm/Analysis/EHPersonalities.h +++ include/llvm/Analysis/EHPersonalities.h @@ -69,6 +69,10 @@ llvm_unreachable("invalid enum"); } +/// \brief Returns a promoted personality function compatible with +/// stack-protection. +Value* getStackGuardEHPersonality(Value *Pers); + /// \brief Return true if this personality may be safely removed if there /// are no invoke instructions remaining in the current function. inline bool isNoOpWithoutInvoke(EHPersonality Pers) { Index: lib/Analysis/EHPersonalities.cpp =================================================================== --- lib/Analysis/EHPersonalities.cpp +++ lib/Analysis/EHPersonalities.cpp @@ -13,6 +13,7 @@ #include "llvm/IR/Constants.h" #include "llvm/IR/Function.h" #include "llvm/IR/Instructions.h" +#include "llvm/IR/Module.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; @@ -40,6 +41,24 @@ .Default(EHPersonality::Unknown); } +Value* llvm::getStackGuardEHPersonality(Value *Pers) { + Function *F = + Pers ? dyn_cast(Pers->stripPointerCasts()) : nullptr; + if (!F) + return nullptr; + + // TODO(etienneb): Upgrade exception handlers when they are working. + StringRef NewName = llvm::StringSwitch(F->getName()) + .Case("_except_handler3", "_except_handler4") + .Default(""); + if (NewName.empty()) + return nullptr; + + Module* M = F->getParent(); + return M->getOrInsertFunction("_except_handler4", F->getFunctionType(), + F->getAttributes()); +} + bool llvm::canSimplifyInvokeNoUnwind(const Function *F) { EHPersonality Personality = classifyEHPersonality(F->getPersonalityFn()); // We can't simplify any invokes to nounwind functions if the personality Index: lib/CodeGen/WinEHPrepare.cpp =================================================================== --- lib/CodeGen/WinEHPrepare.cpp +++ lib/CodeGen/WinEHPrepare.cpp @@ -67,6 +67,7 @@ } private: + void promoteEHPersonality(Function &F); void insertPHIStores(PHINode *OriginalPHI, AllocaInst *SpillSlot); void insertPHIStore(BasicBlock *PredBlock, Value *PredVal, AllocaInst *SpillSlot, @@ -104,6 +105,10 @@ if (!Fn.hasPersonalityFn()) return false; + // When stack-protector is present, some exception handlers need to be + // promoted to a compatible handlers. + promoteEHPersonality(Fn); + // Classify the personality to see what kind of preparation we need. Personality = classifyEHPersonality(Fn.getPersonalityFn()); @@ -666,6 +671,23 @@ calculateStateNumbersForInvokes(Fn, FuncInfo); } +void WinEHPrepare::promoteEHPersonality(Function &F) { + // Promote the exception handler when stack protection is activated. + if (!F.hasFnAttribute(Attribute::StackProtect) && + !F.hasFnAttribute(Attribute::StackProtectReq) && + !F.hasFnAttribute(Attribute::StackProtectStrong)) + return; + + Value* PersonalityFn = F.getPersonalityFn(); + if (PersonalityFn) { + Value* Personality = getStackGuardEHPersonality(PersonalityFn); + if (Personality) { + Function* PromotedFn = cast(Personality); + F.setPersonalityFn(PromotedFn); + } + } +} + void WinEHPrepare::colorFunclets(Function &F) { BlockColors = colorEHFunclets(F); Index: testCodeGenWinEHwineh-promote-eh.ll =================================================================== --- /dev/null +++ testCodeGenWinEHwineh-promote-eh.ll @@ -0,0 +1,16 @@ +; RUN: opt -mtriple=-mtriple=i686-windows-msvc -S -winehprepare %s | FileCheck %s + +declare i32 @_except_handler3(...) + +define void @test1a() personality i32 (...)* @_except_handler3 { +; CHECK: define void @test1a() personality i32 (...)* @_except_handler3 +entry: + ret void +} + +define void @test1b() ssp personality i32 (...)* @_except_handler3 { +; CHECK: define void @test1b() [[attr:.*]] personality i32 (...)* @_except_handler4 +entry: + ret void +} +