LLVM 22.0.0git
MCWin64EH.cpp
Go to the documentation of this file.
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/MCAssembler.h"
12#include "llvm/MC/MCContext.h"
13#include "llvm/MC/MCExpr.h"
15#include "llvm/MC/MCStreamer.h"
16#include "llvm/MC/MCSymbol.h"
17#include "llvm/MC/MCValue.h"
19
20namespace llvm {
21class MCSection;
22
23/// MCExpr that represents the epilog unwind code in an unwind table.
25 const MCSymbol *Function;
26 const MCSymbol *FunctionEnd;
27 const MCSymbol *UnwindV2Start;
28 const MCSymbol *EpilogEnd;
29 uint8_t EpilogSize;
30 SMLoc Loc;
31
34 uint8_t EpilogSize_)
35 : Function(FrameInfo.Function), FunctionEnd(FrameInfo.FuncletOrFuncEnd),
36 UnwindV2Start(Epilog.UnwindV2Start), EpilogEnd(Epilog.End),
37 EpilogSize(EpilogSize_), Loc(Epilog.Loc) {}
38
39public:
41 create(const WinEH::FrameInfo &FrameInfo,
42 const WinEH::FrameInfo::Epilog &Epilog, uint8_t EpilogSize_,
43 MCContext &Ctx) {
44 return new (Ctx) MCUnwindV2EpilogTargetExpr(FrameInfo, Epilog, EpilogSize_);
45 }
46
47 void printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const override {
48 OS << ":epilog:";
49 UnwindV2Start->print(OS, MAI);
50 }
51
53 const MCAssembler *Asm) const override;
54
55 void visitUsedExpr(MCStreamer &Streamer) const override {
56 // Contains no sub-expressions.
57 }
58
60 return UnwindV2Start->getFragment();
61 }
62};
63}
64
65using namespace llvm;
66
67// NOTE: All relocations generated here are 4-byte image-relative.
68
69static uint8_t CountOfUnwindCodes(std::vector<WinEH::Instruction> &Insns) {
70 uint8_t Count = 0;
71 for (const auto &I : Insns) {
72 switch (static_cast<Win64EH::UnwindOpcodes>(I.Operation)) {
73 default:
74 llvm_unreachable("Unsupported unwind code");
79 Count += 1;
80 break;
83 Count += 2;
84 break;
87 Count += 3;
88 break;
90 Count += (I.Offset > 512 * 1024 - 8) ? 3 : 2;
91 break;
92 }
93 }
94 return Count;
95}
96
97static void EmitAbsDifference(MCStreamer &Streamer, const MCSymbol *LHS,
98 const MCSymbol *RHS) {
99 MCContext &Context = Streamer.getContext();
100 const MCExpr *Diff =
103 Streamer.emitValue(Diff, 1);
104}
105
106static void EmitUnwindCode(MCStreamer &streamer, const MCSymbol *begin,
107 WinEH::Instruction &inst) {
108 uint8_t b2;
109 uint16_t w;
110 b2 = (inst.Operation & 0x0F);
111 switch (static_cast<Win64EH::UnwindOpcodes>(inst.Operation)) {
112 default:
113 llvm_unreachable("Unsupported unwind code");
115 EmitAbsDifference(streamer, inst.Label, begin);
116 b2 |= (inst.Register & 0x0F) << 4;
117 streamer.emitInt8(b2);
118 break;
120 EmitAbsDifference(streamer, inst.Label, begin);
121 if (inst.Offset > 512 * 1024 - 8) {
122 b2 |= 0x10;
123 streamer.emitInt8(b2);
124 w = inst.Offset & 0xFFF8;
125 streamer.emitInt16(w);
126 w = inst.Offset >> 16;
127 } else {
128 streamer.emitInt8(b2);
129 w = inst.Offset >> 3;
130 }
131 streamer.emitInt16(w);
132 break;
134 b2 |= (((inst.Offset - 8) >> 3) & 0x0F) << 4;
135 EmitAbsDifference(streamer, inst.Label, begin);
136 streamer.emitInt8(b2);
137 break;
139 EmitAbsDifference(streamer, inst.Label, begin);
140 streamer.emitInt8(b2);
141 break;
144 b2 |= (inst.Register & 0x0F) << 4;
145 EmitAbsDifference(streamer, inst.Label, begin);
146 streamer.emitInt8(b2);
147 w = inst.Offset >> 3;
149 w >>= 1;
150 streamer.emitInt16(w);
151 break;
154 b2 |= (inst.Register & 0x0F) << 4;
155 EmitAbsDifference(streamer, inst.Label, begin);
156 streamer.emitInt8(b2);
158 w = inst.Offset & 0xFFF0;
159 else
160 w = inst.Offset & 0xFFF8;
161 streamer.emitInt16(w);
162 w = inst.Offset >> 16;
163 streamer.emitInt16(w);
164 break;
166 if (inst.Offset == 1)
167 b2 |= 0x10;
168 EmitAbsDifference(streamer, inst.Label, begin);
169 streamer.emitInt8(b2);
170 break;
171 }
172}
173
174static void EmitSymbolRefWithOfs(MCStreamer &streamer,
175 const MCSymbol *Base,
176 int64_t Offset) {
177 MCContext &Context = streamer.getContext();
179 const MCSymbolRefExpr *BaseRefRel = MCSymbolRefExpr::create(Base,
181 Context);
182 streamer.emitValue(MCBinaryExpr::createAdd(BaseRefRel, OffExpr, Context), 4);
183}
184
185static void EmitSymbolRefWithOfs(MCStreamer &streamer,
186 const MCSymbol *Base,
187 const MCSymbol *Other) {
188 MCContext &Context = streamer.getContext();
191 const MCExpr *Ofs = MCBinaryExpr::createSub(OtherRef, BaseRef, Context);
192 const MCSymbolRefExpr *BaseRefRel = MCSymbolRefExpr::create(Base,
194 Context);
195 streamer.emitValue(MCBinaryExpr::createAdd(BaseRefRel, Ofs, Context), 4);
196}
197
198static void EmitRuntimeFunction(MCStreamer &streamer,
199 const WinEH::FrameInfo *info) {
200 MCContext &context = streamer.getContext();
201
202 streamer.emitValueToAlignment(Align(4));
203 EmitSymbolRefWithOfs(streamer, info->Begin, info->Begin);
204 EmitSymbolRefWithOfs(streamer, info->Begin, info->End);
205 streamer.emitValue(MCSymbolRefExpr::create(info->Symbol,
207 context), 4);
208}
209
210static std::optional<int64_t>
211GetOptionalAbsDifference(const MCAssembler &Assembler, const MCSymbol *LHS,
212 const MCSymbol *RHS) {
213 MCContext &Context = Assembler.getContext();
214 const MCExpr *Diff =
217 // It should normally be possible to calculate the length of a function
218 // at this point, but it might not be possible in the presence of certain
219 // unusual constructs, like an inline asm with an alignment directive.
220 int64_t value;
221 if (!Diff->evaluateAsAbsolute(value, Assembler))
222 return std::nullopt;
223 return value;
224}
225
227 // If this UNWIND_INFO already has a symbol, it's already been emitted.
228 if (info->Symbol)
229 return;
230
231 MCContext &context = streamer.getContext();
232 MCObjectStreamer *OS = (MCObjectStreamer *)(&streamer);
233 MCSymbol *Label = context.createTempSymbol();
234
235 streamer.emitValueToAlignment(Align(4));
236 streamer.emitLabel(Label);
237 info->Symbol = Label;
238
239 uint8_t numCodes = CountOfUnwindCodes(info->Instructions);
240 bool LastEpilogIsAtEnd = false;
241 bool AddPaddingEpilogCode = false;
242 uint8_t EpilogSize = 0;
243 bool EnableUnwindV2 = (info->Version >= 2) && !info->EpilogMap.empty();
244 if (EnableUnwindV2) {
245 auto &LastEpilog = info->EpilogMap.back().second;
246
247 // Calculate the size of the epilogs. Note that we +1 to the size so that
248 // the terminator instruction is also included in the epilog (the Windows
249 // unwinder does a simple range check versus the current instruction pointer
250 // so, although there are terminators that are large than 1 byte, the
251 // starting address of the terminator instruction will always be considered
252 // inside the epilog).
253 auto MaybeSize = GetOptionalAbsDifference(
254 OS->getAssembler(), LastEpilog.End, LastEpilog.UnwindV2Start);
255 if (!MaybeSize) {
256 context.reportError(LastEpilog.Loc,
257 "Failed to evaluate epilog size for Unwind v2 in " +
258 info->Function->getName());
259 return;
260 }
261 assert(*MaybeSize >= 0);
262 if (*MaybeSize >= (int64_t)UINT8_MAX) {
263 context.reportError(LastEpilog.Loc,
264 "Epilog size is too large for Unwind v2 in " +
265 info->Function->getName());
266 return;
267 }
268 EpilogSize = *MaybeSize + 1;
269
270 // If the last epilog is at the end of the function, we can use a special
271 // encoding for it. Because of our +1 trick for the size, this will only
272 // work where that final terminator instruction is 1 byte long.
273 auto LastEpilogToFuncEnd = GetOptionalAbsDifference(
274 OS->getAssembler(), info->FuncletOrFuncEnd, LastEpilog.UnwindV2Start);
275 LastEpilogIsAtEnd = (LastEpilogToFuncEnd == EpilogSize);
276
277 // If we have an odd number of epilog codes, we need to add a padding code.
278 size_t numEpilogCodes =
279 info->EpilogMap.size() + (LastEpilogIsAtEnd ? 0 : 1);
280 if ((numEpilogCodes % 2) != 0) {
281 AddPaddingEpilogCode = true;
282 numEpilogCodes++;
283 }
284
285 // Too many epilogs to handle.
286 if ((size_t)numCodes + numEpilogCodes > UINT8_MAX) {
287 context.reportError(info->FunctionLoc,
288 "Too many unwind codes with Unwind v2 enabled in " +
289 info->Function->getName());
290 return;
291 }
292
293 numCodes += numEpilogCodes;
294 }
295
296 // Upper 3 bits are the version number.
297 uint8_t flags = info->Version;
298 if (info->ChainedParent)
299 flags |= Win64EH::UNW_ChainInfo << 3;
300 else {
301 if (info->HandlesUnwind)
302 flags |= Win64EH::UNW_TerminateHandler << 3;
303 if (info->HandlesExceptions)
304 flags |= Win64EH::UNW_ExceptionHandler << 3;
305 }
306 streamer.emitInt8(flags);
307
308 if (info->PrologEnd)
309 EmitAbsDifference(streamer, info->PrologEnd, info->Begin);
310 else
311 streamer.emitInt8(0);
312
313 streamer.emitInt8(numCodes);
314
315 uint8_t frame = 0;
316 if (info->LastFrameInst >= 0) {
317 WinEH::Instruction &frameInst = info->Instructions[info->LastFrameInst];
319 frame = (frameInst.Register & 0x0F) | (frameInst.Offset & 0xF0);
320 }
321 streamer.emitInt8(frame);
322
323 // Emit the epilog instructions.
324 if (EnableUnwindV2) {
325 // Ensure the fixups and appended content apply to the same fragment.
326 OS->ensureHeadroom(info->EpilogMap.size() * 2);
327
328 bool IsLast = true;
329 for (const auto &Epilog : llvm::reverse(info->EpilogMap)) {
330 if (IsLast) {
331 IsLast = false;
332 uint8_t Flags = LastEpilogIsAtEnd ? 0x01 : 0;
333 OS->emitInt8(EpilogSize);
334 OS->emitInt8((Flags << 4) | Win64EH::UOP_Epilog);
335
336 if (LastEpilogIsAtEnd)
337 continue;
338 }
339
340 // Each epilog is emitted as a fixup, since we can't measure the distance
341 // between the start of the epilog and the end of the function until
342 // layout has been completed.
344 EpilogSize, context);
345 OS->addFixup(MCE, FK_Data_2);
346 OS->appendContents(2, 0);
347 }
348 }
349 if (AddPaddingEpilogCode)
350 streamer.emitInt16(Win64EH::UOP_Epilog << 8);
351
352 // Emit unwind instructions (in reverse order).
353 uint8_t numInst = info->Instructions.size();
354 for (uint8_t c = 0; c < numInst; ++c) {
355 WinEH::Instruction inst = info->Instructions.back();
356 info->Instructions.pop_back();
357 EmitUnwindCode(streamer, info->Begin, inst);
358 }
359
360 // For alignment purposes, the instruction array will always have an even
361 // number of entries, with the final entry potentially unused (in which case
362 // the array will be one longer than indicated by the count of unwind codes
363 // field).
364 if (numCodes & 1) {
365 streamer.emitInt16(0);
366 }
367
368 if (flags & (Win64EH::UNW_ChainInfo << 3))
369 EmitRuntimeFunction(streamer, info->ChainedParent);
370 else if (flags &
372 streamer.emitValue(MCSymbolRefExpr::create(info->ExceptionHandler,
374 context), 4);
375 else if (numCodes == 0) {
376 // The minimum size of an UNWIND_INFO struct is 8 bytes. If we're not
377 // a chained unwind info, if there is no handler, and if there are fewer
378 // than 2 slots used in the unwind code array, we have to pad to 8 bytes.
379 streamer.emitInt32(0);
380 }
381}
382
384 MCValue &Res, const MCAssembler *Asm) const {
385 // Calculate the offset to this epilog, and validate it's within the allowed
386 // range.
387 auto Offset = GetOptionalAbsDifference(*Asm, FunctionEnd, UnwindV2Start);
388 if (!Offset) {
389 Asm->getContext().reportError(
390 Loc, "Failed to evaluate epilog offset for Unwind v2 in " +
391 Function->getName());
392 return false;
393 }
394 assert(*Offset > 0);
395 constexpr uint16_t MaxEpilogOffset = 0x0fff;
396 if (*Offset > MaxEpilogOffset) {
397 Asm->getContext().reportError(
398 Loc,
399 "Epilog offset is too large for Unwind v2 in " + Function->getName());
400 return false;
401 }
402
403 // Sanity check that all epilogs are the same size.
404 auto Size = GetOptionalAbsDifference(*Asm, EpilogEnd, UnwindV2Start);
405 if (Size != (EpilogSize - 1)) {
406 Asm->getContext().reportError(
407 Loc, "Size of this epilog does not match size of last epilog in " +
408 Function->getName());
409 return false;
410 }
411
412 auto HighBits = *Offset >> 8;
413 Res = MCValue::get((HighBits << 12) | (Win64EH::UOP_Epilog << 8) |
414 (*Offset & 0xFF));
415 return true;
416}
417
419 // Emit the unwind info structs first.
420 for (const auto &CFI : Streamer.getWinFrameInfos()) {
421 MCSection *XData = Streamer.getAssociatedXDataSection(CFI->TextSection);
422 Streamer.switchSection(XData);
423 ::EmitUnwindInfo(Streamer, CFI.get());
424 }
425
426 // Now emit RUNTIME_FUNCTION entries.
427 for (const auto &CFI : Streamer.getWinFrameInfos()) {
428 MCSection *PData = Streamer.getAssociatedPDataSection(CFI->TextSection);
429 Streamer.switchSection(PData);
430 EmitRuntimeFunction(Streamer, CFI.get());
431 }
432}
433
436 bool HandlerData) const {
437 // Switch sections (the static function above is meant to be called from
438 // here and from Emit().
439 MCSection *XData = Streamer.getAssociatedXDataSection(info->TextSection);
440 Streamer.switchSection(XData);
441
442 ::EmitUnwindInfo(Streamer, info);
443}
444
445static const MCExpr *GetSubDivExpr(MCStreamer &Streamer, const MCSymbol *LHS,
446 const MCSymbol *RHS, int Div) {
447 MCContext &Context = Streamer.getContext();
448 const MCExpr *Expr =
451 if (Div != 1)
453 Context);
454 return Expr;
455}
456
457static std::optional<int64_t> GetOptionalAbsDifference(MCStreamer &Streamer,
458 const MCSymbol *LHS,
459 const MCSymbol *RHS) {
460 MCObjectStreamer *OS = (MCObjectStreamer *)(&Streamer);
461 return GetOptionalAbsDifference(OS->getAssembler(), LHS, RHS);
462}
463
464static int64_t GetAbsDifference(MCStreamer &Streamer, const MCSymbol *LHS,
465 const MCSymbol *RHS) {
466 std::optional<int64_t> MaybeDiff =
467 GetOptionalAbsDifference(Streamer, LHS, RHS);
468 if (!MaybeDiff)
469 report_fatal_error("Failed to evaluate function length in SEH unwind info");
470 return *MaybeDiff;
471}
472
473static void checkARM64Instructions(MCStreamer &Streamer,
475 const MCSymbol *Begin, const MCSymbol *End,
477 if (!End)
478 return;
479 std::optional<int64_t> MaybeDistance =
480 GetOptionalAbsDifference(Streamer, End, Begin);
481 if (!MaybeDistance)
482 return;
483 uint32_t Distance = (uint32_t)*MaybeDistance;
484
485 for (const auto &I : Insns) {
486 switch (static_cast<Win64EH::UnwindOpcodes>(I.Operation)) {
487 default:
488 break;
494 // Can't reason about these opcodes and how they map to actual
495 // instructions.
496 return;
497 }
498 }
499 // Exclude the end opcode which doesn't map to an instruction.
500 uint32_t InstructionBytes = 4 * (Insns.size() - 1);
501 if (Distance != InstructionBytes) {
502 Streamer.getContext().reportError(
503 SMLoc(), "Incorrect size for " + Name + " " + Type + ": " +
504 Twine(Distance) +
505 " bytes of instructions in range, but .seh directives "
506 "corresponding to " +
507 Twine(InstructionBytes) + " bytes\n");
508 }
509}
510
512 uint32_t Count = 0;
513 for (const auto &I : Insns) {
514 switch (static_cast<Win64EH::UnwindOpcodes>(I.Operation)) {
515 default:
516 llvm_unreachable("Unsupported ARM64 unwind code");
518 Count += 1;
519 break;
521 Count += 2;
522 break;
524 Count += 4;
525 break;
527 Count += 1;
528 break;
530 Count += 1;
531 break;
533 Count += 1;
534 break;
536 Count += 2;
537 break;
539 Count += 2;
540 break;
542 Count += 2;
543 break;
545 Count += 2;
546 break;
548 Count += 2;
549 break;
551 Count += 2;
552 break;
554 Count += 2;
555 break;
557 Count += 2;
558 break;
560 Count += 2;
561 break;
563 Count += 1;
564 break;
566 Count += 2;
567 break;
568 case Win64EH::UOP_Nop:
569 Count += 1;
570 break;
571 case Win64EH::UOP_End:
572 Count += 1;
573 break;
575 Count += 1;
576 break;
578 Count += 1;
579 break;
581 Count += 1;
582 break;
584 Count += 1;
585 break;
587 Count += 1;
588 break;
590 Count += 1;
591 break;
593 Count += 1;
594 break;
596 Count += 2;
597 break;
612 Count += 3;
613 break;
614 }
615 }
616 return Count;
617}
618
619// Unwind opcode encodings and restrictions are documented at
620// https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling
621static void ARM64EmitUnwindCode(MCStreamer &streamer,
622 const WinEH::Instruction &inst) {
623 uint8_t b, reg;
624 switch (static_cast<Win64EH::UnwindOpcodes>(inst.Operation)) {
625 default:
626 llvm_unreachable("Unsupported ARM64 unwind code");
628 b = (inst.Offset >> 4) & 0x1F;
629 streamer.emitInt8(b);
630 break;
632 uint16_t hw = (inst.Offset >> 4) & 0x7FF;
633 b = 0xC0;
634 b |= (hw >> 8);
635 streamer.emitInt8(b);
636 b = hw & 0xFF;
637 streamer.emitInt8(b);
638 break;
639 }
641 uint32_t w;
642 b = 0xE0;
643 streamer.emitInt8(b);
644 w = inst.Offset >> 4;
645 b = (w & 0x00FF0000) >> 16;
646 streamer.emitInt8(b);
647 b = (w & 0x0000FF00) >> 8;
648 streamer.emitInt8(b);
649 b = w & 0x000000FF;
650 streamer.emitInt8(b);
651 break;
652 }
654 b = 0xE1;
655 streamer.emitInt8(b);
656 break;
658 b = 0xE2;
659 streamer.emitInt8(b);
660 b = (inst.Offset >> 3);
661 streamer.emitInt8(b);
662 break;
663 case Win64EH::UOP_Nop:
664 b = 0xE3;
665 streamer.emitInt8(b);
666 break;
668 b = 0x20;
669 b |= (inst.Offset >> 3) & 0x1F;
670 streamer.emitInt8(b);
671 break;
673 b = 0x80;
674 b |= ((inst.Offset - 1) >> 3) & 0x3F;
675 streamer.emitInt8(b);
676 break;
678 b = 0x40;
679 b |= (inst.Offset >> 3) & 0x3F;
680 streamer.emitInt8(b);
681 break;
683 assert(inst.Register >= 19 && "Saved reg must be >= 19");
684 reg = inst.Register - 19;
685 b = 0xD0 | ((reg & 0xC) >> 2);
686 streamer.emitInt8(b);
687 b = ((reg & 0x3) << 6) | (inst.Offset >> 3);
688 streamer.emitInt8(b);
689 break;
691 assert(inst.Register >= 19 && "Saved reg must be >= 19");
692 reg = inst.Register - 19;
693 b = 0xD4 | ((reg & 0x8) >> 3);
694 streamer.emitInt8(b);
695 b = ((reg & 0x7) << 5) | ((inst.Offset >> 3) - 1);
696 streamer.emitInt8(b);
697 break;
699 assert(inst.Register >= 19 && "Saved registers must be >= 19");
700 reg = inst.Register - 19;
701 b = 0xC8 | ((reg & 0xC) >> 2);
702 streamer.emitInt8(b);
703 b = ((reg & 0x3) << 6) | (inst.Offset >> 3);
704 streamer.emitInt8(b);
705 break;
707 assert(inst.Register >= 19 && "Saved registers must be >= 19");
708 reg = inst.Register - 19;
709 b = 0xCC | ((reg & 0xC) >> 2);
710 streamer.emitInt8(b);
711 b = ((reg & 0x3) << 6) | ((inst.Offset >> 3) - 1);
712 streamer.emitInt8(b);
713 break;
715 assert(inst.Register >= 19 && "Saved reg must be >= 19");
716 reg = inst.Register - 19;
717 assert((reg % 2) == 0 && "Saved reg must be 19+2*X");
718 reg /= 2;
719 b = 0xD6 | ((reg & 0x7) >> 2);
720 streamer.emitInt8(b);
721 b = ((reg & 0x3) << 6) | (inst.Offset >> 3);
722 streamer.emitInt8(b);
723 break;
725 assert(inst.Register >= 8 && "Saved dreg must be >= 8");
726 reg = inst.Register - 8;
727 b = 0xDC | ((reg & 0x4) >> 2);
728 streamer.emitInt8(b);
729 b = ((reg & 0x3) << 6) | (inst.Offset >> 3);
730 streamer.emitInt8(b);
731 break;
733 assert(inst.Register >= 8 && "Saved dreg must be >= 8");
734 reg = inst.Register - 8;
735 b = 0xDE;
736 streamer.emitInt8(b);
737 b = ((reg & 0x7) << 5) | ((inst.Offset >> 3) - 1);
738 streamer.emitInt8(b);
739 break;
741 assert(inst.Register >= 8 && "Saved dregs must be >= 8");
742 reg = inst.Register - 8;
743 b = 0xD8 | ((reg & 0x4) >> 2);
744 streamer.emitInt8(b);
745 b = ((reg & 0x3) << 6) | (inst.Offset >> 3);
746 streamer.emitInt8(b);
747 break;
749 assert(inst.Register >= 8 && "Saved dregs must be >= 8");
750 reg = inst.Register - 8;
751 b = 0xDA | ((reg & 0x4) >> 2);
752 streamer.emitInt8(b);
753 b = ((reg & 0x3) << 6) | ((inst.Offset >> 3) - 1);
754 streamer.emitInt8(b);
755 break;
756 case Win64EH::UOP_End:
757 b = 0xE4;
758 streamer.emitInt8(b);
759 break;
761 b = 0xE6;
762 streamer.emitInt8(b);
763 break;
765 b = 0xE8;
766 streamer.emitInt8(b);
767 break;
769 b = 0xE9;
770 streamer.emitInt8(b);
771 break;
773 b = 0xEA;
774 streamer.emitInt8(b);
775 break;
777 b = 0xEB;
778 streamer.emitInt8(b);
779 break;
781 b = 0xEC;
782 streamer.emitInt8(b);
783 break;
785 b = 0xFC;
786 streamer.emitInt8(b);
787 break;
800 // This assumes the opcodes are listed in the enum in a particular order.
802 int Writeback = Op / 6;
803 int Paired = Op % 2;
804 int Mode = (Op / 2) % 3;
805 int Offset = inst.Offset >> 3;
806 if (Writeback || Paired || Mode == 2)
807 Offset >>= 1;
808 if (Writeback)
809 --Offset;
810 b = 0xE7;
811 streamer.emitInt8(b);
812 assert(inst.Register < 32);
813 b = inst.Register | (Writeback << 5) | (Paired << 6);
814 streamer.emitInt8(b);
815 b = Offset | (Mode << 6);
816 streamer.emitInt8(b);
817 break;
818 }
819 case Win64EH::UOP_AllocZ: {
820 b = 0xDF;
821 streamer.emitInt8(b);
822 b = inst.Offset;
823 streamer.emitInt8(b);
824 break;
825 }
827 assert(inst.Register >= 8 && inst.Register <= 23);
828 assert(inst.Offset < 256);
829 b = 0xE7;
830 streamer.emitInt8(b);
831 reg = inst.Register - 8;
832 b = ((inst.Offset & 0xC0) >> 1) | reg;
833 streamer.emitInt8(b);
834 b = 0xC0 | (inst.Offset & 0x3F);
835 streamer.emitInt8(b);
836 break;
837 }
839 assert(inst.Register >= 4 && inst.Register <= 15);
840 assert(inst.Offset < 256);
841 b = 0xE7;
842 streamer.emitInt8(b);
843 reg = inst.Register;
844 b = ((inst.Offset & 0xC0) >> 1) | 0x10 | reg;
845 streamer.emitInt8(b);
846 b = 0xC0 | (inst.Offset & 0x3F);
847 streamer.emitInt8(b);
848 break;
849 }
850 }
851}
852
853// Returns the epilog symbol of an epilog with the exact same unwind code
854// sequence, if it exists. Otherwise, returns nullptr.
855// EpilogInstrs - Unwind codes for the current epilog.
856// Epilogs - Epilogs that potentialy match the current epilog.
857static MCSymbol*
858FindMatchingEpilog(const std::vector<WinEH::Instruction>& EpilogInstrs,
859 const std::vector<MCSymbol *>& Epilogs,
860 const WinEH::FrameInfo *info) {
861 for (auto *EpilogStart : Epilogs) {
862 auto InstrsIter = info->EpilogMap.find(EpilogStart);
863 assert(InstrsIter != info->EpilogMap.end() &&
864 "Epilog not found in EpilogMap");
865 const auto &Instrs = InstrsIter->second.Instructions;
866
867 if (Instrs.size() != EpilogInstrs.size())
868 continue;
869
870 bool Match = true;
871 for (unsigned i = 0; i < Instrs.size(); ++i)
872 if (Instrs[i] != EpilogInstrs[i]) {
873 Match = false;
874 break;
875 }
876
877 if (Match)
878 return EpilogStart;
879 }
880 return nullptr;
881}
882
883static void simplifyARM64Opcodes(std::vector<WinEH::Instruction> &Instructions,
884 bool Reverse) {
885 unsigned PrevOffset = -1;
886 unsigned PrevRegister = -1;
887
888 auto VisitInstruction = [&](WinEH::Instruction &Inst) {
889 // Convert 2-byte opcodes into equivalent 1-byte ones.
890 if (Inst.Operation == Win64EH::UOP_SaveRegP && Inst.Register == 29) {
891 Inst.Operation = Win64EH::UOP_SaveFPLR;
892 Inst.Register = -1;
893 } else if (Inst.Operation == Win64EH::UOP_SaveRegPX &&
894 Inst.Register == 29) {
895 Inst.Operation = Win64EH::UOP_SaveFPLRX;
896 Inst.Register = -1;
897 } else if (Inst.Operation == Win64EH::UOP_SaveRegPX &&
898 Inst.Register == 19 && Inst.Offset <= 248) {
899 Inst.Operation = Win64EH::UOP_SaveR19R20X;
900 Inst.Register = -1;
901 } else if (Inst.Operation == Win64EH::UOP_AddFP && Inst.Offset == 0) {
902 Inst.Operation = Win64EH::UOP_SetFP;
903 } else if (Inst.Operation == Win64EH::UOP_SaveRegP &&
904 Inst.Register == PrevRegister + 2 &&
905 Inst.Offset == PrevOffset + 16) {
906 Inst.Operation = Win64EH::UOP_SaveNext;
907 Inst.Register = -1;
908 Inst.Offset = 0;
909 // Intentionally not creating UOP_SaveNext for float register pairs,
910 // as current versions of Windows (up to at least 20.04) is buggy
911 // regarding SaveNext for float pairs.
912 }
913 // Update info about the previous instruction, for detecting if
914 // the next one can be made a UOP_SaveNext
915 if (Inst.Operation == Win64EH::UOP_SaveR19R20X) {
916 PrevOffset = 0;
917 PrevRegister = 19;
918 } else if (Inst.Operation == Win64EH::UOP_SaveRegPX) {
919 PrevOffset = 0;
920 PrevRegister = Inst.Register;
921 } else if (Inst.Operation == Win64EH::UOP_SaveRegP) {
922 PrevOffset = Inst.Offset;
923 PrevRegister = Inst.Register;
924 } else if (Inst.Operation == Win64EH::UOP_SaveNext) {
925 PrevRegister += 2;
926 PrevOffset += 16;
927 } else {
928 PrevRegister = -1;
929 PrevOffset = -1;
930 }
931 };
932
933 // Iterate over instructions in a forward order (for prologues),
934 // backwards for epilogues (i.e. always reverse compared to how the
935 // opcodes are stored).
936 if (Reverse) {
937 for (auto It = Instructions.rbegin(); It != Instructions.rend(); It++)
938 VisitInstruction(*It);
939 } else {
940 for (WinEH::Instruction &Inst : Instructions)
941 VisitInstruction(Inst);
942 }
943}
944
945// Check if an epilog exists as a subset of the end of a prolog (backwards).
946static int
947getARM64OffsetInProlog(const std::vector<WinEH::Instruction> &Prolog,
948 const std::vector<WinEH::Instruction> &Epilog) {
949 // Can't find an epilog as a subset if it is longer than the prolog.
950 if (Epilog.size() > Prolog.size())
951 return -1;
952
953 // Check that the epilog actually is a perfect match for the end (backwrds)
954 // of the prolog.
955 for (int I = Epilog.size() - 1; I >= 0; I--) {
956 if (Prolog[I] != Epilog[Epilog.size() - 1 - I])
957 return -1;
958 }
959
960 if (Epilog.size() == Prolog.size())
961 return 0;
962
963 // If the epilog was a subset of the prolog, find its offset.
965 &Prolog[Epilog.size()], Prolog.size() - Epilog.size()));
966}
967
970 int PrologCodeBytes) {
971 // Can only pack if there's one single epilog
972 if (Seg->Epilogs.size() != 1)
973 return -1;
974
975 MCSymbol *Sym = Seg->Epilogs.begin()->first;
976 const std::vector<WinEH::Instruction> &Epilog =
977 info->EpilogMap[Sym].Instructions;
978
979 // Check that the epilog actually is at the very end of the function,
980 // otherwise it can't be packed.
981 uint32_t DistanceFromEnd =
982 (uint32_t)(Seg->Offset + Seg->Length - Seg->Epilogs.begin()->second);
983 if (DistanceFromEnd / 4 != Epilog.size())
984 return -1;
985
986 int RetVal = -1;
987 // Even if we don't end up sharing opcodes with the prolog, we can still
988 // write the offset as a packed offset, if the single epilog is located at
989 // the end of the function and the offset (pointing after the prolog) fits
990 // as a packed offset.
991 if (PrologCodeBytes <= 31 &&
992 PrologCodeBytes + ARM64CountOfUnwindCodes(Epilog) <= 124)
993 RetVal = PrologCodeBytes;
994
995 int Offset = getARM64OffsetInProlog(info->Instructions, Epilog);
996 if (Offset < 0)
997 return RetVal;
998
999 // Check that the offset and prolog size fits in the first word; it's
1000 // unclear whether the epilog count in the extension word can be taken
1001 // as packed epilog offset.
1002 if (Offset > 31 || PrologCodeBytes > 124)
1003 return RetVal;
1004
1005 // As we choose to express the epilog as part of the prolog, remove the
1006 // epilog from the map, so we don't try to emit its opcodes.
1007 info->EpilogMap.erase(Sym);
1008 return Offset;
1009}
1010
1012 int PackedEpilogOffset) {
1013 if (PackedEpilogOffset == 0) {
1014 // Fully symmetric prolog and epilog, should be ok for packed format.
1015 // For CR=3, the corresponding synthesized epilog actually lacks the
1016 // SetFP opcode, but unwinding should work just fine despite that
1017 // (if at the SetFP opcode, the unwinder considers it as part of the
1018 // function body and just unwinds the full prolog instead).
1019 } else if (PackedEpilogOffset == 1) {
1020 // One single case of differences between prolog and epilog is allowed:
1021 // The epilog can lack a single SetFP that is the last opcode in the
1022 // prolog, for the CR=3 case.
1023 if (info->Instructions.back().Operation != Win64EH::UOP_SetFP)
1024 return false;
1025 } else {
1026 // Too much difference between prolog and epilog.
1027 return false;
1028 }
1029 unsigned RegI = 0, RegF = 0;
1030 int Predecrement = 0;
1031 enum {
1032 Start,
1033 Start2,
1034 Start3,
1035 IntRegs,
1036 FloatRegs,
1037 InputArgs,
1038 StackAdjust,
1039 FrameRecord,
1040 End
1041 } Location = Start;
1042 bool StandaloneLR = false, FPLRPair = false;
1043 bool PAC = false;
1044 int StackOffset = 0;
1045 int Nops = 0;
1046 // Iterate over the prolog and check that all opcodes exactly match
1047 // the canonical order and form. A more lax check could verify that
1048 // all saved registers are in the expected locations, but not enforce
1049 // the order - that would work fine when unwinding from within
1050 // functions, but not be exactly right if unwinding happens within
1051 // prologs/epilogs.
1052 for (const WinEH::Instruction &Inst : info->Instructions) {
1053 switch (Inst.Operation) {
1054 case Win64EH::UOP_End:
1055 if (Location != Start)
1056 return false;
1057 Location = Start2;
1058 break;
1060 if (Location != Start2)
1061 return false;
1062 PAC = true;
1063 Location = Start3;
1064 break;
1066 if (Location != Start2 && Location != Start3)
1067 return false;
1068 Predecrement = Inst.Offset;
1069 RegI = 2;
1070 Location = IntRegs;
1071 break;
1073 if (Location != Start2 && Location != Start3)
1074 return false;
1075 Predecrement = Inst.Offset;
1076 if (Inst.Register == 19)
1077 RegI += 1;
1078 else if (Inst.Register == 30)
1079 StandaloneLR = true;
1080 else
1081 return false;
1082 // Odd register; can't be any further int registers.
1083 Location = FloatRegs;
1084 break;
1086 // Can't have this in a canonical prologue. Either this has been
1087 // canonicalized into SaveR19R20X or SaveFPLRX, or it's an unsupported
1088 // register pair.
1089 // It can't be canonicalized into SaveR19R20X if the offset is
1090 // larger than 248 bytes, but even with the maximum case with
1091 // RegI=10/RegF=8/CR=1/H=1, we end up with SavSZ = 216, which should
1092 // fit into SaveR19R20X.
1093 // The unwinding opcodes can't describe the otherwise seemingly valid
1094 // case for RegI=1 CR=1, that would start with a
1095 // "stp x19, lr, [sp, #-...]!" as that fits neither SaveRegPX nor
1096 // SaveLRPair.
1097 return false;
1099 if (Location != IntRegs || Inst.Offset != 8 * RegI ||
1100 Inst.Register != 19 + RegI)
1101 return false;
1102 RegI += 2;
1103 break;
1105 if (Location != IntRegs || Inst.Offset != 8 * RegI)
1106 return false;
1107 if (Inst.Register == 19 + RegI)
1108 RegI += 1;
1109 else if (Inst.Register == 30)
1110 StandaloneLR = true;
1111 else
1112 return false;
1113 // Odd register; can't be any further int registers.
1114 Location = FloatRegs;
1115 break;
1117 if (Location != IntRegs || Inst.Offset != 8 * RegI ||
1118 Inst.Register != 19 + RegI)
1119 return false;
1120 RegI += 1;
1121 StandaloneLR = true;
1122 Location = FloatRegs;
1123 break;
1125 // Packed unwind can't handle prologs that only save one single
1126 // float register.
1127 return false;
1129 if (Location != FloatRegs || RegF == 0 || Inst.Register != 8 + RegF ||
1130 Inst.Offset != 8 * (RegI + (StandaloneLR ? 1 : 0) + RegF))
1131 return false;
1132 RegF += 1;
1133 Location = InputArgs;
1134 break;
1136 if ((Location != Start2 && Location != Start3) || Inst.Register != 8)
1137 return false;
1138 Predecrement = Inst.Offset;
1139 RegF = 2;
1140 Location = FloatRegs;
1141 break;
1143 if ((Location != IntRegs && Location != FloatRegs) ||
1144 Inst.Register != 8 + RegF ||
1145 Inst.Offset != 8 * (RegI + (StandaloneLR ? 1 : 0) + RegF))
1146 return false;
1147 RegF += 2;
1148 Location = FloatRegs;
1149 break;
1151 if (Location == IntRegs)
1152 RegI += 2;
1153 else if (Location == FloatRegs)
1154 RegF += 2;
1155 else
1156 return false;
1157 break;
1158 case Win64EH::UOP_Nop:
1159 if (Location != IntRegs && Location != FloatRegs && Location != InputArgs)
1160 return false;
1161 Location = InputArgs;
1162 Nops++;
1163 break;
1166 if (Location != Start2 && Location != Start3 && Location != IntRegs &&
1167 Location != FloatRegs && Location != InputArgs &&
1168 Location != StackAdjust)
1169 return false;
1170 // Can have either a single decrement, or a pair of decrements with
1171 // 4080 and another decrement.
1172 if (StackOffset == 0)
1173 StackOffset = Inst.Offset;
1174 else if (StackOffset != 4080)
1175 return false;
1176 else
1177 StackOffset += Inst.Offset;
1178 Location = StackAdjust;
1179 break;
1181 // Not allowing FPLRX after StackAdjust; if a StackAdjust is used, it
1182 // should be followed by a FPLR instead.
1183 if (Location != Start2 && Location != Start3 && Location != IntRegs &&
1184 Location != FloatRegs && Location != InputArgs)
1185 return false;
1186 StackOffset = Inst.Offset;
1187 Location = FrameRecord;
1188 FPLRPair = true;
1189 break;
1191 // This can only follow after a StackAdjust
1192 if (Location != StackAdjust || Inst.Offset != 0)
1193 return false;
1194 Location = FrameRecord;
1195 FPLRPair = true;
1196 break;
1197 case Win64EH::UOP_SetFP:
1198 if (Location != FrameRecord)
1199 return false;
1200 Location = End;
1201 break;
1214 // These are never canonical; they don't show up with the usual Arm64
1215 // calling convention.
1216 return false;
1218 // Allocations this large can't be represented in packed unwind (and
1219 // usually don't fit the canonical form anyway because we need to use
1220 // __chkstk to allocate the stack space).
1221 return false;
1222 case Win64EH::UOP_AddFP:
1223 // "add x29, sp, #N" doesn't show up in the canonical pattern (except for
1224 // N=0, which is UOP_SetFP).
1225 return false;
1229 // Canonical prologues don't support spilling SVE registers.
1230 return false;
1236 // These are special opcodes that aren't normally generated.
1237 return false;
1238 default:
1239 report_fatal_error("Unknown Arm64 unwind opcode");
1240 }
1241 }
1242 if (RegI > 10 || RegF > 8)
1243 return false;
1244 if (StandaloneLR && FPLRPair)
1245 return false;
1246 if (FPLRPair && Location != End)
1247 return false;
1248 if (Nops != 0 && Nops != 4)
1249 return false;
1250 if (PAC && !FPLRPair)
1251 return false;
1252 int H = Nops == 4;
1253 // There's an inconsistency regarding packed unwind info with homed
1254 // parameters; according to the documentation, the epilog shouldn't have
1255 // the same corresponding nops (and thus, to set the H bit, we should
1256 // require an epilog which isn't exactly symmetrical - we shouldn't accept
1257 // an exact mirrored epilog for those cases), but in practice,
1258 // RtlVirtualUnwind behaves as if it does expect the epilogue to contain
1259 // the same nops. See https://github.com/llvm/llvm-project/issues/54879.
1260 // To play it safe, don't produce packed unwind info with homed parameters.
1261 if (H)
1262 return false;
1263 int IntSZ = 8 * RegI;
1264 if (StandaloneLR)
1265 IntSZ += 8;
1266 int FpSZ = 8 * RegF; // RegF not yet decremented
1267 int SavSZ = (IntSZ + FpSZ + 8 * 8 * H + 0xF) & ~0xF;
1268 if (Predecrement != SavSZ)
1269 return false;
1270 if (FPLRPair && StackOffset < 16)
1271 return false;
1272 if (StackOffset % 16)
1273 return false;
1274 uint32_t FrameSize = (StackOffset + SavSZ) / 16;
1275 if (FrameSize > 0x1FF)
1276 return false;
1277 assert(RegF != 1 && "One single float reg not allowed");
1278 if (RegF > 0)
1279 RegF--; // Convert from actual number of registers, to value stored
1280 assert(FuncLength <= 0x7FF && "FuncLength should have been checked earlier");
1281 int Flag = 0x01; // Function segments not supported yet
1282 int CR = PAC ? 2 : FPLRPair ? 3 : StandaloneLR ? 1 : 0;
1283 info->PackedInfo |= Flag << 0;
1284 info->PackedInfo |= (FuncLength & 0x7FF) << 2;
1285 info->PackedInfo |= (RegF & 0x7) << 13;
1286 info->PackedInfo |= (RegI & 0xF) << 16;
1287 info->PackedInfo |= (H & 0x1) << 20;
1288 info->PackedInfo |= (CR & 0x3) << 21;
1289 info->PackedInfo |= (FrameSize & 0x1FF) << 23;
1290 return true;
1291}
1292
1295 uint32_t &TotalCodeBytes,
1296 MapVector<MCSymbol *, uint32_t> &EpilogInfo) {
1297
1298 std::vector<MCSymbol *> EpilogStarts;
1299 for (auto &I : Seg->Epilogs)
1300 EpilogStarts.push_back(I.first);
1301
1302 // Epilogs processed so far.
1303 std::vector<MCSymbol *> AddedEpilogs;
1304 for (auto *S : EpilogStarts) {
1305 MCSymbol *EpilogStart = S;
1306 auto &EpilogInstrs = info->EpilogMap[S].Instructions;
1307 uint32_t CodeBytes = ARM64CountOfUnwindCodes(EpilogInstrs);
1308
1309 MCSymbol* MatchingEpilog =
1310 FindMatchingEpilog(EpilogInstrs, AddedEpilogs, info);
1311 int PrologOffset;
1312 if (MatchingEpilog) {
1313 assert(EpilogInfo.contains(MatchingEpilog) &&
1314 "Duplicate epilog not found");
1315 EpilogInfo[EpilogStart] = EpilogInfo.lookup(MatchingEpilog);
1316 // Clear the unwind codes in the EpilogMap, so that they don't get output
1317 // in ARM64EmitUnwindInfoForSegment().
1318 EpilogInstrs.clear();
1319 } else if ((PrologOffset = getARM64OffsetInProlog(info->Instructions,
1320 EpilogInstrs)) >= 0) {
1321 EpilogInfo[EpilogStart] = PrologOffset;
1322 // If the segment doesn't have a prolog, an end_c will be emitted before
1323 // prolog opcodes. So epilog start index in opcodes array is moved by 1.
1324 if (!Seg->HasProlog)
1325 EpilogInfo[EpilogStart] += 1;
1326 // Clear the unwind codes in the EpilogMap, so that they don't get output
1327 // in ARM64EmitUnwindInfoForSegment().
1328 EpilogInstrs.clear();
1329 } else {
1330 EpilogInfo[EpilogStart] = TotalCodeBytes;
1331 TotalCodeBytes += CodeBytes;
1332 AddedEpilogs.push_back(EpilogStart);
1333 }
1334 }
1335}
1336
1339 int64_t RawFuncLength) {
1340 if (info->PrologEnd)
1341 checkARM64Instructions(streamer, info->Instructions, info->Begin,
1342 info->PrologEnd, info->Function->getName(),
1343 "prologue");
1344 struct EpilogStartEnd {
1345 MCSymbol *Start;
1346 int64_t Offset;
1347 int64_t End;
1348 };
1349 // Record Start and End of each epilog.
1351 for (auto &I : info->EpilogMap) {
1352 MCSymbol *Start = I.first;
1353 auto &Instrs = I.second.Instructions;
1354 int64_t Offset = GetAbsDifference(streamer, Start, info->Begin);
1355 checkARM64Instructions(streamer, Instrs, Start, I.second.End,
1356 info->Function->getName(), "epilogue");
1357 assert((Epilogs.size() == 0 || Offset >= Epilogs.back().End) &&
1358 "Epilogs should be monotonically ordered");
1359 // Exclue the end opcode from Instrs.size() when calculating the end of the
1360 // epilog.
1361 Epilogs.push_back({Start, Offset, Offset + (int64_t)(Instrs.size() - 1) * 4});
1362 }
1363
1364 unsigned E = 0;
1365 int64_t SegLimit = 0xFFFFC;
1366 int64_t SegOffset = 0;
1367
1368 if (RawFuncLength > SegLimit) {
1369
1370 int64_t RemainingLength = RawFuncLength;
1371
1372 while (RemainingLength > SegLimit) {
1373 // Try divide the function into segments, requirements:
1374 // 1. Segment length <= 0xFFFFC;
1375 // 2. Each Prologue or Epilogue must be fully within a segment.
1376 int64_t SegLength = SegLimit;
1377 int64_t SegEnd = SegOffset + SegLength;
1378 // Keep record on symbols and offsets of epilogs in this segment.
1379 MapVector<MCSymbol *, int64_t> EpilogsInSegment;
1380
1381 while (E < Epilogs.size() && Epilogs[E].End < SegEnd) {
1382 // Epilogs within current segment.
1383 EpilogsInSegment[Epilogs[E].Start] = Epilogs[E].Offset;
1384 ++E;
1385 }
1386
1387 // At this point, we have:
1388 // 1. Put all epilogs in segments already. No action needed here; or
1389 // 2. Found an epilog that will cross segments boundry. We need to
1390 // move back current segment's end boundry, so the epilog is entirely
1391 // in the next segment; or
1392 // 3. Left at least one epilog that is entirely after this segment.
1393 // It'll be handled by the next iteration, or the last segment.
1394 if (E < Epilogs.size() && Epilogs[E].Offset <= SegEnd)
1395 // Move back current Segment's end boundry.
1396 SegLength = Epilogs[E].Offset - SegOffset;
1397
1398 auto Seg = WinEH::FrameInfo::Segment(
1399 SegOffset, SegLength, /* HasProlog */!SegOffset);
1400 Seg.Epilogs = std::move(EpilogsInSegment);
1401 info->Segments.push_back(Seg);
1402
1403 SegOffset += SegLength;
1404 RemainingLength -= SegLength;
1405 }
1406 }
1407
1408 // Add the last segment when RawFuncLength > 0xFFFFC,
1409 // or the only segment otherwise.
1410 auto LastSeg =
1411 WinEH::FrameInfo::Segment(SegOffset, RawFuncLength - SegOffset,
1412 /* HasProlog */!SegOffset);
1413 for (; E < Epilogs.size(); ++E)
1414 LastSeg.Epilogs[Epilogs[E].Start] = Epilogs[E].Offset;
1415 info->Segments.push_back(LastSeg);
1416}
1417
1421 bool TryPacked = true) {
1422 MCContext &context = streamer.getContext();
1423 MCSymbol *Label = context.createTempSymbol();
1424
1425 streamer.emitValueToAlignment(Align(4));
1426 streamer.emitLabel(Label);
1427 Seg.Symbol = Label;
1428 // Use the 1st segemnt's label as function's.
1429 if (Seg.Offset == 0)
1430 info->Symbol = Label;
1431
1432 bool HasProlog = Seg.HasProlog;
1433 bool HasEpilogs = (Seg.Epilogs.size() != 0);
1434
1435 uint32_t SegLength = (uint32_t)Seg.Length / 4;
1436 uint32_t PrologCodeBytes = info->PrologCodeBytes;
1437
1438 int PackedEpilogOffset = HasEpilogs ?
1439 checkARM64PackedEpilog(streamer, info, &Seg, PrologCodeBytes) : -1;
1440
1441 // TODO:
1442 // 1. Enable packed unwind info (.pdata only) for multi-segment functions.
1443 // 2. Emit packed unwind info (.pdata only) for segments that have neithor
1444 // prolog nor epilog.
1445 if (info->Segments.size() == 1 && PackedEpilogOffset >= 0 &&
1446 uint32_t(PackedEpilogOffset) < PrologCodeBytes &&
1447 !info->HandlesExceptions && SegLength <= 0x7ff && TryPacked) {
1448 // Matching prolog/epilog and no exception handlers; check if the
1449 // prolog matches the patterns that can be described by the packed
1450 // format.
1451
1452 // info->Symbol was already set even if we didn't actually write any
1453 // unwind info there. Keep using that as indicator that this unwind
1454 // info has been generated already.
1455 if (tryARM64PackedUnwind(info, SegLength, PackedEpilogOffset))
1456 return;
1457 }
1458
1459 // If the prolog is not in this segment, we need to emit an end_c, which takes
1460 // 1 byte, before prolog unwind ops.
1461 if (!HasProlog) {
1462 PrologCodeBytes += 1;
1463 if (PackedEpilogOffset >= 0)
1464 PackedEpilogOffset += 1;
1465 // If a segment has neither prolog nor epilog, "With full .xdata record,
1466 // Epilog Count = 1. Epilog Start Index points to end_c."
1467 // https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling#function-fragments
1468 // TODO: We can remove this if testing shows zero epilog scope is ok with
1469 // MS unwinder.
1470 if (!HasEpilogs)
1471 // Pack the fake epilog into phantom prolog.
1472 PackedEpilogOffset = 0;
1473 }
1474
1475 uint32_t TotalCodeBytes = PrologCodeBytes;
1476
1477 // Process epilogs.
1479 ARM64ProcessEpilogs(info, &Seg, TotalCodeBytes, EpilogInfo);
1480
1481 // Code Words, Epilog count, E, X, Vers, Function Length
1482 uint32_t row1 = 0x0;
1483 uint32_t CodeWords = TotalCodeBytes / 4;
1484 uint32_t CodeWordsMod = TotalCodeBytes % 4;
1485 if (CodeWordsMod)
1486 CodeWords++;
1487 uint32_t EpilogCount =
1488 PackedEpilogOffset >= 0 ? PackedEpilogOffset : Seg.Epilogs.size();
1489 bool ExtensionWord = EpilogCount > 31 || TotalCodeBytes > 124;
1490 if (!ExtensionWord) {
1491 row1 |= (EpilogCount & 0x1F) << 22;
1492 row1 |= (CodeWords & 0x1F) << 27;
1493 }
1494 if (info->HandlesExceptions) // X
1495 row1 |= 1 << 20;
1496 if (PackedEpilogOffset >= 0) // E
1497 row1 |= 1 << 21;
1498 row1 |= SegLength & 0x3FFFF;
1499 streamer.emitInt32(row1);
1500
1501 // Extended Code Words, Extended Epilog Count
1502 if (ExtensionWord) {
1503 // FIXME: We should be able to split unwind info into multiple sections.
1504 if (CodeWords > 0xFF || EpilogCount > 0xFFFF)
1506 "SEH unwind data splitting is only implemented for large functions, "
1507 "cases of too many code words or too many epilogs will be done "
1508 "later");
1509 uint32_t row2 = 0x0;
1510 row2 |= (CodeWords & 0xFF) << 16;
1511 row2 |= (EpilogCount & 0xFFFF);
1512 streamer.emitInt32(row2);
1513 }
1514
1515 if (PackedEpilogOffset < 0) {
1516 // Epilog Start Index, Epilog Start Offset
1517 for (auto &I : EpilogInfo) {
1518 MCSymbol *EpilogStart = I.first;
1519 uint32_t EpilogIndex = I.second;
1520 // Epilog offset within the Segment.
1521 uint32_t EpilogOffset = (uint32_t)(Seg.Epilogs[EpilogStart] - Seg.Offset);
1522 if (EpilogOffset)
1523 EpilogOffset /= 4;
1524 uint32_t row3 = EpilogOffset;
1525 row3 |= (EpilogIndex & 0x3FF) << 22;
1526 streamer.emitInt32(row3);
1527 }
1528 }
1529
1530 // Note that even for segments that have no prolog, we still need to emit
1531 // prolog unwinding opcodes so that the unwinder knows how to unwind from
1532 // such a segment.
1533 // The end_c opcode at the start indicates to the unwinder that the actual
1534 // prolog is outside of the current segment, and the unwinder shouldn't try
1535 // to check for unwinding from a partial prolog.
1536 if (!HasProlog)
1537 // Emit an end_c.
1538 streamer.emitInt8((uint8_t)0xE5);
1539
1540 // Emit prolog unwind instructions (in reverse order).
1541 for (auto Inst : llvm::reverse(info->Instructions))
1542 ARM64EmitUnwindCode(streamer, Inst);
1543
1544 // Emit epilog unwind instructions
1545 for (auto &I : Seg.Epilogs) {
1546 auto &EpilogInstrs = info->EpilogMap[I.first].Instructions;
1547 for (const WinEH::Instruction &inst : EpilogInstrs)
1548 ARM64EmitUnwindCode(streamer, inst);
1549 }
1550
1551 int32_t BytesMod = CodeWords * 4 - TotalCodeBytes;
1552 assert(BytesMod >= 0);
1553 for (int i = 0; i < BytesMod; i++)
1554 streamer.emitInt8(0xE3);
1555
1556 if (info->HandlesExceptions)
1557 streamer.emitValue(
1558 MCSymbolRefExpr::create(info->ExceptionHandler,
1560 4);
1561}
1562
1563// Populate the .xdata section. The format of .xdata on ARM64 is documented at
1564// https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling
1566 bool TryPacked = true) {
1567 // If this UNWIND_INFO already has a symbol, it's already been emitted.
1568 if (info->Symbol)
1569 return;
1570 // If there's no unwind info here (not even a terminating UOP_End), the
1571 // unwind info is considered bogus and skipped. If this was done in
1572 // response to an explicit .seh_handlerdata, the associated trailing
1573 // handler data is left orphaned in the xdata section.
1574 if (info->empty()) {
1575 info->EmitAttempted = true;
1576 return;
1577 }
1578 if (info->EmitAttempted) {
1579 // If we tried to emit unwind info before (due to an explicit
1580 // .seh_handlerdata directive), but skipped it (because there was no
1581 // valid information to emit at the time), and it later got valid unwind
1582 // opcodes, we can't emit it here, because the trailing handler data
1583 // was already emitted elsewhere in the xdata section.
1584 streamer.getContext().reportError(
1585 SMLoc(), "Earlier .seh_handlerdata for " + info->Function->getName() +
1586 " skipped due to no unwind info at the time "
1587 "(.seh_handlerdata too early?), but the function later "
1588 "did get unwind info that can't be emitted");
1589 return;
1590 }
1591
1592 simplifyARM64Opcodes(info->Instructions, false);
1593 for (auto &I : info->EpilogMap)
1594 simplifyARM64Opcodes(I.second.Instructions, true);
1595
1596 int64_t RawFuncLength;
1597 if (!info->FuncletOrFuncEnd) {
1598 report_fatal_error("FuncletOrFuncEnd not set");
1599 } else {
1600 // FIXME: GetAbsDifference tries to compute the length of the function
1601 // immediately, before the whole file is emitted, but in general
1602 // that's impossible: the size in bytes of certain assembler directives
1603 // like .align and .fill is not known until the whole file is parsed and
1604 // relaxations are applied. Currently, GetAbsDifference fails with a fatal
1605 // error in that case. (We mostly don't hit this because inline assembly
1606 // specifying those directives is rare, and we don't normally try to
1607 // align loops on AArch64.)
1608 //
1609 // There are two potential approaches to delaying the computation. One,
1610 // we could emit something like ".word (endfunc-beginfunc)/4+0x10800000",
1611 // as long as we have some conservative estimate we could use to prove
1612 // that we don't need to split the unwind data. Emitting the constant
1613 // is straightforward, but there's no existing code for estimating the
1614 // size of the function.
1615 //
1616 // The other approach would be to use a dedicated, relaxable fragment,
1617 // which could grow to accommodate splitting the unwind data if
1618 // necessary. This is more straightforward, since it automatically works
1619 // without any new infrastructure, and it's consistent with how we handle
1620 // relaxation in other contexts. But it would require some refactoring
1621 // to move parts of the pdata/xdata emission into the implementation of
1622 // a fragment. We could probably continue to encode the unwind codes
1623 // here, but we'd have to emit the pdata, the xdata header, and the
1624 // epilogue scopes later, since they depend on whether the we need to
1625 // split the unwind data.
1626 //
1627 // If this is fixed, remove code in AArch64ISelLowering.cpp that
1628 // disables loop alignment on Windows.
1629 RawFuncLength = GetAbsDifference(streamer, info->FuncletOrFuncEnd,
1630 info->Begin);
1631 }
1632
1633 ARM64FindSegmentsInFunction(streamer, info, RawFuncLength);
1634
1635 info->PrologCodeBytes = ARM64CountOfUnwindCodes(info->Instructions);
1636 for (auto &S : info->Segments)
1637 ARM64EmitUnwindInfoForSegment(streamer, info, S, TryPacked);
1638
1639 // Clear prolog instructions after unwind info is emitted for all segments.
1640 info->Instructions.clear();
1641}
1642
1644 uint32_t Count = 0;
1645 for (const auto &I : Insns) {
1646 switch (static_cast<Win64EH::UnwindOpcodes>(I.Operation)) {
1647 default:
1648 llvm_unreachable("Unsupported ARM unwind code");
1650 Count += 1;
1651 break;
1653 Count += 3;
1654 break;
1656 Count += 4;
1657 break;
1659 Count += 2;
1660 break;
1662 Count += 3;
1663 break;
1665 Count += 4;
1666 break;
1668 Count += 2;
1669 break;
1671 Count += 1;
1672 break;
1674 Count += 1;
1675 break;
1677 Count += 1;
1678 break;
1680 Count += 1;
1681 break;
1683 Count += 2;
1684 break;
1686 Count += 2;
1687 break;
1689 Count += 2;
1690 break;
1692 Count += 2;
1693 break;
1694 case Win64EH::UOP_Nop:
1696 case Win64EH::UOP_End:
1699 Count += 1;
1700 break;
1701 case Win64EH::UOP_Custom: {
1702 int J;
1703 for (J = 3; J > 0; J--)
1704 if (I.Offset & (0xffu << (8 * J)))
1705 break;
1706 Count += J + 1;
1707 break;
1708 }
1709 }
1710 }
1711 return Count;
1712}
1713
1715 bool *HasCustom = nullptr) {
1716 uint32_t Count = 0;
1717 for (const auto &I : Insns) {
1718 switch (static_cast<Win64EH::UnwindOpcodes>(I.Operation)) {
1719 default:
1720 llvm_unreachable("Unsupported ARM unwind code");
1724 Count += 2;
1725 break;
1729 Count += 4;
1730 break;
1733 Count += 4;
1734 break;
1736 Count += 2;
1737 break;
1740 Count += 2;
1741 break;
1745 Count += 4;
1746 break;
1748 Count += 4;
1749 break;
1750 case Win64EH::UOP_Nop:
1752 Count += 2;
1753 break;
1756 Count += 4;
1757 break;
1758 case Win64EH::UOP_End:
1759 // This doesn't map to any instruction
1760 break;
1762 // We can't reason about what instructions this maps to; return a
1763 // phony number to make sure we don't accidentally do epilog packing.
1764 Count += 1000;
1765 if (HasCustom)
1766 *HasCustom = true;
1767 break;
1768 }
1769 }
1770 return Count;
1771}
1772
1773static void checkARMInstructions(MCStreamer &Streamer,
1775 const MCSymbol *Begin, const MCSymbol *End,
1777 if (!End)
1778 return;
1779 std::optional<int64_t> MaybeDistance =
1780 GetOptionalAbsDifference(Streamer, End, Begin);
1781 if (!MaybeDistance)
1782 return;
1783 uint32_t Distance = (uint32_t)*MaybeDistance;
1784 bool HasCustom = false;
1785 uint32_t InstructionBytes = ARMCountOfInstructionBytes(Insns, &HasCustom);
1786 if (HasCustom)
1787 return;
1788 if (Distance != InstructionBytes) {
1789 Streamer.getContext().reportError(
1790 SMLoc(), "Incorrect size for " + Name + " " + Type + ": " +
1791 Twine(Distance) +
1792 " bytes of instructions in range, but .seh directives "
1793 "corresponding to " +
1794 Twine(InstructionBytes) + " bytes\n");
1795 }
1796}
1797
1798static bool isARMTerminator(const WinEH::Instruction &inst) {
1799 switch (static_cast<Win64EH::UnwindOpcodes>(inst.Operation)) {
1800 case Win64EH::UOP_End:
1803 return true;
1804 default:
1805 return false;
1806 }
1807}
1808
1809// Unwind opcode encodings and restrictions are documented at
1810// https://docs.microsoft.com/en-us/cpp/build/arm-exception-handling
1811static void ARMEmitUnwindCode(MCStreamer &streamer,
1812 const WinEH::Instruction &inst) {
1813 uint32_t w, lr;
1814 int i;
1815 switch (static_cast<Win64EH::UnwindOpcodes>(inst.Operation)) {
1816 default:
1817 llvm_unreachable("Unsupported ARM unwind code");
1819 assert((inst.Offset & 3) == 0);
1820 assert(inst.Offset / 4 <= 0x7f);
1821 streamer.emitInt8(inst.Offset / 4);
1822 break;
1824 assert((inst.Register & ~0x5fff) == 0);
1825 lr = (inst.Register >> 14) & 1;
1826 w = 0x8000 | (inst.Register & 0x1fff) | (lr << 13);
1827 streamer.emitInt8((w >> 8) & 0xff);
1828 streamer.emitInt8((w >> 0) & 0xff);
1829 break;
1831 assert(inst.Register <= 0x0f);
1832 streamer.emitInt8(0xc0 | inst.Register);
1833 break;
1835 assert(inst.Register >= 4 && inst.Register <= 7);
1836 assert(inst.Offset <= 1);
1837 streamer.emitInt8(0xd0 | (inst.Register - 4) | (inst.Offset << 2));
1838 break;
1840 assert(inst.Register >= 8 && inst.Register <= 11);
1841 assert(inst.Offset <= 1);
1842 streamer.emitInt8(0xd8 | (inst.Register - 8) | (inst.Offset << 2));
1843 break;
1845 assert(inst.Register >= 8 && inst.Register <= 15);
1846 streamer.emitInt8(0xe0 | (inst.Register - 8));
1847 break;
1849 assert((inst.Offset & 3) == 0);
1850 assert(inst.Offset / 4 <= 0x3ff);
1851 w = 0xe800 | (inst.Offset / 4);
1852 streamer.emitInt8((w >> 8) & 0xff);
1853 streamer.emitInt8((w >> 0) & 0xff);
1854 break;
1856 assert((inst.Register & ~0x40ff) == 0);
1857 lr = (inst.Register >> 14) & 1;
1858 w = 0xec00 | (inst.Register & 0x0ff) | (lr << 8);
1859 streamer.emitInt8((w >> 8) & 0xff);
1860 streamer.emitInt8((w >> 0) & 0xff);
1861 break;
1863 assert((inst.Offset & 3) == 0);
1864 assert(inst.Offset / 4 <= 0x0f);
1865 streamer.emitInt8(0xef);
1866 streamer.emitInt8(inst.Offset / 4);
1867 break;
1869 assert(inst.Register <= 15);
1870 assert(inst.Offset <= 15);
1871 assert(inst.Register <= inst.Offset);
1872 streamer.emitInt8(0xf5);
1873 streamer.emitInt8((inst.Register << 4) | inst.Offset);
1874 break;
1876 assert(inst.Register >= 16 && inst.Register <= 31);
1877 assert(inst.Offset >= 16 && inst.Offset <= 31);
1878 assert(inst.Register <= inst.Offset);
1879 streamer.emitInt8(0xf6);
1880 streamer.emitInt8(((inst.Register - 16) << 4) | (inst.Offset - 16));
1881 break;
1883 assert((inst.Offset & 3) == 0);
1884 assert(inst.Offset / 4 <= 0xffff);
1885 w = inst.Offset / 4;
1886 streamer.emitInt8(0xf7);
1887 streamer.emitInt8((w >> 8) & 0xff);
1888 streamer.emitInt8((w >> 0) & 0xff);
1889 break;
1891 assert((inst.Offset & 3) == 0);
1892 assert(inst.Offset / 4 <= 0xffffff);
1893 w = inst.Offset / 4;
1894 streamer.emitInt8(0xf8);
1895 streamer.emitInt8((w >> 16) & 0xff);
1896 streamer.emitInt8((w >> 8) & 0xff);
1897 streamer.emitInt8((w >> 0) & 0xff);
1898 break;
1900 assert((inst.Offset & 3) == 0);
1901 assert(inst.Offset / 4 <= 0xffff);
1902 w = inst.Offset / 4;
1903 streamer.emitInt8(0xf9);
1904 streamer.emitInt8((w >> 8) & 0xff);
1905 streamer.emitInt8((w >> 0) & 0xff);
1906 break;
1908 assert((inst.Offset & 3) == 0);
1909 assert(inst.Offset / 4 <= 0xffffff);
1910 w = inst.Offset / 4;
1911 streamer.emitInt8(0xfa);
1912 streamer.emitInt8((w >> 16) & 0xff);
1913 streamer.emitInt8((w >> 8) & 0xff);
1914 streamer.emitInt8((w >> 0) & 0xff);
1915 break;
1916 case Win64EH::UOP_Nop:
1917 streamer.emitInt8(0xfb);
1918 break;
1920 streamer.emitInt8(0xfc);
1921 break;
1923 streamer.emitInt8(0xfd);
1924 break;
1926 streamer.emitInt8(0xfe);
1927 break;
1928 case Win64EH::UOP_End:
1929 streamer.emitInt8(0xff);
1930 break;
1932 for (i = 3; i > 0; i--)
1933 if (inst.Offset & (0xffu << (8 * i)))
1934 break;
1935 for (; i >= 0; i--)
1936 streamer.emitInt8((inst.Offset >> (8 * i)) & 0xff);
1937 break;
1938 }
1939}
1940
1941// Check if an epilog exists as a subset of the end of a prolog (backwards).
1942// An epilog may end with one out of three different end opcodes; if this
1943// is the first epilog that shares opcodes with the prolog, we can tolerate
1944// that this opcode differs (and the caller will update the prolog to use
1945// the same end opcode as the epilog). If another epilog already shares
1946// opcodes with the prolog, the ending opcode must be a strict match.
1947static int getARMOffsetInProlog(const std::vector<WinEH::Instruction> &Prolog,
1948 const std::vector<WinEH::Instruction> &Epilog,
1949 bool CanTweakProlog) {
1950 // Can't find an epilog as a subset if it is longer than the prolog.
1951 if (Epilog.size() > Prolog.size())
1952 return -1;
1953
1954 // Check that the epilog actually is a perfect match for the end (backwrds)
1955 // of the prolog.
1956 // If we can adjust the prolog afterwards, don't check that the end opcodes
1957 // match.
1958 int EndIdx = CanTweakProlog ? 1 : 0;
1959 for (int I = Epilog.size() - 1; I >= EndIdx; I--) {
1960 // TODO: Could also allow minor mismatches, e.g. "add sp, #16" vs
1961 // "push {r0-r3}".
1962 if (Prolog[I] != Epilog[Epilog.size() - 1 - I])
1963 return -1;
1964 }
1965
1966 if (CanTweakProlog) {
1967 // Check that both prolog and epilog end with an expected end opcode.
1968 if (Prolog.front().Operation != Win64EH::UOP_End)
1969 return -1;
1970 if (Epilog.back().Operation != Win64EH::UOP_End &&
1971 Epilog.back().Operation != Win64EH::UOP_EndNop &&
1972 Epilog.back().Operation != Win64EH::UOP_WideEndNop)
1973 return -1;
1974 }
1975
1976 // If the epilog was a subset of the prolog, find its offset.
1977 if (Epilog.size() == Prolog.size())
1978 return 0;
1980 &Prolog[Epilog.size()], Prolog.size() - Epilog.size()));
1981}
1982
1984 int PrologCodeBytes) {
1985 // Can only pack if there's one single epilog
1986 if (info->EpilogMap.size() != 1)
1987 return -1;
1988
1989 const WinEH::FrameInfo::Epilog &EpilogInfo = info->EpilogMap.begin()->second;
1990 // Can only pack if the epilog is unconditional
1991 if (EpilogInfo.Condition != 0xe) // ARMCC::AL
1992 return -1;
1993
1994 const std::vector<WinEH::Instruction> &Epilog = EpilogInfo.Instructions;
1995 // Make sure we have at least the trailing end opcode
1996 if (info->Instructions.empty() || Epilog.empty())
1997 return -1;
1998
1999 // Check that the epilog actually is at the very end of the function,
2000 // otherwise it can't be packed.
2001 std::optional<int64_t> MaybeDistance = GetOptionalAbsDifference(
2002 streamer, info->FuncletOrFuncEnd, info->EpilogMap.begin()->first);
2003 if (!MaybeDistance)
2004 return -1;
2005 uint32_t DistanceFromEnd = (uint32_t)*MaybeDistance;
2006 uint32_t InstructionBytes = ARMCountOfInstructionBytes(Epilog);
2007 if (DistanceFromEnd != InstructionBytes)
2008 return -1;
2009
2010 int RetVal = -1;
2011 // Even if we don't end up sharing opcodes with the prolog, we can still
2012 // write the offset as a packed offset, if the single epilog is located at
2013 // the end of the function and the offset (pointing after the prolog) fits
2014 // as a packed offset.
2015 if (PrologCodeBytes <= 31 &&
2016 PrologCodeBytes + ARMCountOfUnwindCodes(Epilog) <= 63)
2017 RetVal = PrologCodeBytes;
2018
2019 int Offset =
2020 getARMOffsetInProlog(info->Instructions, Epilog, /*CanTweakProlog=*/true);
2021 if (Offset < 0)
2022 return RetVal;
2023
2024 // Check that the offset and prolog size fits in the first word; it's
2025 // unclear whether the epilog count in the extension word can be taken
2026 // as packed epilog offset.
2027 if (Offset > 31 || PrologCodeBytes > 63)
2028 return RetVal;
2029
2030 // Replace the regular end opcode of the prolog with the one from the
2031 // epilog.
2032 info->Instructions.front() = Epilog.back();
2033
2034 // As we choose to express the epilog as part of the prolog, remove the
2035 // epilog from the map, so we don't try to emit its opcodes.
2036 info->EpilogMap.clear();
2037 return Offset;
2038}
2039
2040static bool parseRegMask(unsigned Mask, bool &HasLR, bool &HasR11,
2041 unsigned &Folded, int &IntRegs) {
2042 if (Mask & (1 << 14)) {
2043 HasLR = true;
2044 Mask &= ~(1 << 14);
2045 }
2046 if (Mask & (1 << 11)) {
2047 HasR11 = true;
2048 Mask &= ~(1 << 11);
2049 }
2050 Folded = 0;
2051 IntRegs = -1;
2052 if (!Mask)
2053 return true;
2054 int First = 0;
2055 // Shift right until we have the bits at the bottom
2056 while ((Mask & 1) == 0) {
2057 First++;
2058 Mask >>= 1;
2059 }
2060 if ((Mask & (Mask + 1)) != 0)
2061 return false; // Not a consecutive series of bits? Can't be packed.
2062 // Count the bits
2063 int N = 0;
2064 while (Mask & (1 << N))
2065 N++;
2066 if (First < 4) {
2067 if (First + N < 4)
2068 return false;
2069 Folded = 4 - First;
2070 N -= Folded;
2071 First = 4;
2072 }
2073 if (First > 4)
2074 return false; // Can't be packed
2075 if (N >= 1)
2076 IntRegs = N - 1;
2077 return true;
2078}
2079
2081 uint32_t FuncLength) {
2082 int Step = 0;
2083 bool Homing = false;
2084 bool HasR11 = false;
2085 bool HasChain = false;
2086 bool HasLR = false;
2087 int IntRegs = -1; // r4 - r(4+N)
2088 int FloatRegs = -1; // d8 - d(8+N)
2089 unsigned PF = 0; // Number of extra pushed registers
2090 unsigned StackAdjust = 0;
2091 // Iterate over the prolog and check that all opcodes exactly match
2092 // the canonical order and form.
2093 for (const WinEH::Instruction &Inst : info->Instructions) {
2094 switch (Inst.Operation) {
2095 default:
2096 llvm_unreachable("Unsupported ARM unwind code");
2104 // Can't be packed
2105 return false;
2107 // Can't be packed; we can't rely on restoring sp from r11 when
2108 // unwinding a packed prologue.
2109 return false;
2111 // Can't be present in a packed prologue
2112 return false;
2113
2114 case Win64EH::UOP_End:
2117 if (Step != 0)
2118 return false;
2119 Step = 1;
2120 break;
2121
2124 // push {r4-r11,lr}
2125 if (Step != 1 && Step != 2)
2126 return false;
2127 assert(Inst.Register >= 4 && Inst.Register <= 11); // r4-rX
2128 assert(Inst.Offset <= 1); // Lr
2129 IntRegs = Inst.Register - 4;
2130 if (Inst.Register == 11) {
2131 HasR11 = true;
2132 IntRegs--;
2133 }
2134 if (Inst.Offset)
2135 HasLR = true;
2136 Step = 3;
2137 break;
2138
2140 if (Step == 1 && Inst.Register == 0x0f) {
2141 // push {r0-r3}
2142 Homing = true;
2143 Step = 2;
2144 break;
2145 }
2146 [[fallthrough]];
2148 if (Step != 1 && Step != 2)
2149 return false;
2150 // push {r4-r9,r11,lr}
2151 // push {r11,lr}
2152 // push {r1-r5}
2153 if (!parseRegMask(Inst.Register, HasLR, HasR11, PF, IntRegs))
2154 return false;
2155 Step = 3;
2156 break;
2157
2158 case Win64EH::UOP_Nop:
2159 // mov r11, sp
2160 if (Step != 3 || !HasR11 || IntRegs >= 0 || PF > 0)
2161 return false;
2162 HasChain = true;
2163 Step = 4;
2164 break;
2166 // add.w r11, sp, #xx
2167 if (Step != 3 || !HasR11 || (IntRegs < 0 && PF == 0))
2168 return false;
2169 HasChain = true;
2170 Step = 4;
2171 break;
2172
2174 if (Step != 1 && Step != 2 && Step != 3 && Step != 4)
2175 return false;
2176 assert(Inst.Register >= 8 && Inst.Register <= 15);
2177 if (Inst.Register == 15)
2178 return false; // Can't pack this case, R==7 means no IntRegs
2179 if (IntRegs >= 0)
2180 return false;
2181 FloatRegs = Inst.Register - 8;
2182 Step = 5;
2183 break;
2184
2187 if (Step != 1 && Step != 2 && Step != 3 && Step != 4 && Step != 5)
2188 return false;
2189 if (PF > 0) // Can't have both folded and explicit stack allocation
2190 return false;
2191 if (Inst.Offset / 4 >= 0x3f4)
2192 return false;
2193 StackAdjust = Inst.Offset / 4;
2194 Step = 6;
2195 break;
2196 }
2197 }
2198 if (HasR11 && !HasChain) {
2199 if (IntRegs + 4 == 10) {
2200 // r11 stored, but not chaining; can be packed if already saving r4-r10
2201 // and we can fit r11 into this range.
2202 IntRegs++;
2203 HasR11 = false;
2204 } else
2205 return false;
2206 }
2207 if (HasChain && !HasLR)
2208 return false;
2209
2210 // Packed uneind info can't express multiple epilogues.
2211 if (info->EpilogMap.size() > 1)
2212 return false;
2213
2214 unsigned EF = 0;
2215 int Ret = 0;
2216 if (info->EpilogMap.size() == 0) {
2217 Ret = 3; // No epilogue
2218 } else {
2219 // As the prologue and epilogue aren't exact mirrors of each other,
2220 // we have to check the epilogue too and see if it matches what we've
2221 // concluded from the prologue.
2222 const WinEH::FrameInfo::Epilog &EpilogInfo =
2223 info->EpilogMap.begin()->second;
2224 if (EpilogInfo.Condition != 0xe) // ARMCC::AL
2225 return false;
2226 const std::vector<WinEH::Instruction> &Epilog = EpilogInfo.Instructions;
2227 std::optional<int64_t> MaybeDistance = GetOptionalAbsDifference(
2228 streamer, info->FuncletOrFuncEnd, info->EpilogMap.begin()->first);
2229 if (!MaybeDistance)
2230 return false;
2231 uint32_t DistanceFromEnd = (uint32_t)*MaybeDistance;
2232 uint32_t InstructionBytes = ARMCountOfInstructionBytes(Epilog);
2233 if (DistanceFromEnd != InstructionBytes)
2234 return false;
2235
2236 bool GotStackAdjust = false;
2237 bool GotFloatRegs = false;
2238 bool GotIntRegs = false;
2239 bool GotHomingRestore = false;
2240 bool GotLRRestore = false;
2241 bool NeedsReturn = false;
2242 bool GotReturn = false;
2243
2244 Step = 6;
2245 for (const WinEH::Instruction &Inst : Epilog) {
2246 switch (Inst.Operation) {
2247 default:
2248 llvm_unreachable("Unsupported ARM unwind code");
2257 case Win64EH::UOP_Nop:
2259 // Can't be packed in an epilogue
2260 return false;
2261
2264 if (Inst.Offset / 4 >= 0x3f4)
2265 return false;
2266 if (Step == 6) {
2267 if (Homing && FloatRegs < 0 && IntRegs < 0 && StackAdjust == 0 &&
2268 PF == 0 && Inst.Offset == 16) {
2269 GotHomingRestore = true;
2270 Step = 10;
2271 } else {
2272 if (StackAdjust > 0) {
2273 // Got stack adjust in prologue too; must match.
2274 if (StackAdjust != Inst.Offset / 4)
2275 return false;
2276 GotStackAdjust = true;
2277 } else if (PF == Inst.Offset / 4) {
2278 // Folded prologue, non-folded epilogue
2279 StackAdjust = Inst.Offset / 4;
2280 GotStackAdjust = true;
2281 } else {
2282 // StackAdjust == 0 in prologue, mismatch
2283 return false;
2284 }
2285 Step = 7;
2286 }
2287 } else if (Step == 7 || Step == 8 || Step == 9) {
2288 if (!Homing || Inst.Offset != 16)
2289 return false;
2290 GotHomingRestore = true;
2291 Step = 10;
2292 } else
2293 return false;
2294 break;
2295
2297 if (Step != 6 && Step != 7)
2298 return false;
2299 assert(Inst.Register >= 8 && Inst.Register <= 15);
2300 if (FloatRegs != (int)(Inst.Register - 8))
2301 return false;
2302 GotFloatRegs = true;
2303 Step = 8;
2304 break;
2305
2308 // push {r4-r11,lr}
2309 if (Step != 6 && Step != 7 && Step != 8)
2310 return false;
2311 assert(Inst.Register >= 4 && Inst.Register <= 11); // r4-rX
2312 assert(Inst.Offset <= 1); // Lr
2313 if (Homing && HasLR) {
2314 // If homing and LR is backed up, we can either restore LR here
2315 // and return with Ret == 1 or 2, or return with SaveLR below
2316 if (Inst.Offset) {
2317 GotLRRestore = true;
2318 NeedsReturn = true;
2319 } else {
2320 // Expecting a separate SaveLR below
2321 }
2322 } else {
2323 if (HasLR != (Inst.Offset == 1))
2324 return false;
2325 }
2326 GotLRRestore = Inst.Offset == 1;
2327 if (IntRegs < 0) // This opcode must include r4
2328 return false;
2329 int Expected = IntRegs;
2330 if (HasChain) {
2331 // Can't express r11 here unless IntRegs describe r4-r10
2332 if (IntRegs != 6)
2333 return false;
2334 Expected++;
2335 }
2336 if (Expected != (int)(Inst.Register - 4))
2337 return false;
2338 GotIntRegs = true;
2339 Step = 9;
2340 break;
2341 }
2342
2345 if (Step != 6 && Step != 7 && Step != 8)
2346 return false;
2347 // push {r4-r9,r11,lr}
2348 // push {r11,lr}
2349 // push {r1-r5}
2350 bool CurHasLR = false, CurHasR11 = false;
2351 int Regs;
2352 if (!parseRegMask(Inst.Register, CurHasLR, CurHasR11, EF, Regs))
2353 return false;
2354 if (EF > 0) {
2355 if (EF != PF && EF != StackAdjust)
2356 return false;
2357 }
2358 if (Homing && HasLR) {
2359 // If homing and LR is backed up, we can either restore LR here
2360 // and return with Ret == 1 or 2, or return with SaveLR below
2361 if (CurHasLR) {
2362 GotLRRestore = true;
2363 NeedsReturn = true;
2364 } else {
2365 // Expecting a separate SaveLR below
2366 }
2367 } else {
2368 if (CurHasLR != HasLR)
2369 return false;
2370 GotLRRestore = CurHasLR;
2371 }
2372 int Expected = IntRegs;
2373 if (HasChain) {
2374 // If we have chaining, the mask must have included r11.
2375 if (!CurHasR11)
2376 return false;
2377 } else if (Expected == 7) {
2378 // If we don't have chaining, the mask could still include r11,
2379 // expressed as part of IntRegs Instead.
2380 Expected--;
2381 if (!CurHasR11)
2382 return false;
2383 } else {
2384 // Neither HasChain nor r11 included in IntRegs, must not have r11
2385 // here either.
2386 if (CurHasR11)
2387 return false;
2388 }
2389 if (Expected != Regs)
2390 return false;
2391 GotIntRegs = true;
2392 Step = 9;
2393 break;
2394 }
2395
2397 if (Step != 6 && Step != 7 && Step != 8 && Step != 9)
2398 return false;
2399 if (!Homing || Inst.Offset != 20 || GotLRRestore)
2400 return false;
2401 GotLRRestore = true;
2402 GotHomingRestore = true;
2403 Step = 10;
2404 break;
2405
2408 GotReturn = true;
2409 Ret = (Inst.Operation == Win64EH::UOP_EndNop) ? 1 : 2;
2410 [[fallthrough]];
2411 case Win64EH::UOP_End:
2412 if (Step != 6 && Step != 7 && Step != 8 && Step != 9 && Step != 10)
2413 return false;
2414 Step = 11;
2415 break;
2416 }
2417 }
2418
2419 if (Step != 11)
2420 return false;
2421 if (StackAdjust > 0 && !GotStackAdjust && EF == 0)
2422 return false;
2423 if (FloatRegs >= 0 && !GotFloatRegs)
2424 return false;
2425 if (IntRegs >= 0 && !GotIntRegs)
2426 return false;
2427 if (Homing && !GotHomingRestore)
2428 return false;
2429 if (HasLR && !GotLRRestore)
2430 return false;
2431 if (NeedsReturn && !GotReturn)
2432 return false;
2433 }
2434
2435 assert(PF == 0 || EF == 0 ||
2436 StackAdjust == 0); // Can't have adjust in all three
2437 if (PF > 0 || EF > 0) {
2438 StackAdjust = PF > 0 ? (PF - 1) : (EF - 1);
2439 assert(StackAdjust <= 3);
2440 StackAdjust |= 0x3f0;
2441 if (PF > 0)
2442 StackAdjust |= 1 << 2;
2443 if (EF > 0)
2444 StackAdjust |= 1 << 3;
2445 }
2446
2447 assert(FuncLength <= 0x7FF && "FuncLength should have been checked earlier");
2448 int Flag = info->Fragment ? 0x02 : 0x01;
2449 int H = Homing ? 1 : 0;
2450 int L = HasLR ? 1 : 0;
2451 int C = HasChain ? 1 : 0;
2452 assert(IntRegs < 0 || FloatRegs < 0);
2453 unsigned Reg, R;
2454 if (IntRegs >= 0) {
2455 Reg = IntRegs;
2456 assert(Reg <= 7);
2457 R = 0;
2458 } else if (FloatRegs >= 0) {
2459 Reg = FloatRegs;
2460 assert(Reg < 7);
2461 R = 1;
2462 } else {
2463 // No int or float regs stored (except possibly R11,LR)
2464 Reg = 7;
2465 R = 1;
2466 }
2467 info->PackedInfo |= Flag << 0;
2468 info->PackedInfo |= (FuncLength & 0x7FF) << 2;
2469 info->PackedInfo |= (Ret & 0x3) << 13;
2470 info->PackedInfo |= H << 15;
2471 info->PackedInfo |= Reg << 16;
2472 info->PackedInfo |= R << 19;
2473 info->PackedInfo |= L << 20;
2474 info->PackedInfo |= C << 21;
2475 assert(StackAdjust <= 0x3ff);
2476 info->PackedInfo |= StackAdjust << 22;
2477 return true;
2478}
2479
2480// Populate the .xdata section. The format of .xdata on ARM is documented at
2481// https://docs.microsoft.com/en-us/cpp/build/arm-exception-handling
2483 bool TryPacked = true) {
2484 // If this UNWIND_INFO already has a symbol, it's already been emitted.
2485 if (info->Symbol)
2486 return;
2487 // If there's no unwind info here (not even a terminating UOP_End), the
2488 // unwind info is considered bogus and skipped. If this was done in
2489 // response to an explicit .seh_handlerdata, the associated trailing
2490 // handler data is left orphaned in the xdata section.
2491 if (info->empty()) {
2492 info->EmitAttempted = true;
2493 return;
2494 }
2495 if (info->EmitAttempted) {
2496 // If we tried to emit unwind info before (due to an explicit
2497 // .seh_handlerdata directive), but skipped it (because there was no
2498 // valid information to emit at the time), and it later got valid unwind
2499 // opcodes, we can't emit it here, because the trailing handler data
2500 // was already emitted elsewhere in the xdata section.
2501 streamer.getContext().reportError(
2502 SMLoc(), "Earlier .seh_handlerdata for " + info->Function->getName() +
2503 " skipped due to no unwind info at the time "
2504 "(.seh_handlerdata too early?), but the function later "
2505 "did get unwind info that can't be emitted");
2506 return;
2507 }
2508
2509 MCContext &context = streamer.getContext();
2510 MCSymbol *Label = context.createTempSymbol();
2511
2512 streamer.emitValueToAlignment(Align(4));
2513 streamer.emitLabel(Label);
2514 info->Symbol = Label;
2515
2516 if (!info->PrologEnd)
2517 streamer.getContext().reportError(SMLoc(), "Prologue in " +
2518 info->Function->getName() +
2519 " not correctly terminated");
2520
2521 if (info->PrologEnd && !info->Fragment)
2522 checkARMInstructions(streamer, info->Instructions, info->Begin,
2523 info->PrologEnd, info->Function->getName(),
2524 "prologue");
2525 for (auto &I : info->EpilogMap) {
2526 MCSymbol *EpilogStart = I.first;
2527 auto &Epilog = I.second;
2528 checkARMInstructions(streamer, Epilog.Instructions, EpilogStart, Epilog.End,
2529 info->Function->getName(), "epilogue");
2530 if (Epilog.Instructions.empty() ||
2531 !isARMTerminator(Epilog.Instructions.back()))
2532 streamer.getContext().reportError(
2533 SMLoc(), "Epilogue in " + info->Function->getName() +
2534 " not correctly terminated");
2535 }
2536
2537 std::optional<int64_t> RawFuncLength;
2538 const MCExpr *FuncLengthExpr = nullptr;
2539 if (!info->FuncletOrFuncEnd) {
2540 report_fatal_error("FuncletOrFuncEnd not set");
2541 } else {
2542 // As the size of many thumb2 instructions isn't known until later,
2543 // we can't always rely on being able to calculate the absolute
2544 // length of the function here. If we can't calculate it, defer it
2545 // to a relocation.
2546 //
2547 // In such a case, we won't know if the function is too long so that
2548 // the unwind info would need to be split (but this isn't implemented
2549 // anyway).
2550 RawFuncLength =
2551 GetOptionalAbsDifference(streamer, info->FuncletOrFuncEnd, info->Begin);
2552 if (!RawFuncLength)
2553 FuncLengthExpr =
2554 GetSubDivExpr(streamer, info->FuncletOrFuncEnd, info->Begin, 2);
2555 }
2556 uint32_t FuncLength = 0;
2557 if (RawFuncLength)
2558 FuncLength = (uint32_t)*RawFuncLength / 2;
2559 if (FuncLength > 0x3FFFF)
2560 report_fatal_error("SEH unwind data splitting not yet implemented");
2561 uint32_t PrologCodeBytes = ARMCountOfUnwindCodes(info->Instructions);
2562 uint32_t TotalCodeBytes = PrologCodeBytes;
2563
2564 if (!info->HandlesExceptions && RawFuncLength && FuncLength <= 0x7ff &&
2565 TryPacked) {
2566 // No exception handlers; check if the prolog and epilog matches the
2567 // patterns that can be described by the packed format. If we don't
2568 // know the exact function length yet, we can't do this.
2569
2570 // info->Symbol was already set even if we didn't actually write any
2571 // unwind info there. Keep using that as indicator that this unwind
2572 // info has been generated already.
2573
2574 if (tryARMPackedUnwind(streamer, info, FuncLength))
2575 return;
2576 }
2577
2578 int PackedEpilogOffset =
2579 checkARMPackedEpilog(streamer, info, PrologCodeBytes);
2580
2581 // Process epilogs.
2583 // Epilogs processed so far.
2584 std::vector<MCSymbol *> AddedEpilogs;
2585
2586 bool CanTweakProlog = true;
2587 for (auto &I : info->EpilogMap) {
2588 MCSymbol *EpilogStart = I.first;
2589 auto &EpilogInstrs = I.second.Instructions;
2590 uint32_t CodeBytes = ARMCountOfUnwindCodes(EpilogInstrs);
2591
2592 MCSymbol *MatchingEpilog =
2593 FindMatchingEpilog(EpilogInstrs, AddedEpilogs, info);
2594 int PrologOffset;
2595 if (MatchingEpilog) {
2596 assert(EpilogInfo.contains(MatchingEpilog) &&
2597 "Duplicate epilog not found");
2598 EpilogInfo[EpilogStart] = EpilogInfo.lookup(MatchingEpilog);
2599 // Clear the unwind codes in the EpilogMap, so that they don't get output
2600 // in the logic below.
2601 EpilogInstrs.clear();
2602 } else if ((PrologOffset = getARMOffsetInProlog(
2603 info->Instructions, EpilogInstrs, CanTweakProlog)) >= 0) {
2604 if (CanTweakProlog) {
2605 // Replace the regular end opcode of the prolog with the one from the
2606 // epilog.
2607 info->Instructions.front() = EpilogInstrs.back();
2608 // Later epilogs need a strict match for the end opcode.
2609 CanTweakProlog = false;
2610 }
2611 EpilogInfo[EpilogStart] = PrologOffset;
2612 // Clear the unwind codes in the EpilogMap, so that they don't get output
2613 // in the logic below.
2614 EpilogInstrs.clear();
2615 } else {
2616 EpilogInfo[EpilogStart] = TotalCodeBytes;
2617 TotalCodeBytes += CodeBytes;
2618 AddedEpilogs.push_back(EpilogStart);
2619 }
2620 }
2621
2622 // Code Words, Epilog count, F, E, X, Vers, Function Length
2623 uint32_t row1 = 0x0;
2624 uint32_t CodeWords = TotalCodeBytes / 4;
2625 uint32_t CodeWordsMod = TotalCodeBytes % 4;
2626 if (CodeWordsMod)
2627 CodeWords++;
2628 uint32_t EpilogCount =
2629 PackedEpilogOffset >= 0 ? PackedEpilogOffset : info->EpilogMap.size();
2630 bool ExtensionWord = EpilogCount > 31 || CodeWords > 15;
2631 if (!ExtensionWord) {
2632 row1 |= (EpilogCount & 0x1F) << 23;
2633 row1 |= (CodeWords & 0x0F) << 28;
2634 }
2635 if (info->HandlesExceptions) // X
2636 row1 |= 1 << 20;
2637 if (PackedEpilogOffset >= 0) // E
2638 row1 |= 1 << 21;
2639 if (info->Fragment) // F
2640 row1 |= 1 << 22;
2641 row1 |= FuncLength & 0x3FFFF;
2642 if (RawFuncLength)
2643 streamer.emitInt32(row1);
2644 else
2645 streamer.emitValue(
2646 MCBinaryExpr::createOr(FuncLengthExpr,
2647 MCConstantExpr::create(row1, context), context),
2648 4);
2649
2650 // Extended Code Words, Extended Epilog Count
2651 if (ExtensionWord) {
2652 // FIXME: We should be able to split unwind info into multiple sections.
2653 if (CodeWords > 0xFF || EpilogCount > 0xFFFF)
2654 report_fatal_error("SEH unwind data splitting not yet implemented");
2655 uint32_t row2 = 0x0;
2656 row2 |= (CodeWords & 0xFF) << 16;
2657 row2 |= (EpilogCount & 0xFFFF);
2658 streamer.emitInt32(row2);
2659 }
2660
2661 if (PackedEpilogOffset < 0) {
2662 // Epilog Start Index, Epilog Start Offset
2663 for (auto &I : EpilogInfo) {
2664 MCSymbol *EpilogStart = I.first;
2665 uint32_t EpilogIndex = I.second;
2666
2667 std::optional<int64_t> MaybeEpilogOffset =
2668 GetOptionalAbsDifference(streamer, EpilogStart, info->Begin);
2669 const MCExpr *OffsetExpr = nullptr;
2670 uint32_t EpilogOffset = 0;
2671 if (MaybeEpilogOffset)
2672 EpilogOffset = *MaybeEpilogOffset / 2;
2673 else
2674 OffsetExpr = GetSubDivExpr(streamer, EpilogStart, info->Begin, 2);
2675
2676 assert(info->EpilogMap.contains(EpilogStart));
2677 unsigned Condition = info->EpilogMap[EpilogStart].Condition;
2678 assert(Condition <= 0xf);
2679
2680 uint32_t row3 = EpilogOffset;
2681 row3 |= Condition << 20;
2682 row3 |= (EpilogIndex & 0x3FF) << 24;
2683 if (MaybeEpilogOffset)
2684 streamer.emitInt32(row3);
2685 else
2686 streamer.emitValue(
2688 OffsetExpr, MCConstantExpr::create(row3, context), context),
2689 4);
2690 }
2691 }
2692
2693 // Emit prolog unwind instructions (in reverse order).
2694 uint8_t numInst = info->Instructions.size();
2695 for (uint8_t c = 0; c < numInst; ++c) {
2696 WinEH::Instruction inst = info->Instructions.back();
2697 info->Instructions.pop_back();
2698 ARMEmitUnwindCode(streamer, inst);
2699 }
2700
2701 // Emit epilog unwind instructions
2702 for (auto &I : info->EpilogMap) {
2703 auto &EpilogInstrs = I.second.Instructions;
2704 for (const WinEH::Instruction &inst : EpilogInstrs)
2705 ARMEmitUnwindCode(streamer, inst);
2706 }
2707
2708 int32_t BytesMod = CodeWords * 4 - TotalCodeBytes;
2709 assert(BytesMod >= 0);
2710 for (int i = 0; i < BytesMod; i++)
2711 streamer.emitInt8(0xFB);
2712
2713 if (info->HandlesExceptions)
2714 streamer.emitValue(
2715 MCSymbolRefExpr::create(info->ExceptionHandler,
2717 4);
2718}
2719
2721 const WinEH::FrameInfo *info) {
2722 MCContext &context = streamer.getContext();
2723
2724 streamer.emitValueToAlignment(Align(4));
2725 for (const auto &S : info->Segments) {
2726 EmitSymbolRefWithOfs(streamer, info->Begin, S.Offset);
2727 if (info->PackedInfo)
2728 streamer.emitInt32(info->PackedInfo);
2729 else
2730 streamer.emitValue(
2732 context),
2733 4);
2734 }
2735}
2736
2737
2739 const WinEH::FrameInfo *info) {
2740 MCContext &context = streamer.getContext();
2741
2742 streamer.emitValueToAlignment(Align(4));
2743 EmitSymbolRefWithOfs(streamer, info->Begin, info->Begin);
2744 if (info->PackedInfo)
2745 streamer.emitInt32(info->PackedInfo);
2746 else
2747 streamer.emitValue(
2749 context),
2750 4);
2751}
2752
2754 // Emit the unwind info structs first.
2755 for (const auto &CFI : Streamer.getWinFrameInfos()) {
2756 WinEH::FrameInfo *Info = CFI.get();
2757 if (Info->empty())
2758 continue;
2759 MCSection *XData = Streamer.getAssociatedXDataSection(CFI->TextSection);
2760 Streamer.switchSection(XData);
2761 ARM64EmitUnwindInfo(Streamer, Info);
2762 }
2763
2764 // Now emit RUNTIME_FUNCTION entries.
2765 for (const auto &CFI : Streamer.getWinFrameInfos()) {
2766 WinEH::FrameInfo *Info = CFI.get();
2767 // ARM64EmitUnwindInfo above clears the info struct, so we can't check
2768 // empty here. But if a Symbol is set, we should create the corresponding
2769 // pdata entry.
2770 if (!Info->Symbol)
2771 continue;
2772 MCSection *PData = Streamer.getAssociatedPDataSection(CFI->TextSection);
2773 Streamer.switchSection(PData);
2774 ARM64EmitRuntimeFunction(Streamer, Info);
2775 }
2776}
2777
2780 bool HandlerData) const {
2781 // Called if there's an .seh_handlerdata directive before the end of the
2782 // function. This forces writing the xdata record already here - and
2783 // in this case, the function isn't actually ended already, but the xdata
2784 // record needs to know the function length. In these cases, if the funclet
2785 // end hasn't been marked yet, the xdata function length won't cover the
2786 // whole function, only up to this point.
2787 if (!info->FuncletOrFuncEnd) {
2788 Streamer.switchSection(info->TextSection);
2789 info->FuncletOrFuncEnd = Streamer.emitCFILabel();
2790 }
2791 // Switch sections (the static function above is meant to be called from
2792 // here and from Emit().
2793 MCSection *XData = Streamer.getAssociatedXDataSection(info->TextSection);
2794 Streamer.switchSection(XData);
2795 ARM64EmitUnwindInfo(Streamer, info, /* TryPacked = */ !HandlerData);
2796}
2797
2799 // Emit the unwind info structs first.
2800 for (const auto &CFI : Streamer.getWinFrameInfos()) {
2801 WinEH::FrameInfo *Info = CFI.get();
2802 if (Info->empty())
2803 continue;
2804 MCSection *XData = Streamer.getAssociatedXDataSection(CFI->TextSection);
2805 Streamer.switchSection(XData);
2806 ARMEmitUnwindInfo(Streamer, Info);
2807 }
2808
2809 // Now emit RUNTIME_FUNCTION entries.
2810 for (const auto &CFI : Streamer.getWinFrameInfos()) {
2811 WinEH::FrameInfo *Info = CFI.get();
2812 // ARMEmitUnwindInfo above clears the info struct, so we can't check
2813 // empty here. But if a Symbol is set, we should create the corresponding
2814 // pdata entry.
2815 if (!Info->Symbol)
2816 continue;
2817 MCSection *PData = Streamer.getAssociatedPDataSection(CFI->TextSection);
2818 Streamer.switchSection(PData);
2819 ARMEmitRuntimeFunction(Streamer, Info);
2820 }
2821}
2822
2825 bool HandlerData) const {
2826 // Called if there's an .seh_handlerdata directive before the end of the
2827 // function. This forces writing the xdata record already here - and
2828 // in this case, the function isn't actually ended already, but the xdata
2829 // record needs to know the function length. In these cases, if the funclet
2830 // end hasn't been marked yet, the xdata function length won't cover the
2831 // whole function, only up to this point.
2832 if (!info->FuncletOrFuncEnd) {
2833 Streamer.switchSection(info->TextSection);
2834 info->FuncletOrFuncEnd = Streamer.emitCFILabel();
2835 }
2836 // Switch sections (the static function above is meant to be called from
2837 // here and from Emit().
2838 MCSection *XData = Streamer.getAssociatedXDataSection(info->TextSection);
2839 Streamer.switchSection(XData);
2840 ARMEmitUnwindInfo(Streamer, info, /* TryPacked = */ !HandlerData);
2841}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
Analysis containing CSE Info
Definition: CSEInfo.cpp:27
Given that RA is a live value
std::string Name
uint64_t Size
std::optional< std::vector< StOtherPiece > > Other
Definition: ELFYAML.cpp:1328
bool End
Definition: ELF_riscv.cpp:480
Symbol * Sym
Definition: ELF_riscv.cpp:479
lazy value info
static int checkARM64PackedEpilog(MCStreamer &streamer, WinEH::FrameInfo *info, WinEH::FrameInfo::Segment *Seg, int PrologCodeBytes)
Definition: MCWin64EH.cpp:968
static void ARM64EmitUnwindInfoForSegment(MCStreamer &streamer, WinEH::FrameInfo *info, WinEH::FrameInfo::Segment &Seg, bool TryPacked=true)
Definition: MCWin64EH.cpp:1418
static uint32_t ARMCountOfUnwindCodes(ArrayRef< WinEH::Instruction > Insns)
Definition: MCWin64EH.cpp:1643
static uint32_t ARM64CountOfUnwindCodes(ArrayRef< WinEH::Instruction > Insns)
Definition: MCWin64EH.cpp:511
static void checkARMInstructions(MCStreamer &Streamer, ArrayRef< WinEH::Instruction > Insns, const MCSymbol *Begin, const MCSymbol *End, StringRef Name, StringRef Type)
Definition: MCWin64EH.cpp:1773
static bool isARMTerminator(const WinEH::Instruction &inst)
Definition: MCWin64EH.cpp:1798
static void ARM64EmitUnwindCode(MCStreamer &streamer, const WinEH::Instruction &inst)
Definition: MCWin64EH.cpp:621
static void simplifyARM64Opcodes(std::vector< WinEH::Instruction > &Instructions, bool Reverse)
Definition: MCWin64EH.cpp:883
static void ARMEmitUnwindCode(MCStreamer &streamer, const WinEH::Instruction &inst)
Definition: MCWin64EH.cpp:1811
static std::optional< int64_t > GetOptionalAbsDifference(const MCAssembler &Assembler, const MCSymbol *LHS, const MCSymbol *RHS)
Definition: MCWin64EH.cpp:211
static int getARM64OffsetInProlog(const std::vector< WinEH::Instruction > &Prolog, const std::vector< WinEH::Instruction > &Epilog)
Definition: MCWin64EH.cpp:947
static void ARMEmitRuntimeFunction(MCStreamer &streamer, const WinEH::FrameInfo *info)
Definition: MCWin64EH.cpp:2738
static bool tryARM64PackedUnwind(WinEH::FrameInfo *info, uint32_t FuncLength, int PackedEpilogOffset)
Definition: MCWin64EH.cpp:1011
static void EmitUnwindInfo(MCStreamer &streamer, WinEH::FrameInfo *info)
Definition: MCWin64EH.cpp:226
static void EmitUnwindCode(MCStreamer &streamer, const MCSymbol *begin, WinEH::Instruction &inst)
Definition: MCWin64EH.cpp:106
static void ARM64EmitUnwindInfo(MCStreamer &streamer, WinEH::FrameInfo *info, bool TryPacked=true)
Definition: MCWin64EH.cpp:1565
static int getARMOffsetInProlog(const std::vector< WinEH::Instruction > &Prolog, const std::vector< WinEH::Instruction > &Epilog, bool CanTweakProlog)
Definition: MCWin64EH.cpp:1947
static void ARM64EmitRuntimeFunction(MCStreamer &streamer, const WinEH::FrameInfo *info)
Definition: MCWin64EH.cpp:2720
static void EmitSymbolRefWithOfs(MCStreamer &streamer, const MCSymbol *Base, int64_t Offset)
Definition: MCWin64EH.cpp:174
static bool parseRegMask(unsigned Mask, bool &HasLR, bool &HasR11, unsigned &Folded, int &IntRegs)
Definition: MCWin64EH.cpp:2040
static int checkARMPackedEpilog(MCStreamer &streamer, WinEH::FrameInfo *info, int PrologCodeBytes)
Definition: MCWin64EH.cpp:1983
static int64_t GetAbsDifference(MCStreamer &Streamer, const MCSymbol *LHS, const MCSymbol *RHS)
Definition: MCWin64EH.cpp:464
static void ARM64FindSegmentsInFunction(MCStreamer &streamer, WinEH::FrameInfo *info, int64_t RawFuncLength)
Definition: MCWin64EH.cpp:1337
static bool tryARMPackedUnwind(MCStreamer &streamer, WinEH::FrameInfo *info, uint32_t FuncLength)
Definition: MCWin64EH.cpp:2080
static MCSymbol * FindMatchingEpilog(const std::vector< WinEH::Instruction > &EpilogInstrs, const std::vector< MCSymbol * > &Epilogs, const WinEH::FrameInfo *info)
Definition: MCWin64EH.cpp:858
static void EmitRuntimeFunction(MCStreamer &streamer, const WinEH::FrameInfo *info)
Definition: MCWin64EH.cpp:198
static void checkARM64Instructions(MCStreamer &Streamer, ArrayRef< WinEH::Instruction > Insns, const MCSymbol *Begin, const MCSymbol *End, StringRef Name, StringRef Type)
Definition: MCWin64EH.cpp:473
static const MCExpr * GetSubDivExpr(MCStreamer &Streamer, const MCSymbol *LHS, const MCSymbol *RHS, int Div)
Definition: MCWin64EH.cpp:445
static void EmitAbsDifference(MCStreamer &Streamer, const MCSymbol *LHS, const MCSymbol *RHS)
Definition: MCWin64EH.cpp:97
static void ARMEmitUnwindInfo(MCStreamer &streamer, WinEH::FrameInfo *info, bool TryPacked=true)
Definition: MCWin64EH.cpp:2482
static uint32_t ARMCountOfInstructionBytes(ArrayRef< WinEH::Instruction > Insns, bool *HasCustom=nullptr)
Definition: MCWin64EH.cpp:1714
static void ARM64ProcessEpilogs(WinEH::FrameInfo *info, WinEH::FrameInfo::Segment *Seg, uint32_t &TotalCodeBytes, MapVector< MCSymbol *, uint32_t > &EpilogInfo)
Definition: MCWin64EH.cpp:1293
static uint8_t CountOfUnwindCodes(std::vector< WinEH::Instruction > &Insns)
Definition: MCWin64EH.cpp:69
#define I(x, y, z)
Definition: MD5.cpp:58
#define H(x, y, z)
Definition: MD5.cpp:57
raw_pwrite_stream & OS
static const MCPhysReg IntRegs[32]
Value * RHS
Value * LHS
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition: ArrayRef.h:41
size_t size() const
size - Get the array size.
Definition: ArrayRef.h:147
This class represents an Operation in the Expression.
Tagged union holding either a T or a Error.
Definition: Error.h:485
This class is intended to be used as a base class for asm properties and features specific to the tar...
Definition: MCAsmInfo.h:64
MCContext & getContext() const
Definition: MCAssembler.h:169
static const MCBinaryExpr * createAdd(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx, SMLoc Loc=SMLoc())
Definition: MCExpr.h:343
static const MCBinaryExpr * createOr(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx)
Definition: MCExpr.h:408
static const MCBinaryExpr * createDiv(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx)
Definition: MCExpr.h:353
static const MCBinaryExpr * createSub(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx)
Definition: MCExpr.h:428
static LLVM_ABI const MCConstantExpr * create(int64_t Value, MCContext &Ctx, bool PrintInHex=false, unsigned SizeInBytes=0)
Definition: MCExpr.cpp:212
Context object for machine code objects.
Definition: MCContext.h:83
LLVM_ABI MCSymbol * createTempSymbol()
Create a temporary symbol with a unique name.
Definition: MCContext.cpp:386
LLVM_ABI void reportError(SMLoc L, const Twine &Msg)
Definition: MCContext.cpp:1115
Base class for the full range of assembler expressions which are needed for parsing.
Definition: MCExpr.h:34
Streaming object file generation interface.
Instances of this class represent a uniqued identifier for a section in the current translation unit.
Definition: MCSection.h:496
Streaming machine code generation interface.
Definition: MCStreamer.h:220
virtual MCSymbol * emitCFILabel()
When emitting an object file, create and emit a real label.
Definition: MCStreamer.cpp:475
MCSection * getAssociatedPDataSection(const MCSection *TextSec)
Get the .pdata section used for the given section.
Definition: MCStreamer.cpp:867
MCContext & getContext() const
Definition: MCStreamer.h:314
MCSection * getAssociatedXDataSection(const MCSection *TextSec)
Get the .xdata section used for the given section.
Definition: MCStreamer.cpp:873
void emitValue(const MCExpr *Value, unsigned Size, SMLoc Loc=SMLoc())
Definition: MCStreamer.cpp:178
virtual void emitLabel(MCSymbol *Symbol, SMLoc Loc=SMLoc())
Emit a label for Symbol into the current section.
Definition: MCStreamer.cpp:395
virtual void emitValueToAlignment(Align Alignment, int64_t Fill=0, uint8_t FillLen=1, unsigned MaxBytesToEmit=0)
Emit some number of copies of Value until the byte alignment ByteAlignment is reached.
void emitInt16(uint64_t Value)
Definition: MCStreamer.h:749
virtual void switchSection(MCSection *Section, uint32_t Subsec=0)
Set the current section where code is being emitted to Section.
void emitInt32(uint64_t Value)
Definition: MCStreamer.h:750
ArrayRef< std::unique_ptr< WinEH::FrameInfo > > getWinFrameInfos() const
Definition: MCStreamer.h:347
void emitInt8(uint64_t Value)
Definition: MCStreamer.h:748
Represent a reference to a symbol from inside an expression.
Definition: MCExpr.h:190
static const MCSymbolRefExpr * create(const MCSymbol *Symbol, MCContext &Ctx, SMLoc Loc=SMLoc())
Definition: MCExpr.h:214
MCSymbol - Instances of this class represent a symbol name in the MC file, and MCSymbols are created ...
Definition: MCSymbol.h:42
LLVM_ABI void print(raw_ostream &OS, const MCAsmInfo *MAI) const
print - Print the value to the stream OS.
Definition: MCSymbol.cpp:59
MCFragment * getFragment() const
Definition: MCSymbol.h:346
Extension point for target-specific MCExpr subclasses to implement.
Definition: MCExpr.h:465
MCExpr that represents the epilog unwind code in an unwind table.
Definition: MCWin64EH.cpp:24
MCFragment * findAssociatedFragment() const override
Definition: MCWin64EH.cpp:59
void printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const override
Definition: MCWin64EH.cpp:47
bool evaluateAsRelocatableImpl(MCValue &Res, const MCAssembler *Asm) const override
Definition: MCWin64EH.cpp:383
static MCUnwindV2EpilogTargetExpr * create(const WinEH::FrameInfo &FrameInfo, const WinEH::FrameInfo::Epilog &Epilog, uint8_t EpilogSize_, MCContext &Ctx)
Definition: MCWin64EH.cpp:41
void visitUsedExpr(MCStreamer &Streamer) const override
Definition: MCWin64EH.cpp:55
static MCValue get(const MCSymbol *SymA, const MCSymbol *SymB=nullptr, int64_t Val=0, uint32_t Specifier=0)
Definition: MCValue.h:56
This class implements a map that also provides access to all stored values in a deterministic order.
Definition: MapVector.h:36
bool contains(const KeyT &Key) const
Definition: MapVector.h:137
ValueT lookup(const KeyT &Key) const
Definition: MapVector.h:99
void clear()
Definition: MapVector.h:84
Represents a location in source code.
Definition: SMLoc.h:23
size_t size() const
Definition: SmallVector.h:79
void push_back(const T &Elt)
Definition: SmallVector.h:414
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1197
StackOffset holds a fixed and a scalable offset in bytes.
Definition: TypeSize.h:34
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:55
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition: Twine.h:82
The instances of the Type class are immutable: once they are created, they are never changed.
Definition: Type.h:45
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
Definition: Value.cpp:322
void EmitUnwindInfo(MCStreamer &Streamer, WinEH::FrameInfo *FI, bool HandlerData) const override
Definition: MCWin64EH.cpp:2778
void Emit(MCStreamer &Streamer) const override
This emits the unwind info sections (.pdata and .xdata in PE/COFF).
Definition: MCWin64EH.cpp:2753
void Emit(MCStreamer &Streamer) const override
This emits the unwind info sections (.pdata and .xdata in PE/COFF).
Definition: MCWin64EH.cpp:2798
void EmitUnwindInfo(MCStreamer &Streamer, WinEH::FrameInfo *FI, bool HandlerData) const override
Definition: MCWin64EH.cpp:2823
void Emit(MCStreamer &Streamer) const override
This emits the unwind info sections (.pdata and .xdata in PE/COFF).
Definition: MCWin64EH.cpp:418
void EmitUnwindInfo(MCStreamer &Streamer, WinEH::FrameInfo *FI, bool HandlerData) const override
Definition: MCWin64EH.cpp:434
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition: raw_ostream.h:53
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ C
The default llvm calling convention, compatible with C.
Definition: CallingConv.h:34
UnwindOpcodes
UnwindOpcodes - Enumeration whose values specify a single operation in the prolog of a function.
Definition: Win64EH.h:26
@ UOP_SaveFRegP
Definition: Win64EH.h:54
@ UOP_SaveFReg
Definition: Win64EH.h:52
@ UOP_WideEndNop
Definition: Win64EH.h:109
@ UOP_SaveAnyRegDPX
Definition: Win64EH.h:75
@ UOP_SaveRegsR4R7LR
Definition: Win64EH.h:98
@ UOP_SaveFRegPX
Definition: Win64EH.h:55
@ UOP_SaveFPLRX
Definition: Win64EH.h:45
@ UOP_ClearUnwoundToCall
Definition: Win64EH.h:64
@ UOP_SaveNonVolBig
Definition: Win64EH.h:35
@ UOP_WideAllocMedium
Definition: Win64EH.h:92
@ UOP_SaveAnyRegDX
Definition: Win64EH.h:74
@ UOP_AllocHuge
Definition: Win64EH.h:91
@ UOP_SaveFRegD0D15
Definition: Win64EH.h:103
@ UOP_SaveAnyRegQP
Definition: Win64EH.h:71
@ UOP_SaveAnyRegD
Definition: Win64EH.h:68
@ UOP_SaveFPLR
Definition: Win64EH.h:46
@ UOP_WideSaveRegsR4R11LR
Definition: Win64EH.h:99
@ UOP_SaveNonVol
Definition: Win64EH.h:34
@ UOP_SaveAnyRegIPX
Definition: Win64EH.h:73
@ UOP_SavePReg
Definition: Win64EH.h:80
@ UOP_WideAllocHuge
Definition: Win64EH.h:94
@ UOP_SaveRegX
Definition: Win64EH.h:48
@ UOP_SaveAnyRegQX
Definition: Win64EH.h:76
@ UOP_AllocLarge
Definition: Win64EH.h:31
@ UOP_SetFPReg
Definition: Win64EH.h:33
@ UOP_SaveRegMask
Definition: Win64EH.h:101
@ UOP_SaveLRPair
Definition: Win64EH.h:51
@ UOP_SaveAnyRegIX
Definition: Win64EH.h:72
@ UOP_SaveXMM128
Definition: Win64EH.h:38
@ UOP_SaveZReg
Definition: Win64EH.h:79
@ UOP_AllocSmall
Definition: Win64EH.h:32
@ UOP_SaveRegP
Definition: Win64EH.h:49
@ UOP_SaveXMM128Big
Definition: Win64EH.h:39
@ UOP_SaveRegPX
Definition: Win64EH.h:50
@ UOP_SaveAnyRegQ
Definition: Win64EH.h:70
@ UOP_SaveNext
Definition: Win64EH.h:60
@ UOP_SaveAnyRegDP
Definition: Win64EH.h:69
@ UOP_PushNonVol
Definition: Win64EH.h:30
@ UOP_SaveFRegD8D15
Definition: Win64EH.h:100
@ UOP_PushMachFrame
Definition: Win64EH.h:40
@ UOP_SaveR19R20X
Definition: Win64EH.h:44
@ UOP_SaveAnyRegQPX
Definition: Win64EH.h:77
@ UOP_PACSignLR
Definition: Win64EH.h:65
@ UOP_WideAllocLarge
Definition: Win64EH.h:93
@ UOP_ECContext
Definition: Win64EH.h:63
@ UOP_WideSaveRegMask
Definition: Win64EH.h:96
@ UOP_AllocMedium
Definition: Win64EH.h:43
@ UOP_SaveAnyRegIP
Definition: Win64EH.h:67
@ UOP_TrapFrame
Definition: Win64EH.h:61
@ UOP_SaveFRegX
Definition: Win64EH.h:53
@ UOP_SaveFRegD16D31
Definition: Win64EH.h:104
@ UOP_SaveAnyRegI
Definition: Win64EH.h:66
@ UNW_TerminateHandler
UNW_TerminateHandler - Specifies that this function has a termination handler.
Definition: Win64EH.h:143
@ UNW_ExceptionHandler
UNW_ExceptionHandler - Specifies that this function has an exception handler.
Definition: Win64EH.h:140
@ UNW_ChainInfo
UNW_ChainInfo - Specifies that this UnwindInfo structure is chained to another one.
Definition: Win64EH.h:146
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
@ Offset
Definition: DWP.cpp:477
@ FK_Data_2
A two-byte fixup.
Definition: MCFixup.h:35
auto reverse(ContainerTy &&C)
Definition: STLExtras.h:428
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
Definition: Error.cpp:167
@ First
Helpers to iterate all locations in the MemoryEffectsBase class.
#define N
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition: Alignment.h:39
std::vector< Instruction > Instructions
Definition: MCWinEH.h:65
MapVector< MCSymbol *, int64_t > Epilogs
Definition: MCWinEH.h:81
const MCSymbol * Function
Definition: MCWinEH.h:46
const MCSymbol * FuncletOrFuncEnd
Definition: MCWinEH.h:44
const MCSymbol * Label
Definition: MCWinEH.h:24