Index: lib/CodeGen/AsmPrinter/WinException.h =================================================================== --- lib/CodeGen/AsmPrinter/WinException.h +++ lib/CodeGen/AsmPrinter/WinException.h @@ -85,6 +85,7 @@ /// only), it is relative to the frame pointer. int getFrameIndexOffset(int FrameIndex, const WinEHFuncInfo &FuncInfo); + void endFuncletImpl(); public: //===--------------------------------------------------------------------===// // Main entry points. @@ -99,6 +100,8 @@ /// immediately after the function entry point. void beginFunction(const MachineFunction *MF) override; + void markFunctionEnd() override; + /// Gather and emit post-function exception information. void endFunction(const MachineFunction *) override; Index: lib/CodeGen/AsmPrinter/WinException.cpp =================================================================== --- lib/CodeGen/AsmPrinter/WinException.cpp +++ lib/CodeGen/AsmPrinter/WinException.cpp @@ -109,6 +109,12 @@ beginFunclet(MF->front(), Asm->CurrentFnSym); } +void WinException::markFunctionEnd() { + if (isAArch64 && CurrentFuncletEntry && + (shouldEmitMoves || shouldEmitPersonality)) + Asm->OutStreamer->EmitWinCFIFuncletOrFuncEnd(); +} + /// endFunction - Gather and emit post-function exception information. /// void WinException::endFunction(const MachineFunction *MF) { @@ -128,7 +134,7 @@ NonConstMF->tidyLandingPads(); } - endFunclet(); + endFuncletImpl(); // endFunclet will emit the necessary .xdata tables for x64 SEH. if (Per == EHPersonality::MSVC_Win64SEH && MF->hasEHFunclets()) @@ -231,6 +237,15 @@ } void WinException::endFunclet() { + if (isAArch64 && CurrentFuncletEntry && + (shouldEmitMoves || shouldEmitPersonality)) { + Asm->OutStreamer->SwitchSection(CurrentFuncletTextSection); + Asm->OutStreamer->EmitWinCFIFuncletOrFuncEnd(); + } + endFuncletImpl(); +} + +void WinException::endFuncletImpl() { // No funclet to process? Great, we have nothing to do. if (!CurrentFuncletEntry) return; @@ -246,8 +261,6 @@ // to EmitWinEHHandlerData below can calculate the size of the funclet or // function. if (isAArch64) { - Asm->OutStreamer->SwitchSection(CurrentFuncletTextSection); - Asm->OutStreamer->EmitWinCFIFuncletOrFuncEnd(); MCSection *XData = Asm->OutStreamer->getAssociatedXDataSection( Asm->OutStreamer->getCurrentSectionOnly()); Asm->OutStreamer->SwitchSection(XData); Index: lib/MC/MCWin64EH.cpp =================================================================== --- lib/MC/MCWin64EH.cpp +++ lib/MC/MCWin64EH.cpp @@ -255,8 +255,12 @@ MCBinaryExpr::createSub(MCSymbolRefExpr::create(LHS, Context), MCSymbolRefExpr::create(RHS, Context), Context); MCObjectStreamer *OS = (MCObjectStreamer *)(&Streamer); + // It should normally be possible to calculate the length of a function + // at this point, but it might not be possible in the presence of certain + // unusual constructs, like an inline asm with an alignment directive. int64_t value; - Diff->evaluateAsAbsolute(value, OS->getAssembler()); + if (!Diff->evaluateAsAbsolute(value, OS->getAssembler())) + report_fatal_error("Failed to evaluate function length in SEH unwind info"); return value; } @@ -498,11 +502,18 @@ streamer.EmitLabel(Label); info->Symbol = Label; - uint32_t FuncLength = 0x0; - if (info->FuncletOrFuncEnd) - FuncLength = (uint32_t)GetAbsDifference(streamer, info->FuncletOrFuncEnd, - info->Begin); - FuncLength /= 4; + int64_t RawFuncLength; + if (!info->FuncletOrFuncEnd) { + // FIXME: This is very wrong; we emit SEH data which covers zero bytes + // of code. But otherwise test/MC/AArch64/seh.s crashes. + RawFuncLength = 0; + } else { + RawFuncLength = GetAbsDifference(streamer, info->FuncletOrFuncEnd, + info->Begin); + } + if (RawFuncLength > 0xFFFFF) + report_fatal_error("SEH unwind data splitting not yet implemented"); + uint32_t FuncLength = (uint32_t)RawFuncLength / 4; uint32_t PrologCodeBytes = ARM64CountOfUnwindCodes(info->Instructions); uint32_t TotalCodeBytes = PrologCodeBytes; Index: test/CodeGen/AArch64/win64-jumptable.ll =================================================================== --- test/CodeGen/AArch64/win64-jumptable.ll +++ test/CodeGen/AArch64/win64-jumptable.ll @@ -1,4 +1,5 @@ ; RUN: llc -o - %s -mtriple=aarch64-windows -aarch64-enable-compress-jump-tables=0 | FileCheck %s +; RUN: llc -o - %s -mtriple=aarch64-windows -aarch64-enable-compress-jump-tables=0 -filetype=obj | llvm-readobj -unwind | FileCheck %s -check-prefix=UNWIND define void @f(i32 %x) { entry: @@ -46,3 +47,6 @@ ; CHECK: .seh_handlerdata ; CHECK: .text ; CHECK: .seh_endproc + +; Check that we can emit an object file with correct unwind info. +; UNWIND: FunctionLength: {{[1-9][0-9]*}}