1 //===- lib/MC/MCWin64EH.cpp - MCWin64EH implementation --------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "llvm/MC/MCWin64EH.h"
10 #include "llvm/ADT/Twine.h"
11 #include "llvm/MC/MCContext.h"
12 #include "llvm/MC/MCExpr.h"
13 #include "llvm/MC/MCObjectStreamer.h"
14 #include "llvm/MC/MCStreamer.h"
15 #include "llvm/MC/MCSymbol.h"
16 #include "llvm/Support/Win64EH.h"
23 // NOTE: All relocations generated here are 4-byte image-relative.
25 static uint8_t CountOfUnwindCodes(std::vector
<WinEH::Instruction
> &Insns
) {
27 for (const auto &I
: Insns
) {
28 switch (static_cast<Win64EH::UnwindOpcodes
>(I
.Operation
)) {
30 llvm_unreachable("Unsupported unwind code");
31 case Win64EH::UOP_PushNonVol
:
32 case Win64EH::UOP_AllocSmall
:
33 case Win64EH::UOP_SetFPReg
:
34 case Win64EH::UOP_PushMachFrame
:
37 case Win64EH::UOP_SaveNonVol
:
38 case Win64EH::UOP_SaveXMM128
:
41 case Win64EH::UOP_SaveNonVolBig
:
42 case Win64EH::UOP_SaveXMM128Big
:
45 case Win64EH::UOP_AllocLarge
:
46 Count
+= (I
.Offset
> 512 * 1024 - 8) ? 3 : 2;
53 static void EmitAbsDifference(MCStreamer
&Streamer
, const MCSymbol
*LHS
,
54 const MCSymbol
*RHS
) {
55 MCContext
&Context
= Streamer
.getContext();
57 MCBinaryExpr::createSub(MCSymbolRefExpr::create(LHS
, Context
),
58 MCSymbolRefExpr::create(RHS
, Context
), Context
);
59 Streamer
.emitValue(Diff
, 1);
62 static void EmitUnwindCode(MCStreamer
&streamer
, const MCSymbol
*begin
,
63 WinEH::Instruction
&inst
) {
66 b2
= (inst
.Operation
& 0x0F);
67 switch (static_cast<Win64EH::UnwindOpcodes
>(inst
.Operation
)) {
69 llvm_unreachable("Unsupported unwind code");
70 case Win64EH::UOP_PushNonVol
:
71 EmitAbsDifference(streamer
, inst
.Label
, begin
);
72 b2
|= (inst
.Register
& 0x0F) << 4;
73 streamer
.emitInt8(b2
);
75 case Win64EH::UOP_AllocLarge
:
76 EmitAbsDifference(streamer
, inst
.Label
, begin
);
77 if (inst
.Offset
> 512 * 1024 - 8) {
79 streamer
.emitInt8(b2
);
80 w
= inst
.Offset
& 0xFFF8;
81 streamer
.emitInt16(w
);
82 w
= inst
.Offset
>> 16;
84 streamer
.emitInt8(b2
);
87 streamer
.emitInt16(w
);
89 case Win64EH::UOP_AllocSmall
:
90 b2
|= (((inst
.Offset
- 8) >> 3) & 0x0F) << 4;
91 EmitAbsDifference(streamer
, inst
.Label
, begin
);
92 streamer
.emitInt8(b2
);
94 case Win64EH::UOP_SetFPReg
:
95 EmitAbsDifference(streamer
, inst
.Label
, begin
);
96 streamer
.emitInt8(b2
);
98 case Win64EH::UOP_SaveNonVol
:
99 case Win64EH::UOP_SaveXMM128
:
100 b2
|= (inst
.Register
& 0x0F) << 4;
101 EmitAbsDifference(streamer
, inst
.Label
, begin
);
102 streamer
.emitInt8(b2
);
103 w
= inst
.Offset
>> 3;
104 if (inst
.Operation
== Win64EH::UOP_SaveXMM128
)
106 streamer
.emitInt16(w
);
108 case Win64EH::UOP_SaveNonVolBig
:
109 case Win64EH::UOP_SaveXMM128Big
:
110 b2
|= (inst
.Register
& 0x0F) << 4;
111 EmitAbsDifference(streamer
, inst
.Label
, begin
);
112 streamer
.emitInt8(b2
);
113 if (inst
.Operation
== Win64EH::UOP_SaveXMM128Big
)
114 w
= inst
.Offset
& 0xFFF0;
116 w
= inst
.Offset
& 0xFFF8;
117 streamer
.emitInt16(w
);
118 w
= inst
.Offset
>> 16;
119 streamer
.emitInt16(w
);
121 case Win64EH::UOP_PushMachFrame
:
122 if (inst
.Offset
== 1)
124 EmitAbsDifference(streamer
, inst
.Label
, begin
);
125 streamer
.emitInt8(b2
);
130 static void EmitSymbolRefWithOfs(MCStreamer
&streamer
,
131 const MCSymbol
*Base
,
133 MCContext
&Context
= streamer
.getContext();
134 const MCConstantExpr
*OffExpr
= MCConstantExpr::create(Offset
, Context
);
135 const MCSymbolRefExpr
*BaseRefRel
= MCSymbolRefExpr::create(Base
,
136 MCSymbolRefExpr::VK_COFF_IMGREL32
,
138 streamer
.emitValue(MCBinaryExpr::createAdd(BaseRefRel
, OffExpr
, Context
), 4);
141 static void EmitSymbolRefWithOfs(MCStreamer
&streamer
,
142 const MCSymbol
*Base
,
143 const MCSymbol
*Other
) {
144 MCContext
&Context
= streamer
.getContext();
145 const MCSymbolRefExpr
*BaseRef
= MCSymbolRefExpr::create(Base
, Context
);
146 const MCSymbolRefExpr
*OtherRef
= MCSymbolRefExpr::create(Other
, Context
);
147 const MCExpr
*Ofs
= MCBinaryExpr::createSub(OtherRef
, BaseRef
, Context
);
148 const MCSymbolRefExpr
*BaseRefRel
= MCSymbolRefExpr::create(Base
,
149 MCSymbolRefExpr::VK_COFF_IMGREL32
,
151 streamer
.emitValue(MCBinaryExpr::createAdd(BaseRefRel
, Ofs
, Context
), 4);
154 static void EmitRuntimeFunction(MCStreamer
&streamer
,
155 const WinEH::FrameInfo
*info
) {
156 MCContext
&context
= streamer
.getContext();
158 streamer
.emitValueToAlignment(Align(4));
159 EmitSymbolRefWithOfs(streamer
, info
->Begin
, info
->Begin
);
160 EmitSymbolRefWithOfs(streamer
, info
->Begin
, info
->End
);
161 streamer
.emitValue(MCSymbolRefExpr::create(info
->Symbol
,
162 MCSymbolRefExpr::VK_COFF_IMGREL32
,
166 static void EmitUnwindInfo(MCStreamer
&streamer
, WinEH::FrameInfo
*info
) {
167 // If this UNWIND_INFO already has a symbol, it's already been emitted.
171 MCContext
&context
= streamer
.getContext();
172 MCSymbol
*Label
= context
.createTempSymbol();
174 streamer
.emitValueToAlignment(Align(4));
175 streamer
.emitLabel(Label
);
176 info
->Symbol
= Label
;
178 // Upper 3 bits are the version number (currently 1).
179 uint8_t flags
= 0x01;
180 if (info
->ChainedParent
)
181 flags
|= Win64EH::UNW_ChainInfo
<< 3;
183 if (info
->HandlesUnwind
)
184 flags
|= Win64EH::UNW_TerminateHandler
<< 3;
185 if (info
->HandlesExceptions
)
186 flags
|= Win64EH::UNW_ExceptionHandler
<< 3;
188 streamer
.emitInt8(flags
);
191 EmitAbsDifference(streamer
, info
->PrologEnd
, info
->Begin
);
193 streamer
.emitInt8(0);
195 uint8_t numCodes
= CountOfUnwindCodes(info
->Instructions
);
196 streamer
.emitInt8(numCodes
);
199 if (info
->LastFrameInst
>= 0) {
200 WinEH::Instruction
&frameInst
= info
->Instructions
[info
->LastFrameInst
];
201 assert(frameInst
.Operation
== Win64EH::UOP_SetFPReg
);
202 frame
= (frameInst
.Register
& 0x0F) | (frameInst
.Offset
& 0xF0);
204 streamer
.emitInt8(frame
);
206 // Emit unwind instructions (in reverse order).
207 uint8_t numInst
= info
->Instructions
.size();
208 for (uint8_t c
= 0; c
< numInst
; ++c
) {
209 WinEH::Instruction inst
= info
->Instructions
.back();
210 info
->Instructions
.pop_back();
211 EmitUnwindCode(streamer
, info
->Begin
, inst
);
214 // For alignment purposes, the instruction array will always have an even
215 // number of entries, with the final entry potentially unused (in which case
216 // the array will be one longer than indicated by the count of unwind codes
219 streamer
.emitInt16(0);
222 if (flags
& (Win64EH::UNW_ChainInfo
<< 3))
223 EmitRuntimeFunction(streamer
, info
->ChainedParent
);
225 ((Win64EH::UNW_TerminateHandler
|Win64EH::UNW_ExceptionHandler
) << 3))
226 streamer
.emitValue(MCSymbolRefExpr::create(info
->ExceptionHandler
,
227 MCSymbolRefExpr::VK_COFF_IMGREL32
,
229 else if (numCodes
== 0) {
230 // The minimum size of an UNWIND_INFO struct is 8 bytes. If we're not
231 // a chained unwind info, if there is no handler, and if there are fewer
232 // than 2 slots used in the unwind code array, we have to pad to 8 bytes.
233 streamer
.emitInt32(0);
237 void llvm::Win64EH::UnwindEmitter::Emit(MCStreamer
&Streamer
) const {
238 // Emit the unwind info structs first.
239 for (const auto &CFI
: Streamer
.getWinFrameInfos()) {
240 MCSection
*XData
= Streamer
.getAssociatedXDataSection(CFI
->TextSection
);
241 Streamer
.switchSection(XData
);
242 ::EmitUnwindInfo(Streamer
, CFI
.get());
245 // Now emit RUNTIME_FUNCTION entries.
246 for (const auto &CFI
: Streamer
.getWinFrameInfos()) {
247 MCSection
*PData
= Streamer
.getAssociatedPDataSection(CFI
->TextSection
);
248 Streamer
.switchSection(PData
);
249 EmitRuntimeFunction(Streamer
, CFI
.get());
253 void llvm::Win64EH::UnwindEmitter::EmitUnwindInfo(MCStreamer
&Streamer
,
254 WinEH::FrameInfo
*info
,
255 bool HandlerData
) const {
256 // Switch sections (the static function above is meant to be called from
257 // here and from Emit().
258 MCSection
*XData
= Streamer
.getAssociatedXDataSection(info
->TextSection
);
259 Streamer
.switchSection(XData
);
261 ::EmitUnwindInfo(Streamer
, info
);
264 static const MCExpr
*GetSubDivExpr(MCStreamer
&Streamer
, const MCSymbol
*LHS
,
265 const MCSymbol
*RHS
, int Div
) {
266 MCContext
&Context
= Streamer
.getContext();
268 MCBinaryExpr::createSub(MCSymbolRefExpr::create(LHS
, Context
),
269 MCSymbolRefExpr::create(RHS
, Context
), Context
);
271 Expr
= MCBinaryExpr::createDiv(Expr
, MCConstantExpr::create(Div
, Context
),
276 static std::optional
<int64_t> GetOptionalAbsDifference(MCStreamer
&Streamer
,
278 const MCSymbol
*RHS
) {
279 MCContext
&Context
= Streamer
.getContext();
281 MCBinaryExpr::createSub(MCSymbolRefExpr::create(LHS
, Context
),
282 MCSymbolRefExpr::create(RHS
, Context
), Context
);
283 MCObjectStreamer
*OS
= (MCObjectStreamer
*)(&Streamer
);
284 // It should normally be possible to calculate the length of a function
285 // at this point, but it might not be possible in the presence of certain
286 // unusual constructs, like an inline asm with an alignment directive.
288 if (!Diff
->evaluateAsAbsolute(value
, OS
->getAssembler()))
293 static int64_t GetAbsDifference(MCStreamer
&Streamer
, const MCSymbol
*LHS
,
294 const MCSymbol
*RHS
) {
295 std::optional
<int64_t> MaybeDiff
=
296 GetOptionalAbsDifference(Streamer
, LHS
, RHS
);
298 report_fatal_error("Failed to evaluate function length in SEH unwind info");
302 static void checkARM64Instructions(MCStreamer
&Streamer
,
303 ArrayRef
<WinEH::Instruction
> Insns
,
304 const MCSymbol
*Begin
, const MCSymbol
*End
,
305 StringRef Name
, StringRef Type
) {
308 std::optional
<int64_t> MaybeDistance
=
309 GetOptionalAbsDifference(Streamer
, End
, Begin
);
312 uint32_t Distance
= (uint32_t)*MaybeDistance
;
314 for (const auto &I
: Insns
) {
315 switch (static_cast<Win64EH::UnwindOpcodes
>(I
.Operation
)) {
318 case Win64EH::UOP_TrapFrame
:
319 case Win64EH::UOP_PushMachFrame
:
320 case Win64EH::UOP_Context
:
321 case Win64EH::UOP_ClearUnwoundToCall
:
322 // Can't reason about these opcodes and how they map to actual
327 // Exclude the end opcode which doesn't map to an instruction.
328 uint32_t InstructionBytes
= 4 * (Insns
.size() - 1);
329 if (Distance
!= InstructionBytes
) {
330 Streamer
.getContext().reportError(
331 SMLoc(), "Incorrect size for " + Name
+ " " + Type
+ ": " +
333 " bytes of instructions in range, but .seh directives "
334 "corresponding to " +
335 Twine(InstructionBytes
) + " bytes\n");
339 static uint32_t ARM64CountOfUnwindCodes(ArrayRef
<WinEH::Instruction
> Insns
) {
341 for (const auto &I
: Insns
) {
342 switch (static_cast<Win64EH::UnwindOpcodes
>(I
.Operation
)) {
344 llvm_unreachable("Unsupported ARM64 unwind code");
345 case Win64EH::UOP_AllocSmall
:
348 case Win64EH::UOP_AllocMedium
:
351 case Win64EH::UOP_AllocLarge
:
354 case Win64EH::UOP_SaveR19R20X
:
357 case Win64EH::UOP_SaveFPLRX
:
360 case Win64EH::UOP_SaveFPLR
:
363 case Win64EH::UOP_SaveReg
:
366 case Win64EH::UOP_SaveRegP
:
369 case Win64EH::UOP_SaveRegPX
:
372 case Win64EH::UOP_SaveRegX
:
375 case Win64EH::UOP_SaveLRPair
:
378 case Win64EH::UOP_SaveFReg
:
381 case Win64EH::UOP_SaveFRegP
:
384 case Win64EH::UOP_SaveFRegX
:
387 case Win64EH::UOP_SaveFRegPX
:
390 case Win64EH::UOP_SetFP
:
393 case Win64EH::UOP_AddFP
:
396 case Win64EH::UOP_Nop
:
399 case Win64EH::UOP_End
:
402 case Win64EH::UOP_SaveNext
:
405 case Win64EH::UOP_TrapFrame
:
408 case Win64EH::UOP_PushMachFrame
:
411 case Win64EH::UOP_Context
:
414 case Win64EH::UOP_ClearUnwoundToCall
:
417 case Win64EH::UOP_PACSignLR
:
420 case Win64EH::UOP_SaveAnyRegI
:
421 case Win64EH::UOP_SaveAnyRegIP
:
422 case Win64EH::UOP_SaveAnyRegD
:
423 case Win64EH::UOP_SaveAnyRegDP
:
424 case Win64EH::UOP_SaveAnyRegQ
:
425 case Win64EH::UOP_SaveAnyRegQP
:
426 case Win64EH::UOP_SaveAnyRegIX
:
427 case Win64EH::UOP_SaveAnyRegIPX
:
428 case Win64EH::UOP_SaveAnyRegDX
:
429 case Win64EH::UOP_SaveAnyRegDPX
:
430 case Win64EH::UOP_SaveAnyRegQX
:
431 case Win64EH::UOP_SaveAnyRegQPX
:
439 // Unwind opcode encodings and restrictions are documented at
440 // https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling
441 static void ARM64EmitUnwindCode(MCStreamer
&streamer
,
442 const WinEH::Instruction
&inst
) {
444 switch (static_cast<Win64EH::UnwindOpcodes
>(inst
.Operation
)) {
446 llvm_unreachable("Unsupported ARM64 unwind code");
447 case Win64EH::UOP_AllocSmall
:
448 b
= (inst
.Offset
>> 4) & 0x1F;
449 streamer
.emitInt8(b
);
451 case Win64EH::UOP_AllocMedium
: {
452 uint16_t hw
= (inst
.Offset
>> 4) & 0x7FF;
455 streamer
.emitInt8(b
);
457 streamer
.emitInt8(b
);
460 case Win64EH::UOP_AllocLarge
: {
463 streamer
.emitInt8(b
);
464 w
= inst
.Offset
>> 4;
465 b
= (w
& 0x00FF0000) >> 16;
466 streamer
.emitInt8(b
);
467 b
= (w
& 0x0000FF00) >> 8;
468 streamer
.emitInt8(b
);
470 streamer
.emitInt8(b
);
473 case Win64EH::UOP_SetFP
:
475 streamer
.emitInt8(b
);
477 case Win64EH::UOP_AddFP
:
479 streamer
.emitInt8(b
);
480 b
= (inst
.Offset
>> 3);
481 streamer
.emitInt8(b
);
483 case Win64EH::UOP_Nop
:
485 streamer
.emitInt8(b
);
487 case Win64EH::UOP_SaveR19R20X
:
489 b
|= (inst
.Offset
>> 3) & 0x1F;
490 streamer
.emitInt8(b
);
492 case Win64EH::UOP_SaveFPLRX
:
494 b
|= ((inst
.Offset
- 1) >> 3) & 0x3F;
495 streamer
.emitInt8(b
);
497 case Win64EH::UOP_SaveFPLR
:
499 b
|= (inst
.Offset
>> 3) & 0x3F;
500 streamer
.emitInt8(b
);
502 case Win64EH::UOP_SaveReg
:
503 assert(inst
.Register
>= 19 && "Saved reg must be >= 19");
504 reg
= inst
.Register
- 19;
505 b
= 0xD0 | ((reg
& 0xC) >> 2);
506 streamer
.emitInt8(b
);
507 b
= ((reg
& 0x3) << 6) | (inst
.Offset
>> 3);
508 streamer
.emitInt8(b
);
510 case Win64EH::UOP_SaveRegX
:
511 assert(inst
.Register
>= 19 && "Saved reg must be >= 19");
512 reg
= inst
.Register
- 19;
513 b
= 0xD4 | ((reg
& 0x8) >> 3);
514 streamer
.emitInt8(b
);
515 b
= ((reg
& 0x7) << 5) | ((inst
.Offset
>> 3) - 1);
516 streamer
.emitInt8(b
);
518 case Win64EH::UOP_SaveRegP
:
519 assert(inst
.Register
>= 19 && "Saved registers must be >= 19");
520 reg
= inst
.Register
- 19;
521 b
= 0xC8 | ((reg
& 0xC) >> 2);
522 streamer
.emitInt8(b
);
523 b
= ((reg
& 0x3) << 6) | (inst
.Offset
>> 3);
524 streamer
.emitInt8(b
);
526 case Win64EH::UOP_SaveRegPX
:
527 assert(inst
.Register
>= 19 && "Saved registers must be >= 19");
528 reg
= inst
.Register
- 19;
529 b
= 0xCC | ((reg
& 0xC) >> 2);
530 streamer
.emitInt8(b
);
531 b
= ((reg
& 0x3) << 6) | ((inst
.Offset
>> 3) - 1);
532 streamer
.emitInt8(b
);
534 case Win64EH::UOP_SaveLRPair
:
535 assert(inst
.Register
>= 19 && "Saved reg must be >= 19");
536 reg
= inst
.Register
- 19;
537 assert((reg
% 2) == 0 && "Saved reg must be 19+2*X");
539 b
= 0xD6 | ((reg
& 0x7) >> 2);
540 streamer
.emitInt8(b
);
541 b
= ((reg
& 0x3) << 6) | (inst
.Offset
>> 3);
542 streamer
.emitInt8(b
);
544 case Win64EH::UOP_SaveFReg
:
545 assert(inst
.Register
>= 8 && "Saved dreg must be >= 8");
546 reg
= inst
.Register
- 8;
547 b
= 0xDC | ((reg
& 0x4) >> 2);
548 streamer
.emitInt8(b
);
549 b
= ((reg
& 0x3) << 6) | (inst
.Offset
>> 3);
550 streamer
.emitInt8(b
);
552 case Win64EH::UOP_SaveFRegX
:
553 assert(inst
.Register
>= 8 && "Saved dreg must be >= 8");
554 reg
= inst
.Register
- 8;
556 streamer
.emitInt8(b
);
557 b
= ((reg
& 0x7) << 5) | ((inst
.Offset
>> 3) - 1);
558 streamer
.emitInt8(b
);
560 case Win64EH::UOP_SaveFRegP
:
561 assert(inst
.Register
>= 8 && "Saved dregs must be >= 8");
562 reg
= inst
.Register
- 8;
563 b
= 0xD8 | ((reg
& 0x4) >> 2);
564 streamer
.emitInt8(b
);
565 b
= ((reg
& 0x3) << 6) | (inst
.Offset
>> 3);
566 streamer
.emitInt8(b
);
568 case Win64EH::UOP_SaveFRegPX
:
569 assert(inst
.Register
>= 8 && "Saved dregs must be >= 8");
570 reg
= inst
.Register
- 8;
571 b
= 0xDA | ((reg
& 0x4) >> 2);
572 streamer
.emitInt8(b
);
573 b
= ((reg
& 0x3) << 6) | ((inst
.Offset
>> 3) - 1);
574 streamer
.emitInt8(b
);
576 case Win64EH::UOP_End
:
578 streamer
.emitInt8(b
);
580 case Win64EH::UOP_SaveNext
:
582 streamer
.emitInt8(b
);
584 case Win64EH::UOP_TrapFrame
:
586 streamer
.emitInt8(b
);
588 case Win64EH::UOP_PushMachFrame
:
590 streamer
.emitInt8(b
);
592 case Win64EH::UOP_Context
:
594 streamer
.emitInt8(b
);
596 case Win64EH::UOP_ClearUnwoundToCall
:
598 streamer
.emitInt8(b
);
600 case Win64EH::UOP_PACSignLR
:
602 streamer
.emitInt8(b
);
604 case Win64EH::UOP_SaveAnyRegI
:
605 case Win64EH::UOP_SaveAnyRegIP
:
606 case Win64EH::UOP_SaveAnyRegD
:
607 case Win64EH::UOP_SaveAnyRegDP
:
608 case Win64EH::UOP_SaveAnyRegQ
:
609 case Win64EH::UOP_SaveAnyRegQP
:
610 case Win64EH::UOP_SaveAnyRegIX
:
611 case Win64EH::UOP_SaveAnyRegIPX
:
612 case Win64EH::UOP_SaveAnyRegDX
:
613 case Win64EH::UOP_SaveAnyRegDPX
:
614 case Win64EH::UOP_SaveAnyRegQX
:
615 case Win64EH::UOP_SaveAnyRegQPX
: {
616 // This assumes the opcodes are listed in the enum in a particular order.
617 int Op
= inst
.Operation
- Win64EH::UOP_SaveAnyRegI
;
618 int Writeback
= Op
/ 6;
620 int Mode
= (Op
/ 2) % 3;
621 int Offset
= inst
.Offset
>> 3;
622 if (Writeback
|| Paired
|| Mode
== 2)
627 streamer
.emitInt8(b
);
628 assert(inst
.Register
< 32);
629 b
= inst
.Register
| (Writeback
<< 5) | (Paired
<< 6);
630 streamer
.emitInt8(b
);
631 b
= Offset
| (Mode
<< 6);
632 streamer
.emitInt8(b
);
638 // Returns the epilog symbol of an epilog with the exact same unwind code
639 // sequence, if it exists. Otherwise, returns nullptr.
640 // EpilogInstrs - Unwind codes for the current epilog.
641 // Epilogs - Epilogs that potentialy match the current epilog.
643 FindMatchingEpilog(const std::vector
<WinEH::Instruction
>& EpilogInstrs
,
644 const std::vector
<MCSymbol
*>& Epilogs
,
645 const WinEH::FrameInfo
*info
) {
646 for (auto *EpilogStart
: Epilogs
) {
647 auto InstrsIter
= info
->EpilogMap
.find(EpilogStart
);
648 assert(InstrsIter
!= info
->EpilogMap
.end() &&
649 "Epilog not found in EpilogMap");
650 const auto &Instrs
= InstrsIter
->second
.Instructions
;
652 if (Instrs
.size() != EpilogInstrs
.size())
656 for (unsigned i
= 0; i
< Instrs
.size(); ++i
)
657 if (Instrs
[i
] != EpilogInstrs
[i
]) {
668 static void simplifyARM64Opcodes(std::vector
<WinEH::Instruction
> &Instructions
,
670 unsigned PrevOffset
= -1;
671 unsigned PrevRegister
= -1;
673 auto VisitInstruction
= [&](WinEH::Instruction
&Inst
) {
674 // Convert 2-byte opcodes into equivalent 1-byte ones.
675 if (Inst
.Operation
== Win64EH::UOP_SaveRegP
&& Inst
.Register
== 29) {
676 Inst
.Operation
= Win64EH::UOP_SaveFPLR
;
678 } else if (Inst
.Operation
== Win64EH::UOP_SaveRegPX
&&
679 Inst
.Register
== 29) {
680 Inst
.Operation
= Win64EH::UOP_SaveFPLRX
;
682 } else if (Inst
.Operation
== Win64EH::UOP_SaveRegPX
&&
683 Inst
.Register
== 19 && Inst
.Offset
<= 248) {
684 Inst
.Operation
= Win64EH::UOP_SaveR19R20X
;
686 } else if (Inst
.Operation
== Win64EH::UOP_AddFP
&& Inst
.Offset
== 0) {
687 Inst
.Operation
= Win64EH::UOP_SetFP
;
688 } else if (Inst
.Operation
== Win64EH::UOP_SaveRegP
&&
689 Inst
.Register
== PrevRegister
+ 2 &&
690 Inst
.Offset
== PrevOffset
+ 16) {
691 Inst
.Operation
= Win64EH::UOP_SaveNext
;
694 // Intentionally not creating UOP_SaveNext for float register pairs,
695 // as current versions of Windows (up to at least 20.04) is buggy
696 // regarding SaveNext for float pairs.
698 // Update info about the previous instruction, for detecting if
699 // the next one can be made a UOP_SaveNext
700 if (Inst
.Operation
== Win64EH::UOP_SaveR19R20X
) {
703 } else if (Inst
.Operation
== Win64EH::UOP_SaveRegPX
) {
705 PrevRegister
= Inst
.Register
;
706 } else if (Inst
.Operation
== Win64EH::UOP_SaveRegP
) {
707 PrevOffset
= Inst
.Offset
;
708 PrevRegister
= Inst
.Register
;
709 } else if (Inst
.Operation
== Win64EH::UOP_SaveNext
) {
718 // Iterate over instructions in a forward order (for prologues),
719 // backwards for epilogues (i.e. always reverse compared to how the
720 // opcodes are stored).
722 for (auto It
= Instructions
.rbegin(); It
!= Instructions
.rend(); It
++)
723 VisitInstruction(*It
);
725 for (WinEH::Instruction
&Inst
: Instructions
)
726 VisitInstruction(Inst
);
730 // Check if an epilog exists as a subset of the end of a prolog (backwards).
732 getARM64OffsetInProlog(const std::vector
<WinEH::Instruction
> &Prolog
,
733 const std::vector
<WinEH::Instruction
> &Epilog
) {
734 // Can't find an epilog as a subset if it is longer than the prolog.
735 if (Epilog
.size() > Prolog
.size())
738 // Check that the epilog actually is a perfect match for the end (backwrds)
740 for (int I
= Epilog
.size() - 1; I
>= 0; I
--) {
741 if (Prolog
[I
] != Epilog
[Epilog
.size() - 1 - I
])
745 if (Epilog
.size() == Prolog
.size())
748 // If the epilog was a subset of the prolog, find its offset.
749 return ARM64CountOfUnwindCodes(ArrayRef
<WinEH::Instruction
>(
750 &Prolog
[Epilog
.size()], Prolog
.size() - Epilog
.size()));
753 static int checkARM64PackedEpilog(MCStreamer
&streamer
, WinEH::FrameInfo
*info
,
754 WinEH::FrameInfo::Segment
*Seg
,
755 int PrologCodeBytes
) {
756 // Can only pack if there's one single epilog
757 if (Seg
->Epilogs
.size() != 1)
760 MCSymbol
*Sym
= Seg
->Epilogs
.begin()->first
;
761 const std::vector
<WinEH::Instruction
> &Epilog
=
762 info
->EpilogMap
[Sym
].Instructions
;
764 // Check that the epilog actually is at the very end of the function,
765 // otherwise it can't be packed.
766 uint32_t DistanceFromEnd
=
767 (uint32_t)(Seg
->Offset
+ Seg
->Length
- Seg
->Epilogs
.begin()->second
);
768 if (DistanceFromEnd
/ 4 != Epilog
.size())
772 // Even if we don't end up sharing opcodes with the prolog, we can still
773 // write the offset as a packed offset, if the single epilog is located at
774 // the end of the function and the offset (pointing after the prolog) fits
775 // as a packed offset.
776 if (PrologCodeBytes
<= 31 &&
777 PrologCodeBytes
+ ARM64CountOfUnwindCodes(Epilog
) <= 124)
778 RetVal
= PrologCodeBytes
;
780 int Offset
= getARM64OffsetInProlog(info
->Instructions
, Epilog
);
784 // Check that the offset and prolog size fits in the first word; it's
785 // unclear whether the epilog count in the extension word can be taken
786 // as packed epilog offset.
787 if (Offset
> 31 || PrologCodeBytes
> 124)
790 // As we choose to express the epilog as part of the prolog, remove the
791 // epilog from the map, so we don't try to emit its opcodes.
792 info
->EpilogMap
.erase(Sym
);
796 static bool tryARM64PackedUnwind(WinEH::FrameInfo
*info
, uint32_t FuncLength
,
797 int PackedEpilogOffset
) {
798 if (PackedEpilogOffset
== 0) {
799 // Fully symmetric prolog and epilog, should be ok for packed format.
800 // For CR=3, the corresponding synthesized epilog actually lacks the
801 // SetFP opcode, but unwinding should work just fine despite that
802 // (if at the SetFP opcode, the unwinder considers it as part of the
803 // function body and just unwinds the full prolog instead).
804 } else if (PackedEpilogOffset
== 1) {
805 // One single case of differences between prolog and epilog is allowed:
806 // The epilog can lack a single SetFP that is the last opcode in the
807 // prolog, for the CR=3 case.
808 if (info
->Instructions
.back().Operation
!= Win64EH::UOP_SetFP
)
811 // Too much difference between prolog and epilog.
814 unsigned RegI
= 0, RegF
= 0;
815 int Predecrement
= 0;
827 bool StandaloneLR
= false, FPLRPair
= false;
831 // Iterate over the prolog and check that all opcodes exactly match
832 // the canonical order and form. A more lax check could verify that
833 // all saved registers are in the expected locations, but not enforce
834 // the order - that would work fine when unwinding from within
835 // functions, but not be exactly right if unwinding happens within
837 for (const WinEH::Instruction
&Inst
: info
->Instructions
) {
838 switch (Inst
.Operation
) {
839 case Win64EH::UOP_End
:
840 if (Location
!= Start
)
844 case Win64EH::UOP_PACSignLR
:
845 if (Location
!= Start2
)
850 case Win64EH::UOP_SaveR19R20X
:
851 if (Location
!= Start2
&& Location
!= Start3
)
853 Predecrement
= Inst
.Offset
;
857 case Win64EH::UOP_SaveRegX
:
858 if (Location
!= Start2
&& Location
!= Start3
)
860 Predecrement
= Inst
.Offset
;
861 if (Inst
.Register
== 19)
863 else if (Inst
.Register
== 30)
867 // Odd register; can't be any further int registers.
868 Location
= FloatRegs
;
870 case Win64EH::UOP_SaveRegPX
:
871 // Can't have this in a canonical prologue. Either this has been
872 // canonicalized into SaveR19R20X or SaveFPLRX, or it's an unsupported
874 // It can't be canonicalized into SaveR19R20X if the offset is
875 // larger than 248 bytes, but even with the maximum case with
876 // RegI=10/RegF=8/CR=1/H=1, we end up with SavSZ = 216, which should
877 // fit into SaveR19R20X.
878 // The unwinding opcodes can't describe the otherwise seemingly valid
879 // case for RegI=1 CR=1, that would start with a
880 // "stp x19, lr, [sp, #-...]!" as that fits neither SaveRegPX nor
883 case Win64EH::UOP_SaveRegP
:
884 if (Location
!= IntRegs
|| Inst
.Offset
!= 8 * RegI
||
885 Inst
.Register
!= 19 + RegI
)
889 case Win64EH::UOP_SaveReg
:
890 if (Location
!= IntRegs
|| Inst
.Offset
!= 8 * RegI
)
892 if (Inst
.Register
== 19 + RegI
)
894 else if (Inst
.Register
== 30)
898 // Odd register; can't be any further int registers.
899 Location
= FloatRegs
;
901 case Win64EH::UOP_SaveLRPair
:
902 if (Location
!= IntRegs
|| Inst
.Offset
!= 8 * RegI
||
903 Inst
.Register
!= 19 + RegI
)
907 Location
= FloatRegs
;
909 case Win64EH::UOP_SaveFRegX
:
910 // Packed unwind can't handle prologs that only save one single
913 case Win64EH::UOP_SaveFReg
:
914 if (Location
!= FloatRegs
|| RegF
== 0 || Inst
.Register
!= 8 + RegF
||
915 Inst
.Offset
!= 8 * (RegI
+ (StandaloneLR
? 1 : 0) + RegF
))
918 Location
= InputArgs
;
920 case Win64EH::UOP_SaveFRegPX
:
921 if ((Location
!= Start2
&& Location
!= Start3
) || Inst
.Register
!= 8)
923 Predecrement
= Inst
.Offset
;
925 Location
= FloatRegs
;
927 case Win64EH::UOP_SaveFRegP
:
928 if ((Location
!= IntRegs
&& Location
!= FloatRegs
) ||
929 Inst
.Register
!= 8 + RegF
||
930 Inst
.Offset
!= 8 * (RegI
+ (StandaloneLR
? 1 : 0) + RegF
))
933 Location
= FloatRegs
;
935 case Win64EH::UOP_SaveNext
:
936 if (Location
== IntRegs
)
938 else if (Location
== FloatRegs
)
943 case Win64EH::UOP_Nop
:
944 if (Location
!= IntRegs
&& Location
!= FloatRegs
&& Location
!= InputArgs
)
946 Location
= InputArgs
;
949 case Win64EH::UOP_AllocSmall
:
950 case Win64EH::UOP_AllocMedium
:
951 if (Location
!= Start2
&& Location
!= Start3
&& Location
!= IntRegs
&&
952 Location
!= FloatRegs
&& Location
!= InputArgs
&&
953 Location
!= StackAdjust
)
955 // Can have either a single decrement, or a pair of decrements with
956 // 4080 and another decrement.
957 if (StackOffset
== 0)
958 StackOffset
= Inst
.Offset
;
959 else if (StackOffset
!= 4080)
962 StackOffset
+= Inst
.Offset
;
963 Location
= StackAdjust
;
965 case Win64EH::UOP_SaveFPLRX
:
966 // Not allowing FPLRX after StackAdjust; if a StackAdjust is used, it
967 // should be followed by a FPLR instead.
968 if (Location
!= Start2
&& Location
!= Start3
&& Location
!= IntRegs
&&
969 Location
!= FloatRegs
&& Location
!= InputArgs
)
971 StackOffset
= Inst
.Offset
;
972 Location
= FrameRecord
;
975 case Win64EH::UOP_SaveFPLR
:
976 // This can only follow after a StackAdjust
977 if (Location
!= StackAdjust
|| Inst
.Offset
!= 0)
979 Location
= FrameRecord
;
982 case Win64EH::UOP_SetFP
:
983 if (Location
!= FrameRecord
)
987 case Win64EH::UOP_SaveAnyRegI
:
988 case Win64EH::UOP_SaveAnyRegIP
:
989 case Win64EH::UOP_SaveAnyRegD
:
990 case Win64EH::UOP_SaveAnyRegDP
:
991 case Win64EH::UOP_SaveAnyRegQ
:
992 case Win64EH::UOP_SaveAnyRegQP
:
993 case Win64EH::UOP_SaveAnyRegIX
:
994 case Win64EH::UOP_SaveAnyRegIPX
:
995 case Win64EH::UOP_SaveAnyRegDX
:
996 case Win64EH::UOP_SaveAnyRegDPX
:
997 case Win64EH::UOP_SaveAnyRegQX
:
998 case Win64EH::UOP_SaveAnyRegQPX
:
999 // These are never canonical; they don't show up with the usual Arm64
1000 // calling convention.
1002 case Win64EH::UOP_AllocLarge
:
1003 // Allocations this large can't be represented in packed unwind (and
1004 // usually don't fit the canonical form anyway because we need to use
1005 // __chkstk to allocate the stack space).
1007 case Win64EH::UOP_AddFP
:
1008 // "add x29, sp, #N" doesn't show up in the canonical pattern (except for
1009 // N=0, which is UOP_SetFP).
1011 case Win64EH::UOP_TrapFrame
:
1012 case Win64EH::UOP_Context
:
1013 case Win64EH::UOP_ClearUnwoundToCall
:
1014 case Win64EH::UOP_PushMachFrame
:
1015 // These are special opcodes that aren't normally generated.
1018 report_fatal_error("Unknown Arm64 unwind opcode");
1021 if (RegI
> 10 || RegF
> 8)
1023 if (StandaloneLR
&& FPLRPair
)
1025 if (FPLRPair
&& Location
!= End
)
1027 if (Nops
!= 0 && Nops
!= 4)
1029 if (PAC
&& !FPLRPair
)
1032 // There's an inconsistency regarding packed unwind info with homed
1033 // parameters; according to the documentation, the epilog shouldn't have
1034 // the same corresponding nops (and thus, to set the H bit, we should
1035 // require an epilog which isn't exactly symmetrical - we shouldn't accept
1036 // an exact mirrored epilog for those cases), but in practice,
1037 // RtlVirtualUnwind behaves as if it does expect the epilogue to contain
1038 // the same nops. See https://github.com/llvm/llvm-project/issues/54879.
1039 // To play it safe, don't produce packed unwind info with homed parameters.
1042 int IntSZ
= 8 * RegI
;
1045 int FpSZ
= 8 * RegF
; // RegF not yet decremented
1046 int SavSZ
= (IntSZ
+ FpSZ
+ 8 * 8 * H
+ 0xF) & ~0xF;
1047 if (Predecrement
!= SavSZ
)
1049 if (FPLRPair
&& StackOffset
< 16)
1051 if (StackOffset
% 16)
1053 uint32_t FrameSize
= (StackOffset
+ SavSZ
) / 16;
1054 if (FrameSize
> 0x1FF)
1056 assert(RegF
!= 1 && "One single float reg not allowed");
1058 RegF
--; // Convert from actual number of registers, to value stored
1059 assert(FuncLength
<= 0x7FF && "FuncLength should have been checked earlier");
1060 int Flag
= 0x01; // Function segments not supported yet
1061 int CR
= PAC
? 2 : FPLRPair
? 3 : StandaloneLR
? 1 : 0;
1062 info
->PackedInfo
|= Flag
<< 0;
1063 info
->PackedInfo
|= (FuncLength
& 0x7FF) << 2;
1064 info
->PackedInfo
|= (RegF
& 0x7) << 13;
1065 info
->PackedInfo
|= (RegI
& 0xF) << 16;
1066 info
->PackedInfo
|= (H
& 0x1) << 20;
1067 info
->PackedInfo
|= (CR
& 0x3) << 21;
1068 info
->PackedInfo
|= (FrameSize
& 0x1FF) << 23;
1072 static void ARM64ProcessEpilogs(WinEH::FrameInfo
*info
,
1073 WinEH::FrameInfo::Segment
*Seg
,
1074 uint32_t &TotalCodeBytes
,
1075 MapVector
<MCSymbol
*, uint32_t> &EpilogInfo
) {
1077 std::vector
<MCSymbol
*> EpilogStarts
;
1078 for (auto &I
: Seg
->Epilogs
)
1079 EpilogStarts
.push_back(I
.first
);
1081 // Epilogs processed so far.
1082 std::vector
<MCSymbol
*> AddedEpilogs
;
1083 for (auto *S
: EpilogStarts
) {
1084 MCSymbol
*EpilogStart
= S
;
1085 auto &EpilogInstrs
= info
->EpilogMap
[S
].Instructions
;
1086 uint32_t CodeBytes
= ARM64CountOfUnwindCodes(EpilogInstrs
);
1088 MCSymbol
* MatchingEpilog
=
1089 FindMatchingEpilog(EpilogInstrs
, AddedEpilogs
, info
);
1091 if (MatchingEpilog
) {
1092 assert(EpilogInfo
.contains(MatchingEpilog
) &&
1093 "Duplicate epilog not found");
1094 EpilogInfo
[EpilogStart
] = EpilogInfo
.lookup(MatchingEpilog
);
1095 // Clear the unwind codes in the EpilogMap, so that they don't get output
1096 // in ARM64EmitUnwindInfoForSegment().
1097 EpilogInstrs
.clear();
1098 } else if ((PrologOffset
= getARM64OffsetInProlog(info
->Instructions
,
1099 EpilogInstrs
)) >= 0) {
1100 EpilogInfo
[EpilogStart
] = PrologOffset
;
1101 // If the segment doesn't have a prolog, an end_c will be emitted before
1102 // prolog opcodes. So epilog start index in opcodes array is moved by 1.
1103 if (!Seg
->HasProlog
)
1104 EpilogInfo
[EpilogStart
] += 1;
1105 // Clear the unwind codes in the EpilogMap, so that they don't get output
1106 // in ARM64EmitUnwindInfoForSegment().
1107 EpilogInstrs
.clear();
1109 EpilogInfo
[EpilogStart
] = TotalCodeBytes
;
1110 TotalCodeBytes
+= CodeBytes
;
1111 AddedEpilogs
.push_back(EpilogStart
);
1116 static void ARM64FindSegmentsInFunction(MCStreamer
&streamer
,
1117 WinEH::FrameInfo
*info
,
1118 int64_t RawFuncLength
) {
1119 if (info
->PrologEnd
)
1120 checkARM64Instructions(streamer
, info
->Instructions
, info
->Begin
,
1121 info
->PrologEnd
, info
->Function
->getName(),
1123 struct EpilogStartEnd
{
1128 // Record Start and End of each epilog.
1129 SmallVector
<struct EpilogStartEnd
, 4> Epilogs
;
1130 for (auto &I
: info
->EpilogMap
) {
1131 MCSymbol
*Start
= I
.first
;
1132 auto &Instrs
= I
.second
.Instructions
;
1133 int64_t Offset
= GetAbsDifference(streamer
, Start
, info
->Begin
);
1134 checkARM64Instructions(streamer
, Instrs
, Start
, I
.second
.End
,
1135 info
->Function
->getName(), "epilogue");
1136 assert((Epilogs
.size() == 0 || Offset
>= Epilogs
.back().End
) &&
1137 "Epilogs should be monotonically ordered");
1138 // Exclue the end opcode from Instrs.size() when calculating the end of the
1140 Epilogs
.push_back({Start
, Offset
, Offset
+ (int64_t)(Instrs
.size() - 1) * 4});
1144 int64_t SegLimit
= 0xFFFFC;
1145 int64_t SegOffset
= 0;
1147 if (RawFuncLength
> SegLimit
) {
1149 int64_t RemainingLength
= RawFuncLength
;
1151 while (RemainingLength
> SegLimit
) {
1152 // Try divide the function into segments, requirements:
1153 // 1. Segment length <= 0xFFFFC;
1154 // 2. Each Prologue or Epilogue must be fully within a segment.
1155 int64_t SegLength
= SegLimit
;
1156 int64_t SegEnd
= SegOffset
+ SegLength
;
1157 // Keep record on symbols and offsets of epilogs in this segment.
1158 MapVector
<MCSymbol
*, int64_t> EpilogsInSegment
;
1160 while (E
< Epilogs
.size() && Epilogs
[E
].End
< SegEnd
) {
1161 // Epilogs within current segment.
1162 EpilogsInSegment
[Epilogs
[E
].Start
] = Epilogs
[E
].Offset
;
1166 // At this point, we have:
1167 // 1. Put all epilogs in segments already. No action needed here; or
1168 // 2. Found an epilog that will cross segments boundry. We need to
1169 // move back current segment's end boundry, so the epilog is entirely
1170 // in the next segment; or
1171 // 3. Left at least one epilog that is entirely after this segment.
1172 // It'll be handled by the next iteration, or the last segment.
1173 if (E
< Epilogs
.size() && Epilogs
[E
].Offset
<= SegEnd
)
1174 // Move back current Segment's end boundry.
1175 SegLength
= Epilogs
[E
].Offset
- SegOffset
;
1177 auto Seg
= WinEH::FrameInfo::Segment(
1178 SegOffset
, SegLength
, /* HasProlog */!SegOffset
);
1179 Seg
.Epilogs
= std::move(EpilogsInSegment
);
1180 info
->Segments
.push_back(Seg
);
1182 SegOffset
+= SegLength
;
1183 RemainingLength
-= SegLength
;
1187 // Add the last segment when RawFuncLength > 0xFFFFC,
1188 // or the only segment otherwise.
1190 WinEH::FrameInfo::Segment(SegOffset
, RawFuncLength
- SegOffset
,
1191 /* HasProlog */!SegOffset
);
1192 for (; E
< Epilogs
.size(); ++E
)
1193 LastSeg
.Epilogs
[Epilogs
[E
].Start
] = Epilogs
[E
].Offset
;
1194 info
->Segments
.push_back(LastSeg
);
1197 static void ARM64EmitUnwindInfoForSegment(MCStreamer
&streamer
,
1198 WinEH::FrameInfo
*info
,
1199 WinEH::FrameInfo::Segment
&Seg
,
1200 bool TryPacked
= true) {
1201 MCContext
&context
= streamer
.getContext();
1202 MCSymbol
*Label
= context
.createTempSymbol();
1204 streamer
.emitValueToAlignment(Align(4));
1205 streamer
.emitLabel(Label
);
1207 // Use the 1st segemnt's label as function's.
1208 if (Seg
.Offset
== 0)
1209 info
->Symbol
= Label
;
1211 bool HasProlog
= Seg
.HasProlog
;
1212 bool HasEpilogs
= (Seg
.Epilogs
.size() != 0);
1214 uint32_t SegLength
= (uint32_t)Seg
.Length
/ 4;
1215 uint32_t PrologCodeBytes
= info
->PrologCodeBytes
;
1217 int PackedEpilogOffset
= HasEpilogs
?
1218 checkARM64PackedEpilog(streamer
, info
, &Seg
, PrologCodeBytes
) : -1;
1221 // 1. Enable packed unwind info (.pdata only) for multi-segment functions.
1222 // 2. Emit packed unwind info (.pdata only) for segments that have neithor
1223 // prolog nor epilog.
1224 if (info
->Segments
.size() == 1 && PackedEpilogOffset
>= 0 &&
1225 uint32_t(PackedEpilogOffset
) < PrologCodeBytes
&&
1226 !info
->HandlesExceptions
&& SegLength
<= 0x7ff && TryPacked
) {
1227 // Matching prolog/epilog and no exception handlers; check if the
1228 // prolog matches the patterns that can be described by the packed
1231 // info->Symbol was already set even if we didn't actually write any
1232 // unwind info there. Keep using that as indicator that this unwind
1233 // info has been generated already.
1234 if (tryARM64PackedUnwind(info
, SegLength
, PackedEpilogOffset
))
1238 // If the prolog is not in this segment, we need to emit an end_c, which takes
1239 // 1 byte, before prolog unwind ops.
1241 PrologCodeBytes
+= 1;
1242 if (PackedEpilogOffset
>= 0)
1243 PackedEpilogOffset
+= 1;
1244 // If a segment has neither prolog nor epilog, "With full .xdata record,
1245 // Epilog Count = 1. Epilog Start Index points to end_c."
1246 // https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling#function-fragments
1247 // TODO: We can remove this if testing shows zero epilog scope is ok with
1250 // Pack the fake epilog into phantom prolog.
1251 PackedEpilogOffset
= 0;
1254 uint32_t TotalCodeBytes
= PrologCodeBytes
;
1257 MapVector
<MCSymbol
*, uint32_t> EpilogInfo
;
1258 ARM64ProcessEpilogs(info
, &Seg
, TotalCodeBytes
, EpilogInfo
);
1260 // Code Words, Epilog count, E, X, Vers, Function Length
1261 uint32_t row1
= 0x0;
1262 uint32_t CodeWords
= TotalCodeBytes
/ 4;
1263 uint32_t CodeWordsMod
= TotalCodeBytes
% 4;
1266 uint32_t EpilogCount
=
1267 PackedEpilogOffset
>= 0 ? PackedEpilogOffset
: Seg
.Epilogs
.size();
1268 bool ExtensionWord
= EpilogCount
> 31 || TotalCodeBytes
> 124;
1269 if (!ExtensionWord
) {
1270 row1
|= (EpilogCount
& 0x1F) << 22;
1271 row1
|= (CodeWords
& 0x1F) << 27;
1273 if (info
->HandlesExceptions
) // X
1275 if (PackedEpilogOffset
>= 0) // E
1277 row1
|= SegLength
& 0x3FFFF;
1278 streamer
.emitInt32(row1
);
1280 // Extended Code Words, Extended Epilog Count
1281 if (ExtensionWord
) {
1282 // FIXME: We should be able to split unwind info into multiple sections.
1283 if (CodeWords
> 0xFF || EpilogCount
> 0xFFFF)
1285 "SEH unwind data splitting is only implemented for large functions, "
1286 "cases of too many code words or too many epilogs will be done "
1288 uint32_t row2
= 0x0;
1289 row2
|= (CodeWords
& 0xFF) << 16;
1290 row2
|= (EpilogCount
& 0xFFFF);
1291 streamer
.emitInt32(row2
);
1294 if (PackedEpilogOffset
< 0) {
1295 // Epilog Start Index, Epilog Start Offset
1296 for (auto &I
: EpilogInfo
) {
1297 MCSymbol
*EpilogStart
= I
.first
;
1298 uint32_t EpilogIndex
= I
.second
;
1299 // Epilog offset within the Segment.
1300 uint32_t EpilogOffset
= (uint32_t)(Seg
.Epilogs
[EpilogStart
] - Seg
.Offset
);
1303 uint32_t row3
= EpilogOffset
;
1304 row3
|= (EpilogIndex
& 0x3FF) << 22;
1305 streamer
.emitInt32(row3
);
1309 // Note that even for segments that have no prolog, we still need to emit
1310 // prolog unwinding opcodes so that the unwinder knows how to unwind from
1312 // The end_c opcode at the start indicates to the unwinder that the actual
1313 // prolog is outside of the current segment, and the unwinder shouldn't try
1314 // to check for unwinding from a partial prolog.
1317 streamer
.emitInt8((uint8_t)0xE5);
1319 // Emit prolog unwind instructions (in reverse order).
1320 for (auto Inst
: llvm::reverse(info
->Instructions
))
1321 ARM64EmitUnwindCode(streamer
, Inst
);
1323 // Emit epilog unwind instructions
1324 for (auto &I
: Seg
.Epilogs
) {
1325 auto &EpilogInstrs
= info
->EpilogMap
[I
.first
].Instructions
;
1326 for (const WinEH::Instruction
&inst
: EpilogInstrs
)
1327 ARM64EmitUnwindCode(streamer
, inst
);
1330 int32_t BytesMod
= CodeWords
* 4 - TotalCodeBytes
;
1331 assert(BytesMod
>= 0);
1332 for (int i
= 0; i
< BytesMod
; i
++)
1333 streamer
.emitInt8(0xE3);
1335 if (info
->HandlesExceptions
)
1337 MCSymbolRefExpr::create(info
->ExceptionHandler
,
1338 MCSymbolRefExpr::VK_COFF_IMGREL32
, context
),
1342 // Populate the .xdata section. The format of .xdata on ARM64 is documented at
1343 // https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling
1344 static void ARM64EmitUnwindInfo(MCStreamer
&streamer
, WinEH::FrameInfo
*info
,
1345 bool TryPacked
= true) {
1346 // If this UNWIND_INFO already has a symbol, it's already been emitted.
1349 // If there's no unwind info here (not even a terminating UOP_End), the
1350 // unwind info is considered bogus and skipped. If this was done in
1351 // response to an explicit .seh_handlerdata, the associated trailing
1352 // handler data is left orphaned in the xdata section.
1353 if (info
->empty()) {
1354 info
->EmitAttempted
= true;
1357 if (info
->EmitAttempted
) {
1358 // If we tried to emit unwind info before (due to an explicit
1359 // .seh_handlerdata directive), but skipped it (because there was no
1360 // valid information to emit at the time), and it later got valid unwind
1361 // opcodes, we can't emit it here, because the trailing handler data
1362 // was already emitted elsewhere in the xdata section.
1363 streamer
.getContext().reportError(
1364 SMLoc(), "Earlier .seh_handlerdata for " + info
->Function
->getName() +
1365 " skipped due to no unwind info at the time "
1366 "(.seh_handlerdata too early?), but the function later "
1367 "did get unwind info that can't be emitted");
1371 simplifyARM64Opcodes(info
->Instructions
, false);
1372 for (auto &I
: info
->EpilogMap
)
1373 simplifyARM64Opcodes(I
.second
.Instructions
, true);
1375 int64_t RawFuncLength
;
1376 if (!info
->FuncletOrFuncEnd
) {
1377 report_fatal_error("FuncletOrFuncEnd not set");
1379 // FIXME: GetAbsDifference tries to compute the length of the function
1380 // immediately, before the whole file is emitted, but in general
1381 // that's impossible: the size in bytes of certain assembler directives
1382 // like .align and .fill is not known until the whole file is parsed and
1383 // relaxations are applied. Currently, GetAbsDifference fails with a fatal
1384 // error in that case. (We mostly don't hit this because inline assembly
1385 // specifying those directives is rare, and we don't normally try to
1386 // align loops on AArch64.)
1388 // There are two potential approaches to delaying the computation. One,
1389 // we could emit something like ".word (endfunc-beginfunc)/4+0x10800000",
1390 // as long as we have some conservative estimate we could use to prove
1391 // that we don't need to split the unwind data. Emitting the constant
1392 // is straightforward, but there's no existing code for estimating the
1393 // size of the function.
1395 // The other approach would be to use a dedicated, relaxable fragment,
1396 // which could grow to accommodate splitting the unwind data if
1397 // necessary. This is more straightforward, since it automatically works
1398 // without any new infrastructure, and it's consistent with how we handle
1399 // relaxation in other contexts. But it would require some refactoring
1400 // to move parts of the pdata/xdata emission into the implementation of
1401 // a fragment. We could probably continue to encode the unwind codes
1402 // here, but we'd have to emit the pdata, the xdata header, and the
1403 // epilogue scopes later, since they depend on whether the we need to
1404 // split the unwind data.
1406 // If this is fixed, remove code in AArch64ISelLowering.cpp that
1407 // disables loop alignment on Windows.
1408 RawFuncLength
= GetAbsDifference(streamer
, info
->FuncletOrFuncEnd
,
1412 ARM64FindSegmentsInFunction(streamer
, info
, RawFuncLength
);
1414 info
->PrologCodeBytes
= ARM64CountOfUnwindCodes(info
->Instructions
);
1415 for (auto &S
: info
->Segments
)
1416 ARM64EmitUnwindInfoForSegment(streamer
, info
, S
, TryPacked
);
1418 // Clear prolog instructions after unwind info is emitted for all segments.
1419 info
->Instructions
.clear();
1422 static uint32_t ARMCountOfUnwindCodes(ArrayRef
<WinEH::Instruction
> Insns
) {
1424 for (const auto &I
: Insns
) {
1425 switch (static_cast<Win64EH::UnwindOpcodes
>(I
.Operation
)) {
1427 llvm_unreachable("Unsupported ARM unwind code");
1428 case Win64EH::UOP_AllocSmall
:
1431 case Win64EH::UOP_AllocLarge
:
1434 case Win64EH::UOP_AllocHuge
:
1437 case Win64EH::UOP_WideAllocMedium
:
1440 case Win64EH::UOP_WideAllocLarge
:
1443 case Win64EH::UOP_WideAllocHuge
:
1446 case Win64EH::UOP_WideSaveRegMask
:
1449 case Win64EH::UOP_SaveSP
:
1452 case Win64EH::UOP_SaveRegsR4R7LR
:
1455 case Win64EH::UOP_WideSaveRegsR4R11LR
:
1458 case Win64EH::UOP_SaveFRegD8D15
:
1461 case Win64EH::UOP_SaveRegMask
:
1464 case Win64EH::UOP_SaveLR
:
1467 case Win64EH::UOP_SaveFRegD0D15
:
1470 case Win64EH::UOP_SaveFRegD16D31
:
1473 case Win64EH::UOP_Nop
:
1474 case Win64EH::UOP_WideNop
:
1475 case Win64EH::UOP_End
:
1476 case Win64EH::UOP_EndNop
:
1477 case Win64EH::UOP_WideEndNop
:
1480 case Win64EH::UOP_Custom
: {
1482 for (J
= 3; J
> 0; J
--)
1483 if (I
.Offset
& (0xffu
<< (8 * J
)))
1493 static uint32_t ARMCountOfInstructionBytes(ArrayRef
<WinEH::Instruction
> Insns
,
1494 bool *HasCustom
= nullptr) {
1496 for (const auto &I
: Insns
) {
1497 switch (static_cast<Win64EH::UnwindOpcodes
>(I
.Operation
)) {
1499 llvm_unreachable("Unsupported ARM unwind code");
1500 case Win64EH::UOP_AllocSmall
:
1501 case Win64EH::UOP_AllocLarge
:
1502 case Win64EH::UOP_AllocHuge
:
1505 case Win64EH::UOP_WideAllocMedium
:
1506 case Win64EH::UOP_WideAllocLarge
:
1507 case Win64EH::UOP_WideAllocHuge
:
1510 case Win64EH::UOP_WideSaveRegMask
:
1511 case Win64EH::UOP_WideSaveRegsR4R11LR
:
1514 case Win64EH::UOP_SaveSP
:
1517 case Win64EH::UOP_SaveRegMask
:
1518 case Win64EH::UOP_SaveRegsR4R7LR
:
1521 case Win64EH::UOP_SaveFRegD8D15
:
1522 case Win64EH::UOP_SaveFRegD0D15
:
1523 case Win64EH::UOP_SaveFRegD16D31
:
1526 case Win64EH::UOP_SaveLR
:
1529 case Win64EH::UOP_Nop
:
1530 case Win64EH::UOP_EndNop
:
1533 case Win64EH::UOP_WideNop
:
1534 case Win64EH::UOP_WideEndNop
:
1537 case Win64EH::UOP_End
:
1538 // This doesn't map to any instruction
1540 case Win64EH::UOP_Custom
:
1541 // We can't reason about what instructions this maps to; return a
1542 // phony number to make sure we don't accidentally do epilog packing.
1552 static void checkARMInstructions(MCStreamer
&Streamer
,
1553 ArrayRef
<WinEH::Instruction
> Insns
,
1554 const MCSymbol
*Begin
, const MCSymbol
*End
,
1555 StringRef Name
, StringRef Type
) {
1558 std::optional
<int64_t> MaybeDistance
=
1559 GetOptionalAbsDifference(Streamer
, End
, Begin
);
1562 uint32_t Distance
= (uint32_t)*MaybeDistance
;
1563 bool HasCustom
= false;
1564 uint32_t InstructionBytes
= ARMCountOfInstructionBytes(Insns
, &HasCustom
);
1567 if (Distance
!= InstructionBytes
) {
1568 Streamer
.getContext().reportError(
1569 SMLoc(), "Incorrect size for " + Name
+ " " + Type
+ ": " +
1571 " bytes of instructions in range, but .seh directives "
1572 "corresponding to " +
1573 Twine(InstructionBytes
) + " bytes\n");
1577 static bool isARMTerminator(const WinEH::Instruction
&inst
) {
1578 switch (static_cast<Win64EH::UnwindOpcodes
>(inst
.Operation
)) {
1579 case Win64EH::UOP_End
:
1580 case Win64EH::UOP_EndNop
:
1581 case Win64EH::UOP_WideEndNop
:
1588 // Unwind opcode encodings and restrictions are documented at
1589 // https://docs.microsoft.com/en-us/cpp/build/arm-exception-handling
1590 static void ARMEmitUnwindCode(MCStreamer
&streamer
,
1591 const WinEH::Instruction
&inst
) {
1594 switch (static_cast<Win64EH::UnwindOpcodes
>(inst
.Operation
)) {
1596 llvm_unreachable("Unsupported ARM unwind code");
1597 case Win64EH::UOP_AllocSmall
:
1598 assert((inst
.Offset
& 3) == 0);
1599 assert(inst
.Offset
/ 4 <= 0x7f);
1600 streamer
.emitInt8(inst
.Offset
/ 4);
1602 case Win64EH::UOP_WideSaveRegMask
:
1603 assert((inst
.Register
& ~0x5fff) == 0);
1604 lr
= (inst
.Register
>> 14) & 1;
1605 w
= 0x8000 | (inst
.Register
& 0x1fff) | (lr
<< 13);
1606 streamer
.emitInt8((w
>> 8) & 0xff);
1607 streamer
.emitInt8((w
>> 0) & 0xff);
1609 case Win64EH::UOP_SaveSP
:
1610 assert(inst
.Register
<= 0x0f);
1611 streamer
.emitInt8(0xc0 | inst
.Register
);
1613 case Win64EH::UOP_SaveRegsR4R7LR
:
1614 assert(inst
.Register
>= 4 && inst
.Register
<= 7);
1615 assert(inst
.Offset
<= 1);
1616 streamer
.emitInt8(0xd0 | (inst
.Register
- 4) | (inst
.Offset
<< 2));
1618 case Win64EH::UOP_WideSaveRegsR4R11LR
:
1619 assert(inst
.Register
>= 8 && inst
.Register
<= 11);
1620 assert(inst
.Offset
<= 1);
1621 streamer
.emitInt8(0xd8 | (inst
.Register
- 8) | (inst
.Offset
<< 2));
1623 case Win64EH::UOP_SaveFRegD8D15
:
1624 assert(inst
.Register
>= 8 && inst
.Register
<= 15);
1625 streamer
.emitInt8(0xe0 | (inst
.Register
- 8));
1627 case Win64EH::UOP_WideAllocMedium
:
1628 assert((inst
.Offset
& 3) == 0);
1629 assert(inst
.Offset
/ 4 <= 0x3ff);
1630 w
= 0xe800 | (inst
.Offset
/ 4);
1631 streamer
.emitInt8((w
>> 8) & 0xff);
1632 streamer
.emitInt8((w
>> 0) & 0xff);
1634 case Win64EH::UOP_SaveRegMask
:
1635 assert((inst
.Register
& ~0x40ff) == 0);
1636 lr
= (inst
.Register
>> 14) & 1;
1637 w
= 0xec00 | (inst
.Register
& 0x0ff) | (lr
<< 8);
1638 streamer
.emitInt8((w
>> 8) & 0xff);
1639 streamer
.emitInt8((w
>> 0) & 0xff);
1641 case Win64EH::UOP_SaveLR
:
1642 assert((inst
.Offset
& 3) == 0);
1643 assert(inst
.Offset
/ 4 <= 0x0f);
1644 streamer
.emitInt8(0xef);
1645 streamer
.emitInt8(inst
.Offset
/ 4);
1647 case Win64EH::UOP_SaveFRegD0D15
:
1648 assert(inst
.Register
<= 15);
1649 assert(inst
.Offset
<= 15);
1650 assert(inst
.Register
<= inst
.Offset
);
1651 streamer
.emitInt8(0xf5);
1652 streamer
.emitInt8((inst
.Register
<< 4) | inst
.Offset
);
1654 case Win64EH::UOP_SaveFRegD16D31
:
1655 assert(inst
.Register
>= 16 && inst
.Register
<= 31);
1656 assert(inst
.Offset
>= 16 && inst
.Offset
<= 31);
1657 assert(inst
.Register
<= inst
.Offset
);
1658 streamer
.emitInt8(0xf6);
1659 streamer
.emitInt8(((inst
.Register
- 16) << 4) | (inst
.Offset
- 16));
1661 case Win64EH::UOP_AllocLarge
:
1662 assert((inst
.Offset
& 3) == 0);
1663 assert(inst
.Offset
/ 4 <= 0xffff);
1664 w
= inst
.Offset
/ 4;
1665 streamer
.emitInt8(0xf7);
1666 streamer
.emitInt8((w
>> 8) & 0xff);
1667 streamer
.emitInt8((w
>> 0) & 0xff);
1669 case Win64EH::UOP_AllocHuge
:
1670 assert((inst
.Offset
& 3) == 0);
1671 assert(inst
.Offset
/ 4 <= 0xffffff);
1672 w
= inst
.Offset
/ 4;
1673 streamer
.emitInt8(0xf8);
1674 streamer
.emitInt8((w
>> 16) & 0xff);
1675 streamer
.emitInt8((w
>> 8) & 0xff);
1676 streamer
.emitInt8((w
>> 0) & 0xff);
1678 case Win64EH::UOP_WideAllocLarge
:
1679 assert((inst
.Offset
& 3) == 0);
1680 assert(inst
.Offset
/ 4 <= 0xffff);
1681 w
= inst
.Offset
/ 4;
1682 streamer
.emitInt8(0xf9);
1683 streamer
.emitInt8((w
>> 8) & 0xff);
1684 streamer
.emitInt8((w
>> 0) & 0xff);
1686 case Win64EH::UOP_WideAllocHuge
:
1687 assert((inst
.Offset
& 3) == 0);
1688 assert(inst
.Offset
/ 4 <= 0xffffff);
1689 w
= inst
.Offset
/ 4;
1690 streamer
.emitInt8(0xfa);
1691 streamer
.emitInt8((w
>> 16) & 0xff);
1692 streamer
.emitInt8((w
>> 8) & 0xff);
1693 streamer
.emitInt8((w
>> 0) & 0xff);
1695 case Win64EH::UOP_Nop
:
1696 streamer
.emitInt8(0xfb);
1698 case Win64EH::UOP_WideNop
:
1699 streamer
.emitInt8(0xfc);
1701 case Win64EH::UOP_EndNop
:
1702 streamer
.emitInt8(0xfd);
1704 case Win64EH::UOP_WideEndNop
:
1705 streamer
.emitInt8(0xfe);
1707 case Win64EH::UOP_End
:
1708 streamer
.emitInt8(0xff);
1710 case Win64EH::UOP_Custom
:
1711 for (i
= 3; i
> 0; i
--)
1712 if (inst
.Offset
& (0xffu
<< (8 * i
)))
1715 streamer
.emitInt8((inst
.Offset
>> (8 * i
)) & 0xff);
1720 // Check if an epilog exists as a subset of the end of a prolog (backwards).
1721 // An epilog may end with one out of three different end opcodes; if this
1722 // is the first epilog that shares opcodes with the prolog, we can tolerate
1723 // that this opcode differs (and the caller will update the prolog to use
1724 // the same end opcode as the epilog). If another epilog already shares
1725 // opcodes with the prolog, the ending opcode must be a strict match.
1726 static int getARMOffsetInProlog(const std::vector
<WinEH::Instruction
> &Prolog
,
1727 const std::vector
<WinEH::Instruction
> &Epilog
,
1728 bool CanTweakProlog
) {
1729 // Can't find an epilog as a subset if it is longer than the prolog.
1730 if (Epilog
.size() > Prolog
.size())
1733 // Check that the epilog actually is a perfect match for the end (backwrds)
1735 // If we can adjust the prolog afterwards, don't check that the end opcodes
1737 int EndIdx
= CanTweakProlog
? 1 : 0;
1738 for (int I
= Epilog
.size() - 1; I
>= EndIdx
; I
--) {
1739 // TODO: Could also allow minor mismatches, e.g. "add sp, #16" vs
1741 if (Prolog
[I
] != Epilog
[Epilog
.size() - 1 - I
])
1745 if (CanTweakProlog
) {
1746 // Check that both prolog and epilog end with an expected end opcode.
1747 if (Prolog
.front().Operation
!= Win64EH::UOP_End
)
1749 if (Epilog
.back().Operation
!= Win64EH::UOP_End
&&
1750 Epilog
.back().Operation
!= Win64EH::UOP_EndNop
&&
1751 Epilog
.back().Operation
!= Win64EH::UOP_WideEndNop
)
1755 // If the epilog was a subset of the prolog, find its offset.
1756 if (Epilog
.size() == Prolog
.size())
1758 return ARMCountOfUnwindCodes(ArrayRef
<WinEH::Instruction
>(
1759 &Prolog
[Epilog
.size()], Prolog
.size() - Epilog
.size()));
1762 static int checkARMPackedEpilog(MCStreamer
&streamer
, WinEH::FrameInfo
*info
,
1763 int PrologCodeBytes
) {
1764 // Can only pack if there's one single epilog
1765 if (info
->EpilogMap
.size() != 1)
1768 const WinEH::FrameInfo::Epilog
&EpilogInfo
= info
->EpilogMap
.begin()->second
;
1769 // Can only pack if the epilog is unconditional
1770 if (EpilogInfo
.Condition
!= 0xe) // ARMCC::AL
1773 const std::vector
<WinEH::Instruction
> &Epilog
= EpilogInfo
.Instructions
;
1774 // Make sure we have at least the trailing end opcode
1775 if (info
->Instructions
.empty() || Epilog
.empty())
1778 // Check that the epilog actually is at the very end of the function,
1779 // otherwise it can't be packed.
1780 std::optional
<int64_t> MaybeDistance
= GetOptionalAbsDifference(
1781 streamer
, info
->FuncletOrFuncEnd
, info
->EpilogMap
.begin()->first
);
1784 uint32_t DistanceFromEnd
= (uint32_t)*MaybeDistance
;
1785 uint32_t InstructionBytes
= ARMCountOfInstructionBytes(Epilog
);
1786 if (DistanceFromEnd
!= InstructionBytes
)
1790 // Even if we don't end up sharing opcodes with the prolog, we can still
1791 // write the offset as a packed offset, if the single epilog is located at
1792 // the end of the function and the offset (pointing after the prolog) fits
1793 // as a packed offset.
1794 if (PrologCodeBytes
<= 31 &&
1795 PrologCodeBytes
+ ARMCountOfUnwindCodes(Epilog
) <= 63)
1796 RetVal
= PrologCodeBytes
;
1799 getARMOffsetInProlog(info
->Instructions
, Epilog
, /*CanTweakProlog=*/true);
1803 // Check that the offset and prolog size fits in the first word; it's
1804 // unclear whether the epilog count in the extension word can be taken
1805 // as packed epilog offset.
1806 if (Offset
> 31 || PrologCodeBytes
> 63)
1809 // Replace the regular end opcode of the prolog with the one from the
1811 info
->Instructions
.front() = Epilog
.back();
1813 // As we choose to express the epilog as part of the prolog, remove the
1814 // epilog from the map, so we don't try to emit its opcodes.
1815 info
->EpilogMap
.clear();
1819 static bool parseRegMask(unsigned Mask
, bool &HasLR
, bool &HasR11
,
1820 unsigned &Folded
, int &IntRegs
) {
1821 if (Mask
& (1 << 14)) {
1825 if (Mask
& (1 << 11)) {
1834 // Shift right until we have the bits at the bottom
1835 while ((Mask
& 1) == 0) {
1839 if ((Mask
& (Mask
+ 1)) != 0)
1840 return false; // Not a consecutive series of bits? Can't be packed.
1843 while (Mask
& (1 << N
))
1853 return false; // Can't be packed
1859 static bool tryARMPackedUnwind(MCStreamer
&streamer
, WinEH::FrameInfo
*info
,
1860 uint32_t FuncLength
) {
1862 bool Homing
= false;
1863 bool HasR11
= false;
1864 bool HasChain
= false;
1866 int IntRegs
= -1; // r4 - r(4+N)
1867 int FloatRegs
= -1; // d8 - d(8+N)
1868 unsigned PF
= 0; // Number of extra pushed registers
1869 unsigned StackAdjust
= 0;
1870 // Iterate over the prolog and check that all opcodes exactly match
1871 // the canonical order and form.
1872 for (const WinEH::Instruction
&Inst
: info
->Instructions
) {
1873 switch (Inst
.Operation
) {
1875 llvm_unreachable("Unsupported ARM unwind code");
1876 case Win64EH::UOP_Custom
:
1877 case Win64EH::UOP_AllocLarge
:
1878 case Win64EH::UOP_AllocHuge
:
1879 case Win64EH::UOP_WideAllocLarge
:
1880 case Win64EH::UOP_WideAllocHuge
:
1881 case Win64EH::UOP_SaveFRegD0D15
:
1882 case Win64EH::UOP_SaveFRegD16D31
:
1885 case Win64EH::UOP_SaveSP
:
1886 // Can't be packed; we can't rely on restoring sp from r11 when
1887 // unwinding a packed prologue.
1889 case Win64EH::UOP_SaveLR
:
1890 // Can't be present in a packed prologue
1893 case Win64EH::UOP_End
:
1894 case Win64EH::UOP_EndNop
:
1895 case Win64EH::UOP_WideEndNop
:
1901 case Win64EH::UOP_SaveRegsR4R7LR
:
1902 case Win64EH::UOP_WideSaveRegsR4R11LR
:
1904 if (Step
!= 1 && Step
!= 2)
1906 assert(Inst
.Register
>= 4 && Inst
.Register
<= 11); // r4-rX
1907 assert(Inst
.Offset
<= 1); // Lr
1908 IntRegs
= Inst
.Register
- 4;
1909 if (Inst
.Register
== 11) {
1918 case Win64EH::UOP_SaveRegMask
:
1919 if (Step
== 1 && Inst
.Register
== 0x0f) {
1926 case Win64EH::UOP_WideSaveRegMask
:
1927 if (Step
!= 1 && Step
!= 2)
1929 // push {r4-r9,r11,lr}
1932 if (!parseRegMask(Inst
.Register
, HasLR
, HasR11
, PF
, IntRegs
))
1937 case Win64EH::UOP_Nop
:
1939 if (Step
!= 3 || !HasR11
|| IntRegs
>= 0 || PF
> 0)
1944 case Win64EH::UOP_WideNop
:
1945 // add.w r11, sp, #xx
1946 if (Step
!= 3 || !HasR11
|| (IntRegs
< 0 && PF
== 0))
1952 case Win64EH::UOP_SaveFRegD8D15
:
1953 if (Step
!= 1 && Step
!= 2 && Step
!= 3 && Step
!= 4)
1955 assert(Inst
.Register
>= 8 && Inst
.Register
<= 15);
1956 if (Inst
.Register
== 15)
1957 return false; // Can't pack this case, R==7 means no IntRegs
1960 FloatRegs
= Inst
.Register
- 8;
1964 case Win64EH::UOP_AllocSmall
:
1965 case Win64EH::UOP_WideAllocMedium
:
1966 if (Step
!= 1 && Step
!= 2 && Step
!= 3 && Step
!= 4 && Step
!= 5)
1968 if (PF
> 0) // Can't have both folded and explicit stack allocation
1970 if (Inst
.Offset
/ 4 >= 0x3f4)
1972 StackAdjust
= Inst
.Offset
/ 4;
1977 if (HasR11
&& !HasChain
) {
1978 if (IntRegs
+ 4 == 10) {
1979 // r11 stored, but not chaining; can be packed if already saving r4-r10
1980 // and we can fit r11 into this range.
1986 if (HasChain
&& !HasLR
)
1989 // Packed uneind info can't express multiple epilogues.
1990 if (info
->EpilogMap
.size() > 1)
1995 if (info
->EpilogMap
.size() == 0) {
1996 Ret
= 3; // No epilogue
1998 // As the prologue and epilogue aren't exact mirrors of each other,
1999 // we have to check the epilogue too and see if it matches what we've
2000 // concluded from the prologue.
2001 const WinEH::FrameInfo::Epilog
&EpilogInfo
=
2002 info
->EpilogMap
.begin()->second
;
2003 if (EpilogInfo
.Condition
!= 0xe) // ARMCC::AL
2005 const std::vector
<WinEH::Instruction
> &Epilog
= EpilogInfo
.Instructions
;
2006 std::optional
<int64_t> MaybeDistance
= GetOptionalAbsDifference(
2007 streamer
, info
->FuncletOrFuncEnd
, info
->EpilogMap
.begin()->first
);
2010 uint32_t DistanceFromEnd
= (uint32_t)*MaybeDistance
;
2011 uint32_t InstructionBytes
= ARMCountOfInstructionBytes(Epilog
);
2012 if (DistanceFromEnd
!= InstructionBytes
)
2015 bool GotStackAdjust
= false;
2016 bool GotFloatRegs
= false;
2017 bool GotIntRegs
= false;
2018 bool GotHomingRestore
= false;
2019 bool GotLRRestore
= false;
2020 bool NeedsReturn
= false;
2021 bool GotReturn
= false;
2024 for (const WinEH::Instruction
&Inst
: Epilog
) {
2025 switch (Inst
.Operation
) {
2027 llvm_unreachable("Unsupported ARM unwind code");
2028 case Win64EH::UOP_Custom
:
2029 case Win64EH::UOP_AllocLarge
:
2030 case Win64EH::UOP_AllocHuge
:
2031 case Win64EH::UOP_WideAllocLarge
:
2032 case Win64EH::UOP_WideAllocHuge
:
2033 case Win64EH::UOP_SaveFRegD0D15
:
2034 case Win64EH::UOP_SaveFRegD16D31
:
2035 case Win64EH::UOP_SaveSP
:
2036 case Win64EH::UOP_Nop
:
2037 case Win64EH::UOP_WideNop
:
2038 // Can't be packed in an epilogue
2041 case Win64EH::UOP_AllocSmall
:
2042 case Win64EH::UOP_WideAllocMedium
:
2043 if (Inst
.Offset
/ 4 >= 0x3f4)
2046 if (Homing
&& FloatRegs
< 0 && IntRegs
< 0 && StackAdjust
== 0 &&
2047 PF
== 0 && Inst
.Offset
== 16) {
2048 GotHomingRestore
= true;
2051 if (StackAdjust
> 0) {
2052 // Got stack adjust in prologue too; must match.
2053 if (StackAdjust
!= Inst
.Offset
/ 4)
2055 GotStackAdjust
= true;
2056 } else if (PF
== Inst
.Offset
/ 4) {
2057 // Folded prologue, non-folded epilogue
2058 StackAdjust
= Inst
.Offset
/ 4;
2059 GotStackAdjust
= true;
2061 // StackAdjust == 0 in prologue, mismatch
2066 } else if (Step
== 7 || Step
== 8 || Step
== 9) {
2067 if (!Homing
|| Inst
.Offset
!= 16)
2069 GotHomingRestore
= true;
2075 case Win64EH::UOP_SaveFRegD8D15
:
2076 if (Step
!= 6 && Step
!= 7)
2078 assert(Inst
.Register
>= 8 && Inst
.Register
<= 15);
2079 if (FloatRegs
!= (int)(Inst
.Register
- 8))
2081 GotFloatRegs
= true;
2085 case Win64EH::UOP_SaveRegsR4R7LR
:
2086 case Win64EH::UOP_WideSaveRegsR4R11LR
: {
2088 if (Step
!= 6 && Step
!= 7 && Step
!= 8)
2090 assert(Inst
.Register
>= 4 && Inst
.Register
<= 11); // r4-rX
2091 assert(Inst
.Offset
<= 1); // Lr
2092 if (Homing
&& HasLR
) {
2093 // If homing and LR is backed up, we can either restore LR here
2094 // and return with Ret == 1 or 2, or return with SaveLR below
2096 GotLRRestore
= true;
2099 // Expecting a separate SaveLR below
2102 if (HasLR
!= (Inst
.Offset
== 1))
2105 GotLRRestore
= Inst
.Offset
== 1;
2106 if (IntRegs
< 0) // This opcode must include r4
2108 int Expected
= IntRegs
;
2110 // Can't express r11 here unless IntRegs describe r4-r10
2115 if (Expected
!= (int)(Inst
.Register
- 4))
2122 case Win64EH::UOP_SaveRegMask
:
2123 case Win64EH::UOP_WideSaveRegMask
: {
2124 if (Step
!= 6 && Step
!= 7 && Step
!= 8)
2126 // push {r4-r9,r11,lr}
2129 bool CurHasLR
= false, CurHasR11
= false;
2131 if (!parseRegMask(Inst
.Register
, CurHasLR
, CurHasR11
, EF
, Regs
))
2134 if (EF
!= PF
&& EF
!= StackAdjust
)
2137 if (Homing
&& HasLR
) {
2138 // If homing and LR is backed up, we can either restore LR here
2139 // and return with Ret == 1 or 2, or return with SaveLR below
2141 GotLRRestore
= true;
2144 // Expecting a separate SaveLR below
2147 if (CurHasLR
!= HasLR
)
2149 GotLRRestore
= CurHasLR
;
2151 int Expected
= IntRegs
;
2153 // If we have chaining, the mask must have included r11.
2156 } else if (Expected
== 7) {
2157 // If we don't have chaining, the mask could still include r11,
2158 // expressed as part of IntRegs Instead.
2163 // Neither HasChain nor r11 included in IntRegs, must not have r11
2168 if (Expected
!= Regs
)
2175 case Win64EH::UOP_SaveLR
:
2176 if (Step
!= 6 && Step
!= 7 && Step
!= 8 && Step
!= 9)
2178 if (!Homing
|| Inst
.Offset
!= 20 || GotLRRestore
)
2180 GotLRRestore
= true;
2181 GotHomingRestore
= true;
2185 case Win64EH::UOP_EndNop
:
2186 case Win64EH::UOP_WideEndNop
:
2188 Ret
= (Inst
.Operation
== Win64EH::UOP_EndNop
) ? 1 : 2;
2190 case Win64EH::UOP_End
:
2191 if (Step
!= 6 && Step
!= 7 && Step
!= 8 && Step
!= 9 && Step
!= 10)
2200 if (StackAdjust
> 0 && !GotStackAdjust
&& EF
== 0)
2202 if (FloatRegs
>= 0 && !GotFloatRegs
)
2204 if (IntRegs
>= 0 && !GotIntRegs
)
2206 if (Homing
&& !GotHomingRestore
)
2208 if (HasLR
&& !GotLRRestore
)
2210 if (NeedsReturn
&& !GotReturn
)
2214 assert(PF
== 0 || EF
== 0 ||
2215 StackAdjust
== 0); // Can't have adjust in all three
2216 if (PF
> 0 || EF
> 0) {
2217 StackAdjust
= PF
> 0 ? (PF
- 1) : (EF
- 1);
2218 assert(StackAdjust
<= 3);
2219 StackAdjust
|= 0x3f0;
2221 StackAdjust
|= 1 << 2;
2223 StackAdjust
|= 1 << 3;
2226 assert(FuncLength
<= 0x7FF && "FuncLength should have been checked earlier");
2227 int Flag
= info
->Fragment
? 0x02 : 0x01;
2228 int H
= Homing
? 1 : 0;
2229 int L
= HasLR
? 1 : 0;
2230 int C
= HasChain
? 1 : 0;
2231 assert(IntRegs
< 0 || FloatRegs
< 0);
2237 } else if (FloatRegs
>= 0) {
2242 // No int or float regs stored (except possibly R11,LR)
2246 info
->PackedInfo
|= Flag
<< 0;
2247 info
->PackedInfo
|= (FuncLength
& 0x7FF) << 2;
2248 info
->PackedInfo
|= (Ret
& 0x3) << 13;
2249 info
->PackedInfo
|= H
<< 15;
2250 info
->PackedInfo
|= Reg
<< 16;
2251 info
->PackedInfo
|= R
<< 19;
2252 info
->PackedInfo
|= L
<< 20;
2253 info
->PackedInfo
|= C
<< 21;
2254 assert(StackAdjust
<= 0x3ff);
2255 info
->PackedInfo
|= StackAdjust
<< 22;
2259 // Populate the .xdata section. The format of .xdata on ARM is documented at
2260 // https://docs.microsoft.com/en-us/cpp/build/arm-exception-handling
2261 static void ARMEmitUnwindInfo(MCStreamer
&streamer
, WinEH::FrameInfo
*info
,
2262 bool TryPacked
= true) {
2263 // If this UNWIND_INFO already has a symbol, it's already been emitted.
2266 // If there's no unwind info here (not even a terminating UOP_End), the
2267 // unwind info is considered bogus and skipped. If this was done in
2268 // response to an explicit .seh_handlerdata, the associated trailing
2269 // handler data is left orphaned in the xdata section.
2270 if (info
->empty()) {
2271 info
->EmitAttempted
= true;
2274 if (info
->EmitAttempted
) {
2275 // If we tried to emit unwind info before (due to an explicit
2276 // .seh_handlerdata directive), but skipped it (because there was no
2277 // valid information to emit at the time), and it later got valid unwind
2278 // opcodes, we can't emit it here, because the trailing handler data
2279 // was already emitted elsewhere in the xdata section.
2280 streamer
.getContext().reportError(
2281 SMLoc(), "Earlier .seh_handlerdata for " + info
->Function
->getName() +
2282 " skipped due to no unwind info at the time "
2283 "(.seh_handlerdata too early?), but the function later "
2284 "did get unwind info that can't be emitted");
2288 MCContext
&context
= streamer
.getContext();
2289 MCSymbol
*Label
= context
.createTempSymbol();
2291 streamer
.emitValueToAlignment(Align(4));
2292 streamer
.emitLabel(Label
);
2293 info
->Symbol
= Label
;
2295 if (!info
->PrologEnd
)
2296 streamer
.getContext().reportError(SMLoc(), "Prologue in " +
2297 info
->Function
->getName() +
2298 " not correctly terminated");
2300 if (info
->PrologEnd
&& !info
->Fragment
)
2301 checkARMInstructions(streamer
, info
->Instructions
, info
->Begin
,
2302 info
->PrologEnd
, info
->Function
->getName(),
2304 for (auto &I
: info
->EpilogMap
) {
2305 MCSymbol
*EpilogStart
= I
.first
;
2306 auto &Epilog
= I
.second
;
2307 checkARMInstructions(streamer
, Epilog
.Instructions
, EpilogStart
, Epilog
.End
,
2308 info
->Function
->getName(), "epilogue");
2309 if (Epilog
.Instructions
.empty() ||
2310 !isARMTerminator(Epilog
.Instructions
.back()))
2311 streamer
.getContext().reportError(
2312 SMLoc(), "Epilogue in " + info
->Function
->getName() +
2313 " not correctly terminated");
2316 std::optional
<int64_t> RawFuncLength
;
2317 const MCExpr
*FuncLengthExpr
= nullptr;
2318 if (!info
->FuncletOrFuncEnd
) {
2319 report_fatal_error("FuncletOrFuncEnd not set");
2321 // As the size of many thumb2 instructions isn't known until later,
2322 // we can't always rely on being able to calculate the absolute
2323 // length of the function here. If we can't calculate it, defer it
2326 // In such a case, we won't know if the function is too long so that
2327 // the unwind info would need to be split (but this isn't implemented
2330 GetOptionalAbsDifference(streamer
, info
->FuncletOrFuncEnd
, info
->Begin
);
2333 GetSubDivExpr(streamer
, info
->FuncletOrFuncEnd
, info
->Begin
, 2);
2335 uint32_t FuncLength
= 0;
2337 FuncLength
= (uint32_t)*RawFuncLength
/ 2;
2338 if (FuncLength
> 0x3FFFF)
2339 report_fatal_error("SEH unwind data splitting not yet implemented");
2340 uint32_t PrologCodeBytes
= ARMCountOfUnwindCodes(info
->Instructions
);
2341 uint32_t TotalCodeBytes
= PrologCodeBytes
;
2343 if (!info
->HandlesExceptions
&& RawFuncLength
&& FuncLength
<= 0x7ff &&
2345 // No exception handlers; check if the prolog and epilog matches the
2346 // patterns that can be described by the packed format. If we don't
2347 // know the exact function length yet, we can't do this.
2349 // info->Symbol was already set even if we didn't actually write any
2350 // unwind info there. Keep using that as indicator that this unwind
2351 // info has been generated already.
2353 if (tryARMPackedUnwind(streamer
, info
, FuncLength
))
2357 int PackedEpilogOffset
=
2358 checkARMPackedEpilog(streamer
, info
, PrologCodeBytes
);
2361 MapVector
<MCSymbol
*, uint32_t> EpilogInfo
;
2362 // Epilogs processed so far.
2363 std::vector
<MCSymbol
*> AddedEpilogs
;
2365 bool CanTweakProlog
= true;
2366 for (auto &I
: info
->EpilogMap
) {
2367 MCSymbol
*EpilogStart
= I
.first
;
2368 auto &EpilogInstrs
= I
.second
.Instructions
;
2369 uint32_t CodeBytes
= ARMCountOfUnwindCodes(EpilogInstrs
);
2371 MCSymbol
*MatchingEpilog
=
2372 FindMatchingEpilog(EpilogInstrs
, AddedEpilogs
, info
);
2374 if (MatchingEpilog
) {
2375 assert(EpilogInfo
.contains(MatchingEpilog
) &&
2376 "Duplicate epilog not found");
2377 EpilogInfo
[EpilogStart
] = EpilogInfo
.lookup(MatchingEpilog
);
2378 // Clear the unwind codes in the EpilogMap, so that they don't get output
2379 // in the logic below.
2380 EpilogInstrs
.clear();
2381 } else if ((PrologOffset
= getARMOffsetInProlog(
2382 info
->Instructions
, EpilogInstrs
, CanTweakProlog
)) >= 0) {
2383 if (CanTweakProlog
) {
2384 // Replace the regular end opcode of the prolog with the one from the
2386 info
->Instructions
.front() = EpilogInstrs
.back();
2387 // Later epilogs need a strict match for the end opcode.
2388 CanTweakProlog
= false;
2390 EpilogInfo
[EpilogStart
] = PrologOffset
;
2391 // Clear the unwind codes in the EpilogMap, so that they don't get output
2392 // in the logic below.
2393 EpilogInstrs
.clear();
2395 EpilogInfo
[EpilogStart
] = TotalCodeBytes
;
2396 TotalCodeBytes
+= CodeBytes
;
2397 AddedEpilogs
.push_back(EpilogStart
);
2401 // Code Words, Epilog count, F, E, X, Vers, Function Length
2402 uint32_t row1
= 0x0;
2403 uint32_t CodeWords
= TotalCodeBytes
/ 4;
2404 uint32_t CodeWordsMod
= TotalCodeBytes
% 4;
2407 uint32_t EpilogCount
=
2408 PackedEpilogOffset
>= 0 ? PackedEpilogOffset
: info
->EpilogMap
.size();
2409 bool ExtensionWord
= EpilogCount
> 31 || CodeWords
> 15;
2410 if (!ExtensionWord
) {
2411 row1
|= (EpilogCount
& 0x1F) << 23;
2412 row1
|= (CodeWords
& 0x0F) << 28;
2414 if (info
->HandlesExceptions
) // X
2416 if (PackedEpilogOffset
>= 0) // E
2418 if (info
->Fragment
) // F
2420 row1
|= FuncLength
& 0x3FFFF;
2422 streamer
.emitInt32(row1
);
2425 MCBinaryExpr::createOr(FuncLengthExpr
,
2426 MCConstantExpr::create(row1
, context
), context
),
2429 // Extended Code Words, Extended Epilog Count
2430 if (ExtensionWord
) {
2431 // FIXME: We should be able to split unwind info into multiple sections.
2432 if (CodeWords
> 0xFF || EpilogCount
> 0xFFFF)
2433 report_fatal_error("SEH unwind data splitting not yet implemented");
2434 uint32_t row2
= 0x0;
2435 row2
|= (CodeWords
& 0xFF) << 16;
2436 row2
|= (EpilogCount
& 0xFFFF);
2437 streamer
.emitInt32(row2
);
2440 if (PackedEpilogOffset
< 0) {
2441 // Epilog Start Index, Epilog Start Offset
2442 for (auto &I
: EpilogInfo
) {
2443 MCSymbol
*EpilogStart
= I
.first
;
2444 uint32_t EpilogIndex
= I
.second
;
2446 std::optional
<int64_t> MaybeEpilogOffset
=
2447 GetOptionalAbsDifference(streamer
, EpilogStart
, info
->Begin
);
2448 const MCExpr
*OffsetExpr
= nullptr;
2449 uint32_t EpilogOffset
= 0;
2450 if (MaybeEpilogOffset
)
2451 EpilogOffset
= *MaybeEpilogOffset
/ 2;
2453 OffsetExpr
= GetSubDivExpr(streamer
, EpilogStart
, info
->Begin
, 2);
2455 assert(info
->EpilogMap
.contains(EpilogStart
));
2456 unsigned Condition
= info
->EpilogMap
[EpilogStart
].Condition
;
2457 assert(Condition
<= 0xf);
2459 uint32_t row3
= EpilogOffset
;
2460 row3
|= Condition
<< 20;
2461 row3
|= (EpilogIndex
& 0x3FF) << 24;
2462 if (MaybeEpilogOffset
)
2463 streamer
.emitInt32(row3
);
2466 MCBinaryExpr::createOr(
2467 OffsetExpr
, MCConstantExpr::create(row3
, context
), context
),
2472 // Emit prolog unwind instructions (in reverse order).
2473 uint8_t numInst
= info
->Instructions
.size();
2474 for (uint8_t c
= 0; c
< numInst
; ++c
) {
2475 WinEH::Instruction inst
= info
->Instructions
.back();
2476 info
->Instructions
.pop_back();
2477 ARMEmitUnwindCode(streamer
, inst
);
2480 // Emit epilog unwind instructions
2481 for (auto &I
: info
->EpilogMap
) {
2482 auto &EpilogInstrs
= I
.second
.Instructions
;
2483 for (const WinEH::Instruction
&inst
: EpilogInstrs
)
2484 ARMEmitUnwindCode(streamer
, inst
);
2487 int32_t BytesMod
= CodeWords
* 4 - TotalCodeBytes
;
2488 assert(BytesMod
>= 0);
2489 for (int i
= 0; i
< BytesMod
; i
++)
2490 streamer
.emitInt8(0xFB);
2492 if (info
->HandlesExceptions
)
2494 MCSymbolRefExpr::create(info
->ExceptionHandler
,
2495 MCSymbolRefExpr::VK_COFF_IMGREL32
, context
),
2499 static void ARM64EmitRuntimeFunction(MCStreamer
&streamer
,
2500 const WinEH::FrameInfo
*info
) {
2501 MCContext
&context
= streamer
.getContext();
2503 streamer
.emitValueToAlignment(Align(4));
2504 for (const auto &S
: info
->Segments
) {
2505 EmitSymbolRefWithOfs(streamer
, info
->Begin
, S
.Offset
);
2506 if (info
->PackedInfo
)
2507 streamer
.emitInt32(info
->PackedInfo
);
2510 MCSymbolRefExpr::create(S
.Symbol
, MCSymbolRefExpr::VK_COFF_IMGREL32
,
2517 static void ARMEmitRuntimeFunction(MCStreamer
&streamer
,
2518 const WinEH::FrameInfo
*info
) {
2519 MCContext
&context
= streamer
.getContext();
2521 streamer
.emitValueToAlignment(Align(4));
2522 EmitSymbolRefWithOfs(streamer
, info
->Begin
, info
->Begin
);
2523 if (info
->PackedInfo
)
2524 streamer
.emitInt32(info
->PackedInfo
);
2527 MCSymbolRefExpr::create(info
->Symbol
, MCSymbolRefExpr::VK_COFF_IMGREL32
,
2532 void llvm::Win64EH::ARM64UnwindEmitter::Emit(MCStreamer
&Streamer
) const {
2533 // Emit the unwind info structs first.
2534 for (const auto &CFI
: Streamer
.getWinFrameInfos()) {
2535 WinEH::FrameInfo
*Info
= CFI
.get();
2538 MCSection
*XData
= Streamer
.getAssociatedXDataSection(CFI
->TextSection
);
2539 Streamer
.switchSection(XData
);
2540 ARM64EmitUnwindInfo(Streamer
, Info
);
2543 // Now emit RUNTIME_FUNCTION entries.
2544 for (const auto &CFI
: Streamer
.getWinFrameInfos()) {
2545 WinEH::FrameInfo
*Info
= CFI
.get();
2546 // ARM64EmitUnwindInfo above clears the info struct, so we can't check
2547 // empty here. But if a Symbol is set, we should create the corresponding
2551 MCSection
*PData
= Streamer
.getAssociatedPDataSection(CFI
->TextSection
);
2552 Streamer
.switchSection(PData
);
2553 ARM64EmitRuntimeFunction(Streamer
, Info
);
2557 void llvm::Win64EH::ARM64UnwindEmitter::EmitUnwindInfo(MCStreamer
&Streamer
,
2558 WinEH::FrameInfo
*info
,
2559 bool HandlerData
) const {
2560 // Called if there's an .seh_handlerdata directive before the end of the
2561 // function. This forces writing the xdata record already here - and
2562 // in this case, the function isn't actually ended already, but the xdata
2563 // record needs to know the function length. In these cases, if the funclet
2564 // end hasn't been marked yet, the xdata function length won't cover the
2565 // whole function, only up to this point.
2566 if (!info
->FuncletOrFuncEnd
) {
2567 Streamer
.switchSection(info
->TextSection
);
2568 info
->FuncletOrFuncEnd
= Streamer
.emitCFILabel();
2570 // Switch sections (the static function above is meant to be called from
2571 // here and from Emit().
2572 MCSection
*XData
= Streamer
.getAssociatedXDataSection(info
->TextSection
);
2573 Streamer
.switchSection(XData
);
2574 ARM64EmitUnwindInfo(Streamer
, info
, /* TryPacked = */ !HandlerData
);
2577 void llvm::Win64EH::ARMUnwindEmitter::Emit(MCStreamer
&Streamer
) const {
2578 // Emit the unwind info structs first.
2579 for (const auto &CFI
: Streamer
.getWinFrameInfos()) {
2580 WinEH::FrameInfo
*Info
= CFI
.get();
2583 MCSection
*XData
= Streamer
.getAssociatedXDataSection(CFI
->TextSection
);
2584 Streamer
.switchSection(XData
);
2585 ARMEmitUnwindInfo(Streamer
, Info
);
2588 // Now emit RUNTIME_FUNCTION entries.
2589 for (const auto &CFI
: Streamer
.getWinFrameInfos()) {
2590 WinEH::FrameInfo
*Info
= CFI
.get();
2591 // ARMEmitUnwindInfo above clears the info struct, so we can't check
2592 // empty here. But if a Symbol is set, we should create the corresponding
2596 MCSection
*PData
= Streamer
.getAssociatedPDataSection(CFI
->TextSection
);
2597 Streamer
.switchSection(PData
);
2598 ARMEmitRuntimeFunction(Streamer
, Info
);
2602 void llvm::Win64EH::ARMUnwindEmitter::EmitUnwindInfo(MCStreamer
&Streamer
,
2603 WinEH::FrameInfo
*info
,
2604 bool HandlerData
) const {
2605 // Called if there's an .seh_handlerdata directive before the end of the
2606 // function. This forces writing the xdata record already here - and
2607 // in this case, the function isn't actually ended already, but the xdata
2608 // record needs to know the function length. In these cases, if the funclet
2609 // end hasn't been marked yet, the xdata function length won't cover the
2610 // whole function, only up to this point.
2611 if (!info
->FuncletOrFuncEnd
) {
2612 Streamer
.switchSection(info
->TextSection
);
2613 info
->FuncletOrFuncEnd
= Streamer
.emitCFILabel();
2615 // Switch sections (the static function above is meant to be called from
2616 // here and from Emit().
2617 MCSection
*XData
= Streamer
.getAssociatedXDataSection(info
->TextSection
);
2618 Streamer
.switchSection(XData
);
2619 ARMEmitUnwindInfo(Streamer
, info
, /* TryPacked = */ !HandlerData
);