mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-02-01 05:01:59 +01:00
[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. llvm-svn: 237852
This commit is contained in:
parent
b5af4a9342
commit
45341c98d0
@ -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 {
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user