brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.6 KiB · 060d1f8 Raw
267 lines · cpp
1//===-- ARMWinCOFFStreamer.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 "ARMMCTargetDesc.h"10#include "llvm/MC/MCAsmBackend.h"11#include "llvm/MC/MCAssembler.h"12#include "llvm/MC/MCCodeEmitter.h"13#include "llvm/MC/MCContext.h"14#include "llvm/MC/MCObjectWriter.h"15#include "llvm/MC/MCWin64EH.h"16#include "llvm/MC/MCWinCOFFStreamer.h"17 18using namespace llvm;19 20namespace {21class ARMWinCOFFStreamer : public MCWinCOFFStreamer {22  Win64EH::ARMUnwindEmitter EHStreamer;23 24public:25  ARMWinCOFFStreamer(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 34  void finishImpl() override;35};36 37void ARMWinCOFFStreamer::emitWinEHHandlerData(SMLoc Loc) {38  MCStreamer::emitWinEHHandlerData(Loc);39 40  // We have to emit the unwind info now, because this directive41  // actually switches to the .xdata section!42  EHStreamer.EmitUnwindInfo(*this, getCurrentWinFrameInfo(),43                            /* HandlerData = */ true);44}45 46void ARMWinCOFFStreamer::emitWindowsUnwindTables(WinEH::FrameInfo *Frame) {47  EHStreamer.EmitUnwindInfo(*this, Frame, /* HandlerData = */ false);48}49 50void ARMWinCOFFStreamer::emitWindowsUnwindTables() {51  if (!getNumWinFrameInfos())52    return;53  EHStreamer.Emit(*this);54}55 56void ARMWinCOFFStreamer::finishImpl() {57  emitFrames();58  emitWindowsUnwindTables();59 60  MCWinCOFFStreamer::finishImpl();61}62}63 64MCStreamer *65llvm::createARMWinCOFFStreamer(MCContext &Context,66                               std::unique_ptr<MCAsmBackend> &&MAB,67                               std::unique_ptr<MCObjectWriter> &&OW,68                               std::unique_ptr<MCCodeEmitter> &&Emitter) {69  return new ARMWinCOFFStreamer(Context, std::move(MAB), std::move(Emitter),70                                std::move(OW));71}72 73namespace {74class ARMTargetWinCOFFStreamer : public llvm::ARMTargetStreamer {75public:76  ARMTargetWinCOFFStreamer(llvm::MCStreamer &S) : ARMTargetStreamer(S) {}77 78  ARMWinCOFFStreamer &getStreamer() {79    return static_cast<ARMWinCOFFStreamer &>(Streamer);80  }81  void emitThumbFunc(MCSymbol *Symbol) override;82 83  // The unwind codes on ARM Windows are documented at84  // https://docs.microsoft.com/en-us/cpp/build/arm-exception-handling85  void emitARMWinCFIAllocStack(unsigned Size, bool Wide) override;86  void emitARMWinCFISaveRegMask(unsigned Mask, bool Wide) override;87  void emitARMWinCFISaveSP(unsigned Reg) override;88  void emitARMWinCFISaveFRegs(unsigned First, unsigned Last) override;89  void emitARMWinCFISaveLR(unsigned Offset) override;90  void emitARMWinCFIPrologEnd(bool Fragment) override;91  void emitARMWinCFINop(bool Wide) override;92  void emitARMWinCFIEpilogStart(unsigned Condition) override;93  void emitARMWinCFIEpilogEnd() override;94  void emitARMWinCFICustom(unsigned Opcode) override;95 96private:97  void emitARMWinUnwindCode(unsigned UnwindCode, int Reg, int Offset);98};99 100void ARMTargetWinCOFFStreamer::emitThumbFunc(MCSymbol *Symbol) {101  getStreamer().getAssembler().setIsThumbFunc(Symbol);102}103 104// Helper function to common out unwind code setup for those codes that can105// belong to both prolog and epilog.106void ARMTargetWinCOFFStreamer::emitARMWinUnwindCode(unsigned UnwindCode,107                                                    int Reg, int Offset) {108  auto &S = getStreamer();109  WinEH::FrameInfo *CurFrame = S.EnsureValidWinFrameInfo(SMLoc());110  if (!CurFrame)111    return;112  MCSymbol *Label = S.emitCFILabel();113  auto Inst = WinEH::Instruction(UnwindCode, Label, Reg, Offset);114  if (S.isInEpilogCFI())115    S.getCurrentWinEpilog()->Instructions.push_back(Inst);116  else117    CurFrame->Instructions.push_back(Inst);118}119 120void ARMTargetWinCOFFStreamer::emitARMWinCFIAllocStack(unsigned Size,121                                                       bool Wide) {122  unsigned Op = Win64EH::UOP_AllocSmall;123  if (!Wide) {124    if (Size / 4 > 0xffff)125      Op = Win64EH::UOP_AllocHuge;126    else if (Size / 4 > 0x7f)127      Op = Win64EH::UOP_AllocLarge;128  } else {129    Op = Win64EH::UOP_WideAllocMedium;130    if (Size / 4 > 0xffff)131      Op = Win64EH::UOP_WideAllocHuge;132    else if (Size / 4 > 0x3ff)133      Op = Win64EH::UOP_WideAllocLarge;134  }135  emitARMWinUnwindCode(Op, -1, Size);136}137 138void ARMTargetWinCOFFStreamer::emitARMWinCFISaveRegMask(unsigned Mask,139                                                        bool Wide) {140  assert(Mask != 0);141  int Lr = (Mask & 0x4000) ? 1 : 0;142  Mask &= ~0x4000;143  if (Wide)144    assert((Mask & ~0x1fff) == 0);145  else146    assert((Mask & ~0x00ff) == 0);147  if (Mask && ((Mask + (1 << 4)) & Mask) == 0) {148    if (Wide && (Mask & 0x1000) == 0 && (Mask & 0xff) == 0xf0) {149      // One continuous range from r4 to r8-r11150      for (int I = 11; I >= 8; I--) {151        if (Mask & (1 << I)) {152          emitARMWinUnwindCode(Win64EH::UOP_WideSaveRegsR4R11LR, I, Lr);153          return;154        }155      }156      // If it actually was from r4 to r4-r7, continue below.157    } else if (!Wide) {158      // One continuous range from r4 to r4-r7159      for (int I = 7; I >= 4; I--) {160        if (Mask & (1 << I)) {161          emitARMWinUnwindCode(Win64EH::UOP_SaveRegsR4R7LR, I, Lr);162          return;163        }164      }165      llvm_unreachable("logic error");166    }167  }168  Mask |= Lr << 14;169  if (Wide)170    emitARMWinUnwindCode(Win64EH::UOP_WideSaveRegMask, Mask, 0);171  else172    emitARMWinUnwindCode(Win64EH::UOP_SaveRegMask, Mask, 0);173}174 175void ARMTargetWinCOFFStreamer::emitARMWinCFISaveSP(unsigned Reg) {176  emitARMWinUnwindCode(Win64EH::UOP_SaveSP, Reg, 0);177}178 179void ARMTargetWinCOFFStreamer::emitARMWinCFISaveFRegs(unsigned First,180                                                      unsigned Last) {181  assert(First <= Last);182  assert(First >= 16 || Last < 16);183  assert(First <= 31 && Last <= 31);184  if (First == 8)185    emitARMWinUnwindCode(Win64EH::UOP_SaveFRegD8D15, Last, 0);186  else if (First <= 15)187    emitARMWinUnwindCode(Win64EH::UOP_SaveFRegD0D15, First, Last);188  else189    emitARMWinUnwindCode(Win64EH::UOP_SaveFRegD16D31, First, Last);190}191 192void ARMTargetWinCOFFStreamer::emitARMWinCFISaveLR(unsigned Offset) {193  emitARMWinUnwindCode(Win64EH::UOP_SaveLR, 0, Offset);194}195 196void ARMTargetWinCOFFStreamer::emitARMWinCFINop(bool Wide) {197  if (Wide)198    emitARMWinUnwindCode(Win64EH::UOP_WideNop, -1, 0);199  else200    emitARMWinUnwindCode(Win64EH::UOP_Nop, -1, 0);201}202 203void ARMTargetWinCOFFStreamer::emitARMWinCFIPrologEnd(bool Fragment) {204  auto &S = getStreamer();205  WinEH::FrameInfo *CurFrame = S.EnsureValidWinFrameInfo(SMLoc());206  if (!CurFrame)207    return;208 209  MCSymbol *Label = S.emitCFILabel();210  CurFrame->PrologEnd = Label;211  WinEH::Instruction Inst =212      WinEH::Instruction(Win64EH::UOP_End, /*Label=*/nullptr, -1, 0);213  auto it = CurFrame->Instructions.begin();214  CurFrame->Instructions.insert(it, Inst);215  CurFrame->Fragment = Fragment;216}217 218void ARMTargetWinCOFFStreamer::emitARMWinCFIEpilogStart(unsigned Condition) {219  auto &S = getStreamer();220  WinEH::FrameInfo *CurFrame = S.EnsureValidWinFrameInfo(SMLoc());221  if (!CurFrame)222    return;223 224  S.emitWinCFIBeginEpilogue();225  if (S.isInEpilogCFI()) {226    S.getCurrentWinEpilog()->Condition = Condition;227  }228}229 230void ARMTargetWinCOFFStreamer::emitARMWinCFIEpilogEnd() {231  auto &S = getStreamer();232  WinEH::FrameInfo *CurFrame = S.EnsureValidWinFrameInfo(SMLoc());233  if (!CurFrame)234    return;235 236  if (S.isInEpilogCFI()) {237    std::vector<WinEH::Instruction> &Epilog =238        S.getCurrentWinEpilog()->Instructions;239 240    unsigned UnwindCode = Win64EH::UOP_End;241    if (!Epilog.empty()) {242      WinEH::Instruction EndInstr = Epilog.back();243      if (EndInstr.Operation == Win64EH::UOP_Nop) {244        UnwindCode = Win64EH::UOP_EndNop;245        Epilog.pop_back();246      } else if (EndInstr.Operation == Win64EH::UOP_WideNop) {247        UnwindCode = Win64EH::UOP_WideEndNop;248        Epilog.pop_back();249      }250    }251 252    WinEH::Instruction Inst = WinEH::Instruction(UnwindCode, nullptr, -1, 0);253    S.getCurrentWinEpilog()->Instructions.push_back(Inst);254  }255  S.emitWinCFIEndEpilogue();256}257 258void ARMTargetWinCOFFStreamer::emitARMWinCFICustom(unsigned Opcode) {259  emitARMWinUnwindCode(Win64EH::UOP_Custom, 0, Opcode);260}261 262} // end anonymous namespace263 264MCTargetStreamer *llvm::createARMObjectTargetWinCOFFStreamer(MCStreamer &S) {265  return new ARMTargetWinCOFFStreamer(S);266}267