OSDN Git Service

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