diff options
author | Etienne Bergeron <etienneb@google.com> | 2016-06-21 15:58:55 +0000 |
---|---|---|
committer | Etienne Bergeron <etienneb@google.com> | 2016-06-21 15:58:55 +0000 |
commit | f6be62f2c8a5d97e7d738fc03f4b8ed723f1b083 (patch) | |
tree | 6815b526d5640e0e0ba674beb672eed4b4e11708 /llvm/lib/Target/X86/X86WinEHState.cpp | |
parent | 04abc14fb5e9986f17a2d48182667b1e0361de44 (diff) | |
download | llvm-f6be62f2c8a5d97e7d738fc03f4b8ed723f1b083.zip llvm-f6be62f2c8a5d97e7d738fc03f4b8ed723f1b083.tar.gz llvm-f6be62f2c8a5d97e7d738fc03f4b8ed723f1b083.tar.bz2 |
[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
llvm-svn: 273281
Diffstat (limited to 'llvm/lib/Target/X86/X86WinEHState.cpp')
-rw-r--r-- | llvm/lib/Target/X86/X86WinEHState.cpp | 48 |
1 files changed, 41 insertions, 7 deletions
diff --git a/llvm/lib/Target/X86/X86WinEHState.cpp b/llvm/lib/Target/X86/X86WinEHState.cpp index ba82006..99387ed 100644 --- a/llvm/lib/Target/X86/X86WinEHState.cpp +++ b/llvm/lib/Target/X86/X86WinEHState.cpp @@ -106,6 +106,9 @@ private: /// fs:00 chain and the current state. AllocaInst *RegNode = nullptr; + // The allocation containing the EH security guard. + AllocaInst *EHGuardNode = nullptr; + /// The index of the state field of RegNode. int StateFieldIndex = ~0U; @@ -195,6 +198,9 @@ bool WinEHStatePass::runOnFunction(Function &F) { PersonalityFn = nullptr; Personality = EHPersonality::Unknown; UseStackGuard = false; + RegNode = nullptr; + EHGuardNode = nullptr; + return true; } @@ -274,6 +280,9 @@ void WinEHStatePass::emitExceptionRegistrationRecord(Function *F) { IRBuilder<> Builder(&F->getEntryBlock(), F->getEntryBlock().begin()); Type *Int8PtrType = Builder.getInt8PtrTy(); + Type *Int32Ty = Builder.getInt32Ty(); + Type *VoidTy = Builder.getVoidTy(); + if (Personality == EHPersonality::MSVC_CXX) { RegNodeTy = getCXXEHRegistrationType(); RegNode = Builder.CreateAlloca(RegNodeTy); @@ -292,37 +301,53 @@ void WinEHStatePass::emitExceptionRegistrationRecord(Function *F) { CxxLongjmpUnwind = TheModule->getOrInsertFunction( "__CxxLongjmpUnwind", - FunctionType::get(Type::getVoidTy(TheModule->getContext()), Int8PtrType, - /*isVarArg=*/false)); + FunctionType::get(VoidTy, Int8PtrType, /*isVarArg=*/false)); cast<Function>(CxxLongjmpUnwind->stripPointerCasts()) ->setCallingConv(CallingConv::X86_StdCall); } else if (Personality == EHPersonality::MSVC_X86SEH) { // If _except_handler4 is in use, some additional guard checks and prologue // stuff is required. + StringRef PersonalityName = PersonalityFn->getName(); + UseStackGuard = (PersonalityName == "_except_handler4"); + + // Allocate local structures. RegNodeTy = getSEHRegistrationType(); RegNode = Builder.CreateAlloca(RegNodeTy); + if (UseStackGuard) + EHGuardNode = Builder.CreateAlloca(Int32Ty); + // SavedESP = llvm.stacksave() Value *SP = Builder.CreateCall( Intrinsic::getDeclaration(TheModule, Intrinsic::stacksave), {}); Builder.CreateStore(SP, Builder.CreateStructGEP(RegNodeTy, RegNode, 0)); // TryLevel = -2 / -1 StateFieldIndex = 4; - StringRef PersonalityName = PersonalityFn->getName(); - UseStackGuard = (PersonalityName == "_except_handler4"); ParentBaseState = UseStackGuard ? -2 : -1; insertStateNumberStore(&*Builder.GetInsertPoint(), ParentBaseState); // ScopeTable = llvm.x86.seh.lsda(F) Value *LSDA = emitEHLSDA(Builder, F); - Type *Int32Ty = Type::getInt32Ty(TheModule->getContext()); LSDA = Builder.CreatePtrToInt(LSDA, Int32Ty); // If using _except_handler4, xor the address of the table with // __security_cookie. if (UseStackGuard) { Cookie = TheModule->getOrInsertGlobal("__security_cookie", Int32Ty); - Value *Val = Builder.CreateLoad(Int32Ty, Cookie); + Value *Val = Builder.CreateLoad(Int32Ty, Cookie, "cookie"); LSDA = Builder.CreateXor(LSDA, Val); } Builder.CreateStore(LSDA, Builder.CreateStructGEP(RegNodeTy, RegNode, 3)); + + // If using _except_handler4, the EHGuard contains: FramePtr xor Cookie. + if (UseStackGuard) { + Value *Val = Builder.CreateLoad(Int32Ty, Cookie); + Value *FrameAddr = Builder.CreateCall( + Intrinsic::getDeclaration(TheModule, Intrinsic::frameaddress), + Builder.getInt32(0), "frameaddr"); + Value *FrameAddrI32 = Builder.CreatePtrToInt(FrameAddr, Int32Ty); + FrameAddrI32 = Builder.CreateXor(FrameAddrI32, Val); + Builder.CreateStore(FrameAddrI32, EHGuardNode); + } + + // Register the exception handler. Link = Builder.CreateStructGEP(RegNodeTy, RegNode, 2); linkExceptionRegistration(Builder, PersonalityFn); @@ -608,12 +633,21 @@ bool WinEHStatePass::isStateStoreNeeded(EHPersonality Personality, void WinEHStatePass::addStateStores(Function &F, WinEHFuncInfo &FuncInfo) { // Mark the registration node. The backend needs to know which alloca it is so // that it can recover the original frame pointer. - IRBuilder<> Builder(RegNode->getParent(), std::next(RegNode->getIterator())); + IRBuilder<> Builder(RegNode->getNextNode()); Value *RegNodeI8 = Builder.CreateBitCast(RegNode, Builder.getInt8PtrTy()); Builder.CreateCall( Intrinsic::getDeclaration(TheModule, Intrinsic::x86_seh_ehregnode), {RegNodeI8}); + if (EHGuardNode) { + IRBuilder<> Builder(EHGuardNode->getNextNode()); + Value *EHGuardNodeI8 = + Builder.CreateBitCast(EHGuardNode, Builder.getInt8PtrTy()); + Builder.CreateCall( + Intrinsic::getDeclaration(TheModule, Intrinsic::x86_seh_ehguard), + {EHGuardNodeI8}); + } + // Calculate state numbers. if (isAsynchronousEHPersonality(Personality)) calculateSEHStateNumbers(&F, FuncInfo); |