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 9#include "AArch64WinCOFFStreamer.h" 10#include "llvm/MC/MCAsmBackend.h" 11#include "llvm/MC/MCAssembler.h" 12#include "llvm/MC/MCCodeEmitter.h" 13#include "llvm/MC/MCObjectWriter.h" 14#include "llvm/MC/MCWin64EH.h" 15#include "llvm/MC/MCWinCOFFStreamer.h" 16 17using namespace llvm; 18 19namespace { 20 21class AArch64WinCOFFStreamer : public MCWinCOFFStreamer { 22 Win64EH::ARM64UnwindEmitter EHStreamer; 23 24public: 25 AArch64WinCOFFStreamer(MCContext &C, std::unique_ptr<MCAsmBackend> AB, 26 std::unique_ptr<MCCodeEmitter> CE, 27 std::unique_ptr<MCObjectWriter> OW) 28 : MCWinCOFFStreamer(C, std::move(AB), std::move(CE), std::move(OW)) {} 29 30 void emitWinEHHandlerData(SMLoc Loc) override; 31 void emitWindowsUnwindTables() override; 32 void emitWindowsUnwindTables(WinEH::FrameInfo *Frame) override; 33 void finishImpl() override; 34}; 35 36void AArch64WinCOFFStreamer::emitWinEHHandlerData(SMLoc Loc) { 37 MCStreamer::emitWinEHHandlerData(Loc); 38 39 // We have to emit the unwind info now, because this directive 40 // actually switches to the .xdata section! 41 EHStreamer.EmitUnwindInfo(*this, getCurrentWinFrameInfo(), 42 /* HandlerData = */ true); 43} 44 45void AArch64WinCOFFStreamer::emitWindowsUnwindTables(WinEH::FrameInfo *Frame) { 46 EHStreamer.EmitUnwindInfo(*this, Frame, /* HandlerData = */ false); 47} 48 49void AArch64WinCOFFStreamer::emitWindowsUnwindTables() { 50 if (!getNumWinFrameInfos()) 51 return; 52 EHStreamer.Emit(*this); 53} 54 55void AArch64WinCOFFStreamer::finishImpl() { 56 emitFrames(nullptr); 57 emitWindowsUnwindTables(); 58 59 MCWinCOFFStreamer::finishImpl(); 60} 61} // end anonymous namespace 62 63// Helper function to common out unwind code setup for those codes that can 64// belong to both prolog and epilog. 65// There are three types of Windows ARM64 SEH codes. They can 66// 1) take no operands: SEH_Nop, SEH_PrologEnd, SEH_EpilogStart, SEH_EpilogEnd 67// 2) take an offset: SEH_StackAlloc, SEH_SaveFPLR, SEH_SaveFPLR_X 68// 3) take a register and an offset/size: all others 69void AArch64TargetWinCOFFStreamer::emitARM64WinUnwindCode(unsigned UnwindCode, 70 int Reg, int Offset) { 71 auto &S = getStreamer(); 72 WinEH::FrameInfo *CurFrame = S.EnsureValidWinFrameInfo(SMLoc()); 73 if (!CurFrame) 74 return; 75 auto Inst = WinEH::Instruction(UnwindCode, /*Label=*/nullptr, Reg, Offset); 76 if (InEpilogCFI) 77 CurFrame->EpilogMap[CurrentEpilog].Instructions.push_back(Inst); 78 else 79 CurFrame->Instructions.push_back(Inst); 80} 81 82void AArch64TargetWinCOFFStreamer::emitARM64WinCFIAllocStack(unsigned Size) { 83 unsigned Op = Win64EH::UOP_AllocSmall; 84 if (Size >= 16384) 85 Op = Win64EH::UOP_AllocLarge; 86 else if (Size >= 512) 87 Op = Win64EH::UOP_AllocMedium; 88 emitARM64WinUnwindCode(Op, -1, Size); 89} 90 91void AArch64TargetWinCOFFStreamer::emitARM64WinCFISaveR19R20X(int Offset) { 92 emitARM64WinUnwindCode(Win64EH::UOP_SaveR19R20X, -1, Offset); 93} 94 95void AArch64TargetWinCOFFStreamer::emitARM64WinCFISaveFPLR(int Offset) { 96 emitARM64WinUnwindCode(Win64EH::UOP_SaveFPLR, -1, Offset); 97} 98 99void AArch64TargetWinCOFFStreamer::emitARM64WinCFISaveFPLRX(int Offset) { 100 emitARM64WinUnwindCode(Win64EH::UOP_SaveFPLRX, -1, Offset); 101} 102 103void AArch64TargetWinCOFFStreamer::emitARM64WinCFISaveReg(unsigned Reg, 104 int Offset) { 105 assert(Offset >= 0 && Offset <= 504 && 106 "Offset for save reg should be >= 0 && <= 504"); 107 emitARM64WinUnwindCode(Win64EH::UOP_SaveReg, Reg, Offset); 108} 109 110void AArch64TargetWinCOFFStreamer::emitARM64WinCFISaveRegX(unsigned Reg, 111 int Offset) { 112 emitARM64WinUnwindCode(Win64EH::UOP_SaveRegX, Reg, Offset); 113} 114 115void AArch64TargetWinCOFFStreamer::emitARM64WinCFISaveRegP(unsigned Reg, 116 int Offset) { 117 emitARM64WinUnwindCode(Win64EH::UOP_SaveRegP, Reg, Offset); 118} 119 120void AArch64TargetWinCOFFStreamer::emitARM64WinCFISaveRegPX(unsigned Reg, 121 int Offset) { 122 emitARM64WinUnwindCode(Win64EH::UOP_SaveRegPX, Reg, Offset); 123} 124 125void AArch64TargetWinCOFFStreamer::emitARM64WinCFISaveLRPair(unsigned Reg, 126 int Offset) { 127 emitARM64WinUnwindCode(Win64EH::UOP_SaveLRPair, Reg, Offset); 128} 129 130void AArch64TargetWinCOFFStreamer::emitARM64WinCFISaveFReg(unsigned Reg, 131 int Offset) { 132 assert(Offset >= 0 && Offset <= 504 && 133 "Offset for save reg should be >= 0 && <= 504"); 134 emitARM64WinUnwindCode(Win64EH::UOP_SaveFReg, Reg, Offset); 135} 136 137void AArch64TargetWinCOFFStreamer::emitARM64WinCFISaveFRegX(unsigned Reg, 138 int Offset) { 139 emitARM64WinUnwindCode(Win64EH::UOP_SaveFRegX, Reg, Offset); 140} 141 142void AArch64TargetWinCOFFStreamer::emitARM64WinCFISaveFRegP(unsigned Reg, 143 int Offset) { 144 emitARM64WinUnwindCode(Win64EH::UOP_SaveFRegP, Reg, Offset); 145} 146 147void AArch64TargetWinCOFFStreamer::emitARM64WinCFISaveFRegPX(unsigned Reg, 148 int Offset) { 149 emitARM64WinUnwindCode(Win64EH::UOP_SaveFRegPX, Reg, Offset); 150} 151 152void AArch64TargetWinCOFFStreamer::emitARM64WinCFISetFP() { 153 emitARM64WinUnwindCode(Win64EH::UOP_SetFP, -1, 0); 154} 155 156void AArch64TargetWinCOFFStreamer::emitARM64WinCFIAddFP(unsigned Offset) { 157 assert(Offset <= 2040 && "UOP_AddFP must have offset <= 2040"); 158 emitARM64WinUnwindCode(Win64EH::UOP_AddFP, -1, Offset); 159} 160 161void AArch64TargetWinCOFFStreamer::emitARM64WinCFINop() { 162 emitARM64WinUnwindCode(Win64EH::UOP_Nop, -1, 0); 163} 164 165void AArch64TargetWinCOFFStreamer::emitARM64WinCFISaveNext() { 166 emitARM64WinUnwindCode(Win64EH::UOP_SaveNext, -1, 0); 167} 168 169// The functions below handle opcodes that can end up in either a prolog or 170// an epilog, but not both. 171void AArch64TargetWinCOFFStreamer::emitARM64WinCFIPrologEnd() { 172 auto &S = getStreamer(); 173 WinEH::FrameInfo *CurFrame = S.EnsureValidWinFrameInfo(SMLoc()); 174 if (!CurFrame) 175 return; 176 177 MCSymbol *Label = S.emitCFILabel(); 178 CurFrame->PrologEnd = Label; 179 WinEH::Instruction Inst = 180 WinEH::Instruction(Win64EH::UOP_End, /*Label=*/nullptr, -1, 0); 181 auto it = CurFrame->Instructions.begin(); 182 CurFrame->Instructions.insert(it, Inst); 183} 184 185void AArch64TargetWinCOFFStreamer::emitARM64WinCFIEpilogStart() { 186 auto &S = getStreamer(); 187 WinEH::FrameInfo *CurFrame = S.EnsureValidWinFrameInfo(SMLoc()); 188 if (!CurFrame) 189 return; 190 191 InEpilogCFI = true; 192 CurrentEpilog = S.emitCFILabel(); 193} 194 195void AArch64TargetWinCOFFStreamer::emitARM64WinCFIEpilogEnd() { 196 auto &S = getStreamer(); 197 WinEH::FrameInfo *CurFrame = S.EnsureValidWinFrameInfo(SMLoc()); 198 if (!CurFrame) 199 return; 200 201 InEpilogCFI = false; 202 WinEH::Instruction Inst = 203 WinEH::Instruction(Win64EH::UOP_End, /*Label=*/nullptr, -1, 0); 204 CurFrame->EpilogMap[CurrentEpilog].Instructions.push_back(Inst); 205 MCSymbol *Label = S.emitCFILabel(); 206 CurFrame->EpilogMap[CurrentEpilog].End = Label; 207 CurrentEpilog = nullptr; 208} 209 210void AArch64TargetWinCOFFStreamer::emitARM64WinCFITrapFrame() { 211 emitARM64WinUnwindCode(Win64EH::UOP_TrapFrame, -1, 0); 212} 213 214void AArch64TargetWinCOFFStreamer::emitARM64WinCFIMachineFrame() { 215 emitARM64WinUnwindCode(Win64EH::UOP_PushMachFrame, -1, 0); 216} 217 218void AArch64TargetWinCOFFStreamer::emitARM64WinCFIContext() { 219 emitARM64WinUnwindCode(Win64EH::UOP_Context, -1, 0); 220} 221 222void AArch64TargetWinCOFFStreamer::emitARM64WinCFIClearUnwoundToCall() { 223 emitARM64WinUnwindCode(Win64EH::UOP_ClearUnwoundToCall, -1, 0); 224} 225 226void AArch64TargetWinCOFFStreamer::emitARM64WinCFIPACSignLR() { 227 emitARM64WinUnwindCode(Win64EH::UOP_PACSignLR, -1, 0); 228} 229 230void AArch64TargetWinCOFFStreamer::emitARM64WinCFISaveAnyRegI(unsigned Reg, 231 int Offset) { 232 emitARM64WinUnwindCode(Win64EH::UOP_SaveAnyRegI, Reg, Offset); 233} 234 235void AArch64TargetWinCOFFStreamer::emitARM64WinCFISaveAnyRegIP(unsigned Reg, 236 int Offset) { 237 emitARM64WinUnwindCode(Win64EH::UOP_SaveAnyRegIP, Reg, Offset); 238} 239 240void AArch64TargetWinCOFFStreamer::emitARM64WinCFISaveAnyRegD(unsigned Reg, 241 int Offset) { 242 emitARM64WinUnwindCode(Win64EH::UOP_SaveAnyRegD, Reg, Offset); 243} 244 245void AArch64TargetWinCOFFStreamer::emitARM64WinCFISaveAnyRegDP(unsigned Reg, 246 int Offset) { 247 emitARM64WinUnwindCode(Win64EH::UOP_SaveAnyRegDP, Reg, Offset); 248} 249 250void AArch64TargetWinCOFFStreamer::emitARM64WinCFISaveAnyRegQ(unsigned Reg, 251 int Offset) { 252 emitARM64WinUnwindCode(Win64EH::UOP_SaveAnyRegQ, Reg, Offset); 253} 254 255void AArch64TargetWinCOFFStreamer::emitARM64WinCFISaveAnyRegQP(unsigned Reg, 256 int Offset) { 257 emitARM64WinUnwindCode(Win64EH::UOP_SaveAnyRegQP, Reg, Offset); 258} 259 260void AArch64TargetWinCOFFStreamer::emitARM64WinCFISaveAnyRegIX(unsigned Reg, 261 int Offset) { 262 emitARM64WinUnwindCode(Win64EH::UOP_SaveAnyRegIX, Reg, Offset); 263} 264 265void AArch64TargetWinCOFFStreamer::emitARM64WinCFISaveAnyRegIPX(unsigned Reg, 266 int Offset) { 267 emitARM64WinUnwindCode(Win64EH::UOP_SaveAnyRegIPX, Reg, Offset); 268} 269 270void AArch64TargetWinCOFFStreamer::emitARM64WinCFISaveAnyRegDX(unsigned Reg, 271 int Offset) { 272 emitARM64WinUnwindCode(Win64EH::UOP_SaveAnyRegDX, Reg, Offset); 273} 274 275void AArch64TargetWinCOFFStreamer::emitARM64WinCFISaveAnyRegDPX(unsigned Reg, 276 int Offset) { 277 emitARM64WinUnwindCode(Win64EH::UOP_SaveAnyRegDPX, Reg, Offset); 278} 279 280void AArch64TargetWinCOFFStreamer::emitARM64WinCFISaveAnyRegQX(unsigned Reg, 281 int Offset) { 282 emitARM64WinUnwindCode(Win64EH::UOP_SaveAnyRegQX, Reg, Offset); 283} 284 285void AArch64TargetWinCOFFStreamer::emitARM64WinCFISaveAnyRegQPX(unsigned Reg, 286 int Offset) { 287 emitARM64WinUnwindCode(Win64EH::UOP_SaveAnyRegQPX, Reg, Offset); 288} 289 290MCWinCOFFStreamer *llvm::createAArch64WinCOFFStreamer( 291 MCContext &Context, std::unique_ptr<MCAsmBackend> MAB, 292 std::unique_ptr<MCObjectWriter> OW, std::unique_ptr<MCCodeEmitter> Emitter, 293 bool RelaxAll, bool IncrementalLinkerCompatible) { 294 auto *S = new AArch64WinCOFFStreamer(Context, std::move(MAB), 295 std::move(Emitter), std::move(OW)); 296 S->getAssembler().setIncrementalLinkerCompatible(IncrementalLinkerCompatible); 297 return S; 298} 299