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); 58*5ffd83dbSDimitry 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; 72*5ffd83dbSDimitry 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; 78*5ffd83dbSDimitry Andric streamer.emitInt8(b2); 790b57cec5SDimitry Andric w = inst.Offset & 0xFFF8; 80*5ffd83dbSDimitry Andric streamer.emitInt16(w); 810b57cec5SDimitry Andric w = inst.Offset >> 16; 820b57cec5SDimitry Andric } else { 83*5ffd83dbSDimitry Andric streamer.emitInt8(b2); 840b57cec5SDimitry Andric w = inst.Offset >> 3; 850b57cec5SDimitry Andric } 86*5ffd83dbSDimitry 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); 91*5ffd83dbSDimitry Andric streamer.emitInt8(b2); 920b57cec5SDimitry Andric break; 930b57cec5SDimitry Andric case Win64EH::UOP_SetFPReg: 940b57cec5SDimitry Andric EmitAbsDifference(streamer, inst.Label, begin); 95*5ffd83dbSDimitry 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); 101*5ffd83dbSDimitry Andric streamer.emitInt8(b2); 1020b57cec5SDimitry Andric w = inst.Offset >> 3; 1030b57cec5SDimitry Andric if (inst.Operation == Win64EH::UOP_SaveXMM128) 1040b57cec5SDimitry Andric w >>= 1; 105*5ffd83dbSDimitry 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); 111*5ffd83dbSDimitry 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; 116*5ffd83dbSDimitry Andric streamer.emitInt16(w); 1170b57cec5SDimitry Andric w = inst.Offset >> 16; 118*5ffd83dbSDimitry 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); 124*5ffd83dbSDimitry 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); 139*5ffd83dbSDimitry 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 146*5ffd83dbSDimitry Andric streamer.emitValueToAlignment(4); 1470b57cec5SDimitry Andric EmitSymbolRefWithOfs(streamer, info->Function, info->Begin); 1480b57cec5SDimitry Andric EmitSymbolRefWithOfs(streamer, info->Function, info->End); 149*5ffd83dbSDimitry 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 162*5ffd83dbSDimitry Andric streamer.emitValueToAlignment(4); 163*5ffd83dbSDimitry 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 } 176*5ffd83dbSDimitry Andric streamer.emitInt8(flags); 1770b57cec5SDimitry Andric 1780b57cec5SDimitry Andric if (info->PrologEnd) 1790b57cec5SDimitry Andric EmitAbsDifference(streamer, info->PrologEnd, info->Begin); 1800b57cec5SDimitry Andric else 181*5ffd83dbSDimitry Andric streamer.emitInt8(0); 1820b57cec5SDimitry Andric 1830b57cec5SDimitry Andric uint8_t numCodes = CountOfUnwindCodes(info->Instructions); 184*5ffd83dbSDimitry 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 } 192*5ffd83dbSDimitry 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) { 207*5ffd83dbSDimitry 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)) 214*5ffd83dbSDimitry 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. 221*5ffd83dbSDimitry 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 2410b57cec5SDimitry Andric void llvm::Win64EH::UnwindEmitter::EmitUnwindInfo( 2420b57cec5SDimitry Andric MCStreamer &Streamer, WinEH::FrameInfo *info) const { 2430b57cec5SDimitry Andric // Switch sections (the static function above is meant to be called from 2440b57cec5SDimitry Andric // here and from Emit(). 2450b57cec5SDimitry Andric MCSection *XData = Streamer.getAssociatedXDataSection(info->TextSection); 2460b57cec5SDimitry Andric Streamer.SwitchSection(XData); 2470b57cec5SDimitry Andric 2480b57cec5SDimitry Andric ::EmitUnwindInfo(Streamer, info); 2490b57cec5SDimitry Andric } 2500b57cec5SDimitry Andric 2510b57cec5SDimitry Andric static int64_t GetAbsDifference(MCStreamer &Streamer, const MCSymbol *LHS, 2520b57cec5SDimitry Andric const MCSymbol *RHS) { 2530b57cec5SDimitry Andric MCContext &Context = Streamer.getContext(); 2540b57cec5SDimitry Andric const MCExpr *Diff = 2550b57cec5SDimitry Andric MCBinaryExpr::createSub(MCSymbolRefExpr::create(LHS, Context), 2560b57cec5SDimitry Andric MCSymbolRefExpr::create(RHS, Context), Context); 2570b57cec5SDimitry Andric MCObjectStreamer *OS = (MCObjectStreamer *)(&Streamer); 2580b57cec5SDimitry Andric // It should normally be possible to calculate the length of a function 2590b57cec5SDimitry Andric // at this point, but it might not be possible in the presence of certain 2600b57cec5SDimitry Andric // unusual constructs, like an inline asm with an alignment directive. 2610b57cec5SDimitry Andric int64_t value; 2620b57cec5SDimitry Andric if (!Diff->evaluateAsAbsolute(value, OS->getAssembler())) 2630b57cec5SDimitry Andric report_fatal_error("Failed to evaluate function length in SEH unwind info"); 2640b57cec5SDimitry Andric return value; 2650b57cec5SDimitry Andric } 2660b57cec5SDimitry Andric 2670b57cec5SDimitry Andric static uint32_t 2680b57cec5SDimitry Andric ARM64CountOfUnwindCodes(const std::vector<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; 2830b57cec5SDimitry Andric case Win64EH::UOP_SaveFPLRX: 2840b57cec5SDimitry Andric Count += 1; 2850b57cec5SDimitry Andric break; 2860b57cec5SDimitry Andric case Win64EH::UOP_SaveFPLR: 2870b57cec5SDimitry Andric Count += 1; 2880b57cec5SDimitry Andric break; 2890b57cec5SDimitry Andric case Win64EH::UOP_SaveReg: 2900b57cec5SDimitry Andric Count += 2; 2910b57cec5SDimitry Andric break; 2920b57cec5SDimitry Andric case Win64EH::UOP_SaveRegP: 2930b57cec5SDimitry Andric Count += 2; 2940b57cec5SDimitry Andric break; 2950b57cec5SDimitry Andric case Win64EH::UOP_SaveRegPX: 2960b57cec5SDimitry Andric Count += 2; 2970b57cec5SDimitry Andric break; 2980b57cec5SDimitry Andric case Win64EH::UOP_SaveRegX: 2990b57cec5SDimitry Andric Count += 2; 3000b57cec5SDimitry Andric break; 3010b57cec5SDimitry Andric case Win64EH::UOP_SaveFReg: 3020b57cec5SDimitry Andric Count += 2; 3030b57cec5SDimitry Andric break; 3040b57cec5SDimitry Andric case Win64EH::UOP_SaveFRegP: 3050b57cec5SDimitry Andric Count += 2; 3060b57cec5SDimitry Andric break; 3070b57cec5SDimitry Andric case Win64EH::UOP_SaveFRegX: 3080b57cec5SDimitry Andric Count += 2; 3090b57cec5SDimitry Andric break; 3100b57cec5SDimitry Andric case Win64EH::UOP_SaveFRegPX: 3110b57cec5SDimitry Andric Count += 2; 3120b57cec5SDimitry Andric break; 3130b57cec5SDimitry Andric case Win64EH::UOP_SetFP: 3140b57cec5SDimitry Andric Count += 1; 3150b57cec5SDimitry Andric break; 3160b57cec5SDimitry Andric case Win64EH::UOP_AddFP: 3170b57cec5SDimitry Andric Count += 2; 3180b57cec5SDimitry Andric break; 3190b57cec5SDimitry Andric case Win64EH::UOP_Nop: 3200b57cec5SDimitry Andric Count += 1; 3210b57cec5SDimitry Andric break; 3220b57cec5SDimitry Andric case Win64EH::UOP_End: 3230b57cec5SDimitry Andric Count += 1; 3240b57cec5SDimitry Andric break; 3250b57cec5SDimitry Andric } 3260b57cec5SDimitry Andric } 3270b57cec5SDimitry Andric return Count; 3280b57cec5SDimitry Andric } 3290b57cec5SDimitry Andric 3300b57cec5SDimitry Andric // Unwind opcode encodings and restrictions are documented at 3310b57cec5SDimitry Andric // https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling 3320b57cec5SDimitry Andric static void ARM64EmitUnwindCode(MCStreamer &streamer, const MCSymbol *begin, 3330b57cec5SDimitry Andric WinEH::Instruction &inst) { 3340b57cec5SDimitry Andric uint8_t b, reg; 3350b57cec5SDimitry Andric switch (static_cast<Win64EH::UnwindOpcodes>(inst.Operation)) { 3360b57cec5SDimitry Andric default: 3370b57cec5SDimitry Andric llvm_unreachable("Unsupported ARM64 unwind code"); 3380b57cec5SDimitry Andric case Win64EH::UOP_AllocSmall: 3390b57cec5SDimitry Andric b = (inst.Offset >> 4) & 0x1F; 340*5ffd83dbSDimitry Andric streamer.emitInt8(b); 3410b57cec5SDimitry Andric break; 3420b57cec5SDimitry Andric case Win64EH::UOP_AllocMedium: { 3430b57cec5SDimitry Andric uint16_t hw = (inst.Offset >> 4) & 0x7FF; 3440b57cec5SDimitry Andric b = 0xC0; 3450b57cec5SDimitry Andric b |= (hw >> 8); 346*5ffd83dbSDimitry Andric streamer.emitInt8(b); 3470b57cec5SDimitry Andric b = hw & 0xFF; 348*5ffd83dbSDimitry Andric streamer.emitInt8(b); 3490b57cec5SDimitry Andric break; 3500b57cec5SDimitry Andric } 3510b57cec5SDimitry Andric case Win64EH::UOP_AllocLarge: { 3520b57cec5SDimitry Andric uint32_t w; 3530b57cec5SDimitry Andric b = 0xE0; 354*5ffd83dbSDimitry Andric streamer.emitInt8(b); 3550b57cec5SDimitry Andric w = inst.Offset >> 4; 3560b57cec5SDimitry Andric b = (w & 0x00FF0000) >> 16; 357*5ffd83dbSDimitry Andric streamer.emitInt8(b); 3580b57cec5SDimitry Andric b = (w & 0x0000FF00) >> 8; 359*5ffd83dbSDimitry Andric streamer.emitInt8(b); 3600b57cec5SDimitry Andric b = w & 0x000000FF; 361*5ffd83dbSDimitry Andric streamer.emitInt8(b); 3620b57cec5SDimitry Andric break; 3630b57cec5SDimitry Andric } 3640b57cec5SDimitry Andric case Win64EH::UOP_SetFP: 3650b57cec5SDimitry Andric b = 0xE1; 366*5ffd83dbSDimitry Andric streamer.emitInt8(b); 3670b57cec5SDimitry Andric break; 3680b57cec5SDimitry Andric case Win64EH::UOP_AddFP: 3690b57cec5SDimitry Andric b = 0xE2; 370*5ffd83dbSDimitry Andric streamer.emitInt8(b); 3710b57cec5SDimitry Andric b = (inst.Offset >> 3); 372*5ffd83dbSDimitry Andric streamer.emitInt8(b); 3730b57cec5SDimitry Andric break; 3740b57cec5SDimitry Andric case Win64EH::UOP_Nop: 3750b57cec5SDimitry Andric b = 0xE3; 376*5ffd83dbSDimitry Andric streamer.emitInt8(b); 3770b57cec5SDimitry Andric break; 3780b57cec5SDimitry Andric case Win64EH::UOP_SaveFPLRX: 3790b57cec5SDimitry Andric b = 0x80; 3800b57cec5SDimitry Andric b |= ((inst.Offset - 1) >> 3) & 0x3F; 381*5ffd83dbSDimitry Andric streamer.emitInt8(b); 3820b57cec5SDimitry Andric break; 3830b57cec5SDimitry Andric case Win64EH::UOP_SaveFPLR: 3840b57cec5SDimitry Andric b = 0x40; 3850b57cec5SDimitry Andric b |= (inst.Offset >> 3) & 0x3F; 386*5ffd83dbSDimitry Andric streamer.emitInt8(b); 3870b57cec5SDimitry Andric break; 3880b57cec5SDimitry Andric case Win64EH::UOP_SaveReg: 3890b57cec5SDimitry Andric assert(inst.Register >= 19 && "Saved reg must be >= 19"); 3900b57cec5SDimitry Andric reg = inst.Register - 19; 3910b57cec5SDimitry Andric b = 0xD0 | ((reg & 0xC) >> 2); 392*5ffd83dbSDimitry Andric streamer.emitInt8(b); 3930b57cec5SDimitry Andric b = ((reg & 0x3) << 6) | (inst.Offset >> 3); 394*5ffd83dbSDimitry Andric streamer.emitInt8(b); 3950b57cec5SDimitry Andric break; 3960b57cec5SDimitry Andric case Win64EH::UOP_SaveRegX: 3970b57cec5SDimitry Andric assert(inst.Register >= 19 && "Saved reg must be >= 19"); 3980b57cec5SDimitry Andric reg = inst.Register - 19; 3990b57cec5SDimitry Andric b = 0xD4 | ((reg & 0x8) >> 3); 400*5ffd83dbSDimitry Andric streamer.emitInt8(b); 4010b57cec5SDimitry Andric b = ((reg & 0x7) << 5) | ((inst.Offset >> 3) - 1); 402*5ffd83dbSDimitry Andric streamer.emitInt8(b); 4030b57cec5SDimitry Andric break; 4040b57cec5SDimitry Andric case Win64EH::UOP_SaveRegP: 4050b57cec5SDimitry Andric assert(inst.Register >= 19 && "Saved registers must be >= 19"); 4060b57cec5SDimitry Andric reg = inst.Register - 19; 4070b57cec5SDimitry Andric b = 0xC8 | ((reg & 0xC) >> 2); 408*5ffd83dbSDimitry Andric streamer.emitInt8(b); 4090b57cec5SDimitry Andric b = ((reg & 0x3) << 6) | (inst.Offset >> 3); 410*5ffd83dbSDimitry Andric streamer.emitInt8(b); 4110b57cec5SDimitry Andric break; 4120b57cec5SDimitry Andric case Win64EH::UOP_SaveRegPX: 4130b57cec5SDimitry Andric assert(inst.Register >= 19 && "Saved registers must be >= 19"); 4140b57cec5SDimitry Andric reg = inst.Register - 19; 4150b57cec5SDimitry Andric b = 0xCC | ((reg & 0xC) >> 2); 416*5ffd83dbSDimitry Andric streamer.emitInt8(b); 4170b57cec5SDimitry Andric b = ((reg & 0x3) << 6) | ((inst.Offset >> 3) - 1); 418*5ffd83dbSDimitry Andric streamer.emitInt8(b); 4190b57cec5SDimitry Andric break; 4200b57cec5SDimitry Andric case Win64EH::UOP_SaveFReg: 4210b57cec5SDimitry Andric assert(inst.Register >= 8 && "Saved dreg must be >= 8"); 4220b57cec5SDimitry Andric reg = inst.Register - 8; 4230b57cec5SDimitry Andric b = 0xDC | ((reg & 0x4) >> 2); 424*5ffd83dbSDimitry Andric streamer.emitInt8(b); 4250b57cec5SDimitry Andric b = ((reg & 0x3) << 6) | (inst.Offset >> 3); 426*5ffd83dbSDimitry Andric streamer.emitInt8(b); 4270b57cec5SDimitry Andric break; 4280b57cec5SDimitry Andric case Win64EH::UOP_SaveFRegX: 4290b57cec5SDimitry Andric assert(inst.Register >= 8 && "Saved dreg must be >= 8"); 4300b57cec5SDimitry Andric reg = inst.Register - 8; 4310b57cec5SDimitry Andric b = 0xDE; 432*5ffd83dbSDimitry Andric streamer.emitInt8(b); 4330b57cec5SDimitry Andric b = ((reg & 0x7) << 5) | ((inst.Offset >> 3) - 1); 434*5ffd83dbSDimitry Andric streamer.emitInt8(b); 4350b57cec5SDimitry Andric break; 4360b57cec5SDimitry Andric case Win64EH::UOP_SaveFRegP: 4370b57cec5SDimitry Andric assert(inst.Register >= 8 && "Saved dregs must be >= 8"); 4380b57cec5SDimitry Andric reg = inst.Register - 8; 4390b57cec5SDimitry Andric b = 0xD8 | ((reg & 0x4) >> 2); 440*5ffd83dbSDimitry Andric streamer.emitInt8(b); 4410b57cec5SDimitry Andric b = ((reg & 0x3) << 6) | (inst.Offset >> 3); 442*5ffd83dbSDimitry Andric streamer.emitInt8(b); 4430b57cec5SDimitry Andric break; 4440b57cec5SDimitry Andric case Win64EH::UOP_SaveFRegPX: 4450b57cec5SDimitry Andric assert(inst.Register >= 8 && "Saved dregs must be >= 8"); 4460b57cec5SDimitry Andric reg = inst.Register - 8; 4470b57cec5SDimitry Andric b = 0xDA | ((reg & 0x4) >> 2); 448*5ffd83dbSDimitry Andric streamer.emitInt8(b); 4490b57cec5SDimitry Andric b = ((reg & 0x3) << 6) | ((inst.Offset >> 3) - 1); 450*5ffd83dbSDimitry Andric streamer.emitInt8(b); 4510b57cec5SDimitry Andric break; 4520b57cec5SDimitry Andric case Win64EH::UOP_End: 4530b57cec5SDimitry Andric b = 0xE4; 454*5ffd83dbSDimitry Andric streamer.emitInt8(b); 4550b57cec5SDimitry Andric break; 4560b57cec5SDimitry Andric } 4570b57cec5SDimitry Andric } 4580b57cec5SDimitry Andric 4590b57cec5SDimitry Andric // Returns the epilog symbol of an epilog with the exact same unwind code 4600b57cec5SDimitry Andric // sequence, if it exists. Otherwise, returns nulltpr. 4610b57cec5SDimitry Andric // EpilogInstrs - Unwind codes for the current epilog. 4620b57cec5SDimitry Andric // Epilogs - Epilogs that potentialy match the current epilog. 4630b57cec5SDimitry Andric static MCSymbol* 4640b57cec5SDimitry Andric FindMatchingEpilog(const std::vector<WinEH::Instruction>& EpilogInstrs, 4650b57cec5SDimitry Andric const std::vector<MCSymbol *>& Epilogs, 4660b57cec5SDimitry Andric const WinEH::FrameInfo *info) { 4670b57cec5SDimitry Andric for (auto *EpilogStart : Epilogs) { 4680b57cec5SDimitry Andric auto InstrsIter = info->EpilogMap.find(EpilogStart); 4690b57cec5SDimitry Andric assert(InstrsIter != info->EpilogMap.end() && 4700b57cec5SDimitry Andric "Epilog not found in EpilogMap"); 4710b57cec5SDimitry Andric const auto &Instrs = InstrsIter->second; 4720b57cec5SDimitry Andric 4730b57cec5SDimitry Andric if (Instrs.size() != EpilogInstrs.size()) 4740b57cec5SDimitry Andric continue; 4750b57cec5SDimitry Andric 4760b57cec5SDimitry Andric bool Match = true; 4770b57cec5SDimitry Andric for (unsigned i = 0; i < Instrs.size(); ++i) 4780b57cec5SDimitry Andric if (Instrs[i].Operation != EpilogInstrs[i].Operation || 4790b57cec5SDimitry Andric Instrs[i].Offset != EpilogInstrs[i].Offset || 4800b57cec5SDimitry Andric Instrs[i].Register != EpilogInstrs[i].Register) { 4810b57cec5SDimitry Andric Match = false; 4820b57cec5SDimitry Andric break; 4830b57cec5SDimitry Andric } 4840b57cec5SDimitry Andric 4850b57cec5SDimitry Andric if (Match) 4860b57cec5SDimitry Andric return EpilogStart; 4870b57cec5SDimitry Andric } 4880b57cec5SDimitry Andric return nullptr; 4890b57cec5SDimitry Andric } 4900b57cec5SDimitry Andric 4910b57cec5SDimitry Andric // Populate the .xdata section. The format of .xdata on ARM64 is documented at 4920b57cec5SDimitry Andric // https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling 4930b57cec5SDimitry Andric static void ARM64EmitUnwindInfo(MCStreamer &streamer, WinEH::FrameInfo *info) { 4940b57cec5SDimitry Andric // If this UNWIND_INFO already has a symbol, it's already been emitted. 4950b57cec5SDimitry Andric if (info->Symbol) 4960b57cec5SDimitry Andric return; 4970b57cec5SDimitry Andric 4980b57cec5SDimitry Andric MCContext &context = streamer.getContext(); 4990b57cec5SDimitry Andric MCSymbol *Label = context.createTempSymbol(); 5000b57cec5SDimitry Andric 501*5ffd83dbSDimitry Andric streamer.emitValueToAlignment(4); 502*5ffd83dbSDimitry Andric streamer.emitLabel(Label); 5030b57cec5SDimitry Andric info->Symbol = Label; 5040b57cec5SDimitry Andric 5050b57cec5SDimitry Andric int64_t RawFuncLength; 5060b57cec5SDimitry Andric if (!info->FuncletOrFuncEnd) { 5070b57cec5SDimitry Andric // FIXME: This is very wrong; we emit SEH data which covers zero bytes 5080b57cec5SDimitry Andric // of code. But otherwise test/MC/AArch64/seh.s crashes. 5090b57cec5SDimitry Andric RawFuncLength = 0; 5100b57cec5SDimitry Andric } else { 5110b57cec5SDimitry Andric // FIXME: GetAbsDifference tries to compute the length of the function 5120b57cec5SDimitry Andric // immediately, before the whole file is emitted, but in general 5130b57cec5SDimitry Andric // that's impossible: the size in bytes of certain assembler directives 5140b57cec5SDimitry Andric // like .align and .fill is not known until the whole file is parsed and 5150b57cec5SDimitry Andric // relaxations are applied. Currently, GetAbsDifference fails with a fatal 5160b57cec5SDimitry Andric // error in that case. (We mostly don't hit this because inline assembly 5170b57cec5SDimitry Andric // specifying those directives is rare, and we don't normally try to 5180b57cec5SDimitry Andric // align loops on AArch64.) 5190b57cec5SDimitry Andric // 5200b57cec5SDimitry Andric // There are two potential approaches to delaying the computation. One, 5210b57cec5SDimitry Andric // we could emit something like ".word (endfunc-beginfunc)/4+0x10800000", 5220b57cec5SDimitry Andric // as long as we have some conservative estimate we could use to prove 5230b57cec5SDimitry Andric // that we don't need to split the unwind data. Emitting the constant 5240b57cec5SDimitry Andric // is straightforward, but there's no existing code for estimating the 5250b57cec5SDimitry Andric // size of the function. 5260b57cec5SDimitry Andric // 5270b57cec5SDimitry Andric // The other approach would be to use a dedicated, relaxable fragment, 5280b57cec5SDimitry Andric // which could grow to accommodate splitting the unwind data if 5290b57cec5SDimitry Andric // necessary. This is more straightforward, since it automatically works 5300b57cec5SDimitry Andric // without any new infrastructure, and it's consistent with how we handle 5310b57cec5SDimitry Andric // relaxation in other contexts. But it would require some refactoring 5320b57cec5SDimitry Andric // to move parts of the pdata/xdata emission into the implementation of 5330b57cec5SDimitry Andric // a fragment. We could probably continue to encode the unwind codes 5340b57cec5SDimitry Andric // here, but we'd have to emit the pdata, the xdata header, and the 5350b57cec5SDimitry Andric // epilogue scopes later, since they depend on whether the we need to 5360b57cec5SDimitry Andric // split the unwind data. 5370b57cec5SDimitry Andric RawFuncLength = GetAbsDifference(streamer, info->FuncletOrFuncEnd, 5380b57cec5SDimitry Andric info->Begin); 5390b57cec5SDimitry Andric } 5400b57cec5SDimitry Andric if (RawFuncLength > 0xFFFFF) 5410b57cec5SDimitry Andric report_fatal_error("SEH unwind data splitting not yet implemented"); 5420b57cec5SDimitry Andric uint32_t FuncLength = (uint32_t)RawFuncLength / 4; 5430b57cec5SDimitry Andric uint32_t PrologCodeBytes = ARM64CountOfUnwindCodes(info->Instructions); 5440b57cec5SDimitry Andric uint32_t TotalCodeBytes = PrologCodeBytes; 5450b57cec5SDimitry Andric 5460b57cec5SDimitry Andric // Process epilogs. 5470b57cec5SDimitry Andric MapVector<MCSymbol *, uint32_t> EpilogInfo; 5480b57cec5SDimitry Andric // Epilogs processed so far. 5490b57cec5SDimitry Andric std::vector<MCSymbol *> AddedEpilogs; 5500b57cec5SDimitry Andric 5510b57cec5SDimitry Andric for (auto &I : info->EpilogMap) { 5520b57cec5SDimitry Andric MCSymbol *EpilogStart = I.first; 5530b57cec5SDimitry Andric auto &EpilogInstrs = I.second; 5540b57cec5SDimitry Andric uint32_t CodeBytes = ARM64CountOfUnwindCodes(EpilogInstrs); 5550b57cec5SDimitry Andric 5560b57cec5SDimitry Andric MCSymbol* MatchingEpilog = 5570b57cec5SDimitry Andric FindMatchingEpilog(EpilogInstrs, AddedEpilogs, info); 5580b57cec5SDimitry Andric if (MatchingEpilog) { 5590b57cec5SDimitry Andric assert(EpilogInfo.find(MatchingEpilog) != EpilogInfo.end() && 5600b57cec5SDimitry Andric "Duplicate epilog not found"); 5610b57cec5SDimitry Andric EpilogInfo[EpilogStart] = EpilogInfo.lookup(MatchingEpilog); 5620b57cec5SDimitry Andric // Clear the unwind codes in the EpilogMap, so that they don't get output 5630b57cec5SDimitry Andric // in the logic below. 5640b57cec5SDimitry Andric EpilogInstrs.clear(); 5650b57cec5SDimitry Andric } else { 5660b57cec5SDimitry Andric EpilogInfo[EpilogStart] = TotalCodeBytes; 5670b57cec5SDimitry Andric TotalCodeBytes += CodeBytes; 5680b57cec5SDimitry Andric AddedEpilogs.push_back(EpilogStart); 5690b57cec5SDimitry Andric } 5700b57cec5SDimitry Andric } 5710b57cec5SDimitry Andric 5720b57cec5SDimitry Andric // Code Words, Epilog count, E, X, Vers, Function Length 5730b57cec5SDimitry Andric uint32_t row1 = 0x0; 5740b57cec5SDimitry Andric uint32_t CodeWords = TotalCodeBytes / 4; 5750b57cec5SDimitry Andric uint32_t CodeWordsMod = TotalCodeBytes % 4; 5760b57cec5SDimitry Andric if (CodeWordsMod) 5770b57cec5SDimitry Andric CodeWords++; 5780b57cec5SDimitry Andric uint32_t EpilogCount = info->EpilogMap.size(); 5790b57cec5SDimitry Andric bool ExtensionWord = EpilogCount > 31 || TotalCodeBytes > 124; 5800b57cec5SDimitry Andric if (!ExtensionWord) { 5810b57cec5SDimitry Andric row1 |= (EpilogCount & 0x1F) << 22; 5820b57cec5SDimitry Andric row1 |= (CodeWords & 0x1F) << 27; 5830b57cec5SDimitry Andric } 5840b57cec5SDimitry Andric // E is always 0 right now, TODO: packed epilog setup 5850b57cec5SDimitry Andric if (info->HandlesExceptions) // X 5860b57cec5SDimitry Andric row1 |= 1 << 20; 5870b57cec5SDimitry Andric row1 |= FuncLength & 0x3FFFF; 588*5ffd83dbSDimitry Andric streamer.emitInt32(row1); 5890b57cec5SDimitry Andric 5900b57cec5SDimitry Andric // Extended Code Words, Extended Epilog Count 5910b57cec5SDimitry Andric if (ExtensionWord) { 5920b57cec5SDimitry Andric // FIXME: We should be able to split unwind info into multiple sections. 5930b57cec5SDimitry Andric // FIXME: We should share epilog codes across epilogs, where possible, 5940b57cec5SDimitry Andric // which would make this issue show up less frequently. 5950b57cec5SDimitry Andric if (CodeWords > 0xFF || EpilogCount > 0xFFFF) 5960b57cec5SDimitry Andric report_fatal_error("SEH unwind data splitting not yet implemented"); 5970b57cec5SDimitry Andric uint32_t row2 = 0x0; 5980b57cec5SDimitry Andric row2 |= (CodeWords & 0xFF) << 16; 5990b57cec5SDimitry Andric row2 |= (EpilogCount & 0xFFFF); 600*5ffd83dbSDimitry Andric streamer.emitInt32(row2); 6010b57cec5SDimitry Andric } 6020b57cec5SDimitry Andric 6030b57cec5SDimitry Andric // Epilog Start Index, Epilog Start Offset 6040b57cec5SDimitry Andric for (auto &I : EpilogInfo) { 6050b57cec5SDimitry Andric MCSymbol *EpilogStart = I.first; 6060b57cec5SDimitry Andric uint32_t EpilogIndex = I.second; 6070b57cec5SDimitry Andric uint32_t EpilogOffset = 6080b57cec5SDimitry Andric (uint32_t)GetAbsDifference(streamer, EpilogStart, info->Begin); 6090b57cec5SDimitry Andric if (EpilogOffset) 6100b57cec5SDimitry Andric EpilogOffset /= 4; 6110b57cec5SDimitry Andric uint32_t row3 = EpilogOffset; 6120b57cec5SDimitry Andric row3 |= (EpilogIndex & 0x3FF) << 22; 613*5ffd83dbSDimitry Andric streamer.emitInt32(row3); 6140b57cec5SDimitry Andric } 6150b57cec5SDimitry Andric 6160b57cec5SDimitry Andric // Emit prolog unwind instructions (in reverse order). 6170b57cec5SDimitry Andric uint8_t numInst = info->Instructions.size(); 6180b57cec5SDimitry Andric for (uint8_t c = 0; c < numInst; ++c) { 6190b57cec5SDimitry Andric WinEH::Instruction inst = info->Instructions.back(); 6200b57cec5SDimitry Andric info->Instructions.pop_back(); 6210b57cec5SDimitry Andric ARM64EmitUnwindCode(streamer, info->Begin, inst); 6220b57cec5SDimitry Andric } 6230b57cec5SDimitry Andric 6240b57cec5SDimitry Andric // Emit epilog unwind instructions 6250b57cec5SDimitry Andric for (auto &I : info->EpilogMap) { 6260b57cec5SDimitry Andric auto &EpilogInstrs = I.second; 6270b57cec5SDimitry Andric for (uint32_t i = 0; i < EpilogInstrs.size(); i++) { 6280b57cec5SDimitry Andric WinEH::Instruction inst = EpilogInstrs[i]; 6290b57cec5SDimitry Andric ARM64EmitUnwindCode(streamer, info->Begin, inst); 6300b57cec5SDimitry Andric } 6310b57cec5SDimitry Andric } 6320b57cec5SDimitry Andric 6330b57cec5SDimitry Andric int32_t BytesMod = CodeWords * 4 - TotalCodeBytes; 6340b57cec5SDimitry Andric assert(BytesMod >= 0); 6350b57cec5SDimitry Andric for (int i = 0; i < BytesMod; i++) 636*5ffd83dbSDimitry Andric streamer.emitInt8(0xE3); 6370b57cec5SDimitry Andric 6380b57cec5SDimitry Andric if (info->HandlesExceptions) 639*5ffd83dbSDimitry Andric streamer.emitValue( 6400b57cec5SDimitry Andric MCSymbolRefExpr::create(info->ExceptionHandler, 6410b57cec5SDimitry Andric MCSymbolRefExpr::VK_COFF_IMGREL32, context), 6420b57cec5SDimitry Andric 4); 6430b57cec5SDimitry Andric } 6440b57cec5SDimitry Andric 6450b57cec5SDimitry Andric static void ARM64EmitRuntimeFunction(MCStreamer &streamer, 6460b57cec5SDimitry Andric const WinEH::FrameInfo *info) { 6470b57cec5SDimitry Andric MCContext &context = streamer.getContext(); 6480b57cec5SDimitry Andric 649*5ffd83dbSDimitry Andric streamer.emitValueToAlignment(4); 6500b57cec5SDimitry Andric EmitSymbolRefWithOfs(streamer, info->Function, info->Begin); 651*5ffd83dbSDimitry Andric streamer.emitValue(MCSymbolRefExpr::create(info->Symbol, 6520b57cec5SDimitry Andric MCSymbolRefExpr::VK_COFF_IMGREL32, 6530b57cec5SDimitry Andric context), 6540b57cec5SDimitry Andric 4); 6550b57cec5SDimitry Andric } 6560b57cec5SDimitry Andric 6570b57cec5SDimitry Andric void llvm::Win64EH::ARM64UnwindEmitter::Emit(MCStreamer &Streamer) const { 6580b57cec5SDimitry Andric // Emit the unwind info structs first. 6590b57cec5SDimitry Andric for (const auto &CFI : Streamer.getWinFrameInfos()) { 6600b57cec5SDimitry Andric MCSection *XData = Streamer.getAssociatedXDataSection(CFI->TextSection); 6610b57cec5SDimitry Andric Streamer.SwitchSection(XData); 6620b57cec5SDimitry Andric ARM64EmitUnwindInfo(Streamer, CFI.get()); 6630b57cec5SDimitry Andric } 6640b57cec5SDimitry Andric 6650b57cec5SDimitry Andric // Now emit RUNTIME_FUNCTION entries. 6660b57cec5SDimitry Andric for (const auto &CFI : Streamer.getWinFrameInfos()) { 6670b57cec5SDimitry Andric MCSection *PData = Streamer.getAssociatedPDataSection(CFI->TextSection); 6680b57cec5SDimitry Andric Streamer.SwitchSection(PData); 6690b57cec5SDimitry Andric ARM64EmitRuntimeFunction(Streamer, CFI.get()); 6700b57cec5SDimitry Andric } 6710b57cec5SDimitry Andric } 6720b57cec5SDimitry Andric 6730b57cec5SDimitry Andric void llvm::Win64EH::ARM64UnwindEmitter::EmitUnwindInfo( 6740b57cec5SDimitry Andric MCStreamer &Streamer, WinEH::FrameInfo *info) const { 6750b57cec5SDimitry Andric // Switch sections (the static function above is meant to be called from 6760b57cec5SDimitry Andric // here and from Emit(). 6770b57cec5SDimitry Andric MCSection *XData = Streamer.getAssociatedXDataSection(info->TextSection); 6780b57cec5SDimitry Andric Streamer.SwitchSection(XData); 6790b57cec5SDimitry Andric ARM64EmitUnwindInfo(Streamer, info); 6800b57cec5SDimitry Andric } 681