llvm.org GIT mirror llvm / 8d600b5
[StackProtector] Fix computation of GSCookieOffset and EHCookieOffset with SEH4 Summary: Fix the computation of the offsets present in the scopetable when using the SEH (__except_handler4). This patch added an intrinsic to track the position of the allocation on the stack of the EHGuard. This position is needed when producing the ScopeTable. ``` struct _EH4_SCOPETABLE { DWORD GSCookieOffset; DWORD GSCookieXOROffset; DWORD EHCookieOffset; DWORD EHCookieXOROffset; _EH4_SCOPETABLE_RECORD ScopeRecord[1]; }; struct _EH4_SCOPETABLE_RECORD { DWORD EnclosingLevel; long (*FilterFunc)(); union { void (*HandlerAddress)(); void (*FinallyFunc)(); }; }; ``` The code to generate the EHCookie is added in `X86WinEHState.cpp`. Which is adding these instructions when using SEH4. ``` Lfunc_begin0: # BB#0: # %entry pushl %ebp movl %esp, %ebp pushl %ebx pushl %edi pushl %esi subl $28, %esp movl %ebp, %eax <<-- Loading FramePtr movl %esp, -36(%ebp) movl $-2, -16(%ebp) movl $L__ehtable$use_except_handler4_ssp, %ecx xorl ___security_cookie, %ecx movl %ecx, -20(%ebp) xorl ___security_cookie, %eax <<-- XOR FramePtr and Cookie movl %eax, -40(%ebp) <<-- Storing EHGuard leal -28(%ebp), %eax movl $__except_handler4, -24(%ebp) movl %fs:0, %ecx movl %ecx, -28(%ebp) movl %eax, %fs:0 movl $0, -16(%ebp) calll _may_throw_or_crash LBB1_1: # %cont movl -28(%ebp), %eax movl %eax, %fs:0 addl $28, %esp popl %esi popl %edi popl %ebx popl %ebp retl ``` And the corresponding offset is computed: ``` Luse_except_handler4_ssp$parent_frame_offset = -36 .p2align 2 L__ehtable$use_except_handler4_ssp: .long -2 # GSCookieOffset .long 0 # GSCookieXOROffset .long -40 # EHCookieOffset <<---- .long 0 # EHCookieXOROffset .long -2 # ToState .long _catchall_filt # FilterFunction .long LBB1_2 # ExceptionHandler ``` Clang is not yet producing function using SEH4, but it's a work in progress. This patch is a step toward having a valid implementation of SEH4. Unfortunately, it is not yet fully working. The EH registration block is not allocated at the right offset on the stack. Reviewers: rnk, majnemer Subscribers: llvm-commits, chrisha Differential Revision: http://reviews.llvm.org/D21231 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@273281 91177308-0d34-0410-b5e6-96231b3b80d8 Etienne Bergeron 4 years ago
6 changed file(s) with 144 addition(s) and 13 deletion(s). Raw diff Collapse all Expand all
108108
109109 int EHRegNodeFrameIndex = INT_MAX;
110110 int EHRegNodeEndOffset = INT_MAX;
111 int EHGuardFrameIndex = INT_MAX;
111112 int SEHSetFrameOffset = INT_MAX;
112113
113114 WinEHFuncInfo();
2323
2424 // Marks the EH registration node created in LLVM IR prior to code generation.
2525 def int_x86_seh_ehregnode : Intrinsic<[], [llvm_ptr_ty], []>;
26
27 // Marks the EH guard slot node created in LLVM IR prior to code generation.
28 def int_x86_seh_ehguard : Intrinsic<[], [llvm_ptr_ty], []>;
2629
2730 // Given a pointer to the end of an EH registration object, returns the true
2831 // parent frame address that can be used with llvm.localrecover.
953953 // ScopeTableEntry ScopeRecord[];
954954 // };
955955 //
956 // Only the EHCookieOffset field appears to vary, and it appears to be the
957 // offset from the final saved SP value to the retaddr.
956 // Offsets are %ebp relative.
957 //
958 // The GS cookie is present only if the function needs stack protection.
959 // GSCookieOffset = -2 means that GS cookie is not used.
960 //
961 // The EH cookie is always present.
962 //
963 // Check is done the following way:
964 // (ebp+CookieXOROffset) ^ [ebp+CookieOffset] == _security_cookie
965
966 // Retrieve the Guard Stack slot.
967 int GSCookieOffset = -2;
968 const MachineFrameInfo *MFI = MF->getFrameInfo();
969 if (MFI->hasStackProtectorIndex()) {
970 unsigned UnusedReg;
971 const TargetFrameLowering *TFI = MF->getSubtarget().getFrameLowering();
972 int SSPIdx = MFI->getStackProtectorIndex();
973 GSCookieOffset = TFI->getFrameIndexReference(*MF, SSPIdx, UnusedReg);
974 }
975
976 // Retrieve the EH Guard slot.
977 // TODO(etienneb): Get rid of this value and change it for and assertion.
978 int EHCookieOffset = 9999;
979 if (FuncInfo.EHGuardFrameIndex != INT_MAX) {
980 unsigned UnusedReg;
981 const TargetFrameLowering *TFI = MF->getSubtarget().getFrameLowering();
982 int EHGuardIdx = FuncInfo.EHGuardFrameIndex;
983 EHCookieOffset = TFI->getFrameIndexReference(*MF, EHGuardIdx, UnusedReg);
984 }
985
958986 AddComment("GSCookieOffset");
959 OS.EmitIntValue(-2, 4);
987 OS.EmitIntValue(GSCookieOffset, 4);
960988 AddComment("GSCookieXOROffset");
961989 OS.EmitIntValue(0, 4);
962 // FIXME: Calculate.
963990 AddComment("EHCookieOffset");
964 OS.EmitIntValue(9999, 4);
991 OS.EmitIntValue(EHCookieOffset, 4);
965992 AddComment("EHCookieXOROffset");
966993 OS.EmitIntValue(0, 4);
967994 BaseState = -2;
1819218192 return Chain;
1819318193 }
1819418194
18195 static SDValue MarkEHGuard(SDValue Op, SelectionDAG &DAG) {
18196 MachineFunction &MF = DAG.getMachineFunction();
18197 SDValue Chain = Op.getOperand(0);
18198 SDValue EHGuard = Op.getOperand(2);
18199 WinEHFuncInfo *EHInfo = MF.getWinEHFuncInfo();
18200 if (!EHInfo)
18201 report_fatal_error("EHGuard only live in functions using WinEH");
18202
18203 // Cast the operand to an alloca, and remember the frame index.
18204 auto *FINode = dyn_cast(EHGuard);
18205 if (!FINode)
18206 report_fatal_error("llvm.x86.seh.ehguard expects a static alloca");
18207 EHInfo->EHGuardFrameIndex = FINode->getIndex();
18208
18209 // Return the chain operand without making any DAG nodes.
18210 return Chain;
18211 }
18212
1819518213 static SDValue LowerINTRINSIC_W_CHAIN(SDValue Op, const X86Subtarget &Subtarget,
1819618214 SelectionDAG &DAG) {
1819718215 unsigned IntNo = cast(Op.getOperand(1))->getZExtValue();
1820018218 if (!IntrData) {
1820118219 if (IntNo == llvm::Intrinsic::x86_seh_ehregnode)
1820218220 return MarkEHRegistrationNode(Op, DAG);
18221 if (IntNo == llvm::Intrinsic::x86_seh_ehguard)
18222 return MarkEHGuard(Op, DAG);
1820318223 if (IntNo == llvm::Intrinsic::x86_flags_read_u32 ||
1820418224 IntNo == llvm::Intrinsic::x86_flags_read_u64 ||
1820518225 IntNo == llvm::Intrinsic::x86_flags_write_u32 ||
105105 /// fs:00 chain and the current state.
106106 AllocaInst *RegNode = nullptr;
107107
108 // The allocation containing the EH security guard.
109 AllocaInst *EHGuardNode = nullptr;
110
108111 /// The index of the state field of RegNode.
109112 int StateFieldIndex = ~0U;
110113
194197 PersonalityFn = nullptr;
195198 Personality = EHPersonality::Unknown;
196199 UseStackGuard = false;
200 RegNode = nullptr;
201 EHGuardNode = nullptr;
202
197203 return true;
198204 }
199205
273279
274280 IRBuilder<> Builder(&F->getEntryBlock(), F->getEntryBlock().begin());
275281 Type *Int8PtrType = Builder.getInt8PtrTy();
282 Type *Int32Ty = Builder.getInt32Ty();
283 Type *VoidTy = Builder.getVoidTy();
284
276285 if (Personality == EHPersonality::MSVC_CXX) {
277286 RegNodeTy = getCXXEHRegistrationType();
278287 RegNode = Builder.CreateAlloca(RegNodeTy);
291300
292301 CxxLongjmpUnwind = TheModule->getOrInsertFunction(
293302 "__CxxLongjmpUnwind",
294 FunctionType::get(Type::getVoidTy(TheModule->getContext()), Int8PtrType,
295 /*isVarArg=*/false));
303 FunctionType::get(VoidTy, Int8PtrType, /*isVarArg=*/false));
296304 cast(CxxLongjmpUnwind->stripPointerCasts())
297305 ->setCallingConv(CallingConv::X86_StdCall);
298306 } else if (Personality == EHPersonality::MSVC_X86SEH) {
299307 // If _except_handler4 is in use, some additional guard checks and prologue
300308 // stuff is required.
309 StringRef PersonalityName = PersonalityFn->getName();
310 UseStackGuard = (PersonalityName == "_except_handler4");
311
312 // Allocate local structures.
301313 RegNodeTy = getSEHRegistrationType();
302314 RegNode = Builder.CreateAlloca(RegNodeTy);
315 if (UseStackGuard)
316 EHGuardNode = Builder.CreateAlloca(Int32Ty);
317
303318 // SavedESP = llvm.stacksave()
304319 Value *SP = Builder.CreateCall(
305320 Intrinsic::getDeclaration(TheModule, Intrinsic::stacksave), {});
306321 Builder.CreateStore(SP, Builder.CreateStructGEP(RegNodeTy, RegNode, 0));
307322 // TryLevel = -2 / -1
308323 StateFieldIndex = 4;
309 StringRef PersonalityName = PersonalityFn->getName();
310 UseStackGuard = (PersonalityName == "_except_handler4");
311324 ParentBaseState = UseStackGuard ? -2 : -1;
312325 insertStateNumberStore(&*Builder.GetInsertPoint(), ParentBaseState);
313326 // ScopeTable = llvm.x86.seh.lsda(F)
314327 Value *LSDA = emitEHLSDA(Builder, F);
315 Type *Int32Ty = Type::getInt32Ty(TheModule->getContext());
316328 LSDA = Builder.CreatePtrToInt(LSDA, Int32Ty);
317329 // If using _except_handler4, xor the address of the table with
318330 // __security_cookie.
319331 if (UseStackGuard) {
320332 Cookie = TheModule->getOrInsertGlobal("__security_cookie", Int32Ty);
321 Value *Val = Builder.CreateLoad(Int32Ty, Cookie);
333 Value *Val = Builder.CreateLoad(Int32Ty, Cookie, "cookie");
322334 LSDA = Builder.CreateXor(LSDA, Val);
323335 }
324336 Builder.CreateStore(LSDA, Builder.CreateStructGEP(RegNodeTy, RegNode, 3));
337
338 // If using _except_handler4, the EHGuard contains: FramePtr xor Cookie.
339 if (UseStackGuard) {
340 Value *Val = Builder.CreateLoad(Int32Ty, Cookie);
341 Value *FrameAddr = Builder.CreateCall(
342 Intrinsic::getDeclaration(TheModule, Intrinsic::frameaddress),
343 Builder.getInt32(0), "frameaddr");
344 Value *FrameAddrI32 = Builder.CreatePtrToInt(FrameAddr, Int32Ty);
345 FrameAddrI32 = Builder.CreateXor(FrameAddrI32, Val);
346 Builder.CreateStore(FrameAddrI32, EHGuardNode);
347 }
348
349 // Register the exception handler.
325350 Link = Builder.CreateStructGEP(RegNodeTy, RegNode, 2);
326351 linkExceptionRegistration(Builder, PersonalityFn);
327352
607632 void WinEHStatePass::addStateStores(Function &F, WinEHFuncInfo &FuncInfo) {
608633 // Mark the registration node. The backend needs to know which alloca it is so
609634 // that it can recover the original frame pointer.
610 IRBuilder<> Builder(RegNode->getParent(), std::next(RegNode->getIterator()));
635 IRBuilder<> Builder(RegNode->getNextNode());
611636 Value *RegNodeI8 = Builder.CreateBitCast(RegNode, Builder.getInt8PtrTy());
612637 Builder.CreateCall(
613638 Intrinsic::getDeclaration(TheModule, Intrinsic::x86_seh_ehregnode),
614639 {RegNodeI8});
640
641 if (EHGuardNode) {
642 IRBuilder<> Builder(EHGuardNode->getNextNode());
643 Value *EHGuardNodeI8 =
644 Builder.CreateBitCast(EHGuardNode, Builder.getInt8PtrTy());
645 Builder.CreateCall(
646 Intrinsic::getDeclaration(TheModule, Intrinsic::x86_seh_ehguard),
647 {EHGuardNodeI8});
648 }
615649
616650 // Calculate state numbers.
617651 if (isAsynchronousEHPersonality(Personality))
8787 ; CHECK-LABEL: L__ehtable$use_except_handler4:
8888 ; CHECK-NEXT: .long -2
8989 ; CHECK-NEXT: .long 0
90 ; CHECK-NEXT: .long 9999
90 ; CHECK-NEXT: .long -40
9191 ; CHECK-NEXT: .long 0
9292 ; CHECK-NEXT: .long -2
9393 ; CHECK-NEXT: .long _catchall_filt
9494 ; CHECK-NEXT: .long LBB2_2
95
96 define void @use_except_handler4_ssp() sspstrong personality i32 (...)* @_except_handler4 {
97 entry:
98 invoke void @may_throw_or_crash()
99 to label %cont unwind label %lpad
100 cont:
101 ret void
102 lpad:
103 %cs = catchswitch within none [label %catch] unwind to caller
104 catch:
105 %p = catchpad within %cs [i8* bitcast (i32 ()* @catchall_filt to i8*)]
106 catchret from %p to label %cont
107 }
108
109 ; CHECK-LABEL: _use_except_handler4_ssp:
110 ; CHECK: pushl %ebp
111 ; CHECK: movl %esp, %ebp
112 ; CHECK: subl ${{[0-9]+}}, %esp
113 ; CHECK: movl %ebp, %[[ehguard:[^ ,]*]]
114 ; CHECK: movl %esp, -36(%ebp)
115 ; CHECK: movl $-2, -16(%ebp)
116 ; CHECK: movl $L__ehtable$use_except_handler4_ssp, %[[lsda:[^ ,]*]]
117 ; CHECK: xorl ___security_cookie, %[[lsda]]
118 ; CHECK: movl %[[lsda]], -20(%ebp)
119 ; CHECK: xorl ___security_cookie, %[[ehguard]]
120 ; CHECK: movl %[[ehguard]], -40(%ebp)
121 ; CHECK: leal -28(%ebp), %[[node:[^ ,]*]]
122 ; CHECK: movl $__except_handler4, -24(%ebp)
123 ; CHECK: movl %fs:0, %[[next:[^ ,]*]]
124 ; CHECK: movl %[[next]], -28(%ebp)
125 ; CHECK: movl %[[node]], %fs:0
126 ; CHECK: calll _may_throw_or_crash
127 ; CHECK: movl -28(%ebp), %[[next:[^ ,]*]]
128 ; CHECK: movl %[[next]], %fs:0
129 ; CHECK: retl
130 ; CHECK: [[catch:[^ ,]*]]: # %catch{{$}}
131
132 ; CHECK: .section .xdata,"dr"
133 ; CHECK-LABEL: L__ehtable$use_except_handler4_ssp:
134 ; CHECK-NEXT: .long -2
135 ; CHECK-NEXT: .long 0
136 ; CHECK-NEXT: .long -40
137 ; CHECK-NEXT: .long 0
138 ; CHECK-NEXT: .long -2
139 ; CHECK-NEXT: .long _catchall_filt
140 ; CHECK-NEXT: .long [[catch]]
95141
96142 define void @use_CxxFrameHandler3() personality i32 (...)* @__CxxFrameHandler3 {
97143 invoke void @may_throw_or_crash()