diff --git a/llvm/docs/ReleaseNotes.md b/llvm/docs/ReleaseNotes.md index 8b87921f8d0a7..f1df826d6d4f8 100644 --- a/llvm/docs/ReleaseNotes.md +++ b/llvm/docs/ReleaseNotes.md @@ -113,6 +113,9 @@ Changes to the WebAssembly Backend Changes to the Windows Target ----------------------------- +* The `.seh_startchained` and `.seh_endchained` assembly instructions have been removed and replaced + with a new `.seh_splitchained` instruction. + Changes to the X86 Backend -------------------------- diff --git a/llvm/include/llvm/MC/MCStreamer.h b/llvm/include/llvm/MC/MCStreamer.h index 79c715e3820a6..2a0095c9b7613 100644 --- a/llvm/include/llvm/MC/MCStreamer.h +++ b/llvm/include/llvm/MC/MCStreamer.h @@ -1024,8 +1024,7 @@ class LLVM_ABI MCStreamer { /// for the frame. We cannot use the End marker, as it is not set at the /// point of emitting .xdata, in order to indicate that the frame is active. virtual void emitWinCFIFuncletOrFuncEnd(SMLoc Loc = SMLoc()); - virtual void emitWinCFIStartChained(SMLoc Loc = SMLoc()); - virtual void emitWinCFIEndChained(SMLoc Loc = SMLoc()); + virtual void emitWinCFISplitChained(SMLoc Loc = SMLoc()); virtual void emitWinCFIPushReg(MCRegister Register, SMLoc Loc = SMLoc()); virtual void emitWinCFISetFrame(MCRegister Register, unsigned Offset, SMLoc Loc = SMLoc()); diff --git a/llvm/include/llvm/MC/MCWinEH.h b/llvm/include/llvm/MC/MCWinEH.h index b3d5c9cc8620a..9fbfd34da8e64 100644 --- a/llvm/include/llvm/MC/MCWinEH.h +++ b/llvm/include/llvm/MC/MCWinEH.h @@ -59,7 +59,7 @@ struct FrameInfo { uint8_t Version = DefaultVersion; int LastFrameInst = -1; - const FrameInfo *ChainedParent = nullptr; + FrameInfo *ChainedParent = nullptr; std::vector Instructions; struct Epilog { std::vector Instructions; @@ -90,9 +90,9 @@ struct FrameInfo { FrameInfo(const MCSymbol *Function, const MCSymbol *BeginFuncEHLabel) : Begin(BeginFuncEHLabel), Function(Function) {} FrameInfo(const MCSymbol *Function, const MCSymbol *BeginFuncEHLabel, - const FrameInfo *ChainedParent) + FrameInfo *ChainedParent) : Begin(BeginFuncEHLabel), Function(Function), - ChainedParent(ChainedParent) {} + Version(ChainedParent->Version), ChainedParent(ChainedParent) {} bool empty() const { if (!Instructions.empty()) diff --git a/llvm/lib/MC/MCAsmStreamer.cpp b/llvm/lib/MC/MCAsmStreamer.cpp index 33e288ecf991a..d3eea802a6ee3 100644 --- a/llvm/lib/MC/MCAsmStreamer.cpp +++ b/llvm/lib/MC/MCAsmStreamer.cpp @@ -375,8 +375,7 @@ class MCAsmStreamer final : public MCStreamer { void emitWinCFIStartProc(const MCSymbol *Symbol, SMLoc Loc) override; void emitWinCFIEndProc(SMLoc Loc) override; void emitWinCFIFuncletOrFuncEnd(SMLoc Loc) override; - void emitWinCFIStartChained(SMLoc Loc) override; - void emitWinCFIEndChained(SMLoc Loc) override; + void emitWinCFISplitChained(SMLoc Loc) override; void emitWinCFIPushReg(MCRegister Register, SMLoc Loc) override; void emitWinCFISetFrame(MCRegister Register, unsigned Offset, SMLoc Loc) override; @@ -2178,17 +2177,10 @@ void MCAsmStreamer::emitWinCFIFuncletOrFuncEnd(SMLoc Loc) { EmitEOL(); } -void MCAsmStreamer::emitWinCFIStartChained(SMLoc Loc) { - MCStreamer::emitWinCFIStartChained(Loc); +void MCAsmStreamer::emitWinCFISplitChained(SMLoc Loc) { + MCStreamer::emitWinCFISplitChained(Loc); - OS << "\t.seh_startchained"; - EmitEOL(); -} - -void MCAsmStreamer::emitWinCFIEndChained(SMLoc Loc) { - MCStreamer::emitWinCFIEndChained(Loc); - - OS << "\t.seh_endchained"; + OS << "\t.seh_splitchained"; EmitEOL(); } diff --git a/llvm/lib/MC/MCParser/COFFAsmParser.cpp b/llvm/lib/MC/MCParser/COFFAsmParser.cpp index d9ec04c6b6100..fe8a15400035a 100644 --- a/llvm/lib/MC/MCParser/COFFAsmParser.cpp +++ b/llvm/lib/MC/MCParser/COFFAsmParser.cpp @@ -79,10 +79,8 @@ class COFFAsmParser : public MCAsmParserExtension { ".seh_endproc"); addDirectiveHandler<&COFFAsmParser::parseSEHDirectiveEndFuncletOrFunc>( ".seh_endfunclet"); - addDirectiveHandler<&COFFAsmParser::parseSEHDirectiveStartChained>( - ".seh_startchained"); - addDirectiveHandler<&COFFAsmParser::parseSEHDirectiveEndChained>( - ".seh_endchained"); + addDirectiveHandler<&COFFAsmParser::parseSEHDirectiveSplitChained>( + ".seh_splitchained"); addDirectiveHandler<&COFFAsmParser::parseSEHDirectiveHandler>( ".seh_handler"); addDirectiveHandler<&COFFAsmParser::parseSEHDirectiveHandlerData>( @@ -142,8 +140,7 @@ class COFFAsmParser : public MCAsmParserExtension { bool parseSEHDirectiveStartProc(StringRef, SMLoc); bool parseSEHDirectiveEndProc(StringRef, SMLoc); bool parseSEHDirectiveEndFuncletOrFunc(StringRef, SMLoc); - bool parseSEHDirectiveStartChained(StringRef, SMLoc); - bool parseSEHDirectiveEndChained(StringRef, SMLoc); + bool parseSEHDirectiveSplitChained(StringRef, SMLoc); bool parseSEHDirectiveHandler(StringRef, SMLoc); bool parseSEHDirectiveHandlerData(StringRef, SMLoc); bool parseSEHDirectiveAllocStack(StringRef, SMLoc); @@ -684,15 +681,9 @@ bool COFFAsmParser::parseSEHDirectiveEndFuncletOrFunc(StringRef, SMLoc Loc) { return false; } -bool COFFAsmParser::parseSEHDirectiveStartChained(StringRef, SMLoc Loc) { +bool COFFAsmParser::parseSEHDirectiveSplitChained(StringRef, SMLoc Loc) { Lex(); - getStreamer().emitWinCFIStartChained(Loc); - return false; -} - -bool COFFAsmParser::parseSEHDirectiveEndChained(StringRef, SMLoc Loc) { - Lex(); - getStreamer().emitWinCFIEndChained(Loc); + getStreamer().emitWinCFISplitChained(Loc); return false; } diff --git a/llvm/lib/MC/MCStreamer.cpp b/llvm/lib/MC/MCStreamer.cpp index bc7398120096e..55b7f8d0ab97c 100644 --- a/llvm/lib/MC/MCStreamer.cpp +++ b/llvm/lib/MC/MCStreamer.cpp @@ -749,13 +749,23 @@ void MCStreamer::emitWinCFIEndProc(SMLoc Loc) { WinEH::FrameInfo *CurFrame = EnsureValidWinFrameInfo(Loc); if (!CurFrame) return; - if (CurFrame->ChainedParent) - getContext().reportError(Loc, "Not all chained regions terminated!"); + CurrentWinFrameInfo = nullptr; MCSymbol *Label = emitCFILabel(); CurFrame->End = Label; - if (!CurFrame->FuncletOrFuncEnd) - CurFrame->FuncletOrFuncEnd = CurFrame->End; + const MCSymbol **FuncletOrFuncEndPtr = + CurFrame->ChainedParent ? &CurFrame->ChainedParent->FuncletOrFuncEnd + : &CurFrame->FuncletOrFuncEnd; + if (!*FuncletOrFuncEndPtr) + *FuncletOrFuncEndPtr = CurFrame->End; + + if (CurrentWinEpilog) { + // Set End to... something... to prevent crashes later. + CurrentWinEpilog->End = emitCFILabel(); + CurrentWinEpilog = nullptr; + getContext().reportError(Loc, "Missing .seh_endepilogue in " + + CurFrame->Function->getName()); + } for (size_t I = CurrentProcWinFrameInfoStartIndex, E = WinFrameInfos.size(); I != E; ++I) @@ -767,38 +777,38 @@ void MCStreamer::emitWinCFIFuncletOrFuncEnd(SMLoc Loc) { WinEH::FrameInfo *CurFrame = EnsureValidWinFrameInfo(Loc); if (!CurFrame) return; - if (CurFrame->ChainedParent) - getContext().reportError(Loc, "Not all chained regions terminated!"); MCSymbol *Label = emitCFILabel(); - CurFrame->FuncletOrFuncEnd = Label; + const MCSymbol **FuncletOrFuncEndPtr = + CurFrame->ChainedParent ? &CurFrame->ChainedParent->FuncletOrFuncEnd + : &CurFrame->FuncletOrFuncEnd; + *FuncletOrFuncEndPtr = Label; } -void MCStreamer::emitWinCFIStartChained(SMLoc Loc) { +void MCStreamer::emitWinCFISplitChained(SMLoc Loc) { WinEH::FrameInfo *CurFrame = EnsureValidWinFrameInfo(Loc); if (!CurFrame) return; - MCSymbol *StartProc = emitCFILabel(); - - WinFrameInfos.emplace_back(std::make_unique( - CurFrame->Function, StartProc, CurFrame)); - CurrentWinFrameInfo = WinFrameInfos.back().get(); - CurrentWinFrameInfo->TextSection = getCurrentSectionOnly(); -} - -void MCStreamer::emitWinCFIEndChained(SMLoc Loc) { - WinEH::FrameInfo *CurFrame = EnsureValidWinFrameInfo(Loc); - if (!CurFrame) - return; - if (!CurFrame->ChainedParent) + if (!CurFrame->PrologEnd) return getContext().reportError( - Loc, "End of a chained region outside a chained region!"); + Loc, "can't split into a new chained region (.seh_splitchained) in the " + "middle of a prolog in " + + CurFrame->Function->getName()); MCSymbol *Label = emitCFILabel(); + // Complete the current frame before starting a new, chained one. CurFrame->End = Label; - CurrentWinFrameInfo = const_cast(CurFrame->ChainedParent); + + // All chained frames point to the same parent. + WinEH::FrameInfo *ChainedParent = + CurFrame->ChainedParent ? CurFrame->ChainedParent : CurFrame; + + WinFrameInfos.emplace_back(std::make_unique( + CurFrame->Function, Label, ChainedParent)); + CurrentWinFrameInfo = WinFrameInfos.back().get(); + CurrentWinFrameInfo->TextSection = getCurrentSectionOnly(); } void MCStreamer::emitWinEHHandler(const MCSymbol *Sym, bool Unwind, bool Except, @@ -806,9 +816,10 @@ void MCStreamer::emitWinEHHandler(const MCSymbol *Sym, bool Unwind, bool Except, WinEH::FrameInfo *CurFrame = EnsureValidWinFrameInfo(Loc); if (!CurFrame) return; - if (CurFrame->ChainedParent) - return getContext().reportError( - Loc, "Chained unwind areas can't have handlers!"); + + // Handlers are always associated with the parent frame. + CurFrame = CurFrame->ChainedParent ? CurFrame->ChainedParent : CurFrame; + CurFrame->ExceptionHandler = Sym; if (!Except && !Unwind) getContext().reportError(Loc, "Don't know what kind of handler this is!"); @@ -822,8 +833,6 @@ void MCStreamer::emitWinEHHandlerData(SMLoc Loc) { WinEH::FrameInfo *CurFrame = EnsureValidWinFrameInfo(Loc); if (!CurFrame) return; - if (CurFrame->ChainedParent) - getContext().reportError(Loc, "Chained unwind areas can't have handlers!"); } void MCStreamer::emitCGProfileEntry(const MCSymbolRefExpr *From, @@ -994,13 +1003,15 @@ void MCStreamer::emitWinCFIBeginEpilogue(SMLoc Loc) { if (!CurFrame) return; - if (!CurFrame->PrologEnd) - return getContext().reportError( + MCSymbol *Label = emitCFILabel(); + + if (!CurFrame->PrologEnd) { + CurFrame->PrologEnd = Label; + getContext().reportError( Loc, "starting epilogue (.seh_startepilogue) before prologue has ended " "(.seh_endprologue) in " + CurFrame->Function->getName()); - - MCSymbol *Label = emitCFILabel(); + } CurrentWinEpilog = &CurFrame->EpilogMap.insert_or_assign(Label, WinEH::FrameInfo::Epilog()) .first->second; @@ -1017,9 +1028,12 @@ void MCStreamer::emitWinCFIEndEpilogue(SMLoc Loc) { return getContext().reportError(Loc, "Stray .seh_endepilogue in " + CurFrame->Function->getName()); - if ((CurFrame->Version >= 2) && !CurrentWinEpilog->UnwindV2Start) - return getContext().reportError(Loc, "Missing .seh_unwindv2start in " + - CurFrame->Function->getName()); + if ((CurFrame->Version >= 2) && !CurrentWinEpilog->UnwindV2Start) { + // Set UnwindV2Start to... something... to prevent crashes later. + CurrentWinEpilog->UnwindV2Start = CurrentWinEpilog->Start; + getContext().reportError(Loc, "Missing .seh_unwindv2start in " + + CurFrame->Function->getName()); + } CurrentWinEpilog->End = emitCFILabel(); CurrentWinEpilog = nullptr; diff --git a/llvm/lib/MC/MCWin64EH.cpp b/llvm/lib/MC/MCWin64EH.cpp index 7a4b07991c674..e88c37d22ebea 100644 --- a/llvm/lib/MC/MCWin64EH.cpp +++ b/llvm/lib/MC/MCWin64EH.cpp @@ -26,8 +26,7 @@ using namespace llvm; namespace { /// MCExpr that represents the epilog unwind code in an unwind table. class MCUnwindV2EpilogTargetExpr final : public MCTargetExpr { - const MCSymbol *Function; - const MCSymbol *FunctionEnd; + const WinEH::FrameInfo &FrameInfo; const MCSymbol *UnwindV2Start; const MCSymbol *EpilogEnd; uint8_t EpilogSize; @@ -36,9 +35,11 @@ class MCUnwindV2EpilogTargetExpr final : public MCTargetExpr { MCUnwindV2EpilogTargetExpr(const WinEH::FrameInfo &FrameInfo, const WinEH::FrameInfo::Epilog &Epilog, uint8_t EpilogSize_) - : Function(FrameInfo.Function), FunctionEnd(FrameInfo.FuncletOrFuncEnd), - UnwindV2Start(Epilog.UnwindV2Start), EpilogEnd(Epilog.End), - EpilogSize(EpilogSize_), Loc(Epilog.Loc) {} + : FrameInfo(FrameInfo), UnwindV2Start(Epilog.UnwindV2Start), + EpilogEnd(Epilog.End), EpilogSize(EpilogSize_), Loc(Epilog.Loc) { + assert(UnwindV2Start && "Epilog must have a start"); + assert(EpilogEnd && "Epilog must have an end"); + } public: static MCUnwindV2EpilogTargetExpr * @@ -252,6 +253,10 @@ static void EmitUnwindInfo(MCStreamer &streamer, WinEH::FrameInfo *info) { // so, although there are terminators that are large than 1 byte, the // starting address of the terminator instruction will always be considered // inside the epilog). + assert( + LastEpilog.UnwindV2Start && + "If unwind v2 is enabled, epilog must have a unwind v2 start marker"); + assert(LastEpilog.End && "Epilog must have an end"); auto MaybeSize = GetOptionalAbsDifference( OS->getAssembler(), LastEpilog.End, LastEpilog.UnwindV2Start); if (!MaybeSize) { @@ -272,9 +277,14 @@ static void EmitUnwindInfo(MCStreamer &streamer, WinEH::FrameInfo *info) { // If the last epilog is at the end of the function, we can use a special // encoding for it. Because of our +1 trick for the size, this will only // work where that final terminator instruction is 1 byte long. - auto LastEpilogToFuncEnd = GetOptionalAbsDifference( - OS->getAssembler(), info->FuncletOrFuncEnd, LastEpilog.UnwindV2Start); - LastEpilogIsAtEnd = (LastEpilogToFuncEnd == EpilogSize); + // NOTE: At the point where the unwind info is emitted, the function may not + // have ended yet (e.g., if there is EH Handler Data), so assume that we + // aren't at the end (since we can't calculate it). + if (info->End) { + auto LastEpilogToFuncEnd = GetOptionalAbsDifference( + OS->getAssembler(), info->End, LastEpilog.UnwindV2Start); + LastEpilogIsAtEnd = (LastEpilogToFuncEnd == EpilogSize); + } // If we have an odd number of epilog codes, we need to add a padding code. size_t numEpilogCodes = @@ -386,28 +396,28 @@ bool MCUnwindV2EpilogTargetExpr::evaluateAsRelocatableImpl( MCValue &Res, const MCAssembler *Asm) const { // Calculate the offset to this epilog, and validate it's within the allowed // range. - auto Offset = GetOptionalAbsDifference(*Asm, FunctionEnd, UnwindV2Start); + auto Offset = GetOptionalAbsDifference(*Asm, FrameInfo.End, UnwindV2Start); if (!Offset) { Asm->getContext().reportError( Loc, "Failed to evaluate epilog offset for Unwind v2 in " + - Function->getName()); + FrameInfo.Function->getName()); return false; } assert(*Offset > 0); constexpr uint16_t MaxEpilogOffset = 0x0fff; if (*Offset > MaxEpilogOffset) { Asm->getContext().reportError( - Loc, - "Epilog offset is too large for Unwind v2 in " + Function->getName()); + Loc, "Epilog offset is too large for Unwind v2 in " + + FrameInfo.Function->getName()); return false; } - // Sanity check that all epilogs are the same size. + // Validate that all epilogs are the same size. auto Size = GetOptionalAbsDifference(*Asm, EpilogEnd, UnwindV2Start); if (Size != (EpilogSize - 1)) { Asm->getContext().reportError( Loc, "Size of this epilog does not match size of last epilog in " + - Function->getName()); + FrameInfo.Function->getName()); return false; } diff --git a/llvm/lib/Target/X86/MCTargetDesc/X86WinCOFFStreamer.cpp b/llvm/lib/Target/X86/MCTargetDesc/X86WinCOFFStreamer.cpp index abbb0c2466e7d..6eb8dff6a6ed2 100644 --- a/llvm/lib/Target/X86/MCTargetDesc/X86WinCOFFStreamer.cpp +++ b/llvm/lib/Target/X86/MCTargetDesc/X86WinCOFFStreamer.cpp @@ -44,8 +44,11 @@ void X86WinCOFFStreamer::emitWinEHHandlerData(SMLoc Loc) { // We have to emit the unwind info now, because this directive // actually switches to the .xdata section. - if (WinEH::FrameInfo *CurFrame = getCurrentWinFrameInfo()) + if (WinEH::FrameInfo *CurFrame = getCurrentWinFrameInfo()) { + // Handlers are always associated with the parent frame. + CurFrame = CurFrame->ChainedParent ? CurFrame->ChainedParent : CurFrame; EHStreamer.EmitUnwindInfo(*this, CurFrame, /* HandlerData = */ true); + } } void X86WinCOFFStreamer::emitWindowsUnwindTables(WinEH::FrameInfo *Frame) { diff --git a/llvm/test/MC/ARM/seh-checks2.s b/llvm/test/MC/ARM/seh-checks2.s index c8c525649f975..a8b1de898a5ec 100644 --- a/llvm/test/MC/ARM/seh-checks2.s +++ b/llvm/test/MC/ARM/seh-checks2.s @@ -3,7 +3,7 @@ // RUN: not llvm-mc -triple thumbv7-pc-win32 -filetype=obj -o /dev/null %s 2>&1 | FileCheck %s // CHECK: error: Stray .seh_endepilogue in func1 -// CHECK: error: Prologue in func2 not correctly terminated +// CHECK: error: starting epilogue (.seh_startepilogue) before prologue has ended (.seh_endprologue) in func2 // CHECK: error: Epilogue in func3 not correctly terminated // CHECK: error: Epilogue in func4 not correctly terminated diff --git a/llvm/test/MC/AsmParser/directive_seh.s b/llvm/test/MC/AsmParser/directive_seh.s index 8eb50ed996dd3..072d76e357abe 100644 --- a/llvm/test/MC/AsmParser/directive_seh.s +++ b/llvm/test/MC/AsmParser/directive_seh.s @@ -42,13 +42,13 @@ func: # CHECK: .seh_handlerdata .long 0 .text - .seh_startchained .seh_endprologue - .seh_endchained + .seh_splitchained + .seh_endprologue # CHECK: .text -# CHECK: .seh_startchained # CHECK: .seh_endprologue -# CHECK: .seh_endchained +# CHECK: .seh_splitchained +# CHECK: .seh_endprologue .seh_startepilogue # CHECK: .seh_startepilogue lea (%rbx), %rsp diff --git a/llvm/test/MC/AsmParser/seh-directive-errors.s b/llvm/test/MC/AsmParser/seh-directive-errors.s index d9dfe4b4182b9..a5fc2be018801 100644 --- a/llvm/test/MC/AsmParser/seh-directive-errors.s +++ b/llvm/test/MC/AsmParser/seh-directive-errors.s @@ -1,89 +1,91 @@ # RUN: not llvm-mc -triple x86_64-windows-msvc %s -filetype=obj -o /dev/null 2>&1 | FileCheck %s --implicit-check-not=error: # RUN: not llvm-mc -triple x86_64-windows-msvc %s -o /dev/null 2>&1 | FileCheck %s --implicit-check-not=error: - .text + .text # CHECK: error: .seh_ directive must appear within an active frame - .seh_handlerdata + .seh_handlerdata - .seh_pushreg %rsi - # CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: .seh_ directive must appear within an active frame + .seh_pushreg %rsi + # CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: .seh_ directive must appear within an active frame - .seh_stackalloc 32 - # CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: .seh_ directive must appear within an active frame + .seh_stackalloc 32 + # CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: .seh_ directive must appear within an active frame - .seh_startepilogue - # CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: .seh_ directive must appear within an active frame + .seh_startepilogue + # CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: .seh_ directive must appear within an active frame - .seh_endepilogue - # CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: .seh_ directive must appear within an active frame + .seh_endepilogue + # CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: .seh_ directive must appear within an active frame - .seh_unwindv2start - # CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: .seh_ directive must appear within an active frame + .seh_unwindv2start + # CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: .seh_ directive must appear within an active frame - .def f; - .scl 2; - .type 32; - .endef - .globl f # -- Begin function f - .p2align 4, 0x90 + .def f; + .scl 2; + .type 32; + .endef + .globl f # -- Begin function f + .p2align 4, 0x90 f: # @f .seh_proc f - pushq %rsi - .seh_pushreg %rsi - pushq %rdi - .seh_pushreg %rdi - pushq %rbx - .seh_pushreg %rbx - subq $32, %rsp - .seh_stackalloc 0 - # CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: stack allocation size must be non-zero - .seh_stackalloc 7 - # CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: stack allocation size is not a multiple of 8 - .seh_stackalloc 32 - .seh_startepilogue - # CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: starting epilogue (.seh_startepilogue) before prologue has ended (.seh_endprologue) in f - .seh_endprologue - nop - .seh_endepilogue - # CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: Stray .seh_endepilogue in f - .seh_startepilogue - addq $32, %rsp - popq %rbx - popq %rdi - popq %rsi - .seh_endepilogue - retq - .seh_handlerdata - .text - .seh_endproc - - - .seh_pushreg %rsi - # CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: .seh_ directive must appear within an active frame + pushq %rsi + .seh_pushreg %rsi + pushq %rdi + .seh_pushreg %rdi + pushq %rbx + .seh_pushreg %rbx + subq $32, %rsp + .seh_stackalloc 0 + # CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: stack allocation size must be non-zero + .seh_stackalloc 7 + # CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: stack allocation size is not a multiple of 8 + .seh_stackalloc 32 + .seh_splitchained + # CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: can't split into a new chained region (.seh_splitchained) in the middle of a prolog in f + .seh_startepilogue + # CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: starting epilogue (.seh_startepilogue) before prologue has ended (.seh_endprologue) in f + .seh_endprologue + nop + .seh_startepilogue + addq $32, %rsp + popq %rbx + popq %rdi + popq %rsi + .seh_endepilogue + .seh_endepilogue + # CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: Stray .seh_endepilogue in f + retq + .seh_handlerdata + .text + .seh_endproc + + + .seh_pushreg %rsi + # CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: .seh_ directive must appear within an active frame g: - .seh_proc g - pushq %rbp - .seh_pushreg %rbx - pushq %rsi - .seh_pushreg %rsi - .seh_endprologue - .seh_setframe 3 255 - # CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: you must specify a stack pointer offset - .seh_setframe 3, 255 - # CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: offset is not a multiple of 16 - .seh_setframe 3, 256 - # CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: frame offset must be less than or equal to 240 - .seh_setframe 3, 128 - .seh_setframe 3, 128 - # CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: frame register and offset can be set at most once - nop - .seh_startepilogue - popq %rsi - popq %rbp - .seh_endepilogue - retq - .seh_endproc + .seh_proc g + pushq %rbp + .seh_pushreg %rbx + pushq %rsi + .seh_pushreg %rsi + .seh_endprologue + .seh_setframe 3 255 + # CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: you must specify a stack pointer offset + .seh_setframe 3, 255 + # CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: offset is not a multiple of 16 + .seh_setframe 3, 256 + # CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: frame offset must be less than or equal to 240 + .seh_setframe 3, 128 + .seh_setframe 3, 128 + # CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: frame register and offset can be set at most once + nop + .seh_startepilogue + popq %rsi + popq %rbp + .seh_endepilogue + retq + .seh_endproc .globl h # -- Begin function h .p2align 4, 0x90 @@ -94,9 +96,9 @@ h: # @h .seh_stackalloc 72 movaps %xmm7, 48(%rsp) # 16-byte Spill .seh_savexmm 7 44 - # CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: you must specify an offset on the stack + # CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: you must specify an offset on the stack .seh_savexmm %xmm7, 44 - # CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: offset is not a multiple of 16 + # CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: offset is not a multiple of 16 .seh_savexmm %xmm7, 48 movaps %xmm6, 32(%rsp) # 16-byte Spill .seh_savexmm %xmm6, 32 @@ -107,55 +109,71 @@ h: # @h addsd %xmm6, %xmm7 callq getdbl addsd %xmm7, %xmm0 - .seh_startepilogue + .seh_startepilogue movaps 32(%rsp), %xmm6 # 16-byte Reload movaps 48(%rsp), %xmm7 # 16-byte Reload addq $72, %rsp - .seh_endepilogue + .seh_endepilogue retq .seh_handlerdata .text .seh_endproc # -- End function - .globl i - .def i; .scl 2; .type 32; .endef + .globl i + .def i; .scl 2; .type 32; .endef .p2align 4, 0x90 i: - .seh_proc i - pushq %rbp - .seh_pushreg 32 + .seh_proc i + pushq %rbp + .seh_pushreg 32 # CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: incorrect register number for use with this directive - pushq %rbx - .seh_pushreg %xmm0 + pushq %rbx + .seh_pushreg %xmm0 # CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: register is not supported for use with this directive - leaq 16(%rsp), %rbp - .seh_setframe %xmm0, 16 + leaq 16(%rsp), %rbp + .seh_setframe %xmm0, 16 # CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: register is not supported for use with this directive - .seh_endprologue - ret - .seh_endproc + .seh_endprologue + .seh_startepilogue + ret + .seh_endproc +# CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: Missing .seh_endepilogue in i j: - .seh_proc j - .seh_unwindversion 1 + .seh_proc j + .seh_unwindversion 1 # CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: Unsupported version specified in .seh_unwindversion in j - .seh_unwindversion 2 - .seh_unwindversion 2 + .seh_unwindversion 2 + .seh_unwindversion 2 # CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: Duplicate .seh_unwindversion in j - .seh_endprologue - .seh_unwindv2start + .seh_endprologue + .seh_unwindv2start # CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: Stray .seh_unwindv2start in j - .seh_startepilogue - .seh_endepilogue + .seh_startepilogue + .seh_endepilogue # CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: Missing .seh_unwindv2start in j - ret + ret - .seh_startepilogue - .seh_unwindv2start - .seh_unwindv2start + .seh_startepilogue + .seh_unwindv2start + .seh_unwindv2start # CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: Duplicate .seh_unwindv2start in j - .seh_endepilogue - ret - .seh_endproc + .seh_endepilogue + ret + .seh_endproc + +k: + .seh_proc k + .seh_endprologue + .seh_splitchained + pushq %rsi + .seh_pushreg %rsi + .seh_splitchained +# CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: can't split into a new chained region (.seh_splitchained) in the middle of a prolog in k + .seh_startepilogue +# CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: starting epilogue (.seh_startepilogue) before prologue has ended (.seh_endprologue) in k + .seh_endepilogue + ret + .seh_endproc diff --git a/llvm/test/MC/COFF/seh-unwindv2.s b/llvm/test/MC/COFF/seh-unwindv2.s index a746a5ffa5e5b..203ddecf41077 100644 --- a/llvm/test/MC/COFF/seh-unwindv2.s +++ b/llvm/test/MC/COFF/seh-unwindv2.s @@ -152,3 +152,214 @@ mismatched_terminators: // CHECK-NEXT: 0x04: ALLOC_SMALL size=40 // CHECK-NEXT: ] // CHECK-NEXT: } + +chained: + .seh_proc chained + .seh_unwindversion 2 + subq $40, %rsp + .seh_stackalloc 40 + .seh_endprologue + callq c + testl %eax, %eax + jle .L_ELSE_3 + movl %eax, %ecx + .seh_startepilogue + addq $40, %rsp + .seh_unwindv2start + .seh_endepilogue + jmp c + .seh_splitchained + .seh_endprologue +.L_ELSE_3: + nop + .seh_startepilogue + addq $40, %rsp + .seh_unwindv2start + .seh_endepilogue + jmp b + .seh_endproc + +// CHECK: RuntimeFunction { +// CHECK-NEXT: StartAddress: chained (0x30) +// CHECK-NEXT: EndAddress: chained [[EndDisp1:\+0x[A-F0-9]+]] (0x34) +// CHECK-NEXT: UnwindInfoAddress: .xdata [[InfoDisp1:\+0x[A-F0-9]+]] (0x38) +// CHECK-NEXT: UnwindInfo { +// CHECK-NEXT: Version: 2 +// CHECK-NEXT: Flags [ (0x0) +// CHECK-NEXT: ] +// CHECK-NEXT: PrologSize: 4 +// CHECK-NEXT: FrameRegister: - +// CHECK-NEXT: FrameOffset: - +// CHECK-NEXT: UnwindCodeCount: 3 +// CHECK-NEXT: UnwindCodes [ +// CHECK-NEXT: 0x01: EPILOG atend=no, length=0x1 +// CHECK-NEXT: 0x05: EPILOG offset=0x5 +// CHECK-NEXT: 0x04: ALLOC_SMALL size=40 +// CHECK-NEXT: ] +// CHECK-NEXT: } +// CHECK-NEXT: } +// CHECK-NEXT: RuntimeFunction { +// CHECK-NEXT: StartAddress: chained [[EndDisp1]] (0x3C) +// CHECK-NEXT: EndAddress: chained +0x22 (0x40) +// CHECK-NEXT: UnwindInfoAddress: .xdata +0x40 (0x44) +// CHECK-NEXT: UnwindInfo { +// CHECK-NEXT: Version: 2 +// CHECK-NEXT: Flags [ (0x4) +// CHECK-NEXT: ChainInfo (0x4) +// CHECK-NEXT: ] +// CHECK-NEXT: PrologSize: 0 +// CHECK-NEXT: FrameRegister: - +// CHECK-NEXT: FrameOffset: - +// CHECK-NEXT: UnwindCodeCount: 2 +// CHECK-NEXT: UnwindCodes [ +// CHECK-NEXT: 0x01: EPILOG atend=no, length=0x1 +// CHECK-NEXT: 0x05: EPILOG offset=0x5 +// CHECK-NEXT: ] +// CHECK-NEXT: Chained { +// CHECK-NEXT: StartAddress: chained (0x48) +// CHECK-NEXT: EndAddress: chained [[EndDisp1]] (0x4C) +// CHECK-NEXT: UnwindInfoAddress: .xdata [[InfoDisp1]] (0x50) +// CHECK-NEXT: } +// CHECK-NEXT: } +// CHECK-NEXT: } + +has_ex_handler_data: + .seh_proc has_ex_handler_data + .seh_handler __C_specific_handler, @unwind, @except + .seh_unwindversion 2 + pushq %rbp + .seh_pushreg %rbp + subq $32, %rsp + .seh_stackalloc 32 + leaq 32(%rsp), %rbp + .seh_setframe %rbp, 32 + .seh_endprologue +.has_ex_handler_data_callsite: + callq *__imp_callme(%rip) + nop +.has_ex_handler_data_finish: + .seh_startepilogue + addq $32, %rsp + .seh_unwindv2start + popq %rbp + .seh_endepilogue + retq +.has_ex_handler_data_handler: + jmp .has_ex_handler_data_finish + .seh_handlerdata + .long 1 # Number of call sites + .long .has_ex_handler_data_callsite@IMGREL # LabelStart + .long .has_ex_handler_data_finish@IMGREL # LabelEnd + .long 1 # CatchAll + .long .has_ex_handler_data_handler@IMGREL # ExceptionHandler + .text + .seh_endproc +// CHECK-LABEL: StartAddress: has_ex_handler_data +// CHECK-NEXT: EndAddress: .has_ex_handler_data_handler +0x2 +// CHECK-NEXT: UnwindInfoAddress: .xdata +0x54 +// CHECK-NEXT: UnwindInfo { +// CHECK-NEXT: Version: 2 +// CHECK-NEXT: Flags [ (0x3) +// CHECK-NEXT: ExceptionHandler (0x1) +// CHECK-NEXT: TerminateHandler (0x2) +// CHECK-NEXT: ] +// CHECK-NEXT: PrologSize: 10 +// CHECK-NEXT: FrameRegister: RBP +// CHECK-NEXT: FrameOffset: 0x2 +// CHECK-NEXT: UnwindCodeCount: 5 +// CHECK-NEXT: UnwindCodes [ +// CHECK-NEXT: 0x02: EPILOG atend=no, length=0x2 +// CHECK-NEXT: 0x04: EPILOG offset=0x4 +// CHECK-NEXT: 0x0A: SET_FPREG reg=RBP, offset=0x20 +// CHECK-NEXT: 0x05: ALLOC_SMALL size=32 +// CHECK-NEXT: 0x01: PUSH_NONVOL reg=RBP +// CHECK-NEXT: ] +// CHECK-NEXT: Handler: __C_specific_handler +// CHECK-NEXT: } + +has_ex_handler_data_and_chaining: + .seh_proc chained + .seh_handler __C_specific_handler, @unwind, @except + .seh_unwindversion 2 + subq $40, %rsp + .seh_stackalloc 40 + .seh_endprologue + callq c + testl %eax, %eax + jle .L_ELSE_4 +.has_ex_handler_data_and_chaining_callsite: + callq *__imp_callme(%rip) + nop +.has_ex_handler_data_and_chaining_finish: + movl %eax, %ecx + .seh_startepilogue + addq $40, %rsp + .seh_unwindv2start + .seh_endepilogue + jmp c + .seh_splitchained + .seh_endprologue +.L_ELSE_4: + nop + .seh_startepilogue + addq $40, %rsp + .seh_unwindv2start + .seh_endepilogue + jmp b +.has_ex_handler_data_and_chaining_handler: + jmp .has_ex_handler_data_and_chaining_finish + .seh_handlerdata + .long 1 # Number of call sites + .long .has_ex_handler_data_and_chaining_callsite@IMGREL # LabelStart + .long .has_ex_handler_data_and_chaining_finish@IMGREL # LabelEnd + .long 1 # CatchAll + .long .has_ex_handler_data_and_chaining_handler@IMGREL # ExceptionHandler + .text + .seh_endproc + +// CHECK: RuntimeFunction { +// CHECK-NEXT: StartAddress: has_ex_handler_data_and_chaining (0x54) +// CHECK-NEXT: EndAddress: .has_ex_handler_data_and_chaining_finish [[EndDisp2:\+0x[A-F0-9]+]] (0x58) +// CHECK-NEXT: UnwindInfoAddress: .xdata [[InfoDisp2:\+0x[A-F0-9]+]] (0x5C) +// CHECK-NEXT: UnwindInfo { +// CHECK-NEXT: Version: 2 +// CHECK-NEXT: Flags [ (0x3) +// CHECK-NEXT: ExceptionHandler (0x1) +// CHECK-NEXT: TerminateHandler (0x2) +// CHECK-NEXT: ] +// CHECK-NEXT: PrologSize: 4 +// CHECK-NEXT: FrameRegister: - +// CHECK-NEXT: FrameOffset: - +// CHECK-NEXT: UnwindCodeCount: 3 +// CHECK-NEXT: UnwindCodes [ +// CHECK-NEXT: 0x01: EPILOG atend=no, length=0x1 +// CHECK-NEXT: 0x05: EPILOG offset=0x5 +// CHECK-NEXT: 0x04: ALLOC_SMALL size=40 +// CHECK-NEXT: ] +// CHECK-NEXT: Handler: __C_specific_handler +// CHECK-NEXT: } +// CHECK-NEXT: } +// CHECK-NEXT: RuntimeFunction { +// CHECK-NEXT: StartAddress: .has_ex_handler_data_and_chaining_finish [[EndDisp2]] (0x60) +// CHECK-NEXT: EndAddress: .has_ex_handler_data_and_chaining_handler +0x2 (0x64) +// CHECK-NEXT: UnwindInfoAddress: .xdata +0xA0 (0x68) +// CHECK-NEXT: UnwindInfo { +// CHECK-NEXT: Version: 2 +// CHECK-NEXT: Flags [ (0x4) +// CHECK-NEXT: ChainInfo (0x4) +// CHECK-NEXT: ] +// CHECK-NEXT: PrologSize: 0 +// CHECK-NEXT: FrameRegister: - +// CHECK-NEXT: FrameOffset: - +// CHECK-NEXT: UnwindCodeCount: 2 +// CHECK-NEXT: UnwindCodes [ +// CHECK-NEXT: 0x01: EPILOG atend=no, length=0x1 +// CHECK-NEXT: 0x07: EPILOG offset=0x7 +// CHECK-NEXT: ] +// CHECK-NEXT: Chained { +// CHECK-NEXT: StartAddress: has_ex_handler_data_and_chaining (0xA8) +// CHECK-NEXT: EndAddress: .has_ex_handler_data_and_chaining_finish [[EndDisp2]] (0xAC) +// CHECK-NEXT: UnwindInfoAddress: .xdata [[InfoDisp2]] (0xB0) +// CHECK-NEXT: } +// CHECK-NEXT: } +// CHECK-NEXT: } diff --git a/llvm/test/MC/COFF/seh.s b/llvm/test/MC/COFF/seh.s index 31e845397f2d0..2bbcb1f245ab7 100644 --- a/llvm/test/MC/COFF/seh.s +++ b/llvm/test/MC/COFF/seh.s @@ -15,8 +15,8 @@ // CHECK-NEXT: } // CHECK: Section { // CHECK: Name: .xdata -// CHECK: RawDataSize: 52 -// CHECK: RelocationCount: 4 +// CHECK: RawDataSize: 80 +// CHECK: RelocationCount: 7 // CHECK: Characteristics [ // CHECK-NEXT: ALIGN_4BYTES // CHECK-NEXT: CNT_INITIALIZED_DATA @@ -25,7 +25,7 @@ // CHECK-NEXT: } // CHECK: Section { // CHECK: Name: .pdata -// CHECK: RelocationCount: 9 +// CHECK: RelocationCount: 15 // CHECK: Characteristics [ // CHECK-NEXT: ALIGN_4BYTES // CHECK-NEXT: CNT_INITIALIZED_DATA @@ -40,6 +40,9 @@ // CHECK-NEXT: 0x20 IMAGE_REL_AMD64_ADDR32NB .text // CHECK-NEXT: 0x24 IMAGE_REL_AMD64_ADDR32NB .text // CHECK-NEXT: 0x28 IMAGE_REL_AMD64_ADDR32NB .xdata +// CHECK-NEXT: 0x44 IMAGE_REL_AMD64_ADDR32NB .text +// CHECK-NEXT: 0x48 IMAGE_REL_AMD64_ADDR32NB .text +// CHECK-NEXT: 0x4C IMAGE_REL_AMD64_ADDR32NB .xdata // CHECK-NEXT: } // CHECK-NEXT: Section (5) .pdata { // CHECK-NEXT: 0x0 IMAGE_REL_AMD64_ADDR32NB .text @@ -51,6 +54,12 @@ // CHECK-NEXT: 0x18 IMAGE_REL_AMD64_ADDR32NB .text // CHECK-NEXT: 0x1C IMAGE_REL_AMD64_ADDR32NB .text // CHECK-NEXT: 0x20 IMAGE_REL_AMD64_ADDR32NB .xdata +// CHECK-NEXT: 0x24 IMAGE_REL_AMD64_ADDR32NB .text +// CHECK-NEXT: 0x28 IMAGE_REL_AMD64_ADDR32NB .text +// CHECK-NEXT: 0x2C IMAGE_REL_AMD64_ADDR32NB .xdata +// CHECK-NEXT: 0x30 IMAGE_REL_AMD64_ADDR32NB .text +// CHECK-NEXT: 0x34 IMAGE_REL_AMD64_ADDR32NB .text +// CHECK-NEXT: 0x38 IMAGE_REL_AMD64_ADDR32NB .xdata // CHECK-NEXT: } // CHECK-NEXT: ] @@ -81,8 +90,8 @@ // CHECK-NEXT: } // CHECK-NEXT: } // CHECK-NEXT: RuntimeFunction { -// CHECK-NEXT: StartAddress: [[CodeSect2:[^ ]+]] [[BeginDisp2:(\+0x[A-F0-9]+)?]] -// CHECK-NEXT: EndAddress: [[CodeSect2]] [[BeginDisp2:(\+0x[A-F0-9]+)?]] +// CHECK-NEXT: StartAddress: [[CodeSect1]] [[BeginDisp2:(\+0x[A-F0-9]+)?]] +// CHECK-NEXT: EndAddress: [[CodeSect1]] [[EndDisp2:(\+0x[A-F0-9]+)?]] // CHECK-NEXT: UnwindInfoAddress: // CHECK-NEXT: UnwindInfo { // CHECK-NEXT: Version: 1 @@ -104,7 +113,7 @@ // CHECK-NEXT: } // CHECK-NEXT: RuntimeFunction { // CHECK-NEXT: StartAddress: [[CodeSect3:[^ ]+]] [[BeginDisp3:(\+0x[A-F0-9]+)?]] -// CHECK-NEXT: EndAddress: [[CodeSect3]] [[BeginDisp3:(\+0x[A-F0-9]+)?]] +// CHECK-NEXT: EndAddress: [[CodeSect3]] [[EndDisp3:(\+0x[A-F0-9]+)?]] // CHECK-NEXT: UnwindInfoAddress: // CHECK-NEXT: UnwindInfo { // CHECK-NEXT: Version: 1 @@ -118,6 +127,46 @@ // CHECK-NEXT: ] // CHECK-NEXT: } // CHECK-NEXT: } +// CHECK-NEXT: RuntimeFunction { +// CHECK-NEXT: StartAddress: [[CodeSect4:[^ ]+]] [[BeginDisp4:(\+0x[A-F0-9]+)?]] +// CHECK-NEXT: EndAddress: [[CodeSect4]] [[EndDisp4:(\+0x[A-F0-9]+)?]] +// CHECK-NEXT: UnwindInfoAddress: +// CHECK-NEXT: UnwindInfo { +// CHECK-NEXT: Version: 1 +// CHECK-NEXT: Flags [ (0x0) +// CHECK-NEXT: ] +// CHECK-NEXT: PrologSize: 1 +// CHECK-NEXT: FrameRegister: - +// CHECK-NEXT: FrameOffset: - +// CHECK-NEXT: UnwindCodeCount: 1 +// CHECK-NEXT: UnwindCodes [ +// CHECK-NEXT: 0x01: PUSH_NONVOL reg=RBX +// CHECK-NEXT: ] +// CHECK-NEXT: } +// CHECK-NEXT: } +// CHECK-NEXT: RuntimeFunction { +// CHECK-NEXT: StartAddress: [[CodeSect4]] [[BeginDisp5:(\+0x[A-F0-9]+)?]] +// CHECK-NEXT: EndAddress: [[CodeSect4]] [[EndDisp5:(\+0x[A-F0-9]+)?]] +// CHECK-NEXT: UnwindInfoAddress: +// CHECK-NEXT: UnwindInfo { +// CHECK-NEXT: Version: 1 +// CHECK-NEXT: Flags [ (0x4) +// CHECK-NEXT: ChainInfo (0x4) +// CHECK-NEXT: ] +// CHECK-NEXT: PrologSize: 1 +// CHECK-NEXT: FrameRegister: - +// CHECK-NEXT: FrameOffset: - +// CHECK-NEXT: UnwindCodeCount: 1 +// CHECK-NEXT: UnwindCodes [ +// CHECK-NEXT: 0x01: PUSH_NONVOL reg=RSI +// CHECK-NEXT: ] +// CHECK-NEXT: Chained { +// CHECK-NEXT: StartAddress: [[CodeSect4]] [[BeginDisp4]] +// CHECK-NEXT: EndAddress: [[CodeSect4]] [[EndDisp4]] +// CHECK-NEXT: UnwindInfoAddress: +// CHECK-NEXT: } +// CHECK-NEXT: } +// CHECK-NEXT: } // CHECK-NEXT: ] .text @@ -141,9 +190,9 @@ func: .seh_handlerdata .long 0 .text - .seh_startchained .seh_endprologue - .seh_endchained + .seh_splitchained + .seh_endprologue .seh_startepilogue lea (%rbx), %rsp pop %rbx @@ -159,3 +208,22 @@ func: smallFunc: ret .seh_endproc + +// Test chaining prologs together. + .globl split_prolog + .def split_prolog; .scl 2; .type 32; .endef + .seh_proc split_prolog +split_prolog: + pushq %rbx + .seh_pushreg %rbx + .seh_endprologue + .seh_splitchained + pushq %rsi + .seh_pushreg %rsi + .seh_endprologue + .seh_startepilogue + pop %rsi + pop %rbx + .seh_endepilogue + ret + .seh_endproc diff --git a/llvm/test/tools/llvm-objdump/COFF/Inputs/win64-unwind.exe.coff-x86_64.asm b/llvm/test/tools/llvm-objdump/COFF/Inputs/win64-unwind.exe.coff-x86_64.asm index c44d59b324036..9c301652f8ea4 100644 --- a/llvm/test/tools/llvm-objdump/COFF/Inputs/win64-unwind.exe.coff-x86_64.asm +++ b/llvm/test/tools/llvm-objdump/COFF/Inputs/win64-unwind.exe.coff-x86_64.asm @@ -19,9 +19,8 @@ func: .seh_handlerdata .long 0 .text - .seh_startchained .seh_endprologue - .seh_endchained + .seh_splitchained lea (%rbx), %rsp pop %rbx addq $24, %rsp