1*0b57cec5SDimitry Andric //===- lib/MC/MCWin64EH.cpp - MCWin64EH implementation --------------------===// 2*0b57cec5SDimitry Andric // 3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0b57cec5SDimitry Andric // 7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 8*0b57cec5SDimitry Andric 9*0b57cec5SDimitry Andric #include "llvm/MC/MCWin64EH.h" 10*0b57cec5SDimitry Andric #include "llvm/ADT/Twine.h" 11*0b57cec5SDimitry Andric #include "llvm/MC/MCContext.h" 12*0b57cec5SDimitry Andric #include "llvm/MC/MCExpr.h" 13*0b57cec5SDimitry Andric #include "llvm/MC/MCObjectFileInfo.h" 14*0b57cec5SDimitry Andric #include "llvm/MC/MCObjectStreamer.h" 15*0b57cec5SDimitry Andric #include "llvm/MC/MCSectionCOFF.h" 16*0b57cec5SDimitry Andric #include "llvm/MC/MCStreamer.h" 17*0b57cec5SDimitry Andric #include "llvm/MC/MCSymbol.h" 18*0b57cec5SDimitry Andric #include "llvm/Support/Win64EH.h" 19*0b57cec5SDimitry Andric 20*0b57cec5SDimitry Andric using namespace llvm; 21*0b57cec5SDimitry Andric 22*0b57cec5SDimitry Andric // NOTE: All relocations generated here are 4-byte image-relative. 23*0b57cec5SDimitry Andric 24*0b57cec5SDimitry Andric static uint8_t CountOfUnwindCodes(std::vector<WinEH::Instruction> &Insns) { 25*0b57cec5SDimitry Andric uint8_t Count = 0; 26*0b57cec5SDimitry Andric for (const auto &I : Insns) { 27*0b57cec5SDimitry Andric switch (static_cast<Win64EH::UnwindOpcodes>(I.Operation)) { 28*0b57cec5SDimitry Andric default: 29*0b57cec5SDimitry Andric llvm_unreachable("Unsupported unwind code"); 30*0b57cec5SDimitry Andric case Win64EH::UOP_PushNonVol: 31*0b57cec5SDimitry Andric case Win64EH::UOP_AllocSmall: 32*0b57cec5SDimitry Andric case Win64EH::UOP_SetFPReg: 33*0b57cec5SDimitry Andric case Win64EH::UOP_PushMachFrame: 34*0b57cec5SDimitry Andric Count += 1; 35*0b57cec5SDimitry Andric break; 36*0b57cec5SDimitry Andric case Win64EH::UOP_SaveNonVol: 37*0b57cec5SDimitry Andric case Win64EH::UOP_SaveXMM128: 38*0b57cec5SDimitry Andric Count += 2; 39*0b57cec5SDimitry Andric break; 40*0b57cec5SDimitry Andric case Win64EH::UOP_SaveNonVolBig: 41*0b57cec5SDimitry Andric case Win64EH::UOP_SaveXMM128Big: 42*0b57cec5SDimitry Andric Count += 3; 43*0b57cec5SDimitry Andric break; 44*0b57cec5SDimitry Andric case Win64EH::UOP_AllocLarge: 45*0b57cec5SDimitry Andric Count += (I.Offset > 512 * 1024 - 8) ? 3 : 2; 46*0b57cec5SDimitry Andric break; 47*0b57cec5SDimitry Andric } 48*0b57cec5SDimitry Andric } 49*0b57cec5SDimitry Andric return Count; 50*0b57cec5SDimitry Andric } 51*0b57cec5SDimitry Andric 52*0b57cec5SDimitry Andric static void EmitAbsDifference(MCStreamer &Streamer, const MCSymbol *LHS, 53*0b57cec5SDimitry Andric const MCSymbol *RHS) { 54*0b57cec5SDimitry Andric MCContext &Context = Streamer.getContext(); 55*0b57cec5SDimitry Andric const MCExpr *Diff = 56*0b57cec5SDimitry Andric MCBinaryExpr::createSub(MCSymbolRefExpr::create(LHS, Context), 57*0b57cec5SDimitry Andric MCSymbolRefExpr::create(RHS, Context), Context); 58*0b57cec5SDimitry Andric Streamer.EmitValue(Diff, 1); 59*0b57cec5SDimitry Andric } 60*0b57cec5SDimitry Andric 61*0b57cec5SDimitry Andric static void EmitUnwindCode(MCStreamer &streamer, const MCSymbol *begin, 62*0b57cec5SDimitry Andric WinEH::Instruction &inst) { 63*0b57cec5SDimitry Andric uint8_t b2; 64*0b57cec5SDimitry Andric uint16_t w; 65*0b57cec5SDimitry Andric b2 = (inst.Operation & 0x0F); 66*0b57cec5SDimitry Andric switch (static_cast<Win64EH::UnwindOpcodes>(inst.Operation)) { 67*0b57cec5SDimitry Andric default: 68*0b57cec5SDimitry Andric llvm_unreachable("Unsupported unwind code"); 69*0b57cec5SDimitry Andric case Win64EH::UOP_PushNonVol: 70*0b57cec5SDimitry Andric EmitAbsDifference(streamer, inst.Label, begin); 71*0b57cec5SDimitry Andric b2 |= (inst.Register & 0x0F) << 4; 72*0b57cec5SDimitry Andric streamer.EmitIntValue(b2, 1); 73*0b57cec5SDimitry Andric break; 74*0b57cec5SDimitry Andric case Win64EH::UOP_AllocLarge: 75*0b57cec5SDimitry Andric EmitAbsDifference(streamer, inst.Label, begin); 76*0b57cec5SDimitry Andric if (inst.Offset > 512 * 1024 - 8) { 77*0b57cec5SDimitry Andric b2 |= 0x10; 78*0b57cec5SDimitry Andric streamer.EmitIntValue(b2, 1); 79*0b57cec5SDimitry Andric w = inst.Offset & 0xFFF8; 80*0b57cec5SDimitry Andric streamer.EmitIntValue(w, 2); 81*0b57cec5SDimitry Andric w = inst.Offset >> 16; 82*0b57cec5SDimitry Andric } else { 83*0b57cec5SDimitry Andric streamer.EmitIntValue(b2, 1); 84*0b57cec5SDimitry Andric w = inst.Offset >> 3; 85*0b57cec5SDimitry Andric } 86*0b57cec5SDimitry Andric streamer.EmitIntValue(w, 2); 87*0b57cec5SDimitry Andric break; 88*0b57cec5SDimitry Andric case Win64EH::UOP_AllocSmall: 89*0b57cec5SDimitry Andric b2 |= (((inst.Offset - 8) >> 3) & 0x0F) << 4; 90*0b57cec5SDimitry Andric EmitAbsDifference(streamer, inst.Label, begin); 91*0b57cec5SDimitry Andric streamer.EmitIntValue(b2, 1); 92*0b57cec5SDimitry Andric break; 93*0b57cec5SDimitry Andric case Win64EH::UOP_SetFPReg: 94*0b57cec5SDimitry Andric EmitAbsDifference(streamer, inst.Label, begin); 95*0b57cec5SDimitry Andric streamer.EmitIntValue(b2, 1); 96*0b57cec5SDimitry Andric break; 97*0b57cec5SDimitry Andric case Win64EH::UOP_SaveNonVol: 98*0b57cec5SDimitry Andric case Win64EH::UOP_SaveXMM128: 99*0b57cec5SDimitry Andric b2 |= (inst.Register & 0x0F) << 4; 100*0b57cec5SDimitry Andric EmitAbsDifference(streamer, inst.Label, begin); 101*0b57cec5SDimitry Andric streamer.EmitIntValue(b2, 1); 102*0b57cec5SDimitry Andric w = inst.Offset >> 3; 103*0b57cec5SDimitry Andric if (inst.Operation == Win64EH::UOP_SaveXMM128) 104*0b57cec5SDimitry Andric w >>= 1; 105*0b57cec5SDimitry Andric streamer.EmitIntValue(w, 2); 106*0b57cec5SDimitry Andric break; 107*0b57cec5SDimitry Andric case Win64EH::UOP_SaveNonVolBig: 108*0b57cec5SDimitry Andric case Win64EH::UOP_SaveXMM128Big: 109*0b57cec5SDimitry Andric b2 |= (inst.Register & 0x0F) << 4; 110*0b57cec5SDimitry Andric EmitAbsDifference(streamer, inst.Label, begin); 111*0b57cec5SDimitry Andric streamer.EmitIntValue(b2, 1); 112*0b57cec5SDimitry Andric if (inst.Operation == Win64EH::UOP_SaveXMM128Big) 113*0b57cec5SDimitry Andric w = inst.Offset & 0xFFF0; 114*0b57cec5SDimitry Andric else 115*0b57cec5SDimitry Andric w = inst.Offset & 0xFFF8; 116*0b57cec5SDimitry Andric streamer.EmitIntValue(w, 2); 117*0b57cec5SDimitry Andric w = inst.Offset >> 16; 118*0b57cec5SDimitry Andric streamer.EmitIntValue(w, 2); 119*0b57cec5SDimitry Andric break; 120*0b57cec5SDimitry Andric case Win64EH::UOP_PushMachFrame: 121*0b57cec5SDimitry Andric if (inst.Offset == 1) 122*0b57cec5SDimitry Andric b2 |= 0x10; 123*0b57cec5SDimitry Andric EmitAbsDifference(streamer, inst.Label, begin); 124*0b57cec5SDimitry Andric streamer.EmitIntValue(b2, 1); 125*0b57cec5SDimitry Andric break; 126*0b57cec5SDimitry Andric } 127*0b57cec5SDimitry Andric } 128*0b57cec5SDimitry Andric 129*0b57cec5SDimitry Andric static void EmitSymbolRefWithOfs(MCStreamer &streamer, 130*0b57cec5SDimitry Andric const MCSymbol *Base, 131*0b57cec5SDimitry Andric const MCSymbol *Other) { 132*0b57cec5SDimitry Andric MCContext &Context = streamer.getContext(); 133*0b57cec5SDimitry Andric const MCSymbolRefExpr *BaseRef = MCSymbolRefExpr::create(Base, Context); 134*0b57cec5SDimitry Andric const MCSymbolRefExpr *OtherRef = MCSymbolRefExpr::create(Other, Context); 135*0b57cec5SDimitry Andric const MCExpr *Ofs = MCBinaryExpr::createSub(OtherRef, BaseRef, Context); 136*0b57cec5SDimitry Andric const MCSymbolRefExpr *BaseRefRel = MCSymbolRefExpr::create(Base, 137*0b57cec5SDimitry Andric MCSymbolRefExpr::VK_COFF_IMGREL32, 138*0b57cec5SDimitry Andric Context); 139*0b57cec5SDimitry Andric streamer.EmitValue(MCBinaryExpr::createAdd(BaseRefRel, Ofs, Context), 4); 140*0b57cec5SDimitry Andric } 141*0b57cec5SDimitry Andric 142*0b57cec5SDimitry Andric static void EmitRuntimeFunction(MCStreamer &streamer, 143*0b57cec5SDimitry Andric const WinEH::FrameInfo *info) { 144*0b57cec5SDimitry Andric MCContext &context = streamer.getContext(); 145*0b57cec5SDimitry Andric 146*0b57cec5SDimitry Andric streamer.EmitValueToAlignment(4); 147*0b57cec5SDimitry Andric EmitSymbolRefWithOfs(streamer, info->Function, info->Begin); 148*0b57cec5SDimitry Andric EmitSymbolRefWithOfs(streamer, info->Function, info->End); 149*0b57cec5SDimitry Andric streamer.EmitValue(MCSymbolRefExpr::create(info->Symbol, 150*0b57cec5SDimitry Andric MCSymbolRefExpr::VK_COFF_IMGREL32, 151*0b57cec5SDimitry Andric context), 4); 152*0b57cec5SDimitry Andric } 153*0b57cec5SDimitry Andric 154*0b57cec5SDimitry Andric static void EmitUnwindInfo(MCStreamer &streamer, WinEH::FrameInfo *info) { 155*0b57cec5SDimitry Andric // If this UNWIND_INFO already has a symbol, it's already been emitted. 156*0b57cec5SDimitry Andric if (info->Symbol) 157*0b57cec5SDimitry Andric return; 158*0b57cec5SDimitry Andric 159*0b57cec5SDimitry Andric MCContext &context = streamer.getContext(); 160*0b57cec5SDimitry Andric MCSymbol *Label = context.createTempSymbol(); 161*0b57cec5SDimitry Andric 162*0b57cec5SDimitry Andric streamer.EmitValueToAlignment(4); 163*0b57cec5SDimitry Andric streamer.EmitLabel(Label); 164*0b57cec5SDimitry Andric info->Symbol = Label; 165*0b57cec5SDimitry Andric 166*0b57cec5SDimitry Andric // Upper 3 bits are the version number (currently 1). 167*0b57cec5SDimitry Andric uint8_t flags = 0x01; 168*0b57cec5SDimitry Andric if (info->ChainedParent) 169*0b57cec5SDimitry Andric flags |= Win64EH::UNW_ChainInfo << 3; 170*0b57cec5SDimitry Andric else { 171*0b57cec5SDimitry Andric if (info->HandlesUnwind) 172*0b57cec5SDimitry Andric flags |= Win64EH::UNW_TerminateHandler << 3; 173*0b57cec5SDimitry Andric if (info->HandlesExceptions) 174*0b57cec5SDimitry Andric flags |= Win64EH::UNW_ExceptionHandler << 3; 175*0b57cec5SDimitry Andric } 176*0b57cec5SDimitry Andric streamer.EmitIntValue(flags, 1); 177*0b57cec5SDimitry Andric 178*0b57cec5SDimitry Andric if (info->PrologEnd) 179*0b57cec5SDimitry Andric EmitAbsDifference(streamer, info->PrologEnd, info->Begin); 180*0b57cec5SDimitry Andric else 181*0b57cec5SDimitry Andric streamer.EmitIntValue(0, 1); 182*0b57cec5SDimitry Andric 183*0b57cec5SDimitry Andric uint8_t numCodes = CountOfUnwindCodes(info->Instructions); 184*0b57cec5SDimitry Andric streamer.EmitIntValue(numCodes, 1); 185*0b57cec5SDimitry Andric 186*0b57cec5SDimitry Andric uint8_t frame = 0; 187*0b57cec5SDimitry Andric if (info->LastFrameInst >= 0) { 188*0b57cec5SDimitry Andric WinEH::Instruction &frameInst = info->Instructions[info->LastFrameInst]; 189*0b57cec5SDimitry Andric assert(frameInst.Operation == Win64EH::UOP_SetFPReg); 190*0b57cec5SDimitry Andric frame = (frameInst.Register & 0x0F) | (frameInst.Offset & 0xF0); 191*0b57cec5SDimitry Andric } 192*0b57cec5SDimitry Andric streamer.EmitIntValue(frame, 1); 193*0b57cec5SDimitry Andric 194*0b57cec5SDimitry Andric // Emit unwind instructions (in reverse order). 195*0b57cec5SDimitry Andric uint8_t numInst = info->Instructions.size(); 196*0b57cec5SDimitry Andric for (uint8_t c = 0; c < numInst; ++c) { 197*0b57cec5SDimitry Andric WinEH::Instruction inst = info->Instructions.back(); 198*0b57cec5SDimitry Andric info->Instructions.pop_back(); 199*0b57cec5SDimitry Andric EmitUnwindCode(streamer, info->Begin, inst); 200*0b57cec5SDimitry Andric } 201*0b57cec5SDimitry Andric 202*0b57cec5SDimitry Andric // For alignment purposes, the instruction array will always have an even 203*0b57cec5SDimitry Andric // number of entries, with the final entry potentially unused (in which case 204*0b57cec5SDimitry Andric // the array will be one longer than indicated by the count of unwind codes 205*0b57cec5SDimitry Andric // field). 206*0b57cec5SDimitry Andric if (numCodes & 1) { 207*0b57cec5SDimitry Andric streamer.EmitIntValue(0, 2); 208*0b57cec5SDimitry Andric } 209*0b57cec5SDimitry Andric 210*0b57cec5SDimitry Andric if (flags & (Win64EH::UNW_ChainInfo << 3)) 211*0b57cec5SDimitry Andric EmitRuntimeFunction(streamer, info->ChainedParent); 212*0b57cec5SDimitry Andric else if (flags & 213*0b57cec5SDimitry Andric ((Win64EH::UNW_TerminateHandler|Win64EH::UNW_ExceptionHandler) << 3)) 214*0b57cec5SDimitry Andric streamer.EmitValue(MCSymbolRefExpr::create(info->ExceptionHandler, 215*0b57cec5SDimitry Andric MCSymbolRefExpr::VK_COFF_IMGREL32, 216*0b57cec5SDimitry Andric context), 4); 217*0b57cec5SDimitry Andric else if (numCodes == 0) { 218*0b57cec5SDimitry Andric // The minimum size of an UNWIND_INFO struct is 8 bytes. If we're not 219*0b57cec5SDimitry Andric // a chained unwind info, if there is no handler, and if there are fewer 220*0b57cec5SDimitry Andric // than 2 slots used in the unwind code array, we have to pad to 8 bytes. 221*0b57cec5SDimitry Andric streamer.EmitIntValue(0, 4); 222*0b57cec5SDimitry Andric } 223*0b57cec5SDimitry Andric } 224*0b57cec5SDimitry Andric 225*0b57cec5SDimitry Andric void llvm::Win64EH::UnwindEmitter::Emit(MCStreamer &Streamer) const { 226*0b57cec5SDimitry Andric // Emit the unwind info structs first. 227*0b57cec5SDimitry Andric for (const auto &CFI : Streamer.getWinFrameInfos()) { 228*0b57cec5SDimitry Andric MCSection *XData = Streamer.getAssociatedXDataSection(CFI->TextSection); 229*0b57cec5SDimitry Andric Streamer.SwitchSection(XData); 230*0b57cec5SDimitry Andric ::EmitUnwindInfo(Streamer, CFI.get()); 231*0b57cec5SDimitry Andric } 232*0b57cec5SDimitry Andric 233*0b57cec5SDimitry Andric // Now emit RUNTIME_FUNCTION entries. 234*0b57cec5SDimitry Andric for (const auto &CFI : Streamer.getWinFrameInfos()) { 235*0b57cec5SDimitry Andric MCSection *PData = Streamer.getAssociatedPDataSection(CFI->TextSection); 236*0b57cec5SDimitry Andric Streamer.SwitchSection(PData); 237*0b57cec5SDimitry Andric EmitRuntimeFunction(Streamer, CFI.get()); 238*0b57cec5SDimitry Andric } 239*0b57cec5SDimitry Andric } 240*0b57cec5SDimitry Andric 241*0b57cec5SDimitry Andric void llvm::Win64EH::UnwindEmitter::EmitUnwindInfo( 242*0b57cec5SDimitry Andric MCStreamer &Streamer, WinEH::FrameInfo *info) const { 243*0b57cec5SDimitry Andric // Switch sections (the static function above is meant to be called from 244*0b57cec5SDimitry Andric // here and from Emit(). 245*0b57cec5SDimitry Andric MCSection *XData = Streamer.getAssociatedXDataSection(info->TextSection); 246*0b57cec5SDimitry Andric Streamer.SwitchSection(XData); 247*0b57cec5SDimitry Andric 248*0b57cec5SDimitry Andric ::EmitUnwindInfo(Streamer, info); 249*0b57cec5SDimitry Andric } 250*0b57cec5SDimitry Andric 251*0b57cec5SDimitry Andric static int64_t GetAbsDifference(MCStreamer &Streamer, const MCSymbol *LHS, 252*0b57cec5SDimitry Andric const MCSymbol *RHS) { 253*0b57cec5SDimitry Andric MCContext &Context = Streamer.getContext(); 254*0b57cec5SDimitry Andric const MCExpr *Diff = 255*0b57cec5SDimitry Andric MCBinaryExpr::createSub(MCSymbolRefExpr::create(LHS, Context), 256*0b57cec5SDimitry Andric MCSymbolRefExpr::create(RHS, Context), Context); 257*0b57cec5SDimitry Andric MCObjectStreamer *OS = (MCObjectStreamer *)(&Streamer); 258*0b57cec5SDimitry Andric // It should normally be possible to calculate the length of a function 259*0b57cec5SDimitry Andric // at this point, but it might not be possible in the presence of certain 260*0b57cec5SDimitry Andric // unusual constructs, like an inline asm with an alignment directive. 261*0b57cec5SDimitry Andric int64_t value; 262*0b57cec5SDimitry Andric if (!Diff->evaluateAsAbsolute(value, OS->getAssembler())) 263*0b57cec5SDimitry Andric report_fatal_error("Failed to evaluate function length in SEH unwind info"); 264*0b57cec5SDimitry Andric return value; 265*0b57cec5SDimitry Andric } 266*0b57cec5SDimitry Andric 267*0b57cec5SDimitry Andric static uint32_t 268*0b57cec5SDimitry Andric ARM64CountOfUnwindCodes(const std::vector<WinEH::Instruction> &Insns) { 269*0b57cec5SDimitry Andric uint32_t Count = 0; 270*0b57cec5SDimitry Andric for (const auto &I : Insns) { 271*0b57cec5SDimitry Andric switch (static_cast<Win64EH::UnwindOpcodes>(I.Operation)) { 272*0b57cec5SDimitry Andric default: 273*0b57cec5SDimitry Andric llvm_unreachable("Unsupported ARM64 unwind code"); 274*0b57cec5SDimitry Andric case Win64EH::UOP_AllocSmall: 275*0b57cec5SDimitry Andric Count += 1; 276*0b57cec5SDimitry Andric break; 277*0b57cec5SDimitry Andric case Win64EH::UOP_AllocMedium: 278*0b57cec5SDimitry Andric Count += 2; 279*0b57cec5SDimitry Andric break; 280*0b57cec5SDimitry Andric case Win64EH::UOP_AllocLarge: 281*0b57cec5SDimitry Andric Count += 4; 282*0b57cec5SDimitry Andric break; 283*0b57cec5SDimitry Andric case Win64EH::UOP_SaveFPLRX: 284*0b57cec5SDimitry Andric Count += 1; 285*0b57cec5SDimitry Andric break; 286*0b57cec5SDimitry Andric case Win64EH::UOP_SaveFPLR: 287*0b57cec5SDimitry Andric Count += 1; 288*0b57cec5SDimitry Andric break; 289*0b57cec5SDimitry Andric case Win64EH::UOP_SaveReg: 290*0b57cec5SDimitry Andric Count += 2; 291*0b57cec5SDimitry Andric break; 292*0b57cec5SDimitry Andric case Win64EH::UOP_SaveRegP: 293*0b57cec5SDimitry Andric Count += 2; 294*0b57cec5SDimitry Andric break; 295*0b57cec5SDimitry Andric case Win64EH::UOP_SaveRegPX: 296*0b57cec5SDimitry Andric Count += 2; 297*0b57cec5SDimitry Andric break; 298*0b57cec5SDimitry Andric case Win64EH::UOP_SaveRegX: 299*0b57cec5SDimitry Andric Count += 2; 300*0b57cec5SDimitry Andric break; 301*0b57cec5SDimitry Andric case Win64EH::UOP_SaveFReg: 302*0b57cec5SDimitry Andric Count += 2; 303*0b57cec5SDimitry Andric break; 304*0b57cec5SDimitry Andric case Win64EH::UOP_SaveFRegP: 305*0b57cec5SDimitry Andric Count += 2; 306*0b57cec5SDimitry Andric break; 307*0b57cec5SDimitry Andric case Win64EH::UOP_SaveFRegX: 308*0b57cec5SDimitry Andric Count += 2; 309*0b57cec5SDimitry Andric break; 310*0b57cec5SDimitry Andric case Win64EH::UOP_SaveFRegPX: 311*0b57cec5SDimitry Andric Count += 2; 312*0b57cec5SDimitry Andric break; 313*0b57cec5SDimitry Andric case Win64EH::UOP_SetFP: 314*0b57cec5SDimitry Andric Count += 1; 315*0b57cec5SDimitry Andric break; 316*0b57cec5SDimitry Andric case Win64EH::UOP_AddFP: 317*0b57cec5SDimitry Andric Count += 2; 318*0b57cec5SDimitry Andric break; 319*0b57cec5SDimitry Andric case Win64EH::UOP_Nop: 320*0b57cec5SDimitry Andric Count += 1; 321*0b57cec5SDimitry Andric break; 322*0b57cec5SDimitry Andric case Win64EH::UOP_End: 323*0b57cec5SDimitry Andric Count += 1; 324*0b57cec5SDimitry Andric break; 325*0b57cec5SDimitry Andric } 326*0b57cec5SDimitry Andric } 327*0b57cec5SDimitry Andric return Count; 328*0b57cec5SDimitry Andric } 329*0b57cec5SDimitry Andric 330*0b57cec5SDimitry Andric // Unwind opcode encodings and restrictions are documented at 331*0b57cec5SDimitry Andric // https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling 332*0b57cec5SDimitry Andric static void ARM64EmitUnwindCode(MCStreamer &streamer, const MCSymbol *begin, 333*0b57cec5SDimitry Andric WinEH::Instruction &inst) { 334*0b57cec5SDimitry Andric uint8_t b, reg; 335*0b57cec5SDimitry Andric switch (static_cast<Win64EH::UnwindOpcodes>(inst.Operation)) { 336*0b57cec5SDimitry Andric default: 337*0b57cec5SDimitry Andric llvm_unreachable("Unsupported ARM64 unwind code"); 338*0b57cec5SDimitry Andric case Win64EH::UOP_AllocSmall: 339*0b57cec5SDimitry Andric b = (inst.Offset >> 4) & 0x1F; 340*0b57cec5SDimitry Andric streamer.EmitIntValue(b, 1); 341*0b57cec5SDimitry Andric break; 342*0b57cec5SDimitry Andric case Win64EH::UOP_AllocMedium: { 343*0b57cec5SDimitry Andric uint16_t hw = (inst.Offset >> 4) & 0x7FF; 344*0b57cec5SDimitry Andric b = 0xC0; 345*0b57cec5SDimitry Andric b |= (hw >> 8); 346*0b57cec5SDimitry Andric streamer.EmitIntValue(b, 1); 347*0b57cec5SDimitry Andric b = hw & 0xFF; 348*0b57cec5SDimitry Andric streamer.EmitIntValue(b, 1); 349*0b57cec5SDimitry Andric break; 350*0b57cec5SDimitry Andric } 351*0b57cec5SDimitry Andric case Win64EH::UOP_AllocLarge: { 352*0b57cec5SDimitry Andric uint32_t w; 353*0b57cec5SDimitry Andric b = 0xE0; 354*0b57cec5SDimitry Andric streamer.EmitIntValue(b, 1); 355*0b57cec5SDimitry Andric w = inst.Offset >> 4; 356*0b57cec5SDimitry Andric b = (w & 0x00FF0000) >> 16; 357*0b57cec5SDimitry Andric streamer.EmitIntValue(b, 1); 358*0b57cec5SDimitry Andric b = (w & 0x0000FF00) >> 8; 359*0b57cec5SDimitry Andric streamer.EmitIntValue(b, 1); 360*0b57cec5SDimitry Andric b = w & 0x000000FF; 361*0b57cec5SDimitry Andric streamer.EmitIntValue(b, 1); 362*0b57cec5SDimitry Andric break; 363*0b57cec5SDimitry Andric } 364*0b57cec5SDimitry Andric case Win64EH::UOP_SetFP: 365*0b57cec5SDimitry Andric b = 0xE1; 366*0b57cec5SDimitry Andric streamer.EmitIntValue(b, 1); 367*0b57cec5SDimitry Andric break; 368*0b57cec5SDimitry Andric case Win64EH::UOP_AddFP: 369*0b57cec5SDimitry Andric b = 0xE2; 370*0b57cec5SDimitry Andric streamer.EmitIntValue(b, 1); 371*0b57cec5SDimitry Andric b = (inst.Offset >> 3); 372*0b57cec5SDimitry Andric streamer.EmitIntValue(b, 1); 373*0b57cec5SDimitry Andric break; 374*0b57cec5SDimitry Andric case Win64EH::UOP_Nop: 375*0b57cec5SDimitry Andric b = 0xE3; 376*0b57cec5SDimitry Andric streamer.EmitIntValue(b, 1); 377*0b57cec5SDimitry Andric break; 378*0b57cec5SDimitry Andric case Win64EH::UOP_SaveFPLRX: 379*0b57cec5SDimitry Andric b = 0x80; 380*0b57cec5SDimitry Andric b |= ((inst.Offset - 1) >> 3) & 0x3F; 381*0b57cec5SDimitry Andric streamer.EmitIntValue(b, 1); 382*0b57cec5SDimitry Andric break; 383*0b57cec5SDimitry Andric case Win64EH::UOP_SaveFPLR: 384*0b57cec5SDimitry Andric b = 0x40; 385*0b57cec5SDimitry Andric b |= (inst.Offset >> 3) & 0x3F; 386*0b57cec5SDimitry Andric streamer.EmitIntValue(b, 1); 387*0b57cec5SDimitry Andric break; 388*0b57cec5SDimitry Andric case Win64EH::UOP_SaveReg: 389*0b57cec5SDimitry Andric assert(inst.Register >= 19 && "Saved reg must be >= 19"); 390*0b57cec5SDimitry Andric reg = inst.Register - 19; 391*0b57cec5SDimitry Andric b = 0xD0 | ((reg & 0xC) >> 2); 392*0b57cec5SDimitry Andric streamer.EmitIntValue(b, 1); 393*0b57cec5SDimitry Andric b = ((reg & 0x3) << 6) | (inst.Offset >> 3); 394*0b57cec5SDimitry Andric streamer.EmitIntValue(b, 1); 395*0b57cec5SDimitry Andric break; 396*0b57cec5SDimitry Andric case Win64EH::UOP_SaveRegX: 397*0b57cec5SDimitry Andric assert(inst.Register >= 19 && "Saved reg must be >= 19"); 398*0b57cec5SDimitry Andric reg = inst.Register - 19; 399*0b57cec5SDimitry Andric b = 0xD4 | ((reg & 0x8) >> 3); 400*0b57cec5SDimitry Andric streamer.EmitIntValue(b, 1); 401*0b57cec5SDimitry Andric b = ((reg & 0x7) << 5) | ((inst.Offset >> 3) - 1); 402*0b57cec5SDimitry Andric streamer.EmitIntValue(b, 1); 403*0b57cec5SDimitry Andric break; 404*0b57cec5SDimitry Andric case Win64EH::UOP_SaveRegP: 405*0b57cec5SDimitry Andric assert(inst.Register >= 19 && "Saved registers must be >= 19"); 406*0b57cec5SDimitry Andric reg = inst.Register - 19; 407*0b57cec5SDimitry Andric b = 0xC8 | ((reg & 0xC) >> 2); 408*0b57cec5SDimitry Andric streamer.EmitIntValue(b, 1); 409*0b57cec5SDimitry Andric b = ((reg & 0x3) << 6) | (inst.Offset >> 3); 410*0b57cec5SDimitry Andric streamer.EmitIntValue(b, 1); 411*0b57cec5SDimitry Andric break; 412*0b57cec5SDimitry Andric case Win64EH::UOP_SaveRegPX: 413*0b57cec5SDimitry Andric assert(inst.Register >= 19 && "Saved registers must be >= 19"); 414*0b57cec5SDimitry Andric reg = inst.Register - 19; 415*0b57cec5SDimitry Andric b = 0xCC | ((reg & 0xC) >> 2); 416*0b57cec5SDimitry Andric streamer.EmitIntValue(b, 1); 417*0b57cec5SDimitry Andric b = ((reg & 0x3) << 6) | ((inst.Offset >> 3) - 1); 418*0b57cec5SDimitry Andric streamer.EmitIntValue(b, 1); 419*0b57cec5SDimitry Andric break; 420*0b57cec5SDimitry Andric case Win64EH::UOP_SaveFReg: 421*0b57cec5SDimitry Andric assert(inst.Register >= 8 && "Saved dreg must be >= 8"); 422*0b57cec5SDimitry Andric reg = inst.Register - 8; 423*0b57cec5SDimitry Andric b = 0xDC | ((reg & 0x4) >> 2); 424*0b57cec5SDimitry Andric streamer.EmitIntValue(b, 1); 425*0b57cec5SDimitry Andric b = ((reg & 0x3) << 6) | (inst.Offset >> 3); 426*0b57cec5SDimitry Andric streamer.EmitIntValue(b, 1); 427*0b57cec5SDimitry Andric break; 428*0b57cec5SDimitry Andric case Win64EH::UOP_SaveFRegX: 429*0b57cec5SDimitry Andric assert(inst.Register >= 8 && "Saved dreg must be >= 8"); 430*0b57cec5SDimitry Andric reg = inst.Register - 8; 431*0b57cec5SDimitry Andric b = 0xDE; 432*0b57cec5SDimitry Andric streamer.EmitIntValue(b, 1); 433*0b57cec5SDimitry Andric b = ((reg & 0x7) << 5) | ((inst.Offset >> 3) - 1); 434*0b57cec5SDimitry Andric streamer.EmitIntValue(b, 1); 435*0b57cec5SDimitry Andric break; 436*0b57cec5SDimitry Andric case Win64EH::UOP_SaveFRegP: 437*0b57cec5SDimitry Andric assert(inst.Register >= 8 && "Saved dregs must be >= 8"); 438*0b57cec5SDimitry Andric reg = inst.Register - 8; 439*0b57cec5SDimitry Andric b = 0xD8 | ((reg & 0x4) >> 2); 440*0b57cec5SDimitry Andric streamer.EmitIntValue(b, 1); 441*0b57cec5SDimitry Andric b = ((reg & 0x3) << 6) | (inst.Offset >> 3); 442*0b57cec5SDimitry Andric streamer.EmitIntValue(b, 1); 443*0b57cec5SDimitry Andric break; 444*0b57cec5SDimitry Andric case Win64EH::UOP_SaveFRegPX: 445*0b57cec5SDimitry Andric assert(inst.Register >= 8 && "Saved dregs must be >= 8"); 446*0b57cec5SDimitry Andric reg = inst.Register - 8; 447*0b57cec5SDimitry Andric b = 0xDA | ((reg & 0x4) >> 2); 448*0b57cec5SDimitry Andric streamer.EmitIntValue(b, 1); 449*0b57cec5SDimitry Andric b = ((reg & 0x3) << 6) | ((inst.Offset >> 3) - 1); 450*0b57cec5SDimitry Andric streamer.EmitIntValue(b, 1); 451*0b57cec5SDimitry Andric break; 452*0b57cec5SDimitry Andric case Win64EH::UOP_End: 453*0b57cec5SDimitry Andric b = 0xE4; 454*0b57cec5SDimitry Andric streamer.EmitIntValue(b, 1); 455*0b57cec5SDimitry Andric break; 456*0b57cec5SDimitry Andric } 457*0b57cec5SDimitry Andric } 458*0b57cec5SDimitry Andric 459*0b57cec5SDimitry Andric // Returns the epilog symbol of an epilog with the exact same unwind code 460*0b57cec5SDimitry Andric // sequence, if it exists. Otherwise, returns nulltpr. 461*0b57cec5SDimitry Andric // EpilogInstrs - Unwind codes for the current epilog. 462*0b57cec5SDimitry Andric // Epilogs - Epilogs that potentialy match the current epilog. 463*0b57cec5SDimitry Andric static MCSymbol* 464*0b57cec5SDimitry Andric FindMatchingEpilog(const std::vector<WinEH::Instruction>& EpilogInstrs, 465*0b57cec5SDimitry Andric const std::vector<MCSymbol *>& Epilogs, 466*0b57cec5SDimitry Andric const WinEH::FrameInfo *info) { 467*0b57cec5SDimitry Andric for (auto *EpilogStart : Epilogs) { 468*0b57cec5SDimitry Andric auto InstrsIter = info->EpilogMap.find(EpilogStart); 469*0b57cec5SDimitry Andric assert(InstrsIter != info->EpilogMap.end() && 470*0b57cec5SDimitry Andric "Epilog not found in EpilogMap"); 471*0b57cec5SDimitry Andric const auto &Instrs = InstrsIter->second; 472*0b57cec5SDimitry Andric 473*0b57cec5SDimitry Andric if (Instrs.size() != EpilogInstrs.size()) 474*0b57cec5SDimitry Andric continue; 475*0b57cec5SDimitry Andric 476*0b57cec5SDimitry Andric bool Match = true; 477*0b57cec5SDimitry Andric for (unsigned i = 0; i < Instrs.size(); ++i) 478*0b57cec5SDimitry Andric if (Instrs[i].Operation != EpilogInstrs[i].Operation || 479*0b57cec5SDimitry Andric Instrs[i].Offset != EpilogInstrs[i].Offset || 480*0b57cec5SDimitry Andric Instrs[i].Register != EpilogInstrs[i].Register) { 481*0b57cec5SDimitry Andric Match = false; 482*0b57cec5SDimitry Andric break; 483*0b57cec5SDimitry Andric } 484*0b57cec5SDimitry Andric 485*0b57cec5SDimitry Andric if (Match) 486*0b57cec5SDimitry Andric return EpilogStart; 487*0b57cec5SDimitry Andric } 488*0b57cec5SDimitry Andric return nullptr; 489*0b57cec5SDimitry Andric } 490*0b57cec5SDimitry Andric 491*0b57cec5SDimitry Andric // Populate the .xdata section. The format of .xdata on ARM64 is documented at 492*0b57cec5SDimitry Andric // https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling 493*0b57cec5SDimitry Andric static void ARM64EmitUnwindInfo(MCStreamer &streamer, WinEH::FrameInfo *info) { 494*0b57cec5SDimitry Andric // If this UNWIND_INFO already has a symbol, it's already been emitted. 495*0b57cec5SDimitry Andric if (info->Symbol) 496*0b57cec5SDimitry Andric return; 497*0b57cec5SDimitry Andric 498*0b57cec5SDimitry Andric MCContext &context = streamer.getContext(); 499*0b57cec5SDimitry Andric MCSymbol *Label = context.createTempSymbol(); 500*0b57cec5SDimitry Andric 501*0b57cec5SDimitry Andric streamer.EmitValueToAlignment(4); 502*0b57cec5SDimitry Andric streamer.EmitLabel(Label); 503*0b57cec5SDimitry Andric info->Symbol = Label; 504*0b57cec5SDimitry Andric 505*0b57cec5SDimitry Andric int64_t RawFuncLength; 506*0b57cec5SDimitry Andric if (!info->FuncletOrFuncEnd) { 507*0b57cec5SDimitry Andric // FIXME: This is very wrong; we emit SEH data which covers zero bytes 508*0b57cec5SDimitry Andric // of code. But otherwise test/MC/AArch64/seh.s crashes. 509*0b57cec5SDimitry Andric RawFuncLength = 0; 510*0b57cec5SDimitry Andric } else { 511*0b57cec5SDimitry Andric // FIXME: GetAbsDifference tries to compute the length of the function 512*0b57cec5SDimitry Andric // immediately, before the whole file is emitted, but in general 513*0b57cec5SDimitry Andric // that's impossible: the size in bytes of certain assembler directives 514*0b57cec5SDimitry Andric // like .align and .fill is not known until the whole file is parsed and 515*0b57cec5SDimitry Andric // relaxations are applied. Currently, GetAbsDifference fails with a fatal 516*0b57cec5SDimitry Andric // error in that case. (We mostly don't hit this because inline assembly 517*0b57cec5SDimitry Andric // specifying those directives is rare, and we don't normally try to 518*0b57cec5SDimitry Andric // align loops on AArch64.) 519*0b57cec5SDimitry Andric // 520*0b57cec5SDimitry Andric // There are two potential approaches to delaying the computation. One, 521*0b57cec5SDimitry Andric // we could emit something like ".word (endfunc-beginfunc)/4+0x10800000", 522*0b57cec5SDimitry Andric // as long as we have some conservative estimate we could use to prove 523*0b57cec5SDimitry Andric // that we don't need to split the unwind data. Emitting the constant 524*0b57cec5SDimitry Andric // is straightforward, but there's no existing code for estimating the 525*0b57cec5SDimitry Andric // size of the function. 526*0b57cec5SDimitry Andric // 527*0b57cec5SDimitry Andric // The other approach would be to use a dedicated, relaxable fragment, 528*0b57cec5SDimitry Andric // which could grow to accommodate splitting the unwind data if 529*0b57cec5SDimitry Andric // necessary. This is more straightforward, since it automatically works 530*0b57cec5SDimitry Andric // without any new infrastructure, and it's consistent with how we handle 531*0b57cec5SDimitry Andric // relaxation in other contexts. But it would require some refactoring 532*0b57cec5SDimitry Andric // to move parts of the pdata/xdata emission into the implementation of 533*0b57cec5SDimitry Andric // a fragment. We could probably continue to encode the unwind codes 534*0b57cec5SDimitry Andric // here, but we'd have to emit the pdata, the xdata header, and the 535*0b57cec5SDimitry Andric // epilogue scopes later, since they depend on whether the we need to 536*0b57cec5SDimitry Andric // split the unwind data. 537*0b57cec5SDimitry Andric RawFuncLength = GetAbsDifference(streamer, info->FuncletOrFuncEnd, 538*0b57cec5SDimitry Andric info->Begin); 539*0b57cec5SDimitry Andric } 540*0b57cec5SDimitry Andric if (RawFuncLength > 0xFFFFF) 541*0b57cec5SDimitry Andric report_fatal_error("SEH unwind data splitting not yet implemented"); 542*0b57cec5SDimitry Andric uint32_t FuncLength = (uint32_t)RawFuncLength / 4; 543*0b57cec5SDimitry Andric uint32_t PrologCodeBytes = ARM64CountOfUnwindCodes(info->Instructions); 544*0b57cec5SDimitry Andric uint32_t TotalCodeBytes = PrologCodeBytes; 545*0b57cec5SDimitry Andric 546*0b57cec5SDimitry Andric // Process epilogs. 547*0b57cec5SDimitry Andric MapVector<MCSymbol *, uint32_t> EpilogInfo; 548*0b57cec5SDimitry Andric // Epilogs processed so far. 549*0b57cec5SDimitry Andric std::vector<MCSymbol *> AddedEpilogs; 550*0b57cec5SDimitry Andric 551*0b57cec5SDimitry Andric for (auto &I : info->EpilogMap) { 552*0b57cec5SDimitry Andric MCSymbol *EpilogStart = I.first; 553*0b57cec5SDimitry Andric auto &EpilogInstrs = I.second; 554*0b57cec5SDimitry Andric uint32_t CodeBytes = ARM64CountOfUnwindCodes(EpilogInstrs); 555*0b57cec5SDimitry Andric 556*0b57cec5SDimitry Andric MCSymbol* MatchingEpilog = 557*0b57cec5SDimitry Andric FindMatchingEpilog(EpilogInstrs, AddedEpilogs, info); 558*0b57cec5SDimitry Andric if (MatchingEpilog) { 559*0b57cec5SDimitry Andric assert(EpilogInfo.find(MatchingEpilog) != EpilogInfo.end() && 560*0b57cec5SDimitry Andric "Duplicate epilog not found"); 561*0b57cec5SDimitry Andric EpilogInfo[EpilogStart] = EpilogInfo.lookup(MatchingEpilog); 562*0b57cec5SDimitry Andric // Clear the unwind codes in the EpilogMap, so that they don't get output 563*0b57cec5SDimitry Andric // in the logic below. 564*0b57cec5SDimitry Andric EpilogInstrs.clear(); 565*0b57cec5SDimitry Andric } else { 566*0b57cec5SDimitry Andric EpilogInfo[EpilogStart] = TotalCodeBytes; 567*0b57cec5SDimitry Andric TotalCodeBytes += CodeBytes; 568*0b57cec5SDimitry Andric AddedEpilogs.push_back(EpilogStart); 569*0b57cec5SDimitry Andric } 570*0b57cec5SDimitry Andric } 571*0b57cec5SDimitry Andric 572*0b57cec5SDimitry Andric // Code Words, Epilog count, E, X, Vers, Function Length 573*0b57cec5SDimitry Andric uint32_t row1 = 0x0; 574*0b57cec5SDimitry Andric uint32_t CodeWords = TotalCodeBytes / 4; 575*0b57cec5SDimitry Andric uint32_t CodeWordsMod = TotalCodeBytes % 4; 576*0b57cec5SDimitry Andric if (CodeWordsMod) 577*0b57cec5SDimitry Andric CodeWords++; 578*0b57cec5SDimitry Andric uint32_t EpilogCount = info->EpilogMap.size(); 579*0b57cec5SDimitry Andric bool ExtensionWord = EpilogCount > 31 || TotalCodeBytes > 124; 580*0b57cec5SDimitry Andric if (!ExtensionWord) { 581*0b57cec5SDimitry Andric row1 |= (EpilogCount & 0x1F) << 22; 582*0b57cec5SDimitry Andric row1 |= (CodeWords & 0x1F) << 27; 583*0b57cec5SDimitry Andric } 584*0b57cec5SDimitry Andric // E is always 0 right now, TODO: packed epilog setup 585*0b57cec5SDimitry Andric if (info->HandlesExceptions) // X 586*0b57cec5SDimitry Andric row1 |= 1 << 20; 587*0b57cec5SDimitry Andric row1 |= FuncLength & 0x3FFFF; 588*0b57cec5SDimitry Andric streamer.EmitIntValue(row1, 4); 589*0b57cec5SDimitry Andric 590*0b57cec5SDimitry Andric // Extended Code Words, Extended Epilog Count 591*0b57cec5SDimitry Andric if (ExtensionWord) { 592*0b57cec5SDimitry Andric // FIXME: We should be able to split unwind info into multiple sections. 593*0b57cec5SDimitry Andric // FIXME: We should share epilog codes across epilogs, where possible, 594*0b57cec5SDimitry Andric // which would make this issue show up less frequently. 595*0b57cec5SDimitry Andric if (CodeWords > 0xFF || EpilogCount > 0xFFFF) 596*0b57cec5SDimitry Andric report_fatal_error("SEH unwind data splitting not yet implemented"); 597*0b57cec5SDimitry Andric uint32_t row2 = 0x0; 598*0b57cec5SDimitry Andric row2 |= (CodeWords & 0xFF) << 16; 599*0b57cec5SDimitry Andric row2 |= (EpilogCount & 0xFFFF); 600*0b57cec5SDimitry Andric streamer.EmitIntValue(row2, 4); 601*0b57cec5SDimitry Andric } 602*0b57cec5SDimitry Andric 603*0b57cec5SDimitry Andric // Epilog Start Index, Epilog Start Offset 604*0b57cec5SDimitry Andric for (auto &I : EpilogInfo) { 605*0b57cec5SDimitry Andric MCSymbol *EpilogStart = I.first; 606*0b57cec5SDimitry Andric uint32_t EpilogIndex = I.second; 607*0b57cec5SDimitry Andric uint32_t EpilogOffset = 608*0b57cec5SDimitry Andric (uint32_t)GetAbsDifference(streamer, EpilogStart, info->Begin); 609*0b57cec5SDimitry Andric if (EpilogOffset) 610*0b57cec5SDimitry Andric EpilogOffset /= 4; 611*0b57cec5SDimitry Andric uint32_t row3 = EpilogOffset; 612*0b57cec5SDimitry Andric row3 |= (EpilogIndex & 0x3FF) << 22; 613*0b57cec5SDimitry Andric streamer.EmitIntValue(row3, 4); 614*0b57cec5SDimitry Andric } 615*0b57cec5SDimitry Andric 616*0b57cec5SDimitry Andric // Emit prolog unwind instructions (in reverse order). 617*0b57cec5SDimitry Andric uint8_t numInst = info->Instructions.size(); 618*0b57cec5SDimitry Andric for (uint8_t c = 0; c < numInst; ++c) { 619*0b57cec5SDimitry Andric WinEH::Instruction inst = info->Instructions.back(); 620*0b57cec5SDimitry Andric info->Instructions.pop_back(); 621*0b57cec5SDimitry Andric ARM64EmitUnwindCode(streamer, info->Begin, inst); 622*0b57cec5SDimitry Andric } 623*0b57cec5SDimitry Andric 624*0b57cec5SDimitry Andric // Emit epilog unwind instructions 625*0b57cec5SDimitry Andric for (auto &I : info->EpilogMap) { 626*0b57cec5SDimitry Andric auto &EpilogInstrs = I.second; 627*0b57cec5SDimitry Andric for (uint32_t i = 0; i < EpilogInstrs.size(); i++) { 628*0b57cec5SDimitry Andric WinEH::Instruction inst = EpilogInstrs[i]; 629*0b57cec5SDimitry Andric ARM64EmitUnwindCode(streamer, info->Begin, inst); 630*0b57cec5SDimitry Andric } 631*0b57cec5SDimitry Andric } 632*0b57cec5SDimitry Andric 633*0b57cec5SDimitry Andric int32_t BytesMod = CodeWords * 4 - TotalCodeBytes; 634*0b57cec5SDimitry Andric assert(BytesMod >= 0); 635*0b57cec5SDimitry Andric for (int i = 0; i < BytesMod; i++) 636*0b57cec5SDimitry Andric streamer.EmitIntValue(0xE3, 1); 637*0b57cec5SDimitry Andric 638*0b57cec5SDimitry Andric if (info->HandlesExceptions) 639*0b57cec5SDimitry Andric streamer.EmitValue( 640*0b57cec5SDimitry Andric MCSymbolRefExpr::create(info->ExceptionHandler, 641*0b57cec5SDimitry Andric MCSymbolRefExpr::VK_COFF_IMGREL32, context), 642*0b57cec5SDimitry Andric 4); 643*0b57cec5SDimitry Andric } 644*0b57cec5SDimitry Andric 645*0b57cec5SDimitry Andric static void ARM64EmitRuntimeFunction(MCStreamer &streamer, 646*0b57cec5SDimitry Andric const WinEH::FrameInfo *info) { 647*0b57cec5SDimitry Andric MCContext &context = streamer.getContext(); 648*0b57cec5SDimitry Andric 649*0b57cec5SDimitry Andric streamer.EmitValueToAlignment(4); 650*0b57cec5SDimitry Andric EmitSymbolRefWithOfs(streamer, info->Function, info->Begin); 651*0b57cec5SDimitry Andric streamer.EmitValue(MCSymbolRefExpr::create(info->Symbol, 652*0b57cec5SDimitry Andric MCSymbolRefExpr::VK_COFF_IMGREL32, 653*0b57cec5SDimitry Andric context), 654*0b57cec5SDimitry Andric 4); 655*0b57cec5SDimitry Andric } 656*0b57cec5SDimitry Andric 657*0b57cec5SDimitry Andric void llvm::Win64EH::ARM64UnwindEmitter::Emit(MCStreamer &Streamer) const { 658*0b57cec5SDimitry Andric // Emit the unwind info structs first. 659*0b57cec5SDimitry Andric for (const auto &CFI : Streamer.getWinFrameInfos()) { 660*0b57cec5SDimitry Andric MCSection *XData = Streamer.getAssociatedXDataSection(CFI->TextSection); 661*0b57cec5SDimitry Andric Streamer.SwitchSection(XData); 662*0b57cec5SDimitry Andric ARM64EmitUnwindInfo(Streamer, CFI.get()); 663*0b57cec5SDimitry Andric } 664*0b57cec5SDimitry Andric 665*0b57cec5SDimitry Andric // Now emit RUNTIME_FUNCTION entries. 666*0b57cec5SDimitry Andric for (const auto &CFI : Streamer.getWinFrameInfos()) { 667*0b57cec5SDimitry Andric MCSection *PData = Streamer.getAssociatedPDataSection(CFI->TextSection); 668*0b57cec5SDimitry Andric Streamer.SwitchSection(PData); 669*0b57cec5SDimitry Andric ARM64EmitRuntimeFunction(Streamer, CFI.get()); 670*0b57cec5SDimitry Andric } 671*0b57cec5SDimitry Andric } 672*0b57cec5SDimitry Andric 673*0b57cec5SDimitry Andric void llvm::Win64EH::ARM64UnwindEmitter::EmitUnwindInfo( 674*0b57cec5SDimitry Andric MCStreamer &Streamer, WinEH::FrameInfo *info) const { 675*0b57cec5SDimitry Andric // Switch sections (the static function above is meant to be called from 676*0b57cec5SDimitry Andric // here and from Emit(). 677*0b57cec5SDimitry Andric MCSection *XData = Streamer.getAssociatedXDataSection(info->TextSection); 678*0b57cec5SDimitry Andric Streamer.SwitchSection(XData); 679*0b57cec5SDimitry Andric ARM64EmitUnwindInfo(Streamer, info); 680*0b57cec5SDimitry Andric } 681