10b57cec5SDimitry Andric //===- lib/MC/MCWin64EH.cpp - MCWin64EH implementation --------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric 90b57cec5SDimitry Andric #include "llvm/MC/MCWin64EH.h" 100b57cec5SDimitry Andric #include "llvm/ADT/Twine.h" 110b57cec5SDimitry Andric #include "llvm/MC/MCContext.h" 120b57cec5SDimitry Andric #include "llvm/MC/MCExpr.h" 130b57cec5SDimitry Andric #include "llvm/MC/MCObjectFileInfo.h" 140b57cec5SDimitry Andric #include "llvm/MC/MCObjectStreamer.h" 150b57cec5SDimitry Andric #include "llvm/MC/MCSectionCOFF.h" 160b57cec5SDimitry Andric #include "llvm/MC/MCStreamer.h" 170b57cec5SDimitry Andric #include "llvm/MC/MCSymbol.h" 180b57cec5SDimitry Andric #include "llvm/Support/Win64EH.h" 190b57cec5SDimitry Andric 200b57cec5SDimitry Andric using namespace llvm; 210b57cec5SDimitry Andric 220b57cec5SDimitry Andric // NOTE: All relocations generated here are 4-byte image-relative. 230b57cec5SDimitry Andric 240b57cec5SDimitry Andric static uint8_t CountOfUnwindCodes(std::vector<WinEH::Instruction> &Insns) { 250b57cec5SDimitry Andric uint8_t Count = 0; 260b57cec5SDimitry Andric for (const auto &I : Insns) { 270b57cec5SDimitry Andric switch (static_cast<Win64EH::UnwindOpcodes>(I.Operation)) { 280b57cec5SDimitry Andric default: 290b57cec5SDimitry Andric llvm_unreachable("Unsupported unwind code"); 300b57cec5SDimitry Andric case Win64EH::UOP_PushNonVol: 310b57cec5SDimitry Andric case Win64EH::UOP_AllocSmall: 320b57cec5SDimitry Andric case Win64EH::UOP_SetFPReg: 330b57cec5SDimitry Andric case Win64EH::UOP_PushMachFrame: 340b57cec5SDimitry Andric Count += 1; 350b57cec5SDimitry Andric break; 360b57cec5SDimitry Andric case Win64EH::UOP_SaveNonVol: 370b57cec5SDimitry Andric case Win64EH::UOP_SaveXMM128: 380b57cec5SDimitry Andric Count += 2; 390b57cec5SDimitry Andric break; 400b57cec5SDimitry Andric case Win64EH::UOP_SaveNonVolBig: 410b57cec5SDimitry Andric case Win64EH::UOP_SaveXMM128Big: 420b57cec5SDimitry Andric Count += 3; 430b57cec5SDimitry Andric break; 440b57cec5SDimitry Andric case Win64EH::UOP_AllocLarge: 450b57cec5SDimitry Andric Count += (I.Offset > 512 * 1024 - 8) ? 3 : 2; 460b57cec5SDimitry Andric break; 470b57cec5SDimitry Andric } 480b57cec5SDimitry Andric } 490b57cec5SDimitry Andric return Count; 500b57cec5SDimitry Andric } 510b57cec5SDimitry Andric 520b57cec5SDimitry Andric static void EmitAbsDifference(MCStreamer &Streamer, const MCSymbol *LHS, 530b57cec5SDimitry Andric const MCSymbol *RHS) { 540b57cec5SDimitry Andric MCContext &Context = Streamer.getContext(); 550b57cec5SDimitry Andric const MCExpr *Diff = 560b57cec5SDimitry Andric MCBinaryExpr::createSub(MCSymbolRefExpr::create(LHS, Context), 570b57cec5SDimitry Andric MCSymbolRefExpr::create(RHS, Context), Context); 585ffd83dbSDimitry Andric Streamer.emitValue(Diff, 1); 590b57cec5SDimitry Andric } 600b57cec5SDimitry Andric 610b57cec5SDimitry Andric static void EmitUnwindCode(MCStreamer &streamer, const MCSymbol *begin, 620b57cec5SDimitry Andric WinEH::Instruction &inst) { 630b57cec5SDimitry Andric uint8_t b2; 640b57cec5SDimitry Andric uint16_t w; 650b57cec5SDimitry Andric b2 = (inst.Operation & 0x0F); 660b57cec5SDimitry Andric switch (static_cast<Win64EH::UnwindOpcodes>(inst.Operation)) { 670b57cec5SDimitry Andric default: 680b57cec5SDimitry Andric llvm_unreachable("Unsupported unwind code"); 690b57cec5SDimitry Andric case Win64EH::UOP_PushNonVol: 700b57cec5SDimitry Andric EmitAbsDifference(streamer, inst.Label, begin); 710b57cec5SDimitry Andric b2 |= (inst.Register & 0x0F) << 4; 725ffd83dbSDimitry Andric streamer.emitInt8(b2); 730b57cec5SDimitry Andric break; 740b57cec5SDimitry Andric case Win64EH::UOP_AllocLarge: 750b57cec5SDimitry Andric EmitAbsDifference(streamer, inst.Label, begin); 760b57cec5SDimitry Andric if (inst.Offset > 512 * 1024 - 8) { 770b57cec5SDimitry Andric b2 |= 0x10; 785ffd83dbSDimitry Andric streamer.emitInt8(b2); 790b57cec5SDimitry Andric w = inst.Offset & 0xFFF8; 805ffd83dbSDimitry Andric streamer.emitInt16(w); 810b57cec5SDimitry Andric w = inst.Offset >> 16; 820b57cec5SDimitry Andric } else { 835ffd83dbSDimitry Andric streamer.emitInt8(b2); 840b57cec5SDimitry Andric w = inst.Offset >> 3; 850b57cec5SDimitry Andric } 865ffd83dbSDimitry Andric streamer.emitInt16(w); 870b57cec5SDimitry Andric break; 880b57cec5SDimitry Andric case Win64EH::UOP_AllocSmall: 890b57cec5SDimitry Andric b2 |= (((inst.Offset - 8) >> 3) & 0x0F) << 4; 900b57cec5SDimitry Andric EmitAbsDifference(streamer, inst.Label, begin); 915ffd83dbSDimitry Andric streamer.emitInt8(b2); 920b57cec5SDimitry Andric break; 930b57cec5SDimitry Andric case Win64EH::UOP_SetFPReg: 940b57cec5SDimitry Andric EmitAbsDifference(streamer, inst.Label, begin); 955ffd83dbSDimitry Andric streamer.emitInt8(b2); 960b57cec5SDimitry Andric break; 970b57cec5SDimitry Andric case Win64EH::UOP_SaveNonVol: 980b57cec5SDimitry Andric case Win64EH::UOP_SaveXMM128: 990b57cec5SDimitry Andric b2 |= (inst.Register & 0x0F) << 4; 1000b57cec5SDimitry Andric EmitAbsDifference(streamer, inst.Label, begin); 1015ffd83dbSDimitry Andric streamer.emitInt8(b2); 1020b57cec5SDimitry Andric w = inst.Offset >> 3; 1030b57cec5SDimitry Andric if (inst.Operation == Win64EH::UOP_SaveXMM128) 1040b57cec5SDimitry Andric w >>= 1; 1055ffd83dbSDimitry Andric streamer.emitInt16(w); 1060b57cec5SDimitry Andric break; 1070b57cec5SDimitry Andric case Win64EH::UOP_SaveNonVolBig: 1080b57cec5SDimitry Andric case Win64EH::UOP_SaveXMM128Big: 1090b57cec5SDimitry Andric b2 |= (inst.Register & 0x0F) << 4; 1100b57cec5SDimitry Andric EmitAbsDifference(streamer, inst.Label, begin); 1115ffd83dbSDimitry Andric streamer.emitInt8(b2); 1120b57cec5SDimitry Andric if (inst.Operation == Win64EH::UOP_SaveXMM128Big) 1130b57cec5SDimitry Andric w = inst.Offset & 0xFFF0; 1140b57cec5SDimitry Andric else 1150b57cec5SDimitry Andric w = inst.Offset & 0xFFF8; 1165ffd83dbSDimitry Andric streamer.emitInt16(w); 1170b57cec5SDimitry Andric w = inst.Offset >> 16; 1185ffd83dbSDimitry Andric streamer.emitInt16(w); 1190b57cec5SDimitry Andric break; 1200b57cec5SDimitry Andric case Win64EH::UOP_PushMachFrame: 1210b57cec5SDimitry Andric if (inst.Offset == 1) 1220b57cec5SDimitry Andric b2 |= 0x10; 1230b57cec5SDimitry Andric EmitAbsDifference(streamer, inst.Label, begin); 1245ffd83dbSDimitry Andric streamer.emitInt8(b2); 1250b57cec5SDimitry Andric break; 1260b57cec5SDimitry Andric } 1270b57cec5SDimitry Andric } 1280b57cec5SDimitry Andric 1290b57cec5SDimitry Andric static void EmitSymbolRefWithOfs(MCStreamer &streamer, 1300b57cec5SDimitry Andric const MCSymbol *Base, 1310b57cec5SDimitry Andric const MCSymbol *Other) { 1320b57cec5SDimitry Andric MCContext &Context = streamer.getContext(); 1330b57cec5SDimitry Andric const MCSymbolRefExpr *BaseRef = MCSymbolRefExpr::create(Base, Context); 1340b57cec5SDimitry Andric const MCSymbolRefExpr *OtherRef = MCSymbolRefExpr::create(Other, Context); 1350b57cec5SDimitry Andric const MCExpr *Ofs = MCBinaryExpr::createSub(OtherRef, BaseRef, Context); 1360b57cec5SDimitry Andric const MCSymbolRefExpr *BaseRefRel = MCSymbolRefExpr::create(Base, 1370b57cec5SDimitry Andric MCSymbolRefExpr::VK_COFF_IMGREL32, 1380b57cec5SDimitry Andric Context); 1395ffd83dbSDimitry Andric streamer.emitValue(MCBinaryExpr::createAdd(BaseRefRel, Ofs, Context), 4); 1400b57cec5SDimitry Andric } 1410b57cec5SDimitry Andric 1420b57cec5SDimitry Andric static void EmitRuntimeFunction(MCStreamer &streamer, 1430b57cec5SDimitry Andric const WinEH::FrameInfo *info) { 1440b57cec5SDimitry Andric MCContext &context = streamer.getContext(); 1450b57cec5SDimitry Andric 1465ffd83dbSDimitry Andric streamer.emitValueToAlignment(4); 147*349cc55cSDimitry Andric EmitSymbolRefWithOfs(streamer, info->Begin, info->Begin); 148*349cc55cSDimitry Andric EmitSymbolRefWithOfs(streamer, info->Begin, info->End); 1495ffd83dbSDimitry Andric streamer.emitValue(MCSymbolRefExpr::create(info->Symbol, 1500b57cec5SDimitry Andric MCSymbolRefExpr::VK_COFF_IMGREL32, 1510b57cec5SDimitry Andric context), 4); 1520b57cec5SDimitry Andric } 1530b57cec5SDimitry Andric 1540b57cec5SDimitry Andric static void EmitUnwindInfo(MCStreamer &streamer, WinEH::FrameInfo *info) { 1550b57cec5SDimitry Andric // If this UNWIND_INFO already has a symbol, it's already been emitted. 1560b57cec5SDimitry Andric if (info->Symbol) 1570b57cec5SDimitry Andric return; 1580b57cec5SDimitry Andric 1590b57cec5SDimitry Andric MCContext &context = streamer.getContext(); 1600b57cec5SDimitry Andric MCSymbol *Label = context.createTempSymbol(); 1610b57cec5SDimitry Andric 1625ffd83dbSDimitry Andric streamer.emitValueToAlignment(4); 1635ffd83dbSDimitry Andric streamer.emitLabel(Label); 1640b57cec5SDimitry Andric info->Symbol = Label; 1650b57cec5SDimitry Andric 1660b57cec5SDimitry Andric // Upper 3 bits are the version number (currently 1). 1670b57cec5SDimitry Andric uint8_t flags = 0x01; 1680b57cec5SDimitry Andric if (info->ChainedParent) 1690b57cec5SDimitry Andric flags |= Win64EH::UNW_ChainInfo << 3; 1700b57cec5SDimitry Andric else { 1710b57cec5SDimitry Andric if (info->HandlesUnwind) 1720b57cec5SDimitry Andric flags |= Win64EH::UNW_TerminateHandler << 3; 1730b57cec5SDimitry Andric if (info->HandlesExceptions) 1740b57cec5SDimitry Andric flags |= Win64EH::UNW_ExceptionHandler << 3; 1750b57cec5SDimitry Andric } 1765ffd83dbSDimitry Andric streamer.emitInt8(flags); 1770b57cec5SDimitry Andric 1780b57cec5SDimitry Andric if (info->PrologEnd) 1790b57cec5SDimitry Andric EmitAbsDifference(streamer, info->PrologEnd, info->Begin); 1800b57cec5SDimitry Andric else 1815ffd83dbSDimitry Andric streamer.emitInt8(0); 1820b57cec5SDimitry Andric 1830b57cec5SDimitry Andric uint8_t numCodes = CountOfUnwindCodes(info->Instructions); 1845ffd83dbSDimitry Andric streamer.emitInt8(numCodes); 1850b57cec5SDimitry Andric 1860b57cec5SDimitry Andric uint8_t frame = 0; 1870b57cec5SDimitry Andric if (info->LastFrameInst >= 0) { 1880b57cec5SDimitry Andric WinEH::Instruction &frameInst = info->Instructions[info->LastFrameInst]; 1890b57cec5SDimitry Andric assert(frameInst.Operation == Win64EH::UOP_SetFPReg); 1900b57cec5SDimitry Andric frame = (frameInst.Register & 0x0F) | (frameInst.Offset & 0xF0); 1910b57cec5SDimitry Andric } 1925ffd83dbSDimitry Andric streamer.emitInt8(frame); 1930b57cec5SDimitry Andric 1940b57cec5SDimitry Andric // Emit unwind instructions (in reverse order). 1950b57cec5SDimitry Andric uint8_t numInst = info->Instructions.size(); 1960b57cec5SDimitry Andric for (uint8_t c = 0; c < numInst; ++c) { 1970b57cec5SDimitry Andric WinEH::Instruction inst = info->Instructions.back(); 1980b57cec5SDimitry Andric info->Instructions.pop_back(); 1990b57cec5SDimitry Andric EmitUnwindCode(streamer, info->Begin, inst); 2000b57cec5SDimitry Andric } 2010b57cec5SDimitry Andric 2020b57cec5SDimitry Andric // For alignment purposes, the instruction array will always have an even 2030b57cec5SDimitry Andric // number of entries, with the final entry potentially unused (in which case 2040b57cec5SDimitry Andric // the array will be one longer than indicated by the count of unwind codes 2050b57cec5SDimitry Andric // field). 2060b57cec5SDimitry Andric if (numCodes & 1) { 2075ffd83dbSDimitry Andric streamer.emitInt16(0); 2080b57cec5SDimitry Andric } 2090b57cec5SDimitry Andric 2100b57cec5SDimitry Andric if (flags & (Win64EH::UNW_ChainInfo << 3)) 2110b57cec5SDimitry Andric EmitRuntimeFunction(streamer, info->ChainedParent); 2120b57cec5SDimitry Andric else if (flags & 2130b57cec5SDimitry Andric ((Win64EH::UNW_TerminateHandler|Win64EH::UNW_ExceptionHandler) << 3)) 2145ffd83dbSDimitry Andric streamer.emitValue(MCSymbolRefExpr::create(info->ExceptionHandler, 2150b57cec5SDimitry Andric MCSymbolRefExpr::VK_COFF_IMGREL32, 2160b57cec5SDimitry Andric context), 4); 2170b57cec5SDimitry Andric else if (numCodes == 0) { 2180b57cec5SDimitry Andric // The minimum size of an UNWIND_INFO struct is 8 bytes. If we're not 2190b57cec5SDimitry Andric // a chained unwind info, if there is no handler, and if there are fewer 2200b57cec5SDimitry Andric // than 2 slots used in the unwind code array, we have to pad to 8 bytes. 2215ffd83dbSDimitry Andric streamer.emitInt32(0); 2220b57cec5SDimitry Andric } 2230b57cec5SDimitry Andric } 2240b57cec5SDimitry Andric 2250b57cec5SDimitry Andric void llvm::Win64EH::UnwindEmitter::Emit(MCStreamer &Streamer) const { 2260b57cec5SDimitry Andric // Emit the unwind info structs first. 2270b57cec5SDimitry Andric for (const auto &CFI : Streamer.getWinFrameInfos()) { 2280b57cec5SDimitry Andric MCSection *XData = Streamer.getAssociatedXDataSection(CFI->TextSection); 2290b57cec5SDimitry Andric Streamer.SwitchSection(XData); 2300b57cec5SDimitry Andric ::EmitUnwindInfo(Streamer, CFI.get()); 2310b57cec5SDimitry Andric } 2320b57cec5SDimitry Andric 2330b57cec5SDimitry Andric // Now emit RUNTIME_FUNCTION entries. 2340b57cec5SDimitry Andric for (const auto &CFI : Streamer.getWinFrameInfos()) { 2350b57cec5SDimitry Andric MCSection *PData = Streamer.getAssociatedPDataSection(CFI->TextSection); 2360b57cec5SDimitry Andric Streamer.SwitchSection(PData); 2370b57cec5SDimitry Andric EmitRuntimeFunction(Streamer, CFI.get()); 2380b57cec5SDimitry Andric } 2390b57cec5SDimitry Andric } 2400b57cec5SDimitry Andric 241e8d8bef9SDimitry Andric void llvm::Win64EH::UnwindEmitter::EmitUnwindInfo(MCStreamer &Streamer, 242e8d8bef9SDimitry Andric WinEH::FrameInfo *info, 243e8d8bef9SDimitry Andric bool HandlerData) const { 2440b57cec5SDimitry Andric // Switch sections (the static function above is meant to be called from 2450b57cec5SDimitry Andric // here and from Emit(). 2460b57cec5SDimitry Andric MCSection *XData = Streamer.getAssociatedXDataSection(info->TextSection); 2470b57cec5SDimitry Andric Streamer.SwitchSection(XData); 2480b57cec5SDimitry Andric 2490b57cec5SDimitry Andric ::EmitUnwindInfo(Streamer, info); 2500b57cec5SDimitry Andric } 2510b57cec5SDimitry Andric 2520b57cec5SDimitry Andric static int64_t GetAbsDifference(MCStreamer &Streamer, const MCSymbol *LHS, 2530b57cec5SDimitry Andric const MCSymbol *RHS) { 2540b57cec5SDimitry Andric MCContext &Context = Streamer.getContext(); 2550b57cec5SDimitry Andric const MCExpr *Diff = 2560b57cec5SDimitry Andric MCBinaryExpr::createSub(MCSymbolRefExpr::create(LHS, Context), 2570b57cec5SDimitry Andric MCSymbolRefExpr::create(RHS, Context), Context); 2580b57cec5SDimitry Andric MCObjectStreamer *OS = (MCObjectStreamer *)(&Streamer); 2590b57cec5SDimitry Andric // It should normally be possible to calculate the length of a function 2600b57cec5SDimitry Andric // at this point, but it might not be possible in the presence of certain 2610b57cec5SDimitry Andric // unusual constructs, like an inline asm with an alignment directive. 2620b57cec5SDimitry Andric int64_t value; 2630b57cec5SDimitry Andric if (!Diff->evaluateAsAbsolute(value, OS->getAssembler())) 2640b57cec5SDimitry Andric report_fatal_error("Failed to evaluate function length in SEH unwind info"); 2650b57cec5SDimitry Andric return value; 2660b57cec5SDimitry Andric } 2670b57cec5SDimitry Andric 268e8d8bef9SDimitry Andric static uint32_t ARM64CountOfUnwindCodes(ArrayRef<WinEH::Instruction> Insns) { 2690b57cec5SDimitry Andric uint32_t Count = 0; 2700b57cec5SDimitry Andric for (const auto &I : Insns) { 2710b57cec5SDimitry Andric switch (static_cast<Win64EH::UnwindOpcodes>(I.Operation)) { 2720b57cec5SDimitry Andric default: 2730b57cec5SDimitry Andric llvm_unreachable("Unsupported ARM64 unwind code"); 2740b57cec5SDimitry Andric case Win64EH::UOP_AllocSmall: 2750b57cec5SDimitry Andric Count += 1; 2760b57cec5SDimitry Andric break; 2770b57cec5SDimitry Andric case Win64EH::UOP_AllocMedium: 2780b57cec5SDimitry Andric Count += 2; 2790b57cec5SDimitry Andric break; 2800b57cec5SDimitry Andric case Win64EH::UOP_AllocLarge: 2810b57cec5SDimitry Andric Count += 4; 2820b57cec5SDimitry Andric break; 283e8d8bef9SDimitry Andric case Win64EH::UOP_SaveR19R20X: 284e8d8bef9SDimitry Andric Count += 1; 285e8d8bef9SDimitry Andric break; 2860b57cec5SDimitry Andric case Win64EH::UOP_SaveFPLRX: 2870b57cec5SDimitry Andric Count += 1; 2880b57cec5SDimitry Andric break; 2890b57cec5SDimitry Andric case Win64EH::UOP_SaveFPLR: 2900b57cec5SDimitry Andric Count += 1; 2910b57cec5SDimitry Andric break; 2920b57cec5SDimitry Andric case Win64EH::UOP_SaveReg: 2930b57cec5SDimitry Andric Count += 2; 2940b57cec5SDimitry Andric break; 2950b57cec5SDimitry Andric case Win64EH::UOP_SaveRegP: 2960b57cec5SDimitry Andric Count += 2; 2970b57cec5SDimitry Andric break; 2980b57cec5SDimitry Andric case Win64EH::UOP_SaveRegPX: 2990b57cec5SDimitry Andric Count += 2; 3000b57cec5SDimitry Andric break; 3010b57cec5SDimitry Andric case Win64EH::UOP_SaveRegX: 3020b57cec5SDimitry Andric Count += 2; 3030b57cec5SDimitry Andric break; 304e8d8bef9SDimitry Andric case Win64EH::UOP_SaveLRPair: 305e8d8bef9SDimitry Andric Count += 2; 306e8d8bef9SDimitry Andric break; 3070b57cec5SDimitry Andric case Win64EH::UOP_SaveFReg: 3080b57cec5SDimitry Andric Count += 2; 3090b57cec5SDimitry Andric break; 3100b57cec5SDimitry Andric case Win64EH::UOP_SaveFRegP: 3110b57cec5SDimitry Andric Count += 2; 3120b57cec5SDimitry Andric break; 3130b57cec5SDimitry Andric case Win64EH::UOP_SaveFRegX: 3140b57cec5SDimitry Andric Count += 2; 3150b57cec5SDimitry Andric break; 3160b57cec5SDimitry Andric case Win64EH::UOP_SaveFRegPX: 3170b57cec5SDimitry Andric Count += 2; 3180b57cec5SDimitry Andric break; 3190b57cec5SDimitry Andric case Win64EH::UOP_SetFP: 3200b57cec5SDimitry Andric Count += 1; 3210b57cec5SDimitry Andric break; 3220b57cec5SDimitry Andric case Win64EH::UOP_AddFP: 3230b57cec5SDimitry Andric Count += 2; 3240b57cec5SDimitry Andric break; 3250b57cec5SDimitry Andric case Win64EH::UOP_Nop: 3260b57cec5SDimitry Andric Count += 1; 3270b57cec5SDimitry Andric break; 3280b57cec5SDimitry Andric case Win64EH::UOP_End: 3290b57cec5SDimitry Andric Count += 1; 3300b57cec5SDimitry Andric break; 331e8d8bef9SDimitry Andric case Win64EH::UOP_SaveNext: 332e8d8bef9SDimitry Andric Count += 1; 333e8d8bef9SDimitry Andric break; 334e8d8bef9SDimitry Andric case Win64EH::UOP_TrapFrame: 335e8d8bef9SDimitry Andric Count += 1; 336e8d8bef9SDimitry Andric break; 337e8d8bef9SDimitry Andric case Win64EH::UOP_PushMachFrame: 338e8d8bef9SDimitry Andric Count += 1; 339e8d8bef9SDimitry Andric break; 340e8d8bef9SDimitry Andric case Win64EH::UOP_Context: 341e8d8bef9SDimitry Andric Count += 1; 342e8d8bef9SDimitry Andric break; 343e8d8bef9SDimitry Andric case Win64EH::UOP_ClearUnwoundToCall: 344e8d8bef9SDimitry Andric Count += 1; 345e8d8bef9SDimitry Andric break; 3460b57cec5SDimitry Andric } 3470b57cec5SDimitry Andric } 3480b57cec5SDimitry Andric return Count; 3490b57cec5SDimitry Andric } 3500b57cec5SDimitry Andric 3510b57cec5SDimitry Andric // Unwind opcode encodings and restrictions are documented at 3520b57cec5SDimitry Andric // https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling 3530b57cec5SDimitry Andric static void ARM64EmitUnwindCode(MCStreamer &streamer, const MCSymbol *begin, 3540b57cec5SDimitry Andric WinEH::Instruction &inst) { 3550b57cec5SDimitry Andric uint8_t b, reg; 3560b57cec5SDimitry Andric switch (static_cast<Win64EH::UnwindOpcodes>(inst.Operation)) { 3570b57cec5SDimitry Andric default: 3580b57cec5SDimitry Andric llvm_unreachable("Unsupported ARM64 unwind code"); 3590b57cec5SDimitry Andric case Win64EH::UOP_AllocSmall: 3600b57cec5SDimitry Andric b = (inst.Offset >> 4) & 0x1F; 3615ffd83dbSDimitry Andric streamer.emitInt8(b); 3620b57cec5SDimitry Andric break; 3630b57cec5SDimitry Andric case Win64EH::UOP_AllocMedium: { 3640b57cec5SDimitry Andric uint16_t hw = (inst.Offset >> 4) & 0x7FF; 3650b57cec5SDimitry Andric b = 0xC0; 3660b57cec5SDimitry Andric b |= (hw >> 8); 3675ffd83dbSDimitry Andric streamer.emitInt8(b); 3680b57cec5SDimitry Andric b = hw & 0xFF; 3695ffd83dbSDimitry Andric streamer.emitInt8(b); 3700b57cec5SDimitry Andric break; 3710b57cec5SDimitry Andric } 3720b57cec5SDimitry Andric case Win64EH::UOP_AllocLarge: { 3730b57cec5SDimitry Andric uint32_t w; 3740b57cec5SDimitry Andric b = 0xE0; 3755ffd83dbSDimitry Andric streamer.emitInt8(b); 3760b57cec5SDimitry Andric w = inst.Offset >> 4; 3770b57cec5SDimitry Andric b = (w & 0x00FF0000) >> 16; 3785ffd83dbSDimitry Andric streamer.emitInt8(b); 3790b57cec5SDimitry Andric b = (w & 0x0000FF00) >> 8; 3805ffd83dbSDimitry Andric streamer.emitInt8(b); 3810b57cec5SDimitry Andric b = w & 0x000000FF; 3825ffd83dbSDimitry Andric streamer.emitInt8(b); 3830b57cec5SDimitry Andric break; 3840b57cec5SDimitry Andric } 3850b57cec5SDimitry Andric case Win64EH::UOP_SetFP: 3860b57cec5SDimitry Andric b = 0xE1; 3875ffd83dbSDimitry Andric streamer.emitInt8(b); 3880b57cec5SDimitry Andric break; 3890b57cec5SDimitry Andric case Win64EH::UOP_AddFP: 3900b57cec5SDimitry Andric b = 0xE2; 3915ffd83dbSDimitry Andric streamer.emitInt8(b); 3920b57cec5SDimitry Andric b = (inst.Offset >> 3); 3935ffd83dbSDimitry Andric streamer.emitInt8(b); 3940b57cec5SDimitry Andric break; 3950b57cec5SDimitry Andric case Win64EH::UOP_Nop: 3960b57cec5SDimitry Andric b = 0xE3; 3975ffd83dbSDimitry Andric streamer.emitInt8(b); 3980b57cec5SDimitry Andric break; 399e8d8bef9SDimitry Andric case Win64EH::UOP_SaveR19R20X: 400e8d8bef9SDimitry Andric b = 0x20; 401e8d8bef9SDimitry Andric b |= (inst.Offset >> 3) & 0x1F; 402e8d8bef9SDimitry Andric streamer.emitInt8(b); 403e8d8bef9SDimitry Andric break; 4040b57cec5SDimitry Andric case Win64EH::UOP_SaveFPLRX: 4050b57cec5SDimitry Andric b = 0x80; 4060b57cec5SDimitry Andric b |= ((inst.Offset - 1) >> 3) & 0x3F; 4075ffd83dbSDimitry Andric streamer.emitInt8(b); 4080b57cec5SDimitry Andric break; 4090b57cec5SDimitry Andric case Win64EH::UOP_SaveFPLR: 4100b57cec5SDimitry Andric b = 0x40; 4110b57cec5SDimitry Andric b |= (inst.Offset >> 3) & 0x3F; 4125ffd83dbSDimitry Andric streamer.emitInt8(b); 4130b57cec5SDimitry Andric break; 4140b57cec5SDimitry Andric case Win64EH::UOP_SaveReg: 4150b57cec5SDimitry Andric assert(inst.Register >= 19 && "Saved reg must be >= 19"); 4160b57cec5SDimitry Andric reg = inst.Register - 19; 4170b57cec5SDimitry Andric b = 0xD0 | ((reg & 0xC) >> 2); 4185ffd83dbSDimitry Andric streamer.emitInt8(b); 4190b57cec5SDimitry Andric b = ((reg & 0x3) << 6) | (inst.Offset >> 3); 4205ffd83dbSDimitry Andric streamer.emitInt8(b); 4210b57cec5SDimitry Andric break; 4220b57cec5SDimitry Andric case Win64EH::UOP_SaveRegX: 4230b57cec5SDimitry Andric assert(inst.Register >= 19 && "Saved reg must be >= 19"); 4240b57cec5SDimitry Andric reg = inst.Register - 19; 4250b57cec5SDimitry Andric b = 0xD4 | ((reg & 0x8) >> 3); 4265ffd83dbSDimitry Andric streamer.emitInt8(b); 4270b57cec5SDimitry Andric b = ((reg & 0x7) << 5) | ((inst.Offset >> 3) - 1); 4285ffd83dbSDimitry Andric streamer.emitInt8(b); 4290b57cec5SDimitry Andric break; 4300b57cec5SDimitry Andric case Win64EH::UOP_SaveRegP: 4310b57cec5SDimitry Andric assert(inst.Register >= 19 && "Saved registers must be >= 19"); 4320b57cec5SDimitry Andric reg = inst.Register - 19; 4330b57cec5SDimitry Andric b = 0xC8 | ((reg & 0xC) >> 2); 4345ffd83dbSDimitry Andric streamer.emitInt8(b); 4350b57cec5SDimitry Andric b = ((reg & 0x3) << 6) | (inst.Offset >> 3); 4365ffd83dbSDimitry Andric streamer.emitInt8(b); 4370b57cec5SDimitry Andric break; 4380b57cec5SDimitry Andric case Win64EH::UOP_SaveRegPX: 4390b57cec5SDimitry Andric assert(inst.Register >= 19 && "Saved registers must be >= 19"); 4400b57cec5SDimitry Andric reg = inst.Register - 19; 4410b57cec5SDimitry Andric b = 0xCC | ((reg & 0xC) >> 2); 4425ffd83dbSDimitry Andric streamer.emitInt8(b); 4430b57cec5SDimitry Andric b = ((reg & 0x3) << 6) | ((inst.Offset >> 3) - 1); 4445ffd83dbSDimitry Andric streamer.emitInt8(b); 4450b57cec5SDimitry Andric break; 446e8d8bef9SDimitry Andric case Win64EH::UOP_SaveLRPair: 447e8d8bef9SDimitry Andric assert(inst.Register >= 19 && "Saved reg must be >= 19"); 448e8d8bef9SDimitry Andric reg = inst.Register - 19; 449e8d8bef9SDimitry Andric assert((reg % 2) == 0 && "Saved reg must be 19+2*X"); 450e8d8bef9SDimitry Andric reg /= 2; 451e8d8bef9SDimitry Andric b = 0xD6 | ((reg & 0x7) >> 2); 452e8d8bef9SDimitry Andric streamer.emitInt8(b); 453e8d8bef9SDimitry Andric b = ((reg & 0x3) << 6) | (inst.Offset >> 3); 454e8d8bef9SDimitry Andric streamer.emitInt8(b); 455e8d8bef9SDimitry Andric break; 4560b57cec5SDimitry Andric case Win64EH::UOP_SaveFReg: 4570b57cec5SDimitry Andric assert(inst.Register >= 8 && "Saved dreg must be >= 8"); 4580b57cec5SDimitry Andric reg = inst.Register - 8; 4590b57cec5SDimitry Andric b = 0xDC | ((reg & 0x4) >> 2); 4605ffd83dbSDimitry Andric streamer.emitInt8(b); 4610b57cec5SDimitry Andric b = ((reg & 0x3) << 6) | (inst.Offset >> 3); 4625ffd83dbSDimitry Andric streamer.emitInt8(b); 4630b57cec5SDimitry Andric break; 4640b57cec5SDimitry Andric case Win64EH::UOP_SaveFRegX: 4650b57cec5SDimitry Andric assert(inst.Register >= 8 && "Saved dreg must be >= 8"); 4660b57cec5SDimitry Andric reg = inst.Register - 8; 4670b57cec5SDimitry Andric b = 0xDE; 4685ffd83dbSDimitry Andric streamer.emitInt8(b); 4690b57cec5SDimitry Andric b = ((reg & 0x7) << 5) | ((inst.Offset >> 3) - 1); 4705ffd83dbSDimitry Andric streamer.emitInt8(b); 4710b57cec5SDimitry Andric break; 4720b57cec5SDimitry Andric case Win64EH::UOP_SaveFRegP: 4730b57cec5SDimitry Andric assert(inst.Register >= 8 && "Saved dregs must be >= 8"); 4740b57cec5SDimitry Andric reg = inst.Register - 8; 4750b57cec5SDimitry Andric b = 0xD8 | ((reg & 0x4) >> 2); 4765ffd83dbSDimitry Andric streamer.emitInt8(b); 4770b57cec5SDimitry Andric b = ((reg & 0x3) << 6) | (inst.Offset >> 3); 4785ffd83dbSDimitry Andric streamer.emitInt8(b); 4790b57cec5SDimitry Andric break; 4800b57cec5SDimitry Andric case Win64EH::UOP_SaveFRegPX: 4810b57cec5SDimitry Andric assert(inst.Register >= 8 && "Saved dregs must be >= 8"); 4820b57cec5SDimitry Andric reg = inst.Register - 8; 4830b57cec5SDimitry Andric b = 0xDA | ((reg & 0x4) >> 2); 4845ffd83dbSDimitry Andric streamer.emitInt8(b); 4850b57cec5SDimitry Andric b = ((reg & 0x3) << 6) | ((inst.Offset >> 3) - 1); 4865ffd83dbSDimitry Andric streamer.emitInt8(b); 4870b57cec5SDimitry Andric break; 4880b57cec5SDimitry Andric case Win64EH::UOP_End: 4890b57cec5SDimitry Andric b = 0xE4; 4905ffd83dbSDimitry Andric streamer.emitInt8(b); 4910b57cec5SDimitry Andric break; 492e8d8bef9SDimitry Andric case Win64EH::UOP_SaveNext: 493e8d8bef9SDimitry Andric b = 0xE6; 494e8d8bef9SDimitry Andric streamer.emitInt8(b); 495e8d8bef9SDimitry Andric break; 496e8d8bef9SDimitry Andric case Win64EH::UOP_TrapFrame: 497e8d8bef9SDimitry Andric b = 0xE8; 498e8d8bef9SDimitry Andric streamer.emitInt8(b); 499e8d8bef9SDimitry Andric break; 500e8d8bef9SDimitry Andric case Win64EH::UOP_PushMachFrame: 501e8d8bef9SDimitry Andric b = 0xE9; 502e8d8bef9SDimitry Andric streamer.emitInt8(b); 503e8d8bef9SDimitry Andric break; 504e8d8bef9SDimitry Andric case Win64EH::UOP_Context: 505e8d8bef9SDimitry Andric b = 0xEA; 506e8d8bef9SDimitry Andric streamer.emitInt8(b); 507e8d8bef9SDimitry Andric break; 508e8d8bef9SDimitry Andric case Win64EH::UOP_ClearUnwoundToCall: 509e8d8bef9SDimitry Andric b = 0xEC; 510e8d8bef9SDimitry Andric streamer.emitInt8(b); 511e8d8bef9SDimitry Andric break; 5120b57cec5SDimitry Andric } 5130b57cec5SDimitry Andric } 5140b57cec5SDimitry Andric 5150b57cec5SDimitry Andric // Returns the epilog symbol of an epilog with the exact same unwind code 5160b57cec5SDimitry Andric // sequence, if it exists. Otherwise, returns nulltpr. 5170b57cec5SDimitry Andric // EpilogInstrs - Unwind codes for the current epilog. 5180b57cec5SDimitry Andric // Epilogs - Epilogs that potentialy match the current epilog. 5190b57cec5SDimitry Andric static MCSymbol* 5200b57cec5SDimitry Andric FindMatchingEpilog(const std::vector<WinEH::Instruction>& EpilogInstrs, 5210b57cec5SDimitry Andric const std::vector<MCSymbol *>& Epilogs, 5220b57cec5SDimitry Andric const WinEH::FrameInfo *info) { 5230b57cec5SDimitry Andric for (auto *EpilogStart : Epilogs) { 5240b57cec5SDimitry Andric auto InstrsIter = info->EpilogMap.find(EpilogStart); 5250b57cec5SDimitry Andric assert(InstrsIter != info->EpilogMap.end() && 5260b57cec5SDimitry Andric "Epilog not found in EpilogMap"); 5270b57cec5SDimitry Andric const auto &Instrs = InstrsIter->second; 5280b57cec5SDimitry Andric 5290b57cec5SDimitry Andric if (Instrs.size() != EpilogInstrs.size()) 5300b57cec5SDimitry Andric continue; 5310b57cec5SDimitry Andric 5320b57cec5SDimitry Andric bool Match = true; 5330b57cec5SDimitry Andric for (unsigned i = 0; i < Instrs.size(); ++i) 5340b57cec5SDimitry Andric if (Instrs[i].Operation != EpilogInstrs[i].Operation || 5350b57cec5SDimitry Andric Instrs[i].Offset != EpilogInstrs[i].Offset || 5360b57cec5SDimitry Andric Instrs[i].Register != EpilogInstrs[i].Register) { 5370b57cec5SDimitry Andric Match = false; 5380b57cec5SDimitry Andric break; 5390b57cec5SDimitry Andric } 5400b57cec5SDimitry Andric 5410b57cec5SDimitry Andric if (Match) 5420b57cec5SDimitry Andric return EpilogStart; 5430b57cec5SDimitry Andric } 5440b57cec5SDimitry Andric return nullptr; 5450b57cec5SDimitry Andric } 5460b57cec5SDimitry Andric 547e8d8bef9SDimitry Andric static void simplifyOpcodes(std::vector<WinEH::Instruction> &Instructions, 548e8d8bef9SDimitry Andric bool Reverse) { 549e8d8bef9SDimitry Andric unsigned PrevOffset = -1; 550e8d8bef9SDimitry Andric unsigned PrevRegister = -1; 551e8d8bef9SDimitry Andric 552e8d8bef9SDimitry Andric auto VisitInstruction = [&](WinEH::Instruction &Inst) { 553e8d8bef9SDimitry Andric // Convert 2-byte opcodes into equivalent 1-byte ones. 554e8d8bef9SDimitry Andric if (Inst.Operation == Win64EH::UOP_SaveRegP && Inst.Register == 29) { 555e8d8bef9SDimitry Andric Inst.Operation = Win64EH::UOP_SaveFPLR; 556e8d8bef9SDimitry Andric Inst.Register = -1; 557e8d8bef9SDimitry Andric } else if (Inst.Operation == Win64EH::UOP_SaveRegPX && 558e8d8bef9SDimitry Andric Inst.Register == 29) { 559e8d8bef9SDimitry Andric Inst.Operation = Win64EH::UOP_SaveFPLRX; 560e8d8bef9SDimitry Andric Inst.Register = -1; 561e8d8bef9SDimitry Andric } else if (Inst.Operation == Win64EH::UOP_SaveRegPX && 562e8d8bef9SDimitry Andric Inst.Register == 19 && Inst.Offset <= 248) { 563e8d8bef9SDimitry Andric Inst.Operation = Win64EH::UOP_SaveR19R20X; 564e8d8bef9SDimitry Andric Inst.Register = -1; 565e8d8bef9SDimitry Andric } else if (Inst.Operation == Win64EH::UOP_AddFP && Inst.Offset == 0) { 566e8d8bef9SDimitry Andric Inst.Operation = Win64EH::UOP_SetFP; 567e8d8bef9SDimitry Andric } else if (Inst.Operation == Win64EH::UOP_SaveRegP && 568e8d8bef9SDimitry Andric Inst.Register == PrevRegister + 2 && 569e8d8bef9SDimitry Andric Inst.Offset == PrevOffset + 16) { 570e8d8bef9SDimitry Andric Inst.Operation = Win64EH::UOP_SaveNext; 571e8d8bef9SDimitry Andric Inst.Register = -1; 572e8d8bef9SDimitry Andric Inst.Offset = 0; 573e8d8bef9SDimitry Andric // Intentionally not creating UOP_SaveNext for float register pairs, 574e8d8bef9SDimitry Andric // as current versions of Windows (up to at least 20.04) is buggy 575e8d8bef9SDimitry Andric // regarding SaveNext for float pairs. 576e8d8bef9SDimitry Andric } 577e8d8bef9SDimitry Andric // Update info about the previous instruction, for detecting if 578e8d8bef9SDimitry Andric // the next one can be made a UOP_SaveNext 579e8d8bef9SDimitry Andric if (Inst.Operation == Win64EH::UOP_SaveR19R20X) { 580e8d8bef9SDimitry Andric PrevOffset = 0; 581e8d8bef9SDimitry Andric PrevRegister = 19; 582e8d8bef9SDimitry Andric } else if (Inst.Operation == Win64EH::UOP_SaveRegPX) { 583e8d8bef9SDimitry Andric PrevOffset = 0; 584e8d8bef9SDimitry Andric PrevRegister = Inst.Register; 585e8d8bef9SDimitry Andric } else if (Inst.Operation == Win64EH::UOP_SaveRegP) { 586e8d8bef9SDimitry Andric PrevOffset = Inst.Offset; 587e8d8bef9SDimitry Andric PrevRegister = Inst.Register; 588e8d8bef9SDimitry Andric } else if (Inst.Operation == Win64EH::UOP_SaveNext) { 589e8d8bef9SDimitry Andric PrevRegister += 2; 590e8d8bef9SDimitry Andric PrevOffset += 16; 591e8d8bef9SDimitry Andric } else { 592e8d8bef9SDimitry Andric PrevRegister = -1; 593e8d8bef9SDimitry Andric PrevOffset = -1; 594e8d8bef9SDimitry Andric } 595e8d8bef9SDimitry Andric }; 596e8d8bef9SDimitry Andric 597e8d8bef9SDimitry Andric // Iterate over instructions in a forward order (for prologues), 598e8d8bef9SDimitry Andric // backwards for epilogues (i.e. always reverse compared to how the 599e8d8bef9SDimitry Andric // opcodes are stored). 600e8d8bef9SDimitry Andric if (Reverse) { 601e8d8bef9SDimitry Andric for (auto It = Instructions.rbegin(); It != Instructions.rend(); It++) 602e8d8bef9SDimitry Andric VisitInstruction(*It); 603e8d8bef9SDimitry Andric } else { 604e8d8bef9SDimitry Andric for (WinEH::Instruction &Inst : Instructions) 605e8d8bef9SDimitry Andric VisitInstruction(Inst); 606e8d8bef9SDimitry Andric } 607e8d8bef9SDimitry Andric } 608e8d8bef9SDimitry Andric 609e8d8bef9SDimitry Andric static int checkPackedEpilog(MCStreamer &streamer, WinEH::FrameInfo *info, 610e8d8bef9SDimitry Andric int PrologCodeBytes) { 611e8d8bef9SDimitry Andric // Can only pack if there's one single epilog 612e8d8bef9SDimitry Andric if (info->EpilogMap.size() != 1) 613e8d8bef9SDimitry Andric return -1; 614e8d8bef9SDimitry Andric 615e8d8bef9SDimitry Andric const std::vector<WinEH::Instruction> &Epilog = 616e8d8bef9SDimitry Andric info->EpilogMap.begin()->second; 617e8d8bef9SDimitry Andric 618e8d8bef9SDimitry Andric // Can pack if the epilog is a subset of the prolog but not vice versa 619e8d8bef9SDimitry Andric if (Epilog.size() > info->Instructions.size()) 620e8d8bef9SDimitry Andric return -1; 621e8d8bef9SDimitry Andric 622e8d8bef9SDimitry Andric // Check that the epilog actually is a perfect match for the end (backwrds) 623e8d8bef9SDimitry Andric // of the prolog. 624e8d8bef9SDimitry Andric for (int I = Epilog.size() - 1; I >= 0; I--) { 625e8d8bef9SDimitry Andric if (info->Instructions[I] != Epilog[Epilog.size() - 1 - I]) 626e8d8bef9SDimitry Andric return -1; 627e8d8bef9SDimitry Andric } 628e8d8bef9SDimitry Andric 629e8d8bef9SDimitry Andric // Check that the epilog actually is at the very end of the function, 630e8d8bef9SDimitry Andric // otherwise it can't be packed. 631e8d8bef9SDimitry Andric uint32_t DistanceFromEnd = (uint32_t)GetAbsDifference( 632e8d8bef9SDimitry Andric streamer, info->FuncletOrFuncEnd, info->EpilogMap.begin()->first); 633e8d8bef9SDimitry Andric if (DistanceFromEnd / 4 != Epilog.size()) 634e8d8bef9SDimitry Andric return -1; 635e8d8bef9SDimitry Andric 636e8d8bef9SDimitry Andric int Offset = Epilog.size() == info->Instructions.size() 637e8d8bef9SDimitry Andric ? 0 638e8d8bef9SDimitry Andric : ARM64CountOfUnwindCodes(ArrayRef<WinEH::Instruction>( 639e8d8bef9SDimitry Andric &info->Instructions[Epilog.size()], 640e8d8bef9SDimitry Andric info->Instructions.size() - Epilog.size())); 641e8d8bef9SDimitry Andric 642e8d8bef9SDimitry Andric // Check that the offset and prolog size fits in the first word; it's 643e8d8bef9SDimitry Andric // unclear whether the epilog count in the extension word can be taken 644e8d8bef9SDimitry Andric // as packed epilog offset. 645e8d8bef9SDimitry Andric if (Offset > 31 || PrologCodeBytes > 124) 646e8d8bef9SDimitry Andric return -1; 647e8d8bef9SDimitry Andric 648e8d8bef9SDimitry Andric info->EpilogMap.clear(); 649e8d8bef9SDimitry Andric return Offset; 650e8d8bef9SDimitry Andric } 651e8d8bef9SDimitry Andric 652e8d8bef9SDimitry Andric static bool tryPackedUnwind(WinEH::FrameInfo *info, uint32_t FuncLength, 653e8d8bef9SDimitry Andric int PackedEpilogOffset) { 654e8d8bef9SDimitry Andric if (PackedEpilogOffset == 0) { 655e8d8bef9SDimitry Andric // Fully symmetric prolog and epilog, should be ok for packed format. 656e8d8bef9SDimitry Andric // For CR=3, the corresponding synthesized epilog actually lacks the 657e8d8bef9SDimitry Andric // SetFP opcode, but unwinding should work just fine despite that 658e8d8bef9SDimitry Andric // (if at the SetFP opcode, the unwinder considers it as part of the 659e8d8bef9SDimitry Andric // function body and just unwinds the full prolog instead). 660e8d8bef9SDimitry Andric } else if (PackedEpilogOffset == 1) { 661e8d8bef9SDimitry Andric // One single case of differences between prolog and epilog is allowed: 662e8d8bef9SDimitry Andric // The epilog can lack a single SetFP that is the last opcode in the 663e8d8bef9SDimitry Andric // prolog, for the CR=3 case. 664e8d8bef9SDimitry Andric if (info->Instructions.back().Operation != Win64EH::UOP_SetFP) 665e8d8bef9SDimitry Andric return false; 666e8d8bef9SDimitry Andric } else { 667e8d8bef9SDimitry Andric // Too much difference between prolog and epilog. 668e8d8bef9SDimitry Andric return false; 669e8d8bef9SDimitry Andric } 670e8d8bef9SDimitry Andric unsigned RegI = 0, RegF = 0; 671e8d8bef9SDimitry Andric int Predecrement = 0; 672e8d8bef9SDimitry Andric enum { 673e8d8bef9SDimitry Andric Start, 674e8d8bef9SDimitry Andric Start2, 675e8d8bef9SDimitry Andric IntRegs, 676e8d8bef9SDimitry Andric FloatRegs, 677e8d8bef9SDimitry Andric InputArgs, 678e8d8bef9SDimitry Andric StackAdjust, 679e8d8bef9SDimitry Andric FrameRecord, 680e8d8bef9SDimitry Andric End 681e8d8bef9SDimitry Andric } Location = Start; 682e8d8bef9SDimitry Andric bool StandaloneLR = false, FPLRPair = false; 683e8d8bef9SDimitry Andric int StackOffset = 0; 684e8d8bef9SDimitry Andric int Nops = 0; 685e8d8bef9SDimitry Andric // Iterate over the prolog and check that all opcodes exactly match 686e8d8bef9SDimitry Andric // the canonical order and form. A more lax check could verify that 687e8d8bef9SDimitry Andric // all saved registers are in the expected locations, but not enforce 688e8d8bef9SDimitry Andric // the order - that would work fine when unwinding from within 689e8d8bef9SDimitry Andric // functions, but not be exactly right if unwinding happens within 690e8d8bef9SDimitry Andric // prologs/epilogs. 691e8d8bef9SDimitry Andric for (const WinEH::Instruction &Inst : info->Instructions) { 692e8d8bef9SDimitry Andric switch (Inst.Operation) { 693e8d8bef9SDimitry Andric case Win64EH::UOP_End: 694e8d8bef9SDimitry Andric if (Location != Start) 695e8d8bef9SDimitry Andric return false; 696e8d8bef9SDimitry Andric Location = Start2; 697e8d8bef9SDimitry Andric break; 698e8d8bef9SDimitry Andric case Win64EH::UOP_SaveR19R20X: 699e8d8bef9SDimitry Andric if (Location != Start2) 700e8d8bef9SDimitry Andric return false; 701e8d8bef9SDimitry Andric Predecrement = Inst.Offset; 702e8d8bef9SDimitry Andric RegI = 2; 703e8d8bef9SDimitry Andric Location = IntRegs; 704e8d8bef9SDimitry Andric break; 705e8d8bef9SDimitry Andric case Win64EH::UOP_SaveRegX: 706e8d8bef9SDimitry Andric if (Location != Start2) 707e8d8bef9SDimitry Andric return false; 708e8d8bef9SDimitry Andric Predecrement = Inst.Offset; 709e8d8bef9SDimitry Andric if (Inst.Register == 19) 710e8d8bef9SDimitry Andric RegI += 1; 711e8d8bef9SDimitry Andric else if (Inst.Register == 30) 712e8d8bef9SDimitry Andric StandaloneLR = true; 713e8d8bef9SDimitry Andric else 714e8d8bef9SDimitry Andric return false; 715e8d8bef9SDimitry Andric // Odd register; can't be any further int registers. 716e8d8bef9SDimitry Andric Location = FloatRegs; 717e8d8bef9SDimitry Andric break; 718e8d8bef9SDimitry Andric case Win64EH::UOP_SaveRegPX: 719e8d8bef9SDimitry Andric // Can't have this in a canonical prologue. Either this has been 720e8d8bef9SDimitry Andric // canonicalized into SaveR19R20X or SaveFPLRX, or it's an unsupported 721e8d8bef9SDimitry Andric // register pair. 722e8d8bef9SDimitry Andric // It can't be canonicalized into SaveR19R20X if the offset is 723e8d8bef9SDimitry Andric // larger than 248 bytes, but even with the maximum case with 724e8d8bef9SDimitry Andric // RegI=10/RegF=8/CR=1/H=1, we end up with SavSZ = 216, which should 725e8d8bef9SDimitry Andric // fit into SaveR19R20X. 726e8d8bef9SDimitry Andric // The unwinding opcodes can't describe the otherwise seemingly valid 727e8d8bef9SDimitry Andric // case for RegI=1 CR=1, that would start with a 728e8d8bef9SDimitry Andric // "stp x19, lr, [sp, #-...]!" as that fits neither SaveRegPX nor 729e8d8bef9SDimitry Andric // SaveLRPair. 730e8d8bef9SDimitry Andric return false; 731e8d8bef9SDimitry Andric case Win64EH::UOP_SaveRegP: 732e8d8bef9SDimitry Andric if (Location != IntRegs || Inst.Offset != 8 * RegI || 733e8d8bef9SDimitry Andric Inst.Register != 19 + RegI) 734e8d8bef9SDimitry Andric return false; 735e8d8bef9SDimitry Andric RegI += 2; 736e8d8bef9SDimitry Andric break; 737e8d8bef9SDimitry Andric case Win64EH::UOP_SaveReg: 738e8d8bef9SDimitry Andric if (Location != IntRegs || Inst.Offset != 8 * RegI) 739e8d8bef9SDimitry Andric return false; 740e8d8bef9SDimitry Andric if (Inst.Register == 19 + RegI) 741e8d8bef9SDimitry Andric RegI += 1; 742e8d8bef9SDimitry Andric else if (Inst.Register == 30) 743e8d8bef9SDimitry Andric StandaloneLR = true; 744e8d8bef9SDimitry Andric else 745e8d8bef9SDimitry Andric return false; 746e8d8bef9SDimitry Andric // Odd register; can't be any further int registers. 747e8d8bef9SDimitry Andric Location = FloatRegs; 748e8d8bef9SDimitry Andric break; 749e8d8bef9SDimitry Andric case Win64EH::UOP_SaveLRPair: 750e8d8bef9SDimitry Andric if (Location != IntRegs || Inst.Offset != 8 * RegI || 751e8d8bef9SDimitry Andric Inst.Register != 19 + RegI) 752e8d8bef9SDimitry Andric return false; 753e8d8bef9SDimitry Andric RegI += 1; 754e8d8bef9SDimitry Andric StandaloneLR = true; 755e8d8bef9SDimitry Andric Location = FloatRegs; 756e8d8bef9SDimitry Andric break; 757e8d8bef9SDimitry Andric case Win64EH::UOP_SaveFRegX: 758e8d8bef9SDimitry Andric // Packed unwind can't handle prologs that only save one single 759e8d8bef9SDimitry Andric // float register. 760e8d8bef9SDimitry Andric return false; 761e8d8bef9SDimitry Andric case Win64EH::UOP_SaveFReg: 762e8d8bef9SDimitry Andric if (Location != FloatRegs || RegF == 0 || Inst.Register != 8 + RegF || 763e8d8bef9SDimitry Andric Inst.Offset != 8 * (RegI + (StandaloneLR ? 1 : 0) + RegF)) 764e8d8bef9SDimitry Andric return false; 765e8d8bef9SDimitry Andric RegF += 1; 766e8d8bef9SDimitry Andric Location = InputArgs; 767e8d8bef9SDimitry Andric break; 768e8d8bef9SDimitry Andric case Win64EH::UOP_SaveFRegPX: 769e8d8bef9SDimitry Andric if (Location != Start2 || Inst.Register != 8) 770e8d8bef9SDimitry Andric return false; 771e8d8bef9SDimitry Andric Predecrement = Inst.Offset; 772e8d8bef9SDimitry Andric RegF = 2; 773e8d8bef9SDimitry Andric Location = FloatRegs; 774e8d8bef9SDimitry Andric break; 775e8d8bef9SDimitry Andric case Win64EH::UOP_SaveFRegP: 776e8d8bef9SDimitry Andric if ((Location != IntRegs && Location != FloatRegs) || 777e8d8bef9SDimitry Andric Inst.Register != 8 + RegF || 778e8d8bef9SDimitry Andric Inst.Offset != 8 * (RegI + (StandaloneLR ? 1 : 0) + RegF)) 779e8d8bef9SDimitry Andric return false; 780e8d8bef9SDimitry Andric RegF += 2; 781e8d8bef9SDimitry Andric Location = FloatRegs; 782e8d8bef9SDimitry Andric break; 783e8d8bef9SDimitry Andric case Win64EH::UOP_SaveNext: 784e8d8bef9SDimitry Andric if (Location == IntRegs) 785e8d8bef9SDimitry Andric RegI += 2; 786e8d8bef9SDimitry Andric else if (Location == FloatRegs) 787e8d8bef9SDimitry Andric RegF += 2; 788e8d8bef9SDimitry Andric else 789e8d8bef9SDimitry Andric return false; 790e8d8bef9SDimitry Andric break; 791e8d8bef9SDimitry Andric case Win64EH::UOP_Nop: 792e8d8bef9SDimitry Andric if (Location != IntRegs && Location != FloatRegs && Location != InputArgs) 793e8d8bef9SDimitry Andric return false; 794e8d8bef9SDimitry Andric Location = InputArgs; 795e8d8bef9SDimitry Andric Nops++; 796e8d8bef9SDimitry Andric break; 797e8d8bef9SDimitry Andric case Win64EH::UOP_AllocSmall: 798e8d8bef9SDimitry Andric case Win64EH::UOP_AllocMedium: 799e8d8bef9SDimitry Andric if (Location != Start2 && Location != IntRegs && Location != FloatRegs && 800e8d8bef9SDimitry Andric Location != InputArgs && Location != StackAdjust) 801e8d8bef9SDimitry Andric return false; 802e8d8bef9SDimitry Andric // Can have either a single decrement, or a pair of decrements with 803e8d8bef9SDimitry Andric // 4080 and another decrement. 804e8d8bef9SDimitry Andric if (StackOffset == 0) 805e8d8bef9SDimitry Andric StackOffset = Inst.Offset; 806e8d8bef9SDimitry Andric else if (StackOffset != 4080) 807e8d8bef9SDimitry Andric return false; 808e8d8bef9SDimitry Andric else 809e8d8bef9SDimitry Andric StackOffset += Inst.Offset; 810e8d8bef9SDimitry Andric Location = StackAdjust; 811e8d8bef9SDimitry Andric break; 812e8d8bef9SDimitry Andric case Win64EH::UOP_SaveFPLRX: 813e8d8bef9SDimitry Andric // Not allowing FPLRX after StackAdjust; if a StackAdjust is used, it 814e8d8bef9SDimitry Andric // should be followed by a FPLR instead. 815e8d8bef9SDimitry Andric if (Location != Start2 && Location != IntRegs && Location != FloatRegs && 816e8d8bef9SDimitry Andric Location != InputArgs) 817e8d8bef9SDimitry Andric return false; 818e8d8bef9SDimitry Andric StackOffset = Inst.Offset; 819e8d8bef9SDimitry Andric Location = FrameRecord; 820e8d8bef9SDimitry Andric FPLRPair = true; 821e8d8bef9SDimitry Andric break; 822e8d8bef9SDimitry Andric case Win64EH::UOP_SaveFPLR: 823e8d8bef9SDimitry Andric // This can only follow after a StackAdjust 824e8d8bef9SDimitry Andric if (Location != StackAdjust || Inst.Offset != 0) 825e8d8bef9SDimitry Andric return false; 826e8d8bef9SDimitry Andric Location = FrameRecord; 827e8d8bef9SDimitry Andric FPLRPair = true; 828e8d8bef9SDimitry Andric break; 829e8d8bef9SDimitry Andric case Win64EH::UOP_SetFP: 830e8d8bef9SDimitry Andric if (Location != FrameRecord) 831e8d8bef9SDimitry Andric return false; 832e8d8bef9SDimitry Andric Location = End; 833e8d8bef9SDimitry Andric break; 834e8d8bef9SDimitry Andric } 835e8d8bef9SDimitry Andric } 836e8d8bef9SDimitry Andric if (RegI > 10 || RegF > 8) 837e8d8bef9SDimitry Andric return false; 838e8d8bef9SDimitry Andric if (StandaloneLR && FPLRPair) 839e8d8bef9SDimitry Andric return false; 840e8d8bef9SDimitry Andric if (FPLRPair && Location != End) 841e8d8bef9SDimitry Andric return false; 842e8d8bef9SDimitry Andric if (Nops != 0 && Nops != 4) 843e8d8bef9SDimitry Andric return false; 844e8d8bef9SDimitry Andric int H = Nops == 4; 845e8d8bef9SDimitry Andric int IntSZ = 8 * RegI; 846e8d8bef9SDimitry Andric if (StandaloneLR) 847e8d8bef9SDimitry Andric IntSZ += 8; 848e8d8bef9SDimitry Andric int FpSZ = 8 * RegF; // RegF not yet decremented 849e8d8bef9SDimitry Andric int SavSZ = (IntSZ + FpSZ + 8 * 8 * H + 0xF) & ~0xF; 850e8d8bef9SDimitry Andric if (Predecrement != SavSZ) 851e8d8bef9SDimitry Andric return false; 852e8d8bef9SDimitry Andric if (FPLRPair && StackOffset < 16) 853e8d8bef9SDimitry Andric return false; 854e8d8bef9SDimitry Andric if (StackOffset % 16) 855e8d8bef9SDimitry Andric return false; 856e8d8bef9SDimitry Andric uint32_t FrameSize = (StackOffset + SavSZ) / 16; 857e8d8bef9SDimitry Andric if (FrameSize > 0x1FF) 858e8d8bef9SDimitry Andric return false; 859e8d8bef9SDimitry Andric assert(RegF != 1 && "One single float reg not allowed"); 860e8d8bef9SDimitry Andric if (RegF > 0) 861e8d8bef9SDimitry Andric RegF--; // Convert from actual number of registers, to value stored 862e8d8bef9SDimitry Andric assert(FuncLength <= 0x7FF && "FuncLength should have been checked earlier"); 863e8d8bef9SDimitry Andric int Flag = 0x01; // Function segments not supported yet 864e8d8bef9SDimitry Andric int CR = FPLRPair ? 3 : StandaloneLR ? 1 : 0; 865e8d8bef9SDimitry Andric info->PackedInfo |= Flag << 0; 866e8d8bef9SDimitry Andric info->PackedInfo |= (FuncLength & 0x7FF) << 2; 867e8d8bef9SDimitry Andric info->PackedInfo |= (RegF & 0x7) << 13; 868e8d8bef9SDimitry Andric info->PackedInfo |= (RegI & 0xF) << 16; 869e8d8bef9SDimitry Andric info->PackedInfo |= (H & 0x1) << 20; 870e8d8bef9SDimitry Andric info->PackedInfo |= (CR & 0x3) << 21; 871e8d8bef9SDimitry Andric info->PackedInfo |= (FrameSize & 0x1FF) << 23; 872e8d8bef9SDimitry Andric return true; 873e8d8bef9SDimitry Andric } 874e8d8bef9SDimitry Andric 8750b57cec5SDimitry Andric // Populate the .xdata section. The format of .xdata on ARM64 is documented at 8760b57cec5SDimitry Andric // https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling 877e8d8bef9SDimitry Andric static void ARM64EmitUnwindInfo(MCStreamer &streamer, WinEH::FrameInfo *info, 878e8d8bef9SDimitry Andric bool TryPacked = true) { 8790b57cec5SDimitry Andric // If this UNWIND_INFO already has a symbol, it's already been emitted. 8800b57cec5SDimitry Andric if (info->Symbol) 8810b57cec5SDimitry Andric return; 882e8d8bef9SDimitry Andric // If there's no unwind info here (not even a terminating UOP_End), the 883e8d8bef9SDimitry Andric // unwind info is considered bogus and skipped. If this was done in 884e8d8bef9SDimitry Andric // response to an explicit .seh_handlerdata, the associated trailing 885e8d8bef9SDimitry Andric // handler data is left orphaned in the xdata section. 886e8d8bef9SDimitry Andric if (info->empty()) { 887e8d8bef9SDimitry Andric info->EmitAttempted = true; 888e8d8bef9SDimitry Andric return; 889e8d8bef9SDimitry Andric } 890e8d8bef9SDimitry Andric if (info->EmitAttempted) { 891e8d8bef9SDimitry Andric // If we tried to emit unwind info before (due to an explicit 892e8d8bef9SDimitry Andric // .seh_handlerdata directive), but skipped it (because there was no 893e8d8bef9SDimitry Andric // valid information to emit at the time), and it later got valid unwind 894e8d8bef9SDimitry Andric // opcodes, we can't emit it here, because the trailing handler data 895e8d8bef9SDimitry Andric // was already emitted elsewhere in the xdata section. 896e8d8bef9SDimitry Andric streamer.getContext().reportError( 897e8d8bef9SDimitry Andric SMLoc(), "Earlier .seh_handlerdata for " + info->Function->getName() + 898e8d8bef9SDimitry Andric " skipped due to no unwind info at the time " 899e8d8bef9SDimitry Andric "(.seh_handlerdata too early?), but the function later " 900e8d8bef9SDimitry Andric "did get unwind info that can't be emitted"); 901e8d8bef9SDimitry Andric return; 902e8d8bef9SDimitry Andric } 903e8d8bef9SDimitry Andric 904e8d8bef9SDimitry Andric simplifyOpcodes(info->Instructions, false); 905e8d8bef9SDimitry Andric for (auto &I : info->EpilogMap) 906e8d8bef9SDimitry Andric simplifyOpcodes(I.second, true); 9070b57cec5SDimitry Andric 9080b57cec5SDimitry Andric MCContext &context = streamer.getContext(); 9090b57cec5SDimitry Andric MCSymbol *Label = context.createTempSymbol(); 9100b57cec5SDimitry Andric 9115ffd83dbSDimitry Andric streamer.emitValueToAlignment(4); 9125ffd83dbSDimitry Andric streamer.emitLabel(Label); 9130b57cec5SDimitry Andric info->Symbol = Label; 9140b57cec5SDimitry Andric 9150b57cec5SDimitry Andric int64_t RawFuncLength; 9160b57cec5SDimitry Andric if (!info->FuncletOrFuncEnd) { 917e8d8bef9SDimitry Andric report_fatal_error("FuncletOrFuncEnd not set"); 9180b57cec5SDimitry Andric } else { 9190b57cec5SDimitry Andric // FIXME: GetAbsDifference tries to compute the length of the function 9200b57cec5SDimitry Andric // immediately, before the whole file is emitted, but in general 9210b57cec5SDimitry Andric // that's impossible: the size in bytes of certain assembler directives 9220b57cec5SDimitry Andric // like .align and .fill is not known until the whole file is parsed and 9230b57cec5SDimitry Andric // relaxations are applied. Currently, GetAbsDifference fails with a fatal 9240b57cec5SDimitry Andric // error in that case. (We mostly don't hit this because inline assembly 9250b57cec5SDimitry Andric // specifying those directives is rare, and we don't normally try to 9260b57cec5SDimitry Andric // align loops on AArch64.) 9270b57cec5SDimitry Andric // 9280b57cec5SDimitry Andric // There are two potential approaches to delaying the computation. One, 9290b57cec5SDimitry Andric // we could emit something like ".word (endfunc-beginfunc)/4+0x10800000", 9300b57cec5SDimitry Andric // as long as we have some conservative estimate we could use to prove 9310b57cec5SDimitry Andric // that we don't need to split the unwind data. Emitting the constant 9320b57cec5SDimitry Andric // is straightforward, but there's no existing code for estimating the 9330b57cec5SDimitry Andric // size of the function. 9340b57cec5SDimitry Andric // 9350b57cec5SDimitry Andric // The other approach would be to use a dedicated, relaxable fragment, 9360b57cec5SDimitry Andric // which could grow to accommodate splitting the unwind data if 9370b57cec5SDimitry Andric // necessary. This is more straightforward, since it automatically works 9380b57cec5SDimitry Andric // without any new infrastructure, and it's consistent with how we handle 9390b57cec5SDimitry Andric // relaxation in other contexts. But it would require some refactoring 9400b57cec5SDimitry Andric // to move parts of the pdata/xdata emission into the implementation of 9410b57cec5SDimitry Andric // a fragment. We could probably continue to encode the unwind codes 9420b57cec5SDimitry Andric // here, but we'd have to emit the pdata, the xdata header, and the 9430b57cec5SDimitry Andric // epilogue scopes later, since they depend on whether the we need to 9440b57cec5SDimitry Andric // split the unwind data. 9450b57cec5SDimitry Andric RawFuncLength = GetAbsDifference(streamer, info->FuncletOrFuncEnd, 9460b57cec5SDimitry Andric info->Begin); 9470b57cec5SDimitry Andric } 9480b57cec5SDimitry Andric if (RawFuncLength > 0xFFFFF) 9490b57cec5SDimitry Andric report_fatal_error("SEH unwind data splitting not yet implemented"); 9500b57cec5SDimitry Andric uint32_t FuncLength = (uint32_t)RawFuncLength / 4; 9510b57cec5SDimitry Andric uint32_t PrologCodeBytes = ARM64CountOfUnwindCodes(info->Instructions); 9520b57cec5SDimitry Andric uint32_t TotalCodeBytes = PrologCodeBytes; 9530b57cec5SDimitry Andric 954e8d8bef9SDimitry Andric int PackedEpilogOffset = checkPackedEpilog(streamer, info, PrologCodeBytes); 955e8d8bef9SDimitry Andric 956e8d8bef9SDimitry Andric if (PackedEpilogOffset >= 0 && !info->HandlesExceptions && 957e8d8bef9SDimitry Andric FuncLength <= 0x7ff && TryPacked) { 958e8d8bef9SDimitry Andric // Matching prolog/epilog and no exception handlers; check if the 959e8d8bef9SDimitry Andric // prolog matches the patterns that can be described by the packed 960e8d8bef9SDimitry Andric // format. 961e8d8bef9SDimitry Andric 962e8d8bef9SDimitry Andric // info->Symbol was already set even if we didn't actually write any 963e8d8bef9SDimitry Andric // unwind info there. Keep using that as indicator that this unwind 964e8d8bef9SDimitry Andric // info has been generated already. 965e8d8bef9SDimitry Andric 966e8d8bef9SDimitry Andric if (tryPackedUnwind(info, FuncLength, PackedEpilogOffset)) 967e8d8bef9SDimitry Andric return; 968e8d8bef9SDimitry Andric } 969e8d8bef9SDimitry Andric 9700b57cec5SDimitry Andric // Process epilogs. 9710b57cec5SDimitry Andric MapVector<MCSymbol *, uint32_t> EpilogInfo; 9720b57cec5SDimitry Andric // Epilogs processed so far. 9730b57cec5SDimitry Andric std::vector<MCSymbol *> AddedEpilogs; 9740b57cec5SDimitry Andric 9750b57cec5SDimitry Andric for (auto &I : info->EpilogMap) { 9760b57cec5SDimitry Andric MCSymbol *EpilogStart = I.first; 9770b57cec5SDimitry Andric auto &EpilogInstrs = I.second; 9780b57cec5SDimitry Andric uint32_t CodeBytes = ARM64CountOfUnwindCodes(EpilogInstrs); 9790b57cec5SDimitry Andric 9800b57cec5SDimitry Andric MCSymbol* MatchingEpilog = 9810b57cec5SDimitry Andric FindMatchingEpilog(EpilogInstrs, AddedEpilogs, info); 9820b57cec5SDimitry Andric if (MatchingEpilog) { 9830b57cec5SDimitry Andric assert(EpilogInfo.find(MatchingEpilog) != EpilogInfo.end() && 9840b57cec5SDimitry Andric "Duplicate epilog not found"); 9850b57cec5SDimitry Andric EpilogInfo[EpilogStart] = EpilogInfo.lookup(MatchingEpilog); 9860b57cec5SDimitry Andric // Clear the unwind codes in the EpilogMap, so that they don't get output 9870b57cec5SDimitry Andric // in the logic below. 9880b57cec5SDimitry Andric EpilogInstrs.clear(); 9890b57cec5SDimitry Andric } else { 9900b57cec5SDimitry Andric EpilogInfo[EpilogStart] = TotalCodeBytes; 9910b57cec5SDimitry Andric TotalCodeBytes += CodeBytes; 9920b57cec5SDimitry Andric AddedEpilogs.push_back(EpilogStart); 9930b57cec5SDimitry Andric } 9940b57cec5SDimitry Andric } 9950b57cec5SDimitry Andric 9960b57cec5SDimitry Andric // Code Words, Epilog count, E, X, Vers, Function Length 9970b57cec5SDimitry Andric uint32_t row1 = 0x0; 9980b57cec5SDimitry Andric uint32_t CodeWords = TotalCodeBytes / 4; 9990b57cec5SDimitry Andric uint32_t CodeWordsMod = TotalCodeBytes % 4; 10000b57cec5SDimitry Andric if (CodeWordsMod) 10010b57cec5SDimitry Andric CodeWords++; 1002e8d8bef9SDimitry Andric uint32_t EpilogCount = 1003e8d8bef9SDimitry Andric PackedEpilogOffset >= 0 ? PackedEpilogOffset : info->EpilogMap.size(); 10040b57cec5SDimitry Andric bool ExtensionWord = EpilogCount > 31 || TotalCodeBytes > 124; 10050b57cec5SDimitry Andric if (!ExtensionWord) { 10060b57cec5SDimitry Andric row1 |= (EpilogCount & 0x1F) << 22; 10070b57cec5SDimitry Andric row1 |= (CodeWords & 0x1F) << 27; 10080b57cec5SDimitry Andric } 10090b57cec5SDimitry Andric if (info->HandlesExceptions) // X 10100b57cec5SDimitry Andric row1 |= 1 << 20; 1011e8d8bef9SDimitry Andric if (PackedEpilogOffset >= 0) // E 1012e8d8bef9SDimitry Andric row1 |= 1 << 21; 10130b57cec5SDimitry Andric row1 |= FuncLength & 0x3FFFF; 10145ffd83dbSDimitry Andric streamer.emitInt32(row1); 10150b57cec5SDimitry Andric 10160b57cec5SDimitry Andric // Extended Code Words, Extended Epilog Count 10170b57cec5SDimitry Andric if (ExtensionWord) { 10180b57cec5SDimitry Andric // FIXME: We should be able to split unwind info into multiple sections. 10190b57cec5SDimitry Andric // FIXME: We should share epilog codes across epilogs, where possible, 10200b57cec5SDimitry Andric // which would make this issue show up less frequently. 10210b57cec5SDimitry Andric if (CodeWords > 0xFF || EpilogCount > 0xFFFF) 10220b57cec5SDimitry Andric report_fatal_error("SEH unwind data splitting not yet implemented"); 10230b57cec5SDimitry Andric uint32_t row2 = 0x0; 10240b57cec5SDimitry Andric row2 |= (CodeWords & 0xFF) << 16; 10250b57cec5SDimitry Andric row2 |= (EpilogCount & 0xFFFF); 10265ffd83dbSDimitry Andric streamer.emitInt32(row2); 10270b57cec5SDimitry Andric } 10280b57cec5SDimitry Andric 10290b57cec5SDimitry Andric // Epilog Start Index, Epilog Start Offset 10300b57cec5SDimitry Andric for (auto &I : EpilogInfo) { 10310b57cec5SDimitry Andric MCSymbol *EpilogStart = I.first; 10320b57cec5SDimitry Andric uint32_t EpilogIndex = I.second; 10330b57cec5SDimitry Andric uint32_t EpilogOffset = 10340b57cec5SDimitry Andric (uint32_t)GetAbsDifference(streamer, EpilogStart, info->Begin); 10350b57cec5SDimitry Andric if (EpilogOffset) 10360b57cec5SDimitry Andric EpilogOffset /= 4; 10370b57cec5SDimitry Andric uint32_t row3 = EpilogOffset; 10380b57cec5SDimitry Andric row3 |= (EpilogIndex & 0x3FF) << 22; 10395ffd83dbSDimitry Andric streamer.emitInt32(row3); 10400b57cec5SDimitry Andric } 10410b57cec5SDimitry Andric 10420b57cec5SDimitry Andric // Emit prolog unwind instructions (in reverse order). 10430b57cec5SDimitry Andric uint8_t numInst = info->Instructions.size(); 10440b57cec5SDimitry Andric for (uint8_t c = 0; c < numInst; ++c) { 10450b57cec5SDimitry Andric WinEH::Instruction inst = info->Instructions.back(); 10460b57cec5SDimitry Andric info->Instructions.pop_back(); 10470b57cec5SDimitry Andric ARM64EmitUnwindCode(streamer, info->Begin, inst); 10480b57cec5SDimitry Andric } 10490b57cec5SDimitry Andric 10500b57cec5SDimitry Andric // Emit epilog unwind instructions 10510b57cec5SDimitry Andric for (auto &I : info->EpilogMap) { 10520b57cec5SDimitry Andric auto &EpilogInstrs = I.second; 10530b57cec5SDimitry Andric for (uint32_t i = 0; i < EpilogInstrs.size(); i++) { 10540b57cec5SDimitry Andric WinEH::Instruction inst = EpilogInstrs[i]; 10550b57cec5SDimitry Andric ARM64EmitUnwindCode(streamer, info->Begin, inst); 10560b57cec5SDimitry Andric } 10570b57cec5SDimitry Andric } 10580b57cec5SDimitry Andric 10590b57cec5SDimitry Andric int32_t BytesMod = CodeWords * 4 - TotalCodeBytes; 10600b57cec5SDimitry Andric assert(BytesMod >= 0); 10610b57cec5SDimitry Andric for (int i = 0; i < BytesMod; i++) 10625ffd83dbSDimitry Andric streamer.emitInt8(0xE3); 10630b57cec5SDimitry Andric 10640b57cec5SDimitry Andric if (info->HandlesExceptions) 10655ffd83dbSDimitry Andric streamer.emitValue( 10660b57cec5SDimitry Andric MCSymbolRefExpr::create(info->ExceptionHandler, 10670b57cec5SDimitry Andric MCSymbolRefExpr::VK_COFF_IMGREL32, context), 10680b57cec5SDimitry Andric 4); 10690b57cec5SDimitry Andric } 10700b57cec5SDimitry Andric 10710b57cec5SDimitry Andric static void ARM64EmitRuntimeFunction(MCStreamer &streamer, 10720b57cec5SDimitry Andric const WinEH::FrameInfo *info) { 10730b57cec5SDimitry Andric MCContext &context = streamer.getContext(); 10740b57cec5SDimitry Andric 10755ffd83dbSDimitry Andric streamer.emitValueToAlignment(4); 1076*349cc55cSDimitry Andric EmitSymbolRefWithOfs(streamer, info->Begin, info->Begin); 1077e8d8bef9SDimitry Andric if (info->PackedInfo) 1078e8d8bef9SDimitry Andric streamer.emitInt32(info->PackedInfo); 1079e8d8bef9SDimitry Andric else 1080e8d8bef9SDimitry Andric streamer.emitValue( 1081e8d8bef9SDimitry Andric MCSymbolRefExpr::create(info->Symbol, MCSymbolRefExpr::VK_COFF_IMGREL32, 10820b57cec5SDimitry Andric context), 10830b57cec5SDimitry Andric 4); 10840b57cec5SDimitry Andric } 10850b57cec5SDimitry Andric 10860b57cec5SDimitry Andric void llvm::Win64EH::ARM64UnwindEmitter::Emit(MCStreamer &Streamer) const { 10870b57cec5SDimitry Andric // Emit the unwind info structs first. 10880b57cec5SDimitry Andric for (const auto &CFI : Streamer.getWinFrameInfos()) { 1089e8d8bef9SDimitry Andric WinEH::FrameInfo *Info = CFI.get(); 1090e8d8bef9SDimitry Andric if (Info->empty()) 1091e8d8bef9SDimitry Andric continue; 10920b57cec5SDimitry Andric MCSection *XData = Streamer.getAssociatedXDataSection(CFI->TextSection); 10930b57cec5SDimitry Andric Streamer.SwitchSection(XData); 1094e8d8bef9SDimitry Andric ARM64EmitUnwindInfo(Streamer, Info); 10950b57cec5SDimitry Andric } 10960b57cec5SDimitry Andric 10970b57cec5SDimitry Andric // Now emit RUNTIME_FUNCTION entries. 10980b57cec5SDimitry Andric for (const auto &CFI : Streamer.getWinFrameInfos()) { 1099e8d8bef9SDimitry Andric WinEH::FrameInfo *Info = CFI.get(); 1100e8d8bef9SDimitry Andric // ARM64EmitUnwindInfo above clears the info struct, so we can't check 1101e8d8bef9SDimitry Andric // empty here. But if a Symbol is set, we should create the corresponding 1102e8d8bef9SDimitry Andric // pdata entry. 1103e8d8bef9SDimitry Andric if (!Info->Symbol) 1104e8d8bef9SDimitry Andric continue; 11050b57cec5SDimitry Andric MCSection *PData = Streamer.getAssociatedPDataSection(CFI->TextSection); 11060b57cec5SDimitry Andric Streamer.SwitchSection(PData); 1107e8d8bef9SDimitry Andric ARM64EmitRuntimeFunction(Streamer, Info); 11080b57cec5SDimitry Andric } 11090b57cec5SDimitry Andric } 11100b57cec5SDimitry Andric 1111e8d8bef9SDimitry Andric void llvm::Win64EH::ARM64UnwindEmitter::EmitUnwindInfo(MCStreamer &Streamer, 1112e8d8bef9SDimitry Andric WinEH::FrameInfo *info, 1113e8d8bef9SDimitry Andric bool HandlerData) const { 1114e8d8bef9SDimitry Andric // Called if there's an .seh_handlerdata directive before the end of the 1115e8d8bef9SDimitry Andric // function. This forces writing the xdata record already here - and 1116e8d8bef9SDimitry Andric // in this case, the function isn't actually ended already, but the xdata 1117e8d8bef9SDimitry Andric // record needs to know the function length. In these cases, if the funclet 1118e8d8bef9SDimitry Andric // end hasn't been marked yet, the xdata function length won't cover the 1119e8d8bef9SDimitry Andric // whole function, only up to this point. 1120e8d8bef9SDimitry Andric if (!info->FuncletOrFuncEnd) { 1121e8d8bef9SDimitry Andric Streamer.SwitchSection(info->TextSection); 1122e8d8bef9SDimitry Andric info->FuncletOrFuncEnd = Streamer.emitCFILabel(); 1123e8d8bef9SDimitry Andric } 11240b57cec5SDimitry Andric // Switch sections (the static function above is meant to be called from 11250b57cec5SDimitry Andric // here and from Emit(). 11260b57cec5SDimitry Andric MCSection *XData = Streamer.getAssociatedXDataSection(info->TextSection); 11270b57cec5SDimitry Andric Streamer.SwitchSection(XData); 1128e8d8bef9SDimitry Andric ARM64EmitUnwindInfo(Streamer, info, /* TryPacked = */ !HandlerData); 11290b57cec5SDimitry Andric } 1130