From 7681f6a1b0f79683b963c5061335eff88a5a55ad Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Wed, 20 May 2015 23:08:04 +0000 Subject: [PATCH] [WinEH] Store pointers to the LSDA in the exception registration object We aren't yet emitting the LSDA yet, so this will still fail to assemble. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@237852 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/IR/IntrinsicsX86.td | 6 +++ include/llvm/MC/MCContext.h | 2 + lib/MC/MCContext.cpp | 5 ++ lib/Target/X86/X86ISelLowering.cpp | 18 +++++++ lib/Target/X86/X86WinEHState.cpp | 83 +++++++++++++++++++++++++----- test/CodeGen/X86/win32-eh.ll | 14 +++++ 6 files changed, 115 insertions(+), 13 deletions(-) diff --git a/include/llvm/IR/IntrinsicsX86.td b/include/llvm/IR/IntrinsicsX86.td index 12a55cd433c..3a8a4a643a4 100644 --- a/include/llvm/IR/IntrinsicsX86.td +++ b/include/llvm/IR/IntrinsicsX86.td @@ -17,6 +17,12 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". def int_x86_int : Intrinsic<[], [llvm_i8_ty]>; } +//===----------------------------------------------------------------------===// +// SEH LSDA for Windows +let TargetPrefix = "x86" in { + def int_x86_seh_lsda : Intrinsic<[llvm_ptr_ty], [llvm_ptr_ty], [IntrNoMem]>; +} + //===----------------------------------------------------------------------===// // Read Time Stamp Counter. let TargetPrefix = "x86" in { diff --git a/include/llvm/MC/MCContext.h b/include/llvm/MC/MCContext.h index b62b84a34ce..fd0181e66ab 100644 --- a/include/llvm/MC/MCContext.h +++ b/include/llvm/MC/MCContext.h @@ -275,6 +275,8 @@ namespace llvm { MCSymbol *getOrCreateParentFrameOffsetSymbol(StringRef FuncName); + MCSymbol *getOrCreateLSDASymbol(StringRef FuncName); + /// Get the symbol for \p Name, or null. MCSymbol *lookupSymbol(const Twine &Name) const; diff --git a/lib/MC/MCContext.cpp b/lib/MC/MCContext.cpp index 0d43c262bad..0a13c9e6edb 100644 --- a/lib/MC/MCContext.cpp +++ b/lib/MC/MCContext.cpp @@ -144,6 +144,11 @@ MCSymbol *MCContext::getOrCreateParentFrameOffsetSymbol(StringRef FuncName) { "$parent_frame_offset"); } +MCSymbol *MCContext::getOrCreateLSDASymbol(StringRef FuncName) { + return getOrCreateSymbol(Twine(MAI->getPrivateGlobalPrefix()) + "__ehtable$" + + FuncName); +} + MCSymbol *MCContext::CreateSymbol(StringRef Name, bool AlwaysAddSuffix) { // Determine whether this is an assembler temporary or normal label, if used. bool IsTemporary = false; diff --git a/lib/Target/X86/X86ISelLowering.cpp b/lib/Target/X86/X86ISelLowering.cpp index 964a599e881..de28fdbb229 100644 --- a/lib/Target/X86/X86ISelLowering.cpp +++ b/lib/Target/X86/X86ISelLowering.cpp @@ -15288,6 +15288,24 @@ static SDValue LowerINTRINSIC_WO_CHAIN(SDValue Op, const X86Subtarget *Subtarget SDVTList VTs = DAG.getVTList(Op.getValueType(), MVT::i32); return DAG.getNode(Opcode, dl, VTs, NewOps); } + + case Intrinsic::x86_seh_lsda: { + // Compute the symbol for the LSDA. We know it'll get emitted later. + MachineFunction &MF = DAG.getMachineFunction(); + SDValue Op1 = Op.getOperand(1); + Op1->dump(); + auto *Fn = cast(cast(Op1)->getGlobal()); + MCSymbol *LSDASym = MF.getMMI().getContext().getOrCreateLSDASymbol( + GlobalValue::getRealLinkageName(Fn->getName())); + StringRef Name = LSDASym->getName(); + assert(Name.data()[Name.size()] == '\0' && "not null terminated"); + + // Generate a simple absolute symbol reference. This intrinsic is only + // supported on 32-bit Windows, which isn't PIC. + SDValue Result = + DAG.getTargetExternalSymbol(Name.data(), VT, X86II::MO_NOPREFIX); + return DAG.getNode(X86ISD::Wrapper, dl, VT, Result); + } } } diff --git a/lib/Target/X86/X86WinEHState.cpp b/lib/Target/X86/X86WinEHState.cpp index db00c80afef..4efaada4092 100644 --- a/lib/Target/X86/X86WinEHState.cpp +++ b/lib/Target/X86/X86WinEHState.cpp @@ -63,6 +63,10 @@ private: Value *Handler); void unlinkExceptionRegistration(IRBuilder<> &Builder, Value *RegNode); + Value *emitEHLSDA(IRBuilder<> &Builder, Function *F); + + Function *generateLSDAInEAXThunk(Function *ParentFunc); + // Module-level type getters. Type *getEHRegistrationType(); Type *getSEH3RegistrationType(); @@ -108,6 +112,13 @@ void WinEHStatePass::getAnalysisUsage(AnalysisUsage &AU) const { } bool WinEHStatePass::runOnFunction(Function &F) { + // If this is an outlined handler, don't do anything. We'll do state insertion + // for it in the parent. + StringRef WinEHParentName = + F.getFnAttribute("wineh-parent").getValueAsString(); + if (WinEHParentName != F.getName() && !WinEHParentName.empty()) + return false; + // Check the personality. Do nothing if this is not an MSVC personality. LandingPadInst *LP = nullptr; for (BasicBlock &BB : F) { @@ -135,9 +146,11 @@ bool WinEHStatePass::runOnFunction(Function &F) { } /// Get the common EH registration subobject: +/// typedef _EXCEPTION_DISPOSITION (*PEXCEPTION_ROUTINE)( +/// _EXCEPTION_RECORD *, void *, _CONTEXT *, void *); /// struct EHRegistrationNode { /// EHRegistrationNode *Next; -/// EXCEPTION_DISPOSITION (*Handler)(...); +/// PEXCEPTION_ROUTINE Handler; /// }; Type *WinEHStatePass::getEHRegistrationType() { if (EHRegistrationTy) @@ -237,20 +250,19 @@ void WinEHStatePass::emitExceptionRegistrationRecord(Function *F) { // TryLevel = -1 Builder.CreateStore(Builder.getInt32(-1), Builder.CreateStructGEP(RegNodeTy, RegNode, 2)); - // FIXME: 'Personality' is incorrect here. We need to generate a trampoline - // that effectively gets the LSDA. + // Handler = __ehhandler$F + Function *Trampoline = generateLSDAInEAXThunk(F); SubRecord = Builder.CreateStructGEP(RegNodeTy, RegNode, 1); - linkExceptionRegistration(Builder, SubRecord, PersonalityFn); + linkExceptionRegistration(Builder, SubRecord, Trampoline); } else if (PersonalityName == "_except_handler3") { Type *RegNodeTy = getSEH3RegistrationType(); Value *RegNode = Builder.CreateAlloca(RegNodeTy); // TryLevel = -1 Builder.CreateStore(Builder.getInt32(-1), Builder.CreateStructGEP(RegNodeTy, RegNode, 2)); - // FIXME: Generalize llvm.eh.sjljl.lsda for this. - // ScopeTable = nullptr - Builder.CreateStore(Constant::getNullValue(Int8PtrType), - Builder.CreateStructGEP(RegNodeTy, RegNode, 1)); + // ScopeTable = llvm.x86.seh.lsda(F) + Value *LSDA = emitEHLSDA(Builder, F); + Builder.CreateStore(LSDA, Builder.CreateStructGEP(RegNodeTy, RegNode, 1)); SubRecord = Builder.CreateStructGEP(RegNodeTy, RegNode, 0); linkExceptionRegistration(Builder, SubRecord, PersonalityFn); } else if (PersonalityName == "_except_handler4") { @@ -263,11 +275,12 @@ void WinEHStatePass::emitExceptionRegistrationRecord(Function *F) { // TryLevel = -2 Builder.CreateStore(Builder.getInt32(-2), Builder.CreateStructGEP(RegNodeTy, RegNode, 4)); - // FIXME: Generalize llvm.eh.sjljl.lsda for this, and then do the stack - // cookie xor. - // ScopeTable = nullptr - Builder.CreateStore(Builder.getInt32(0), - Builder.CreateStructGEP(RegNodeTy, RegNode, 3)); + // FIXME: XOR the LSDA with __security_cookie. + // ScopeTable = llvm.x86.seh.lsda(F) + Value *FI8 = Builder.CreateBitCast(F, Int8PtrType); + Value *LSDA = Builder.CreateCall( + Intrinsic::getDeclaration(TheModule, Intrinsic::x86_seh_lsda), FI8); + Builder.CreateStore(LSDA, Builder.CreateStructGEP(RegNodeTy, RegNode, 1)); SubRecord = Builder.CreateStructGEP(RegNodeTy, RegNode, 2); linkExceptionRegistration(Builder, SubRecord, PersonalityFn); } else { @@ -284,6 +297,50 @@ void WinEHStatePass::emitExceptionRegistrationRecord(Function *F) { } } +Value *WinEHStatePass::emitEHLSDA(IRBuilder<> &Builder, Function *F) { + Value *FI8 = Builder.CreateBitCast(F, Type::getInt8PtrTy(F->getContext())); + return Builder.CreateCall( + Intrinsic::getDeclaration(TheModule, Intrinsic::x86_seh_lsda), FI8); +} + +/// Generate a thunk that puts the LSDA of ParentFunc in EAX and then calls +/// PersonalityFn, forwarding the parameters passed to PEXCEPTION_ROUTINE: +/// typedef _EXCEPTION_DISPOSITION (*PEXCEPTION_ROUTINE)( +/// _EXCEPTION_RECORD *, void *, _CONTEXT *, void *); +/// We essentially want this code: +/// movl $lsda, %eax +/// jmpl ___CxxFrameHandler3 +Function *WinEHStatePass::generateLSDAInEAXThunk(Function *ParentFunc) { + LLVMContext &Context = ParentFunc->getContext(); + Type *Int32Ty = Type::getInt32Ty(Context); + Type *Int8PtrType = Type::getInt8PtrTy(Context); + Type *ArgTys[5] = {Int8PtrType, Int8PtrType, Int8PtrType, Int8PtrType, + Int8PtrType}; + FunctionType *TrampolineTy = + FunctionType::get(Int32Ty, makeArrayRef(&ArgTys[0], 4), + /*isVarArg=*/false); + FunctionType *TargetFuncTy = + FunctionType::get(Int32Ty, makeArrayRef(&ArgTys[0], 5), + /*isVarArg=*/false); + Function *Trampoline = Function::Create( + TrampolineTy, GlobalValue::InternalLinkage, + Twine("__ehhandler$") + ParentFunc->getName(), TheModule); + BasicBlock *EntryBB = BasicBlock::Create(Context, "entry", Trampoline); + IRBuilder<> Builder(EntryBB); + Value *LSDA = emitEHLSDA(Builder, ParentFunc); + Value *CastPersonality = + Builder.CreateBitCast(PersonalityFn, TargetFuncTy->getPointerTo()); + auto AI = Trampoline->arg_begin(); + Value *Args[5] = {LSDA, AI++, AI++, AI++, AI++}; + CallInst *Call = Builder.CreateCall(CastPersonality, Args); + // Can't use musttail due to prototype mismatch, but we can use tail. + Call->setTailCall(true); + // Set inreg so we pass it in EAX. + Call->addAttribute(1, Attribute::InReg); + Builder.CreateRet(Call); + return Trampoline; +} + void WinEHStatePass::linkExceptionRegistration(IRBuilder<> &Builder, Value *RegNode, Value *Handler) { Type *RegNodeTy = getEHRegistrationType(); diff --git a/test/CodeGen/X86/win32-eh.ll b/test/CodeGen/X86/win32-eh.ll index 875949740ec..4d3c34ed6c1 100644 --- a/test/CodeGen/X86/win32-eh.ll +++ b/test/CodeGen/X86/win32-eh.ll @@ -20,6 +20,9 @@ catchall: ; CHECK-LABEL: _use_except_handler3: ; CHECK: subl ${{[0-9]+}}, %esp +; CHECK: movl $-1, 12(%esp) +; CHECK: movl $L__ehtable$use_except_handler3, 8(%esp) +; CHECK: movl $__except_handler3, 4(%esp) ; CHECK: movl %fs:0, %[[next:[^ ,]*]] ; CHECK: movl %[[next]], (%esp) ; CHECK: leal (%esp), %[[node:[^ ,]*]] @@ -42,7 +45,11 @@ catchall: ; CHECK-LABEL: _use_except_handler4: ; CHECK: subl ${{[0-9]+}}, %esp +; CHECK: movl %esp, (%esp) +; CHECK: movl $-2, 20(%esp) +; CHECK: movl $L__ehtable$use_except_handler4, 4(%esp) ; CHECK: leal 8(%esp), %[[node:[^ ,]*]] +; CHECK: movl $__except_handler4, 12(%esp) ; CHECK: movl %fs:0, %[[next:[^ ,]*]] ; CHECK: movl %[[next]], 8(%esp) ; CHECK: movl %[[node]], %fs:0 @@ -67,7 +74,10 @@ catchall: ; CHECK-LABEL: _use_CxxFrameHandler3: ; CHECK: subl ${{[0-9]+}}, %esp +; CHECK: movl %esp, (%esp) +; CHECK: movl $-1, 12(%esp) ; CHECK: leal 4(%esp), %[[node:[^ ,]*]] +; CHECK: movl $___ehhandler$use_CxxFrameHandler3, 8(%esp) ; CHECK: movl %fs:0, %[[next:[^ ,]*]] ; CHECK: movl %[[next]], 4(%esp) ; CHECK: movl %[[node]], %fs:0 @@ -75,3 +85,7 @@ catchall: ; CHECK: movl 4(%esp), %[[next:[^ ,]*]] ; CHECK: movl %[[next]], %fs:0 ; CHECK: retl + +; CHECK-LABEL: ___ehhandler$use_CxxFrameHandler3: +; CHECK: movl $L__ehtable$use_CxxFrameHandler3, %eax +; CHECK: jmp ___CxxFrameHandler3 # TAILCALL -- 2.34.1