summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorReid Kleckner <reid@kleckner.net>2015-05-20 23:08:04 +0000
committerReid Kleckner <reid@kleckner.net>2015-05-20 23:08:04 +0000
commit7681f6a1b0f79683b963c5061335eff88a5a55ad (patch)
tree337091a8a8fb22322e8ca481b97bb7e9195f89b3
parent05b0f7dc93cfbf49be663b6701841bcae75cb576 (diff)
[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
-rw-r--r--include/llvm/IR/IntrinsicsX86.td6
-rw-r--r--include/llvm/MC/MCContext.h2
-rw-r--r--lib/MC/MCContext.cpp5
-rw-r--r--lib/Target/X86/X86ISelLowering.cpp18
-rw-r--r--lib/Target/X86/X86WinEHState.cpp83
-rw-r--r--test/CodeGen/X86/win32-eh.ll14
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
@@ -18,6 +18,12 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.".
}
//===----------------------------------------------------------------------===//
+// 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 {
def int_x86_rdtsc : GCCBuiltin<"__builtin_ia32_rdtsc">,
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<Function>(cast<GlobalAddressSDNode>(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