1 //===- lib/MC/MCWin64EH.cpp - MCWin64EH implementation --------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "llvm/MC/MCWin64EH.h" 11 #include "llvm/ADT/Twine.h" 12 #include "llvm/MC/MCContext.h" 13 #include "llvm/MC/MCExpr.h" 14 #include "llvm/MC/MCObjectFileInfo.h" 15 #include "llvm/MC/MCObjectStreamer.h" 16 #include "llvm/MC/MCSectionCOFF.h" 17 #include "llvm/MC/MCStreamer.h" 18 #include "llvm/MC/MCSymbol.h" 19 #include "llvm/Support/Win64EH.h" 20 21 using namespace llvm; 22 23 // NOTE: All relocations generated here are 4-byte image-relative. 24 25 static uint8_t CountOfUnwindCodes(std::vector<WinEH::Instruction> &Insns) { 26 uint8_t Count = 0; 27 for (const auto &I : Insns) { 28 switch (static_cast<Win64EH::UnwindOpcodes>(I.Operation)) { 29 default: 30 llvm_unreachable("Unsupported unwind code"); 31 case Win64EH::UOP_PushNonVol: 32 case Win64EH::UOP_AllocSmall: 33 case Win64EH::UOP_SetFPReg: 34 case Win64EH::UOP_PushMachFrame: 35 Count += 1; 36 break; 37 case Win64EH::UOP_SaveNonVol: 38 case Win64EH::UOP_SaveXMM128: 39 Count += 2; 40 break; 41 case Win64EH::UOP_SaveNonVolBig: 42 case Win64EH::UOP_SaveXMM128Big: 43 Count += 3; 44 break; 45 case Win64EH::UOP_AllocLarge: 46 Count += (I.Offset > 512 * 1024 - 8) ? 3 : 2; 47 break; 48 } 49 } 50 return Count; 51 } 52 53 static void EmitAbsDifference(MCStreamer &Streamer, const MCSymbol *LHS, 54 const MCSymbol *RHS) { 55 MCContext &Context = Streamer.getContext(); 56 const MCExpr *Diff = 57 MCBinaryExpr::createSub(MCSymbolRefExpr::create(LHS, Context), 58 MCSymbolRefExpr::create(RHS, Context), Context); 59 Streamer.EmitValue(Diff, 1); 60 } 61 62 static void EmitUnwindCode(MCStreamer &streamer, const MCSymbol *begin, 63 WinEH::Instruction &inst) { 64 uint8_t b2; 65 uint16_t w; 66 b2 = (inst.Operation & 0x0F); 67 switch (static_cast<Win64EH::UnwindOpcodes>(inst.Operation)) { 68 default: 69 llvm_unreachable("Unsupported unwind code"); 70 case Win64EH::UOP_PushNonVol: 71 EmitAbsDifference(streamer, inst.Label, begin); 72 b2 |= (inst.Register & 0x0F) << 4; 73 streamer.EmitIntValue(b2, 1); 74 break; 75 case Win64EH::UOP_AllocLarge: 76 EmitAbsDifference(streamer, inst.Label, begin); 77 if (inst.Offset > 512 * 1024 - 8) { 78 b2 |= 0x10; 79 streamer.EmitIntValue(b2, 1); 80 w = inst.Offset & 0xFFF8; 81 streamer.EmitIntValue(w, 2); 82 w = inst.Offset >> 16; 83 } else { 84 streamer.EmitIntValue(b2, 1); 85 w = inst.Offset >> 3; 86 } 87 streamer.EmitIntValue(w, 2); 88 break; 89 case Win64EH::UOP_AllocSmall: 90 b2 |= (((inst.Offset - 8) >> 3) & 0x0F) << 4; 91 EmitAbsDifference(streamer, inst.Label, begin); 92 streamer.EmitIntValue(b2, 1); 93 break; 94 case Win64EH::UOP_SetFPReg: 95 EmitAbsDifference(streamer, inst.Label, begin); 96 streamer.EmitIntValue(b2, 1); 97 break; 98 case Win64EH::UOP_SaveNonVol: 99 case Win64EH::UOP_SaveXMM128: 100 b2 |= (inst.Register & 0x0F) << 4; 101 EmitAbsDifference(streamer, inst.Label, begin); 102 streamer.EmitIntValue(b2, 1); 103 w = inst.Offset >> 3; 104 if (inst.Operation == Win64EH::UOP_SaveXMM128) 105 w >>= 1; 106 streamer.EmitIntValue(w, 2); 107 break; 108 case Win64EH::UOP_SaveNonVolBig: 109 case Win64EH::UOP_SaveXMM128Big: 110 b2 |= (inst.Register & 0x0F) << 4; 111 EmitAbsDifference(streamer, inst.Label, begin); 112 streamer.EmitIntValue(b2, 1); 113 if (inst.Operation == Win64EH::UOP_SaveXMM128Big) 114 w = inst.Offset & 0xFFF0; 115 else 116 w = inst.Offset & 0xFFF8; 117 streamer.EmitIntValue(w, 2); 118 w = inst.Offset >> 16; 119 streamer.EmitIntValue(w, 2); 120 break; 121 case Win64EH::UOP_PushMachFrame: 122 if (inst.Offset == 1) 123 b2 |= 0x10; 124 EmitAbsDifference(streamer, inst.Label, begin); 125 streamer.EmitIntValue(b2, 1); 126 break; 127 } 128 } 129 130 static void EmitSymbolRefWithOfs(MCStreamer &streamer, 131 const MCSymbol *Base, 132 const MCSymbol *Other) { 133 MCContext &Context = streamer.getContext(); 134 const MCSymbolRefExpr *BaseRef = MCSymbolRefExpr::create(Base, Context); 135 const MCSymbolRefExpr *OtherRef = MCSymbolRefExpr::create(Other, Context); 136 const MCExpr *Ofs = MCBinaryExpr::createSub(OtherRef, BaseRef, Context); 137 const MCSymbolRefExpr *BaseRefRel = MCSymbolRefExpr::create(Base, 138 MCSymbolRefExpr::VK_COFF_IMGREL32, 139 Context); 140 streamer.EmitValue(MCBinaryExpr::createAdd(BaseRefRel, Ofs, Context), 4); 141 } 142 143 static void EmitRuntimeFunction(MCStreamer &streamer, 144 const WinEH::FrameInfo *info) { 145 MCContext &context = streamer.getContext(); 146 147 streamer.EmitValueToAlignment(4); 148 EmitSymbolRefWithOfs(streamer, info->Function, info->Begin); 149 EmitSymbolRefWithOfs(streamer, info->Function, info->End); 150 streamer.EmitValue(MCSymbolRefExpr::create(info->Symbol, 151 MCSymbolRefExpr::VK_COFF_IMGREL32, 152 context), 4); 153 } 154 155 static void EmitUnwindInfo(MCStreamer &streamer, WinEH::FrameInfo *info) { 156 // If this UNWIND_INFO already has a symbol, it's already been emitted. 157 if (info->Symbol) 158 return; 159 160 MCContext &context = streamer.getContext(); 161 MCSymbol *Label = context.createTempSymbol(); 162 163 streamer.EmitValueToAlignment(4); 164 streamer.EmitLabel(Label); 165 info->Symbol = Label; 166 167 // Upper 3 bits are the version number (currently 1). 168 uint8_t flags = 0x01; 169 if (info->ChainedParent) 170 flags |= Win64EH::UNW_ChainInfo << 3; 171 else { 172 if (info->HandlesUnwind) 173 flags |= Win64EH::UNW_TerminateHandler << 3; 174 if (info->HandlesExceptions) 175 flags |= Win64EH::UNW_ExceptionHandler << 3; 176 } 177 streamer.EmitIntValue(flags, 1); 178 179 if (info->PrologEnd) 180 EmitAbsDifference(streamer, info->PrologEnd, info->Begin); 181 else 182 streamer.EmitIntValue(0, 1); 183 184 uint8_t numCodes = CountOfUnwindCodes(info->Instructions); 185 streamer.EmitIntValue(numCodes, 1); 186 187 uint8_t frame = 0; 188 if (info->LastFrameInst >= 0) { 189 WinEH::Instruction &frameInst = info->Instructions[info->LastFrameInst]; 190 assert(frameInst.Operation == Win64EH::UOP_SetFPReg); 191 frame = (frameInst.Register & 0x0F) | (frameInst.Offset & 0xF0); 192 } 193 streamer.EmitIntValue(frame, 1); 194 195 // Emit unwind instructions (in reverse order). 196 uint8_t numInst = info->Instructions.size(); 197 for (uint8_t c = 0; c < numInst; ++c) { 198 WinEH::Instruction inst = info->Instructions.back(); 199 info->Instructions.pop_back(); 200 EmitUnwindCode(streamer, info->Begin, inst); 201 } 202 203 // For alignment purposes, the instruction array will always have an even 204 // number of entries, with the final entry potentially unused (in which case 205 // the array will be one longer than indicated by the count of unwind codes 206 // field). 207 if (numCodes & 1) { 208 streamer.EmitIntValue(0, 2); 209 } 210 211 if (flags & (Win64EH::UNW_ChainInfo << 3)) 212 EmitRuntimeFunction(streamer, info->ChainedParent); 213 else if (flags & 214 ((Win64EH::UNW_TerminateHandler|Win64EH::UNW_ExceptionHandler) << 3)) 215 streamer.EmitValue(MCSymbolRefExpr::create(info->ExceptionHandler, 216 MCSymbolRefExpr::VK_COFF_IMGREL32, 217 context), 4); 218 else if (numCodes == 0) { 219 // The minimum size of an UNWIND_INFO struct is 8 bytes. If we're not 220 // a chained unwind info, if there is no handler, and if there are fewer 221 // than 2 slots used in the unwind code array, we have to pad to 8 bytes. 222 streamer.EmitIntValue(0, 4); 223 } 224 } 225 226 void llvm::Win64EH::UnwindEmitter::Emit(MCStreamer &Streamer) const { 227 // Emit the unwind info structs first. 228 for (const auto &CFI : Streamer.getWinFrameInfos()) { 229 MCSection *XData = Streamer.getAssociatedXDataSection(CFI->TextSection); 230 Streamer.SwitchSection(XData); 231 ::EmitUnwindInfo(Streamer, CFI.get()); 232 } 233 234 // Now emit RUNTIME_FUNCTION entries. 235 for (const auto &CFI : Streamer.getWinFrameInfos()) { 236 MCSection *PData = Streamer.getAssociatedPDataSection(CFI->TextSection); 237 Streamer.SwitchSection(PData); 238 EmitRuntimeFunction(Streamer, CFI.get()); 239 } 240 } 241 242 void llvm::Win64EH::UnwindEmitter::EmitUnwindInfo( 243 MCStreamer &Streamer, WinEH::FrameInfo *info) const { 244 // Switch sections (the static function above is meant to be called from 245 // here and from Emit(). 246 MCSection *XData = Streamer.getAssociatedXDataSection(info->TextSection); 247 Streamer.SwitchSection(XData); 248 249 ::EmitUnwindInfo(Streamer, info); 250 } 251 252 static int64_t GetAbsDifference(MCStreamer &Streamer, const MCSymbol *LHS, 253 const MCSymbol *RHS) { 254 MCContext &Context = Streamer.getContext(); 255 const MCExpr *Diff = 256 MCBinaryExpr::createSub(MCSymbolRefExpr::create(LHS, Context), 257 MCSymbolRefExpr::create(RHS, Context), Context); 258 MCObjectStreamer *OS = (MCObjectStreamer *)(&Streamer); 259 int64_t value; 260 Diff->evaluateAsAbsolute(value, OS->getAssembler()); 261 return value; 262 } 263 264 static uint32_t 265 ARM64CountOfUnwindCodes(const std::vector<WinEH::Instruction> &Insns) { 266 uint32_t Count = 0; 267 for (const auto &I : Insns) { 268 switch (static_cast<Win64EH::UnwindOpcodes>(I.Operation)) { 269 default: 270 llvm_unreachable("Unsupported ARM64 unwind code"); 271 case Win64EH::UOP_AllocSmall: 272 Count += 1; 273 break; 274 case Win64EH::UOP_AllocMedium: 275 Count += 2; 276 break; 277 case Win64EH::UOP_AllocLarge: 278 Count += 4; 279 break; 280 case Win64EH::UOP_SaveFPLRX: 281 Count += 1; 282 break; 283 case Win64EH::UOP_SaveFPLR: 284 Count += 1; 285 break; 286 case Win64EH::UOP_SaveReg: 287 Count += 2; 288 break; 289 case Win64EH::UOP_SaveRegP: 290 Count += 2; 291 break; 292 case Win64EH::UOP_SaveRegPX: 293 Count += 2; 294 break; 295 case Win64EH::UOP_SaveRegX: 296 Count += 2; 297 break; 298 case Win64EH::UOP_SaveFReg: 299 Count += 2; 300 break; 301 case Win64EH::UOP_SaveFRegP: 302 Count += 2; 303 break; 304 case Win64EH::UOP_SaveFRegX: 305 Count += 2; 306 break; 307 case Win64EH::UOP_SaveFRegPX: 308 Count += 2; 309 break; 310 case Win64EH::UOP_SetFP: 311 Count += 1; 312 break; 313 case Win64EH::UOP_AddFP: 314 Count += 2; 315 break; 316 case Win64EH::UOP_Nop: 317 Count += 1; 318 break; 319 case Win64EH::UOP_End: 320 Count += 1; 321 break; 322 } 323 } 324 return Count; 325 } 326 327 // Unwind opcode encodings and restrictions are documented at 328 // https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling 329 static void ARM64EmitUnwindCode(MCStreamer &streamer, const MCSymbol *begin, 330 WinEH::Instruction &inst) { 331 uint8_t b, reg; 332 switch (static_cast<Win64EH::UnwindOpcodes>(inst.Operation)) { 333 default: 334 llvm_unreachable("Unsupported ARM64 unwind code"); 335 case Win64EH::UOP_AllocSmall: 336 b = (inst.Offset >> 4) & 0x1F; 337 streamer.EmitIntValue(b, 1); 338 break; 339 case Win64EH::UOP_AllocMedium: { 340 uint16_t hw = (inst.Offset >> 4) & 0x7FF; 341 b = 0xC0; 342 b |= (hw >> 8); 343 streamer.EmitIntValue(b, 1); 344 b = hw & 0xFF; 345 streamer.EmitIntValue(b, 1); 346 break; 347 } 348 case Win64EH::UOP_AllocLarge: { 349 uint32_t w; 350 b = 0xE0; 351 streamer.EmitIntValue(b, 1); 352 w = inst.Offset >> 4; 353 b = (w & 0x00FF0000) >> 16; 354 streamer.EmitIntValue(b, 1); 355 b = (w & 0x0000FF00) >> 8; 356 streamer.EmitIntValue(b, 1); 357 b = w & 0x000000FF; 358 streamer.EmitIntValue(b, 1); 359 break; 360 } 361 case Win64EH::UOP_SetFP: 362 b = 0xE1; 363 streamer.EmitIntValue(b, 1); 364 break; 365 case Win64EH::UOP_AddFP: 366 b = 0xE2; 367 streamer.EmitIntValue(b, 1); 368 b = (inst.Offset >> 3); 369 streamer.EmitIntValue(b, 1); 370 break; 371 case Win64EH::UOP_Nop: 372 b = 0xE3; 373 streamer.EmitIntValue(b, 1); 374 break; 375 case Win64EH::UOP_SaveFPLRX: 376 b = 0x80; 377 b |= ((inst.Offset - 1) >> 3) & 0x3F; 378 streamer.EmitIntValue(b, 1); 379 break; 380 case Win64EH::UOP_SaveFPLR: 381 b = 0x40; 382 b |= (inst.Offset >> 3) & 0x3F; 383 streamer.EmitIntValue(b, 1); 384 break; 385 case Win64EH::UOP_SaveReg: 386 assert(inst.Register >= 19 && "Saved reg must be >= 19"); 387 reg = inst.Register - 19; 388 b = 0xD0 | ((reg & 0xC) >> 2); 389 streamer.EmitIntValue(b, 1); 390 b = ((reg & 0x3) << 6) | (inst.Offset >> 3); 391 streamer.EmitIntValue(b, 1); 392 break; 393 case Win64EH::UOP_SaveRegX: 394 assert(inst.Register >= 19 && "Saved reg must be >= 19"); 395 reg = inst.Register - 19; 396 b = 0xD4 | ((reg & 0x8) >> 3); 397 streamer.EmitIntValue(b, 1); 398 b = ((reg & 0x7) << 5) | ((inst.Offset >> 3) - 1); 399 streamer.EmitIntValue(b, 1); 400 break; 401 case Win64EH::UOP_SaveRegP: 402 assert(inst.Register >= 19 && "Saved registers must be >= 19"); 403 reg = inst.Register - 19; 404 b = 0xC8 | ((reg & 0xC) >> 2); 405 streamer.EmitIntValue(b, 1); 406 b = ((reg & 0x3) << 6) | (inst.Offset >> 3); 407 streamer.EmitIntValue(b, 1); 408 break; 409 case Win64EH::UOP_SaveRegPX: 410 assert(inst.Register >= 19 && "Saved registers must be >= 19"); 411 reg = inst.Register - 19; 412 b = 0xCC | ((reg & 0xC) >> 2); 413 streamer.EmitIntValue(b, 1); 414 b = ((reg & 0x3) << 6) | ((inst.Offset >> 3) - 1); 415 streamer.EmitIntValue(b, 1); 416 break; 417 case Win64EH::UOP_SaveFReg: 418 assert(inst.Register >= 8 && "Saved dreg must be >= 8"); 419 reg = inst.Register - 8; 420 b = 0xDC | ((reg & 0x4) >> 2); 421 streamer.EmitIntValue(b, 1); 422 b = ((reg & 0x3) << 6) | (inst.Offset >> 3); 423 streamer.EmitIntValue(b, 1); 424 break; 425 case Win64EH::UOP_SaveFRegX: 426 assert(inst.Register >= 8 && "Saved dreg must be >= 8"); 427 reg = inst.Register - 8; 428 b = 0xDE; 429 streamer.EmitIntValue(b, 1); 430 b = ((reg & 0x7) << 5) | ((inst.Offset >> 3) - 1); 431 streamer.EmitIntValue(b, 1); 432 break; 433 case Win64EH::UOP_SaveFRegP: 434 assert(inst.Register >= 8 && "Saved dregs must be >= 8"); 435 reg = inst.Register - 8; 436 b = 0xD8 | ((reg & 0x4) >> 2); 437 streamer.EmitIntValue(b, 1); 438 b = ((reg & 0x3) << 6) | (inst.Offset >> 3); 439 streamer.EmitIntValue(b, 1); 440 break; 441 case Win64EH::UOP_SaveFRegPX: 442 assert(inst.Register >= 8 && "Saved dregs must be >= 8"); 443 reg = inst.Register - 8; 444 b = 0xDA | ((reg & 0x4) >> 2); 445 streamer.EmitIntValue(b, 1); 446 b = ((reg & 0x3) << 6) | ((inst.Offset >> 3) - 1); 447 streamer.EmitIntValue(b, 1); 448 break; 449 case Win64EH::UOP_End: 450 b = 0xE4; 451 streamer.EmitIntValue(b, 1); 452 break; 453 } 454 } 455 456 // Populate the .xdata section. The format of .xdata on ARM64 is documented at 457 // https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling 458 static void ARM64EmitUnwindInfo(MCStreamer &streamer, WinEH::FrameInfo *info) { 459 // If this UNWIND_INFO already has a symbol, it's already been emitted. 460 if (info->Symbol) 461 return; 462 463 MCContext &context = streamer.getContext(); 464 MCSymbol *Label = context.createTempSymbol(); 465 466 streamer.EmitValueToAlignment(4); 467 streamer.EmitLabel(Label); 468 info->Symbol = Label; 469 470 uint32_t FuncLength = 0x0; 471 FuncLength = (uint32_t)GetAbsDifference(streamer, info->FuncletOrFuncEnd, 472 info->Begin); 473 if (FuncLength) 474 FuncLength /= 4; 475 uint32_t PrologCodeBytes = ARM64CountOfUnwindCodes(info->Instructions); 476 uint32_t TotalCodeBytes = PrologCodeBytes; 477 478 // Process epilogs. 479 MapVector<MCSymbol *, uint32_t> EpilogInfo; 480 for (auto &I : info->EpilogMap) { 481 MCSymbol *EpilogStart = I.first; 482 auto &EpilogInstrs = I.second; 483 uint32_t CodeBytes = ARM64CountOfUnwindCodes(EpilogInstrs); 484 EpilogInfo[EpilogStart] = TotalCodeBytes; 485 TotalCodeBytes += CodeBytes; 486 } 487 488 // Code Words, Epilog count, E, X, Vers, Function Length 489 uint32_t row1 = 0x0; 490 uint8_t CodeWords = TotalCodeBytes / 4; 491 uint8_t CodeWordsMod = TotalCodeBytes % 4; 492 if (CodeWordsMod) 493 CodeWords++; 494 uint32_t EpilogCount = info->EpilogMap.size(); 495 bool ExtensionWord = EpilogCount > 31 || TotalCodeBytes > 124; 496 if (!ExtensionWord) { 497 row1 |= (EpilogCount & 0x1F) << 22; 498 row1 |= (CodeWords & 0x1F) << 27; 499 } 500 // E is always 0 right now, TODO: packed epilog setup 501 if (info->HandlesExceptions) // X 502 row1 |= 1 << 20; 503 row1 |= FuncLength & 0x3FFFF; 504 streamer.EmitIntValue(row1, 4); 505 506 // Extended Code Words, Extended Epilog Count 507 if (ExtensionWord) { 508 uint32_t row2 = 0x0; 509 row2 |= (CodeWords & 0xFF) << 16; 510 row2 |= (EpilogCount & 0xFFFF); 511 streamer.EmitIntValue(row2, 4); 512 } 513 514 // Epilog Start Index, Epilog Start Offset 515 for (auto &I : EpilogInfo) { 516 MCSymbol *EpilogStart = I.first; 517 uint32_t EpilogIndex = I.second; 518 uint32_t EpilogOffset = 519 (uint32_t)GetAbsDifference(streamer, EpilogStart, info->Begin); 520 if (EpilogOffset) 521 EpilogOffset /= 4; 522 uint32_t row3 = EpilogOffset; 523 row3 |= (EpilogIndex & 0x3FF) << 22; 524 streamer.EmitIntValue(row3, 4); 525 } 526 527 // Emit prolog unwind instructions (in reverse order). 528 uint8_t numInst = info->Instructions.size(); 529 for (uint8_t c = 0; c < numInst; ++c) { 530 WinEH::Instruction inst = info->Instructions.back(); 531 info->Instructions.pop_back(); 532 ARM64EmitUnwindCode(streamer, info->Begin, inst); 533 } 534 535 // Emit epilog unwind instructions 536 for (auto &I : info->EpilogMap) { 537 auto &EpilogInstrs = I.second; 538 for (uint32_t i = 0; i < EpilogInstrs.size(); i++) { 539 WinEH::Instruction inst = EpilogInstrs[i]; 540 ARM64EmitUnwindCode(streamer, info->Begin, inst); 541 } 542 } 543 544 int32_t BytesMod = CodeWords * 4 - TotalCodeBytes; 545 assert(BytesMod >= 0); 546 for (int i = 0; i < BytesMod; i++) 547 streamer.EmitIntValue(0xE3, 1); 548 549 if (info->HandlesExceptions) 550 streamer.EmitValue( 551 MCSymbolRefExpr::create(info->ExceptionHandler, 552 MCSymbolRefExpr::VK_COFF_IMGREL32, context), 553 4); 554 } 555 556 static void ARM64EmitRuntimeFunction(MCStreamer &streamer, 557 const WinEH::FrameInfo *info) { 558 MCContext &context = streamer.getContext(); 559 560 streamer.EmitValueToAlignment(4); 561 EmitSymbolRefWithOfs(streamer, info->Function, info->Begin); 562 streamer.EmitValue(MCSymbolRefExpr::create(info->Symbol, 563 MCSymbolRefExpr::VK_COFF_IMGREL32, 564 context), 565 4); 566 } 567 568 void llvm::Win64EH::ARM64UnwindEmitter::Emit(MCStreamer &Streamer) const { 569 // Emit the unwind info structs first. 570 for (const auto &CFI : Streamer.getWinFrameInfos()) { 571 MCSection *XData = Streamer.getAssociatedXDataSection(CFI->TextSection); 572 Streamer.SwitchSection(XData); 573 ARM64EmitUnwindInfo(Streamer, CFI.get()); 574 } 575 576 // Now emit RUNTIME_FUNCTION entries. 577 for (const auto &CFI : Streamer.getWinFrameInfos()) { 578 MCSection *PData = Streamer.getAssociatedPDataSection(CFI->TextSection); 579 Streamer.SwitchSection(PData); 580 ARM64EmitRuntimeFunction(Streamer, CFI.get()); 581 } 582 } 583 584 void llvm::Win64EH::ARM64UnwindEmitter::EmitUnwindInfo( 585 MCStreamer &Streamer, WinEH::FrameInfo *info) const { 586 // Switch sections (the static function above is meant to be called from 587 // here and from Emit(). 588 MCSection *XData = Streamer.getAssociatedXDataSection(info->TextSection); 589 Streamer.SwitchSection(XData); 590 ARM64EmitUnwindInfo(Streamer, info); 591 } 592