diff options
author | Reid Kleckner <reid@kleckner.net> | 2015-06-09 21:42:19 +0000 |
---|---|---|
committer | Reid Kleckner <reid@kleckner.net> | 2015-06-09 21:42:19 +0000 |
commit | f12c030f4879e2bf2caca21976f5de9ba8c48bdd (patch) | |
tree | 21b2e4664e29273f3905ed81222e87a61abeec1c /llvm/lib/CodeGen/AsmPrinter/WinException.cpp | |
parent | cf90acc1041fea47db7d862a21b24534b5df21b0 (diff) | |
download | bcm5719-llvm-f12c030f4879e2bf2caca21976f5de9ba8c48bdd.tar.gz bcm5719-llvm-f12c030f4879e2bf2caca21976f5de9ba8c48bdd.zip |
[WinEH] Add 32-bit SEH state table emission prototype
This gets all the handler info through to the asm printer and we can
look at the .xdata tables now. I've convinced one small catch-all test
case to work, but other than that, it would be a stretch to say this is
functional.
The state numbering algorithm avoids doing any scope reconstruction as
we do for C++ to simplify the implementation.
llvm-svn: 239433
Diffstat (limited to 'llvm/lib/CodeGen/AsmPrinter/WinException.cpp')
-rw-r--r-- | llvm/lib/CodeGen/AsmPrinter/WinException.cpp | 89 |
1 files changed, 88 insertions, 1 deletions
diff --git a/llvm/lib/CodeGen/AsmPrinter/WinException.cpp b/llvm/lib/CodeGen/AsmPrinter/WinException.cpp index f1663503c08..1143b044cad 100644 --- a/llvm/lib/CodeGen/AsmPrinter/WinException.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/WinException.cpp @@ -144,7 +144,7 @@ void WinException::endFunction(const MachineFunction *MF) { if (Per == EHPersonality::MSVC_Win64SEH) emitCSpecificHandlerTable(); else if (Per == EHPersonality::MSVC_X86SEH) - emitCSpecificHandlerTable(); // FIXME + emitExceptHandlerTable(MF); else if (Per == EHPersonality::MSVC_CXX) emitCXXFrameHandler3Table(MF); else @@ -541,3 +541,90 @@ void WinException::extendIP2StateTable(const MachineFunction *MF, } } } + +/// Emit the language-specific data that _except_handler3 and 4 expect. This is +/// functionally equivalent to the __C_specific_handler table, except it is +/// indexed by state number instead of IP. +void WinException::emitExceptHandlerTable(const MachineFunction *MF) { + auto &OS = *Asm->OutStreamer; + + // Emit the __ehtable label that we use for llvm.x86.seh.lsda. + const Function *F = MF->getFunction(); + StringRef FLinkageName = GlobalValue::getRealLinkageName(F->getName()); + MCSymbol *LSDALabel = Asm->OutContext.getOrCreateLSDASymbol(FLinkageName); + OS.EmitLabel(LSDALabel); + + const Function *Per = MMI->getPersonality(); + StringRef PerName = Per->getName(); + int BaseState = -1; + if (PerName == "_except_handler4") { + // The LSDA for _except_handler4 starts with this struct, followed by the + // scope table: + // + // struct EH4ScopeTable { + // int32_t GSCookieOffset; + // int32_t GSCookieXOROffset; + // int32_t EHCookieOffset; + // int32_t EHCookieXOROffset; + // ScopeTableEntry ScopeRecord[]; + // }; + // + // Only the EHCookieOffset field appears to vary, and it appears to be the + // offset from the final saved SP value to the retaddr. + OS.EmitIntValue(-2, 4); + OS.EmitIntValue(0, 4); + // FIXME: Calculate. + OS.EmitIntValue(9999, 4); + OS.EmitIntValue(0, 4); + BaseState = -2; + } + + // Build a list of pointers to LandingPadInfos and then sort by WinEHState. + const std::vector<LandingPadInfo> &PadInfos = MMI->getLandingPads(); + SmallVector<const LandingPadInfo *, 4> LPads; + LPads.reserve((PadInfos.size())); + for (const LandingPadInfo &LPInfo : PadInfos) + LPads.push_back(&LPInfo); + std::sort(LPads.begin(), LPads.end(), + [](const LandingPadInfo *L, const LandingPadInfo *R) { + return L->WinEHState < R->WinEHState; + }); + + // For each action in each lpad, emit one of these: + // struct ScopeTableEntry { + // int32_t EnclosingLevel; + // int32_t (__cdecl *FilterOrFinally)(); + // void *HandlerLabel; + // }; + // + // The "outermost" action will use BaseState as its enclosing level. Each + // other action will refer to the previous state as its enclosing level. + int CurState = 0; + for (const LandingPadInfo *LPInfo : LPads) { + int EnclosingLevel = BaseState; + assert(CurState + LPInfo->SEHHandlers.size() - 1 == LPInfo->WinEHState && + "gaps in the SEH scope table"); + for (const SEHHandler &Handler : LPInfo->SEHHandlers) { + // Emit the filter or finally function pointer, if present. Otherwise, + // emit '1' to indicate a catch-all. + const MCExpr *FilterOrFinally; + if (const Function *F = Handler.FilterOrFinally) + FilterOrFinally = create32bitRef(Asm->getSymbol(F)); + else + FilterOrFinally = MCConstantExpr::create(1, Asm->OutContext); + + // Compute the recovery address, which is a block address or null. + const BlockAddress *BA = Handler.RecoverBA; + const MCExpr *RecoverBBOrNull = + create32bitRef(BA ? Asm->GetBlockAddressSymbol(BA) : nullptr); + + OS.EmitIntValue(EnclosingLevel, 4); + OS.EmitValue(FilterOrFinally, 4); + OS.EmitValue(RecoverBBOrNull, 4); + + // The next state unwinds to this state. + EnclosingLevel = CurState; + CurState++; + } + } +} |