309 lines · cpp
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-exception6//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 directive40 // 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();57 emitWindowsUnwindTables();58 59 MCWinCOFFStreamer::finishImpl();60}61} // end anonymous namespace62 63// Helper function to common out unwind code setup for those codes that can64// belong to both prolog and epilog.65// There are three types of Windows ARM64 SEH codes. They can66// 1) take no operands: SEH_Nop, SEH_PrologEnd, SEH_EpilogStart, SEH_EpilogEnd67// 2) take an offset: SEH_StackAlloc, SEH_SaveFPLR, SEH_SaveFPLR_X68// 3) take a register and an offset/size: all others69void 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 (S.isInEpilogCFI())77 S.getCurrentWinEpilog()->Instructions.push_back(Inst);78 else79 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 or170// 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 getStreamer().emitWinCFIBeginEpilogue();187}188 189void AArch64TargetWinCOFFStreamer::emitARM64WinCFIEpilogEnd() {190 auto &S = getStreamer();191 WinEH::FrameInfo *CurFrame = S.EnsureValidWinFrameInfo(SMLoc());192 if (!CurFrame)193 return;194 195 if (S.isInEpilogCFI()) {196 WinEH::Instruction Inst =197 WinEH::Instruction(Win64EH::UOP_End, /*Label=*/nullptr, -1, 0);198 S.getCurrentWinEpilog()->Instructions.push_back(Inst);199 }200 S.emitWinCFIEndEpilogue();201}202 203void AArch64TargetWinCOFFStreamer::emitARM64WinCFITrapFrame() {204 emitARM64WinUnwindCode(Win64EH::UOP_TrapFrame, -1, 0);205}206 207void AArch64TargetWinCOFFStreamer::emitARM64WinCFIMachineFrame() {208 emitARM64WinUnwindCode(Win64EH::UOP_PushMachFrame, -1, 0);209}210 211void AArch64TargetWinCOFFStreamer::emitARM64WinCFIContext() {212 emitARM64WinUnwindCode(Win64EH::UOP_Context, -1, 0);213}214 215void AArch64TargetWinCOFFStreamer::emitARM64WinCFIECContext() {216 emitARM64WinUnwindCode(Win64EH::UOP_ECContext, -1, 0);217}218 219void AArch64TargetWinCOFFStreamer::emitARM64WinCFIClearUnwoundToCall() {220 emitARM64WinUnwindCode(Win64EH::UOP_ClearUnwoundToCall, -1, 0);221}222 223void AArch64TargetWinCOFFStreamer::emitARM64WinCFIPACSignLR() {224 emitARM64WinUnwindCode(Win64EH::UOP_PACSignLR, -1, 0);225}226 227void AArch64TargetWinCOFFStreamer::emitARM64WinCFISaveAnyRegI(unsigned Reg,228 int Offset) {229 emitARM64WinUnwindCode(Win64EH::UOP_SaveAnyRegI, Reg, Offset);230}231 232void AArch64TargetWinCOFFStreamer::emitARM64WinCFISaveAnyRegIP(unsigned Reg,233 int Offset) {234 emitARM64WinUnwindCode(Win64EH::UOP_SaveAnyRegIP, Reg, Offset);235}236 237void AArch64TargetWinCOFFStreamer::emitARM64WinCFISaveAnyRegD(unsigned Reg,238 int Offset) {239 emitARM64WinUnwindCode(Win64EH::UOP_SaveAnyRegD, Reg, Offset);240}241 242void AArch64TargetWinCOFFStreamer::emitARM64WinCFISaveAnyRegDP(unsigned Reg,243 int Offset) {244 emitARM64WinUnwindCode(Win64EH::UOP_SaveAnyRegDP, Reg, Offset);245}246 247void AArch64TargetWinCOFFStreamer::emitARM64WinCFISaveAnyRegQ(unsigned Reg,248 int Offset) {249 emitARM64WinUnwindCode(Win64EH::UOP_SaveAnyRegQ, Reg, Offset);250}251 252void AArch64TargetWinCOFFStreamer::emitARM64WinCFISaveAnyRegQP(unsigned Reg,253 int Offset) {254 emitARM64WinUnwindCode(Win64EH::UOP_SaveAnyRegQP, Reg, Offset);255}256 257void AArch64TargetWinCOFFStreamer::emitARM64WinCFISaveAnyRegIX(unsigned Reg,258 int Offset) {259 emitARM64WinUnwindCode(Win64EH::UOP_SaveAnyRegIX, Reg, Offset);260}261 262void AArch64TargetWinCOFFStreamer::emitARM64WinCFISaveAnyRegIPX(unsigned Reg,263 int Offset) {264 emitARM64WinUnwindCode(Win64EH::UOP_SaveAnyRegIPX, Reg, Offset);265}266 267void AArch64TargetWinCOFFStreamer::emitARM64WinCFISaveAnyRegDX(unsigned Reg,268 int Offset) {269 emitARM64WinUnwindCode(Win64EH::UOP_SaveAnyRegDX, Reg, Offset);270}271 272void AArch64TargetWinCOFFStreamer::emitARM64WinCFISaveAnyRegDPX(unsigned Reg,273 int Offset) {274 emitARM64WinUnwindCode(Win64EH::UOP_SaveAnyRegDPX, Reg, Offset);275}276 277void AArch64TargetWinCOFFStreamer::emitARM64WinCFISaveAnyRegQX(unsigned Reg,278 int Offset) {279 emitARM64WinUnwindCode(Win64EH::UOP_SaveAnyRegQX, Reg, Offset);280}281 282void AArch64TargetWinCOFFStreamer::emitARM64WinCFISaveAnyRegQPX(unsigned Reg,283 int Offset) {284 emitARM64WinUnwindCode(Win64EH::UOP_SaveAnyRegQPX, Reg, Offset);285}286 287void AArch64TargetWinCOFFStreamer::emitARM64WinCFIAllocZ(int Offset) {288 emitARM64WinUnwindCode(Win64EH::UOP_AllocZ, 0, Offset);289}290 291void AArch64TargetWinCOFFStreamer::emitARM64WinCFISaveZReg(unsigned Reg,292 int Offset) {293 emitARM64WinUnwindCode(Win64EH::UOP_SaveZReg, Reg, Offset);294}295 296void AArch64TargetWinCOFFStreamer::emitARM64WinCFISavePReg(unsigned Reg,297 int Offset) {298 emitARM64WinUnwindCode(Win64EH::UOP_SavePReg, Reg, Offset);299}300 301MCStreamer *302llvm::createAArch64WinCOFFStreamer(MCContext &Context,303 std::unique_ptr<MCAsmBackend> &&MAB,304 std::unique_ptr<MCObjectWriter> &&OW,305 std::unique_ptr<MCCodeEmitter> &&Emitter) {306 return new AArch64WinCOFFStreamer(Context, std::move(MAB), std::move(Emitter),307 std::move(OW));308}309