LLVM 24.0.0git
AArch64WinCOFFStreamer.cpp
Go to the documentation of this file.
1//===-- AArch64WinCOFFStreamer.cpp - ARM Target WinCOFF Streamer ----*- C++ -*-===//
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
11#include "llvm/MC/MCAssembler.h"
13#include "llvm/MC/MCContext.h"
15#include "llvm/MC/MCWin64EH.h"
17
18using namespace llvm;
19
20namespace {
21
22class AArch64WinCOFFStreamer : public MCWinCOFFStreamer {
23 Win64EH::ARM64UnwindEmitter EHStreamer;
24
25public:
26 AArch64WinCOFFStreamer(MCContext &C, std::unique_ptr<MCAsmBackend> AB,
27 std::unique_ptr<MCCodeEmitter> CE,
28 std::unique_ptr<MCObjectWriter> OW)
29 : MCWinCOFFStreamer(C, std::move(AB), std::move(CE), std::move(OW)) {}
30
31 void emitWinEHHandlerData(SMLoc Loc) override;
32 void emitWindowsUnwindTables() override;
33 void emitWindowsUnwindTables(WinEH::FrameInfo *Frame) override;
34 void finishImpl() override;
35};
36
37void AArch64WinCOFFStreamer::emitWinEHHandlerData(SMLoc Loc) {
39
40 // We have to emit the unwind info now, because this directive
41 // actually switches to the .xdata section!
42 EHStreamer.EmitUnwindInfo(*this, getCurrentWinFrameInfo(),
43 /* HandlerData = */ true);
44}
45
46void AArch64WinCOFFStreamer::emitWindowsUnwindTables(WinEH::FrameInfo *Frame) {
47 EHStreamer.EmitUnwindInfo(*this, Frame, /* HandlerData = */ false);
48}
49
50void AArch64WinCOFFStreamer::emitWindowsUnwindTables() {
51 if (!getNumWinFrameInfos())
52 return;
53 EHStreamer.Emit(*this);
54}
55
56void AArch64WinCOFFStreamer::finishImpl() {
57 emitFrames();
58 emitWindowsUnwindTables();
59
61}
62} // end anonymous namespace
63
64// Helper function to common out unwind code setup for those codes that can
65// belong to both prolog and epilog.
66// There are three types of Windows ARM64 SEH codes. They can
67// 1) take no operands: SEH_Nop, SEH_PrologEnd, SEH_EpilogStart, SEH_EpilogEnd
68// 2) take an offset: SEH_StackAlloc, SEH_SaveFPLR, SEH_SaveFPLR_X
69// 3) take a register and an offset/size: all others
70void AArch64TargetWinCOFFStreamer::emitARM64WinUnwindCode(unsigned UnwindCode,
71 int Reg, int Offset) {
72 auto &S = getStreamer();
73 WinEH::FrameInfo *CurFrame = S.EnsureValidWinFrameInfo(SMLoc());
74 if (!CurFrame)
75 return;
76 auto Inst = WinEH::Instruction(UnwindCode, /*Label=*/nullptr, Reg, Offset);
77 if (S.isInEpilogCFI())
78 S.getCurrentWinEpilog()->Instructions.push_back(Inst);
79 else
80 CurFrame->Instructions.push_back(Inst);
81}
82
84 unsigned Op = Win64EH::UOP_AllocSmall;
85 if (Size >= 16384)
87 else if (Size >= 512)
89 emitARM64WinUnwindCode(Op, -1, Size);
90}
91
95
99
103
105 int Offset) {
106 assert(Offset >= 0 && Offset <= 504 &&
107 "Offset for save reg should be >= 0 && <= 504");
108 emitARM64WinUnwindCode(Win64EH::UOP_SaveReg, Reg, Offset);
109}
110
112 int Offset) {
113 emitARM64WinUnwindCode(Win64EH::UOP_SaveRegX, Reg, Offset);
114}
115
117 int Offset) {
118 emitARM64WinUnwindCode(Win64EH::UOP_SaveRegP, Reg, Offset);
119}
120
122 int Offset) {
123 emitARM64WinUnwindCode(Win64EH::UOP_SaveRegPX, Reg, Offset);
124}
125
127 int Offset) {
128 emitARM64WinUnwindCode(Win64EH::UOP_SaveLRPair, Reg, Offset);
129}
130
132 int Offset) {
133 assert(Offset >= 0 && Offset <= 504 &&
134 "Offset for save reg should be >= 0 && <= 504");
135 emitARM64WinUnwindCode(Win64EH::UOP_SaveFReg, Reg, Offset);
136}
137
139 int Offset) {
140 emitARM64WinUnwindCode(Win64EH::UOP_SaveFRegX, Reg, Offset);
141}
142
144 int Offset) {
145 emitARM64WinUnwindCode(Win64EH::UOP_SaveFRegP, Reg, Offset);
146}
147
149 int Offset) {
150 emitARM64WinUnwindCode(Win64EH::UOP_SaveFRegPX, Reg, Offset);
151}
152
154 emitARM64WinUnwindCode(Win64EH::UOP_SetFP, -1, 0);
155}
156
158 assert(Offset <= 2040 && "UOP_AddFP must have offset <= 2040");
159 emitARM64WinUnwindCode(Win64EH::UOP_AddFP, -1, Offset);
160}
161
163 emitARM64WinUnwindCode(Win64EH::UOP_Nop, -1, 0);
164}
165
167 emitARM64WinUnwindCode(Win64EH::UOP_SaveNext, -1, 0);
168}
169
170// The functions below handle opcodes that can end up in either a prolog or
171// an epilog, but not both.
173 auto &S = getStreamer();
174 WinEH::FrameInfo *CurFrame = S.EnsureValidWinFrameInfo(SMLoc());
175 if (!CurFrame)
176 return;
177
178 MCSymbol *Label = S.emitCFILabel();
179 CurFrame->PrologEnd = Label;
180 WinEH::Instruction Inst =
181 WinEH::Instruction(Win64EH::UOP_End, /*Label=*/nullptr, -1, 0);
182 auto it = CurFrame->Instructions.begin();
183 CurFrame->Instructions.insert(it, Inst);
184}
185
187 auto &S = getStreamer();
188 WinEH::FrameInfo *CurFrame = S.EnsureValidWinFrameInfo(SMLoc());
189 if (!CurFrame)
190 return;
191 bool InEpilogue = S.isInEpilogCFI();
192 auto &Instructions = InEpilogue ? S.getCurrentWinEpilog()->Instructions
193 : CurFrame->Instructions;
194 if ((!InEpilogue && CurFrame->PrologEnd) ||
195 llvm::any_of(Instructions, [](const WinEH::Instruction &I) {
196 return I.Operation == Win64EH::UOP_EndC;
197 })) {
198 S.getContext().reportError(
199 SMLoc(), ".seh_end_c must appear once in a prologue or epilogue");
200 return;
201 }
202 emitARM64WinUnwindCode(Win64EH::UOP_EndC, -1, 0);
203}
204
206 getStreamer().emitWinCFIBeginEpilogue();
207}
208
210 auto &S = getStreamer();
211 WinEH::FrameInfo *CurFrame = S.EnsureValidWinFrameInfo(SMLoc());
212 if (!CurFrame)
213 return;
214
215 if (S.isInEpilogCFI()) {
216 WinEH::Instruction Inst =
217 WinEH::Instruction(Win64EH::UOP_End, /*Label=*/nullptr, -1, 0);
218 S.getCurrentWinEpilog()->Instructions.push_back(Inst);
219 }
220 S.emitWinCFIEndEpilogue();
221}
222
226
230
232 emitARM64WinUnwindCode(Win64EH::UOP_Context, -1, 0);
233}
234
238
242
246
248 int Offset) {
249 emitARM64WinUnwindCode(Win64EH::UOP_SaveAnyRegI, Reg, Offset);
250}
251
253 int Offset) {
254 emitARM64WinUnwindCode(Win64EH::UOP_SaveAnyRegIP, Reg, Offset);
255}
256
258 int Offset) {
259 emitARM64WinUnwindCode(Win64EH::UOP_SaveAnyRegD, Reg, Offset);
260}
261
263 int Offset) {
264 emitARM64WinUnwindCode(Win64EH::UOP_SaveAnyRegDP, Reg, Offset);
265}
266
268 int Offset) {
269 emitARM64WinUnwindCode(Win64EH::UOP_SaveAnyRegQ, Reg, Offset);
270}
271
273 int Offset) {
274 emitARM64WinUnwindCode(Win64EH::UOP_SaveAnyRegQP, Reg, Offset);
275}
276
278 int Offset) {
279 emitARM64WinUnwindCode(Win64EH::UOP_SaveAnyRegIX, Reg, Offset);
280}
281
283 int Offset) {
284 emitARM64WinUnwindCode(Win64EH::UOP_SaveAnyRegIPX, Reg, Offset);
285}
286
288 int Offset) {
289 emitARM64WinUnwindCode(Win64EH::UOP_SaveAnyRegDX, Reg, Offset);
290}
291
293 int Offset) {
294 emitARM64WinUnwindCode(Win64EH::UOP_SaveAnyRegDPX, Reg, Offset);
295}
296
298 int Offset) {
299 emitARM64WinUnwindCode(Win64EH::UOP_SaveAnyRegQX, Reg, Offset);
300}
301
303 int Offset) {
304 emitARM64WinUnwindCode(Win64EH::UOP_SaveAnyRegQPX, Reg, Offset);
305}
306
310
312 int Offset) {
313 emitARM64WinUnwindCode(Win64EH::UOP_SaveZReg, Reg, Offset);
314}
315
317 int Offset) {
318 emitARM64WinUnwindCode(Win64EH::UOP_SavePReg, Reg, Offset);
319}
320
323 std::unique_ptr<MCAsmBackend> &&MAB,
324 std::unique_ptr<MCObjectWriter> &&OW,
325 std::unique_ptr<MCCodeEmitter> &&Emitter) {
326 return new AArch64WinCOFFStreamer(Context, std::move(MAB), std::move(Emitter),
327 std::move(OW));
328}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
dxil DXContainer Global Emitter
#define I(x, y, z)
Definition MD5.cpp:57
Register Reg
void emitARM64WinCFISaveAnyRegQX(unsigned Reg, int Offset) override
void emitARM64WinCFISaveAnyRegDX(unsigned Reg, int Offset) override
void emitARM64WinCFISaveAnyRegIP(unsigned Reg, int Offset) override
void emitARM64WinCFISaveAnyRegQ(unsigned Reg, int Offset) override
void emitARM64WinCFIAllocZ(int Offset) override
void emitARM64WinCFISaveFRegP(unsigned Reg, int Offset) override
void emitARM64WinCFISaveFRegPX(unsigned Reg, int Offset) override
void emitARM64WinCFISaveRegP(unsigned Reg, int Offset) override
void emitARM64WinCFISaveR19R20X(int Offset) override
void emitARM64WinCFISaveRegPX(unsigned Reg, int Offset) override
void emitARM64WinCFISaveRegX(unsigned Reg, int Offset) override
void emitARM64WinCFISavePReg(unsigned Reg, int Offset) override
void emitARM64WinCFISaveAnyRegQPX(unsigned Reg, int Offset) override
void emitARM64WinCFISaveAnyRegIPX(unsigned Reg, int Offset) override
void emitARM64WinCFISaveFPLR(int Offset) override
void emitARM64WinCFISaveZReg(unsigned Reg, int Offset) override
void emitARM64WinCFISaveFRegX(unsigned Reg, int Offset) override
void emitARM64WinCFISaveAnyRegDPX(unsigned Reg, int Offset) override
void emitARM64WinCFIAllocStack(unsigned Size) override
void emitARM64WinCFISaveAnyRegD(unsigned Reg, int Offset) override
void emitARM64WinCFISaveAnyRegI(unsigned Reg, int Offset) override
void emitARM64WinCFISaveFReg(unsigned Reg, int Offset) override
void emitARM64WinCFISaveAnyRegIX(unsigned Reg, int Offset) override
void emitARM64WinCFISaveFPLRX(int Offset) override
void emitARM64WinCFISaveReg(unsigned Reg, int Offset) override
void emitARM64WinCFIAddFP(unsigned Size) override
void emitARM64WinCFISaveAnyRegDP(unsigned Reg, int Offset) override
void emitARM64WinCFISaveLRPair(unsigned Reg, int Offset) override
void emitARM64WinCFISaveAnyRegQP(unsigned Reg, int Offset) override
Context object for machine code objects.
Definition MCContext.h:83
Streaming machine code generation interface.
Definition MCStreamer.h:222
virtual void emitWinEHHandlerData(SMLoc Loc=SMLoc())
MCSymbol - Instances of this class represent a symbol name in the MC file, and MCSymbols are created ...
Definition MCSymbol.h:42
MCStreamer & getStreamer()
Definition MCStreamer.h:103
void finishImpl() override
Streamer specific finalization.
Represents a location in source code.
Definition SMLoc.h:22
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).
@ UOP_SaveAnyRegDPX
Definition Win64EH.h:80
@ UOP_ClearUnwoundToCall
Definition Win64EH.h:69
@ UOP_SaveAnyRegDX
Definition Win64EH.h:79
@ UOP_SaveAnyRegQP
Definition Win64EH.h:76
@ UOP_SaveAnyRegD
Definition Win64EH.h:73
@ UOP_SaveAnyRegIPX
Definition Win64EH.h:78
@ UOP_SaveAnyRegQX
Definition Win64EH.h:81
@ UOP_SaveAnyRegIX
Definition Win64EH.h:77
@ UOP_SaveAnyRegQ
Definition Win64EH.h:75
@ UOP_SaveAnyRegDP
Definition Win64EH.h:74
@ UOP_PushMachFrame
Definition Win64EH.h:44
@ UOP_SaveR19R20X
Definition Win64EH.h:48
@ UOP_SaveAnyRegQPX
Definition Win64EH.h:82
@ UOP_AllocMedium
Definition Win64EH.h:47
@ UOP_SaveAnyRegIP
Definition Win64EH.h:72
@ UOP_SaveAnyRegI
Definition Win64EH.h:71
@ CE
Windows NT (Windows on ARM)
Definition MCAsmInfo.h:51
This is an optimization pass for GlobalISel generic memory operations.
@ Offset
Definition DWP.cpp:577
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1762
MCStreamer * createAArch64WinCOFFStreamer(MCContext &Context, std::unique_ptr< MCAsmBackend > &&TAB, std::unique_ptr< MCObjectWriter > &&OW, std::unique_ptr< MCCodeEmitter > &&Emitter)
DWARFExpression::Operation Op
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1933
std::vector< Instruction > Instructions
Definition MCWinEH.h:68
const MCSymbol * PrologEnd
Definition MCWinEH.h:53