LLVM API Documentation

MCWin64EH.cpp
Go to the documentation of this file.
00001 //===- lib/MC/MCWin64EH.cpp - MCWin64EH implementation --------------------===//
00002 //
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file is distributed under the University of Illinois Open Source
00006 // License. See LICENSE.TXT for details.
00007 //
00008 //===----------------------------------------------------------------------===//
00009 
00010 #include "llvm/MC/MCWin64EH.h"
00011 #include "llvm/ADT/Twine.h"
00012 #include "llvm/MC/MCContext.h"
00013 #include "llvm/MC/MCExpr.h"
00014 #include "llvm/MC/MCObjectFileInfo.h"
00015 #include "llvm/MC/MCSectionCOFF.h"
00016 #include "llvm/MC/MCStreamer.h"
00017 #include "llvm/MC/MCSymbol.h"
00018 #include "llvm/Support/Win64EH.h"
00019 
00020 namespace llvm {
00021 
00022 // NOTE: All relocations generated here are 4-byte image-relative.
00023 
00024 static uint8_t CountOfUnwindCodes(std::vector<WinEH::Instruction> &Insns) {
00025   uint8_t Count = 0;
00026   for (const auto &I : Insns) {
00027     switch (static_cast<Win64EH::UnwindOpcodes>(I.Operation)) {
00028     case Win64EH::UOP_PushNonVol:
00029     case Win64EH::UOP_AllocSmall:
00030     case Win64EH::UOP_SetFPReg:
00031     case Win64EH::UOP_PushMachFrame:
00032       Count += 1;
00033       break;
00034     case Win64EH::UOP_SaveNonVol:
00035     case Win64EH::UOP_SaveXMM128:
00036       Count += 2;
00037       break;
00038     case Win64EH::UOP_SaveNonVolBig:
00039     case Win64EH::UOP_SaveXMM128Big:
00040       Count += 3;
00041       break;
00042     case Win64EH::UOP_AllocLarge:
00043       Count += (I.Offset > 512 * 1024 - 8) ? 3 : 2;
00044       break;
00045     }
00046   }
00047   return Count;
00048 }
00049 
00050 static void EmitAbsDifference(MCStreamer &Streamer, const MCSymbol *LHS,
00051                               const MCSymbol *RHS) {
00052   MCContext &Context = Streamer.getContext();
00053   const MCExpr *Diff =
00054       MCBinaryExpr::CreateSub(MCSymbolRefExpr::Create(LHS, Context),
00055                               MCSymbolRefExpr::Create(RHS, Context), Context);
00056   Streamer.EmitValue(Diff, 1);
00057 }
00058 
00059 static void EmitUnwindCode(MCStreamer &streamer, const MCSymbol *begin,
00060                            WinEH::Instruction &inst) {
00061   uint8_t b2;
00062   uint16_t w;
00063   b2 = (inst.Operation & 0x0F);
00064   switch (static_cast<Win64EH::UnwindOpcodes>(inst.Operation)) {
00065   case Win64EH::UOP_PushNonVol:
00066     EmitAbsDifference(streamer, inst.Label, begin);
00067     b2 |= (inst.Register & 0x0F) << 4;
00068     streamer.EmitIntValue(b2, 1);
00069     break;
00070   case Win64EH::UOP_AllocLarge:
00071     EmitAbsDifference(streamer, inst.Label, begin);
00072     if (inst.Offset > 512 * 1024 - 8) {
00073       b2 |= 0x10;
00074       streamer.EmitIntValue(b2, 1);
00075       w = inst.Offset & 0xFFF8;
00076       streamer.EmitIntValue(w, 2);
00077       w = inst.Offset >> 16;
00078     } else {
00079       streamer.EmitIntValue(b2, 1);
00080       w = inst.Offset >> 3;
00081     }
00082     streamer.EmitIntValue(w, 2);
00083     break;
00084   case Win64EH::UOP_AllocSmall:
00085     b2 |= (((inst.Offset - 8) >> 3) & 0x0F) << 4;
00086     EmitAbsDifference(streamer, inst.Label, begin);
00087     streamer.EmitIntValue(b2, 1);
00088     break;
00089   case Win64EH::UOP_SetFPReg:
00090     EmitAbsDifference(streamer, inst.Label, begin);
00091     streamer.EmitIntValue(b2, 1);
00092     break;
00093   case Win64EH::UOP_SaveNonVol:
00094   case Win64EH::UOP_SaveXMM128:
00095     b2 |= (inst.Register & 0x0F) << 4;
00096     EmitAbsDifference(streamer, inst.Label, begin);
00097     streamer.EmitIntValue(b2, 1);
00098     w = inst.Offset >> 3;
00099     if (inst.Operation == Win64EH::UOP_SaveXMM128)
00100       w >>= 1;
00101     streamer.EmitIntValue(w, 2);
00102     break;
00103   case Win64EH::UOP_SaveNonVolBig:
00104   case Win64EH::UOP_SaveXMM128Big:
00105     b2 |= (inst.Register & 0x0F) << 4;
00106     EmitAbsDifference(streamer, inst.Label, begin);
00107     streamer.EmitIntValue(b2, 1);
00108     if (inst.Operation == Win64EH::UOP_SaveXMM128Big)
00109       w = inst.Offset & 0xFFF0;
00110     else
00111       w = inst.Offset & 0xFFF8;
00112     streamer.EmitIntValue(w, 2);
00113     w = inst.Offset >> 16;
00114     streamer.EmitIntValue(w, 2);
00115     break;
00116   case Win64EH::UOP_PushMachFrame:
00117     if (inst.Offset == 1)
00118       b2 |= 0x10;
00119     EmitAbsDifference(streamer, inst.Label, begin);
00120     streamer.EmitIntValue(b2, 1);
00121     break;
00122   }
00123 }
00124 
00125 static void EmitSymbolRefWithOfs(MCStreamer &streamer,
00126                                  const MCSymbol *Base,
00127                                  const MCSymbol *Other) {
00128   MCContext &Context = streamer.getContext();
00129   const MCSymbolRefExpr *BaseRef = MCSymbolRefExpr::Create(Base, Context);
00130   const MCSymbolRefExpr *OtherRef = MCSymbolRefExpr::Create(Other, Context);
00131   const MCExpr *Ofs = MCBinaryExpr::CreateSub(OtherRef, BaseRef, Context);
00132   const MCSymbolRefExpr *BaseRefRel = MCSymbolRefExpr::Create(Base,
00133                                               MCSymbolRefExpr::VK_COFF_IMGREL32,
00134                                               Context);
00135   streamer.EmitValue(MCBinaryExpr::CreateAdd(BaseRefRel, Ofs, Context), 4);
00136 }
00137 
00138 static void EmitRuntimeFunction(MCStreamer &streamer,
00139                                 const WinEH::FrameInfo *info) {
00140   MCContext &context = streamer.getContext();
00141 
00142   streamer.EmitValueToAlignment(4);
00143   EmitSymbolRefWithOfs(streamer, info->Function, info->Begin);
00144   EmitSymbolRefWithOfs(streamer, info->Function, info->End);
00145   streamer.EmitValue(MCSymbolRefExpr::Create(info->Symbol,
00146                                              MCSymbolRefExpr::VK_COFF_IMGREL32,
00147                                              context), 4);
00148 }
00149 
00150 static void EmitUnwindInfo(MCStreamer &streamer, WinEH::FrameInfo *info) {
00151   // If this UNWIND_INFO already has a symbol, it's already been emitted.
00152   if (info->Symbol)
00153     return;
00154 
00155   MCContext &context = streamer.getContext();
00156   MCSymbol *Label = context.CreateTempSymbol();
00157 
00158   streamer.EmitValueToAlignment(4);
00159   streamer.EmitLabel(Label);
00160   info->Symbol = Label;
00161 
00162   // Upper 3 bits are the version number (currently 1).
00163   uint8_t flags = 0x01;
00164   if (info->ChainedParent)
00165     flags |= Win64EH::UNW_ChainInfo << 3;
00166   else {
00167     if (info->HandlesUnwind)
00168       flags |= Win64EH::UNW_TerminateHandler << 3;
00169     if (info->HandlesExceptions)
00170       flags |= Win64EH::UNW_ExceptionHandler << 3;
00171   }
00172   streamer.EmitIntValue(flags, 1);
00173 
00174   if (info->PrologEnd)
00175     EmitAbsDifference(streamer, info->PrologEnd, info->Begin);
00176   else
00177     streamer.EmitIntValue(0, 1);
00178 
00179   uint8_t numCodes = CountOfUnwindCodes(info->Instructions);
00180   streamer.EmitIntValue(numCodes, 1);
00181 
00182   uint8_t frame = 0;
00183   if (info->LastFrameInst >= 0) {
00184     WinEH::Instruction &frameInst = info->Instructions[info->LastFrameInst];
00185     assert(frameInst.Operation == Win64EH::UOP_SetFPReg);
00186     frame = (frameInst.Register & 0x0F) | (frameInst.Offset & 0xF0);
00187   }
00188   streamer.EmitIntValue(frame, 1);
00189 
00190   // Emit unwind instructions (in reverse order).
00191   uint8_t numInst = info->Instructions.size();
00192   for (uint8_t c = 0; c < numInst; ++c) {
00193     WinEH::Instruction inst = info->Instructions.back();
00194     info->Instructions.pop_back();
00195     EmitUnwindCode(streamer, info->Begin, inst);
00196   }
00197 
00198   // For alignment purposes, the instruction array will always have an even
00199   // number of entries, with the final entry potentially unused (in which case
00200   // the array will be one longer than indicated by the count of unwind codes
00201   // field).
00202   if (numCodes & 1) {
00203     streamer.EmitIntValue(0, 2);
00204   }
00205 
00206   if (flags & (Win64EH::UNW_ChainInfo << 3))
00207     EmitRuntimeFunction(streamer, info->ChainedParent);
00208   else if (flags &
00209            ((Win64EH::UNW_TerminateHandler|Win64EH::UNW_ExceptionHandler) << 3))
00210     streamer.EmitValue(MCSymbolRefExpr::Create(info->ExceptionHandler,
00211                                               MCSymbolRefExpr::VK_COFF_IMGREL32,
00212                                               context), 4);
00213   else if (numCodes == 0) {
00214     // The minimum size of an UNWIND_INFO struct is 8 bytes. If we're not
00215     // a chained unwind info, if there is no handler, and if there are fewer
00216     // than 2 slots used in the unwind code array, we have to pad to 8 bytes.
00217     streamer.EmitIntValue(0, 4);
00218   }
00219 }
00220 
00221 namespace Win64EH {
00222 void UnwindEmitter::Emit(MCStreamer &Streamer) const {
00223   MCContext &Context = Streamer.getContext();
00224 
00225   // Emit the unwind info structs first.
00226   for (const auto &CFI : Streamer.getWinFrameInfos()) {
00227     const MCSection *XData =
00228         getXDataSection(CFI->Function, Context);
00229     Streamer.SwitchSection(XData);
00230     EmitUnwindInfo(Streamer, CFI);
00231   }
00232 
00233   // Now emit RUNTIME_FUNCTION entries.
00234   for (const auto &CFI : Streamer.getWinFrameInfos()) {
00235     const MCSection *PData =
00236         getPDataSection(CFI->Function, Context);
00237     Streamer.SwitchSection(PData);
00238     EmitRuntimeFunction(Streamer, CFI);
00239   }
00240 }
00241 
00242 void UnwindEmitter::EmitUnwindInfo(MCStreamer &Streamer,
00243                                    WinEH::FrameInfo *info) const {
00244   // Switch sections (the static function above is meant to be called from
00245   // here and from Emit().
00246   MCContext &context = Streamer.getContext();
00247   const MCSection *xdataSect =
00248     getXDataSection(info->Function, context);
00249   Streamer.SwitchSection(xdataSect);
00250 
00251   llvm::EmitUnwindInfo(Streamer, info);
00252 }
00253 }
00254 } // End of namespace llvm
00255