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