llvm.org GIT mirror llvm / 34c6bb0
[SEH] Add new intrinsics for recovering and restoring parent frames The incoming EBP value established by the runtime is actually a pointer to the end of the EH registration object, and not the true parent function frame pointer. Clang doesn't need llvm.x86.seh.exceptioninfo anymore because we know that the exception info pointer is at a fixed offset from this incoming EBP. The llvm.x86.seh.recoverfp intrinsic takes an EBP value provided by the EH runtime and returns a pointer that is usable with llvm.framerecover. The llvm.x86.seh.restoreframe intrinsic is inserted by the 32-bit specific preparation pass in blocks targetted by the EH runtime. It re-establishes any physical registers used by the parent function to address the stack, such as the frame, base, and stack pointers. Neither of these intrinsics correctly handle stack realignment prologues yet, but it's possible to add that later. Reviewers: majnemer Differential Revision: http://reviews.llvm.org/D10848 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@241125 91177308-0d34-0410-b5e6-96231b3b80d8 Reid Kleckner 5 years ago
7 changed file(s) with 173 addition(s) and 86 deletion(s). Raw diff Collapse all Expand all
2020 // SEH intrinsics for Windows
2121 let TargetPrefix = "x86" in {
2222 def int_x86_seh_lsda : Intrinsic<[llvm_ptr_ty], [llvm_ptr_ty], [IntrNoMem]>;
23 def int_x86_seh_exceptioninfo : Intrinsic<[llvm_ptr_ty],
24 [llvm_ptr_ty, llvm_ptr_ty],
25 [IntrReadMem]>;
23
24 // Restores the frame, base, and stack pointers as necessary after recovering
25 // from an exception. Any block resuming control flow in the parent function
26 // should call this before accessing any stack memory.
27 def int_x86_seh_restoreframe : Intrinsic<[], [], []>;
28
29 // Given a pointer to the end of an EH registration object, returns the true
30 // parent frame address that can be used with llvm.framerecover.
31 def int_x86_seh_recoverfp : Intrinsic<[llvm_ptr_ty],
32 [llvm_ptr_ty, llvm_ptr_ty],
33 [IntrNoMem]>;
2634 }
2735
2836 //===----------------------------------------------------------------------===//
318318 return;
319319 } else {
320320 FuncInfoXData = Asm->OutContext.getOrCreateLSDASymbol(ParentLinkageName);
321 emitEHRegistrationOffsetLabel(FuncInfo, ParentLinkageName);
321322 }
322323
323324 MCSymbol *UnwindMapXData = nullptr;
546547 }
547548 }
548549
550 void WinException::emitEHRegistrationOffsetLabel(const WinEHFuncInfo &FuncInfo,
551 StringRef FLinkageName) {
552 // Outlined helpers called by the EH runtime need to know the offset of the EH
553 // registration in order to recover the parent frame pointer. Now that we know
554 // we've code generated the parent, we can emit the label assignment that
555 // those helpers use to get the offset of the registration node.
556 assert(FuncInfo.EHRegNodeEscapeIndex != INT_MAX &&
557 "no EH reg node frameescape index");
558 MCSymbol *ParentFrameOffset =
559 Asm->OutContext.getOrCreateParentFrameOffsetSymbol(FLinkageName);
560 MCSymbol *RegistrationOffsetSym = Asm->OutContext.getOrCreateFrameAllocSymbol(
561 FLinkageName, FuncInfo.EHRegNodeEscapeIndex);
562 const MCExpr *RegistrationOffsetSymRef =
563 MCSymbolRefExpr::create(RegistrationOffsetSym, Asm->OutContext);
564 Asm->OutStreamer->EmitAssignment(ParentFrameOffset, RegistrationOffsetSymRef);
565 }
566
549567 /// Emit the language-specific data that _except_handler3 and 4 expect. This is
550568 /// functionally equivalent to the __C_specific_handler table, except it is
551569 /// indexed by state number instead of IP.
552570 void WinException::emitExceptHandlerTable(const MachineFunction *MF) {
553571 MCStreamer &OS = *Asm->OutStreamer;
554
555 // Define the EH registration node offset label in terms of its frameescape
556 // label. The WinEHStatePass ensures that the registration node is passed to
557 // frameescape. This allows SEH filter functions to access the
558 // EXCEPTION_POINTERS field, which is filled in by the _except_handlerN.
559572 const Function *F = MF->getFunction();
573 StringRef FLinkageName = GlobalValue::getRealLinkageName(F->getName());
574
560575 WinEHFuncInfo &FuncInfo = MMI->getWinEHFuncInfo(F);
561 assert(FuncInfo.EHRegNodeEscapeIndex != INT_MAX &&
562 "no EH reg node frameescape index");
563 StringRef FLinkageName = GlobalValue::getRealLinkageName(F->getName());
564 MCSymbol *ParentFrameOffset =
565 Asm->OutContext.getOrCreateParentFrameOffsetSymbol(FLinkageName);
566 MCSymbol *FrameAllocSym = Asm->OutContext.getOrCreateFrameAllocSymbol(
567 FLinkageName, FuncInfo.EHRegNodeEscapeIndex);
568 const MCSymbolRefExpr *FrameAllocSymRef =
569 MCSymbolRefExpr::create(FrameAllocSym, Asm->OutContext);
570 OS.EmitAssignment(ParentFrameOffset, FrameAllocSymRef);
576 emitEHRegistrationOffsetLabel(FuncInfo, FLinkageName);
571577
572578 // Emit the __ehtable label that we use for llvm.x86.seh.lsda.
573579 MCSymbol *LSDALabel = Asm->OutContext.getOrCreateLSDASymbol(FLinkageName);
4949 void extendIP2StateTable(const MachineFunction *MF, const Function *ParentF,
5050 WinEHFuncInfo &FuncInfo);
5151
52 /// Emits the label used with llvm.x86.seh.recoverfp, which is used by
53 /// outlined funclets.
54 void emitEHRegistrationOffsetLabel(const WinEHFuncInfo &FuncInfo,
55 StringRef FLinkageName);
56
5257 const MCExpr *create32bitRef(const MCSymbol *Value);
5358 const MCExpr *create32bitRef(const GlobalValue *GV);
5459
1499414994 return DAG.getNode(X86ISD::SELECT, dl, VT, IMask, Op, PreservedSrc);
1499514995 }
1499614996
14997 /// When the 32-bit MSVC runtime transfers control to us, either to an outlined
14998 /// function or when returning to a parent frame after catching an exception, we
14999 /// recover the parent frame pointer by doing arithmetic on the incoming EBP.
15000 /// Here's the math:
15001 /// RegNodeBase = EntryEBP - RegNodeSize
15002 /// ParentFP = RegNodeBase - RegNodeFrameOffset
15003 /// Subtracting RegNodeSize takes us to the offset of the registration node, and
15004 /// subtracting the offset (negative on x86) takes us back to the parent FP.
15005 static SDValue recoverFramePointer(SelectionDAG &DAG, const Function *Fn,
15006 SDValue EntryEBP) {
15007 MachineFunction &MF = DAG.getMachineFunction();
15008 SDLoc dl;
15009
15010 const TargetLowering &TLI = DAG.getTargetLoweringInfo();
15011 MVT PtrVT = TLI.getPointerTy();
15012
15013 // The RegNodeSize is 6 32-bit words for SEH and 4 for C++ EH. See
15014 // WinEHStatePass for the full struct definition.
15015 int RegNodeSize;
15016 switch (classifyEHPersonality(Fn->getPersonalityFn())) {
15017 default:
15018 report_fatal_error("can only recover FP for MSVC EH personality functions");
15019 case EHPersonality::MSVC_X86SEH: RegNodeSize = 24; break;
15020 case EHPersonality::MSVC_CXX: RegNodeSize = 16; break;
15021 }
15022
15023 // Get an MCSymbol that will ultimately resolve to the frame offset of the EH
15024 // registration.
15025 MCSymbol *OffsetSym =
15026 MF.getMMI().getContext().getOrCreateParentFrameOffsetSymbol(
15027 GlobalValue::getRealLinkageName(Fn->getName()));
15028 SDValue OffsetSymVal = DAG.getMCSymbol(OffsetSym, PtrVT);
15029 SDValue RegNodeFrameOffset =
15030 DAG.getNode(ISD::FRAME_ALLOC_RECOVER, dl, PtrVT, OffsetSymVal);
15031
15032 // RegNodeBase = EntryEBP - RegNodeSize
15033 // ParentFP = RegNodeBase - RegNodeFrameOffset
15034 SDValue RegNodeBase = DAG.getNode(ISD::SUB, dl, PtrVT, EntryEBP,
15035 DAG.getConstant(RegNodeSize, dl, PtrVT));
15036 return DAG.getNode(ISD::SUB, dl, PtrVT, RegNodeBase, RegNodeFrameOffset);
15037 }
15038
1499715039 static SDValue LowerINTRINSIC_WO_CHAIN(SDValue Op, const X86Subtarget *Subtarget,
1499815040 SelectionDAG &DAG) {
1499915041 SDLoc dl(Op);
1543915481 SDValue Result = DAG.getMCSymbol(LSDASym, VT);
1544015482 return DAG.getNode(X86ISD::Wrapper, dl, VT, Result);
1544115483 }
15484
15485 case Intrinsic::x86_seh_recoverfp: {
15486 SDValue FnOp = Op.getOperand(1);
15487 SDValue IncomingFPOp = Op.getOperand(2);
15488 GlobalAddressSDNode *GSD = dyn_cast(FnOp);
15489 auto *Fn = dyn_cast_or_null(GSD ? GSD->getGlobal() : nullptr);
15490 if (!Fn)
15491 report_fatal_error(
15492 "llvm.x86.seh.recoverfp must take a function as the first argument");
15493 return recoverFramePointer(DAG, Fn, IncomingFPOp);
15494 }
1544215495 }
1544315496 }
1544415497
1564915702 return DAG.getMergeValues(Results, DL);
1565015703 }
1565115704
15652 static SDValue LowerEXCEPTIONINFO(SDValue Op, const X86Subtarget *Subtarget,
15653 SelectionDAG &DAG) {
15705 static SDValue LowerSEHRESTOREFRAME(SDValue Op, const X86Subtarget *Subtarget,
15706 SelectionDAG &DAG) {
1565415707 MachineFunction &MF = DAG.getMachineFunction();
1565515708 SDLoc dl(Op);
15656 SDValue FnOp = Op.getOperand(2);
15657 SDValue FPOp = Op.getOperand(3);
15658
15659 // Compute the symbol for the parent EH registration. We know it'll get
15660 // emitted later.
15661 auto *Fn = cast(cast(FnOp)->getGlobal());
15662 MCSymbol *ParentFrameSym =
15663 MF.getMMI().getContext().getOrCreateParentFrameOffsetSymbol(
15664 GlobalValue::getRealLinkageName(Fn->getName()));
15665
15666 // Create a TargetExternalSymbol for the label to avoid any target lowering
15667 // that would make this PC relative.
15668 MVT PtrVT = Op.getSimpleValueType();
15669 SDValue OffsetSym = DAG.getMCSymbol(ParentFrameSym, PtrVT);
15670 SDValue OffsetVal =
15671 DAG.getNode(ISD::FRAME_ALLOC_RECOVER, dl, PtrVT, OffsetSym);
15672
15673 // Add the offset to the FP.
15674 SDValue Add = DAG.getNode(ISD::ADD, dl, PtrVT, FPOp, OffsetVal);
15675
15676 // Load the second field of the struct, which is 4 bytes in. See
15677 // WinEHStatePass for more info.
15678 Add = DAG.getNode(ISD::ADD, dl, PtrVT, Add, DAG.getConstant(4, dl, PtrVT));
15679 return DAG.getLoad(PtrVT, dl, DAG.getEntryNode(), Add, MachinePointerInfo(),
15680 false, false, false, 0);
15709 SDValue Chain = Op.getOperand(0);
15710
15711 const TargetLowering &TLI = DAG.getTargetLoweringInfo();
15712 MVT VT = TLI.getPointerTy();
15713
15714 const X86RegisterInfo *RegInfo = Subtarget->getRegisterInfo();
15715 unsigned FrameReg =
15716 RegInfo->getPtrSizedFrameRegister(DAG.getMachineFunction());
15717 unsigned SPReg = RegInfo->getStackRegister();
15718
15719 // Get incoming EBP.
15720 SDValue IncomingEBP =
15721 DAG.getCopyFromReg(Chain, dl, FrameReg, VT);
15722
15723 // Load [EBP-24] into SP.
15724 SDValue SPAddr =
15725 DAG.getNode(ISD::ADD, dl, VT, IncomingEBP, DAG.getConstant(-24, dl, VT));
15726 SDValue NewSP =
15727 DAG.getLoad(VT, dl, Chain, SPAddr, MachinePointerInfo(), false, false,
15728 false, VT.getScalarSizeInBits() / 8);
15729 Chain = DAG.getCopyToReg(Chain, dl, SPReg, NewSP);
15730
15731 // FIXME: Restore the base pointer in case of stack realignment!
15732
15733 // Adjust EBP to point back to the original frame position.
15734 SDValue NewFP = recoverFramePointer(DAG, MF.getFunction(), IncomingEBP);
15735 Chain = DAG.getCopyToReg(Chain, dl, FrameReg, NewFP);
15736 return Chain;
1568115737 }
1568215738
1568315739 static SDValue LowerINTRINSIC_W_CHAIN(SDValue Op, const X86Subtarget *Subtarget,
1568615742
1568715743 const IntrinsicData* IntrData = getIntrinsicWithChain(IntNo);
1568815744 if (!IntrData) {
15689 if (IntNo == Intrinsic::x86_seh_exceptioninfo)
15690 return LowerEXCEPTIONINFO(Op, Subtarget, DAG);
15745 if (IntNo == llvm::Intrinsic::x86_seh_restoreframe)
15746 return LowerSEHRESTOREFRAME(Op, Subtarget, DAG);
1569115747 return SDValue();
1569215748 }
1569315749
397397
398398 // Set up RegNodeEscapeIndex
399399 int RegNodeEscapeIndex = escapeRegNode(F);
400 FuncInfo.EHRegNodeEscapeIndex = RegNodeEscapeIndex;
400401
401402 // Only insert stores in catch handlers.
402403 Constant *FI8 =
479480 WinEHFuncInfo &FuncInfo = MMI.getWinEHFuncInfo(&F);
480481
481482 // Remember and return the index that we used. We save it in WinEHFuncInfo so
482 // that we can lower llvm.x86.seh.exceptioninfo later in filter functions
483 // without too much trouble.
483 // that we can lower llvm.x86.seh.recoverfp later in filter functions without
484 // too much trouble.
484485 int RegNodeEscapeIndex = escapeRegNode(F);
485486 FuncInfo.EHRegNodeEscapeIndex = RegNodeEscapeIndex;
486487
527528 }
528529 }
529530
530 // Insert llvm.stackrestore into each __except block.
531 Function *StackRestore =
532 Intrinsic::getDeclaration(TheModule, Intrinsic::stackrestore);
531 // Insert llvm.x86.seh.restoreframe() into each __except block.
532 Function *RestoreFrame =
533 Intrinsic::getDeclaration(TheModule, Intrinsic::x86_seh_restoreframe);
533534 for (BasicBlock *ExceptBB : ExceptBlocks) {
534535 IRBuilder<> Builder(ExceptBB->begin());
535 Value *SP =
536 Builder.CreateLoad(Builder.CreateStructGEP(RegNodeTy, RegNode, 0));
537 Builder.CreateCall(StackRestore, {SP});
536 Builder.CreateCall(RestoreFrame, {});
538537 }
539538 }
540539
1111 declare i8* @llvm.frameaddress(i32)
1212 declare i8* @llvm.framerecover(i8*, i8*, i32)
1313 declare void @llvm.frameescape(...)
14 declare i8* @llvm.x86.seh.exceptioninfo(i8*, i8*)
14 declare i8* @llvm.x86.seh.recoverfp(i8*, i8*)
1515
1616 define i32 @main() personality i8* bitcast (i32 (...)* @_except_handler3 to i8*) {
1717 entry:
4242
4343 define internal i32 @"filt$main"() {
4444 entry:
45 %0 = tail call i8* @llvm.frameaddress(i32 1)
46 %1 = tail call i8* @llvm.framerecover(i8* bitcast (i32 ()* @main to i8*), i8* %0, i32 0)
47 %__exceptioncode = bitcast i8* %1 to i32*
48 %2 = tail call i8* @llvm.x86.seh.exceptioninfo(i8* bitcast (i32 ()* @main to i8*), i8* %0)
49 %3 = bitcast i8* %2 to i32**
50 %4 = load i32*, i32** %3, align 4
51 %5 = load i32, i32* %4, align 4
52 store i32 %5, i32* %__exceptioncode, align 4
45 %ebp = tail call i8* @llvm.frameaddress(i32 1)
46 %parentfp = tail call i8* @llvm.x86.seh.recoverfp(i8* bitcast (i32 ()* @main to i8*), i8* %ebp)
47 %code.i8 = tail call i8* @llvm.framerecover(i8* bitcast (i32 ()* @main to i8*), i8* %parentfp, i32 0)
48 %__exceptioncode = bitcast i8* %code.i8 to i32*
49 %info.addr = getelementptr inbounds i8, i8* %ebp, i32 -20
50 %0 = bitcast i8* %info.addr to i32***
51 %1 = load i32**, i32*** %0, align 4
52 %2 = load i32*, i32** %1, align 4
53 %3 = load i32, i32* %2, align 4
54 store i32 %3, i32* %__exceptioncode, align 4
5355 ret i32 1
5456 }
5557
7577 ; CHECK: calll _printf
7678
7779 ; CHECK: .section .xdata,"dr"
80 ; CHECK: Lmain$parent_frame_offset = Lmain$frame_escape_1
7881 ; CHECK: L__ehtable$main
7982 ; CHECK-NEXT: .long -1
8083 ; CHECK-NEXT: .long _filt$main
8184 ; CHECK-NEXT: .long Ltmp{{[0-9]+}}
8285
8386 ; CHECK-LABEL: _filt$main:
84 ; CHECK: movl
87 ; CHECK: pushl %ebp
88 ; CHECK: movl %esp, %ebp
89 ; CHECK: movl (%ebp), %[[oldebp:[a-z]+]]
90 ; CHECK: movl -20(%[[oldebp]]), %[[ehinfo:[a-z]+]]
91 ; CHECK: movl (%[[ehinfo]]), %[[ehrec:[a-z]+]]
92 ; CHECK: movl (%[[ehrec]]), %[[ehcode:[a-z]+]]
93 ; CHECK: movl %[[ehcode]], {{.*}}(%{{.*}})
121121 ; ...
122122 ; } EXCEPTION_RECORD;
123123
124 ; FIXME: Use llvm.eh.exceptioninfo for this.
125 declare i32 @safe_div_filt0()
126 declare i32 @safe_div_filt1()
127 ; define i32 @safe_div_filt0() {
128 ; %eh_ptrs_c = bitcast i8* %eh_ptrs to i32**
129 ; %eh_rec = load i32*, i32** %eh_ptrs_c
130 ; %eh_code = load i32, i32* %eh_rec
131 ; ; EXCEPTION_ACCESS_VIOLATION = 0xC0000005
132 ; %cmp = icmp eq i32 %eh_code, 3221225477
133 ; %filt.res = zext i1 %cmp to i32
134 ; ret i32 %filt.res
135 ; }
136 ; define i32 @safe_div_filt1() {
137 ; %eh_ptrs_c = bitcast i8* %eh_ptrs to i32**
138 ; %eh_rec = load i32*, i32** %eh_ptrs_c
139 ; %eh_code = load i32, i32* %eh_rec
140 ; ; EXCEPTION_INT_DIVIDE_BY_ZERO = 0xC0000094
141 ; %cmp = icmp eq i32 %eh_code, 3221225620
142 ; %filt.res = zext i1 %cmp to i32
143 ; ret i32 %filt.res
144 ; }
124 define i32 @safe_div_filt0() {
125 %ebp = call i8* @llvm.frameaddress(i32 1)
126 %eh_ptrs.addr.i8 = getelementptr inbounds i8, i8* %ebp, i32 -20
127 %eh_ptrs.addr = bitcast i8* %eh_ptrs.addr.i8 to i32***
128 %eh_ptrs = load i32**, i32*** %eh_ptrs.addr
129 %eh_rec = load i32*, i32** %eh_ptrs
130 %eh_code = load i32, i32* %eh_rec
131 ; EXCEPTION_ACCESS_VIOLATION = 0xC0000005
132 %cmp = icmp eq i32 %eh_code, 3221225477
133 %filt.res = zext i1 %cmp to i32
134 ret i32 %filt.res
135 }
136 define i32 @safe_div_filt1() {
137 %ebp = call i8* @llvm.frameaddress(i32 1)
138 %eh_ptrs.addr.i8 = getelementptr inbounds i8, i8* %ebp, i32 -20
139 %eh_ptrs.addr = bitcast i8* %eh_ptrs.addr.i8 to i32***
140 %eh_ptrs = load i32**, i32*** %eh_ptrs.addr
141 %eh_rec = load i32*, i32** %eh_ptrs
142 %eh_code = load i32, i32* %eh_rec
143 ; EXCEPTION_INT_DIVIDE_BY_ZERO = 0xC0000094
144 %cmp = icmp eq i32 %eh_code, 3221225620
145 %filt.res = zext i1 %cmp to i32
146 ret i32 %filt.res
147 }
145148
146149 @str_result = internal constant [21 x i8] c"safe_div result: %d\0A\00"
147150
169172 declare void @puts(i8*)
170173 declare void @printf(i8*, ...)
171174 declare void @abort()
175 declare i8* @llvm.frameaddress(i32)