MCWin64EH.cpp 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. //===- lib/MC/MCWin64EH.cpp - MCWin64EH implementation --------------------===//
  2. //
  3. // The LLVM Compiler Infrastructure
  4. //
  5. // This file is distributed under the University of Illinois Open Source
  6. // License. See LICENSE.TXT for details.
  7. //
  8. //===----------------------------------------------------------------------===//
  9. #include "llvm/MC/MCWin64EH.h"
  10. #include "llvm/ADT/Twine.h"
  11. #include "llvm/MC/MCContext.h"
  12. #include "llvm/MC/MCExpr.h"
  13. #include "llvm/MC/MCObjectFileInfo.h"
  14. #include "llvm/MC/MCSectionCOFF.h"
  15. #include "llvm/MC/MCStreamer.h"
  16. #include "llvm/MC/MCSymbol.h"
  17. #include "llvm/Support/Win64EH.h"
  18. namespace llvm {
  19. // NOTE: All relocations generated here are 4-byte image-relative.
  20. static uint8_t CountOfUnwindCodes(std::vector<WinEH::Instruction> &Insns) {
  21. uint8_t Count = 0;
  22. for (const auto &I : Insns) {
  23. switch (static_cast<Win64EH::UnwindOpcodes>(I.Operation)) {
  24. case Win64EH::UOP_PushNonVol:
  25. case Win64EH::UOP_AllocSmall:
  26. case Win64EH::UOP_SetFPReg:
  27. case Win64EH::UOP_PushMachFrame:
  28. Count += 1;
  29. break;
  30. case Win64EH::UOP_SaveNonVol:
  31. case Win64EH::UOP_SaveXMM128:
  32. Count += 2;
  33. break;
  34. case Win64EH::UOP_SaveNonVolBig:
  35. case Win64EH::UOP_SaveXMM128Big:
  36. Count += 3;
  37. break;
  38. case Win64EH::UOP_AllocLarge:
  39. Count += (I.Offset > 512 * 1024 - 8) ? 3 : 2;
  40. break;
  41. }
  42. }
  43. return Count;
  44. }
  45. static void EmitAbsDifference(MCStreamer &Streamer, const MCSymbol *LHS,
  46. const MCSymbol *RHS) {
  47. MCContext &Context = Streamer.getContext();
  48. const MCExpr *Diff =
  49. MCBinaryExpr::createSub(MCSymbolRefExpr::create(LHS, Context),
  50. MCSymbolRefExpr::create(RHS, Context), Context);
  51. Streamer.EmitValue(Diff, 1);
  52. }
  53. static void EmitUnwindCode(MCStreamer &streamer, const MCSymbol *begin,
  54. WinEH::Instruction &inst) {
  55. uint8_t b2;
  56. uint16_t w;
  57. b2 = (inst.Operation & 0x0F);
  58. switch (static_cast<Win64EH::UnwindOpcodes>(inst.Operation)) {
  59. case Win64EH::UOP_PushNonVol:
  60. EmitAbsDifference(streamer, inst.Label, begin);
  61. b2 |= (inst.Register & 0x0F) << 4;
  62. streamer.EmitIntValue(b2, 1);
  63. break;
  64. case Win64EH::UOP_AllocLarge:
  65. EmitAbsDifference(streamer, inst.Label, begin);
  66. if (inst.Offset > 512 * 1024 - 8) {
  67. b2 |= 0x10;
  68. streamer.EmitIntValue(b2, 1);
  69. w = inst.Offset & 0xFFF8;
  70. streamer.EmitIntValue(w, 2);
  71. w = inst.Offset >> 16;
  72. } else {
  73. streamer.EmitIntValue(b2, 1);
  74. w = inst.Offset >> 3;
  75. }
  76. streamer.EmitIntValue(w, 2);
  77. break;
  78. case Win64EH::UOP_AllocSmall:
  79. b2 |= (((inst.Offset - 8) >> 3) & 0x0F) << 4;
  80. EmitAbsDifference(streamer, inst.Label, begin);
  81. streamer.EmitIntValue(b2, 1);
  82. break;
  83. case Win64EH::UOP_SetFPReg:
  84. EmitAbsDifference(streamer, inst.Label, begin);
  85. streamer.EmitIntValue(b2, 1);
  86. break;
  87. case Win64EH::UOP_SaveNonVol:
  88. case Win64EH::UOP_SaveXMM128:
  89. b2 |= (inst.Register & 0x0F) << 4;
  90. EmitAbsDifference(streamer, inst.Label, begin);
  91. streamer.EmitIntValue(b2, 1);
  92. w = inst.Offset >> 3;
  93. if (inst.Operation == Win64EH::UOP_SaveXMM128)
  94. w >>= 1;
  95. streamer.EmitIntValue(w, 2);
  96. break;
  97. case Win64EH::UOP_SaveNonVolBig:
  98. case Win64EH::UOP_SaveXMM128Big:
  99. b2 |= (inst.Register & 0x0F) << 4;
  100. EmitAbsDifference(streamer, inst.Label, begin);
  101. streamer.EmitIntValue(b2, 1);
  102. if (inst.Operation == Win64EH::UOP_SaveXMM128Big)
  103. w = inst.Offset & 0xFFF0;
  104. else
  105. w = inst.Offset & 0xFFF8;
  106. streamer.EmitIntValue(w, 2);
  107. w = inst.Offset >> 16;
  108. streamer.EmitIntValue(w, 2);
  109. break;
  110. case Win64EH::UOP_PushMachFrame:
  111. if (inst.Offset == 1)
  112. b2 |= 0x10;
  113. EmitAbsDifference(streamer, inst.Label, begin);
  114. streamer.EmitIntValue(b2, 1);
  115. break;
  116. }
  117. }
  118. static void EmitSymbolRefWithOfs(MCStreamer &streamer,
  119. const MCSymbol *Base,
  120. const MCSymbol *Other) {
  121. MCContext &Context = streamer.getContext();
  122. const MCSymbolRefExpr *BaseRef = MCSymbolRefExpr::create(Base, Context);
  123. const MCSymbolRefExpr *OtherRef = MCSymbolRefExpr::create(Other, Context);
  124. const MCExpr *Ofs = MCBinaryExpr::createSub(OtherRef, BaseRef, Context);
  125. const MCSymbolRefExpr *BaseRefRel = MCSymbolRefExpr::create(Base,
  126. MCSymbolRefExpr::VK_COFF_IMGREL32,
  127. Context);
  128. streamer.EmitValue(MCBinaryExpr::createAdd(BaseRefRel, Ofs, Context), 4);
  129. }
  130. static void EmitRuntimeFunction(MCStreamer &streamer,
  131. const WinEH::FrameInfo *info) {
  132. MCContext &context = streamer.getContext();
  133. streamer.EmitValueToAlignment(4);
  134. EmitSymbolRefWithOfs(streamer, info->Function, info->Begin);
  135. EmitSymbolRefWithOfs(streamer, info->Function, info->End);
  136. streamer.EmitValue(MCSymbolRefExpr::create(info->Symbol,
  137. MCSymbolRefExpr::VK_COFF_IMGREL32,
  138. context), 4);
  139. }
  140. static void EmitUnwindInfo(MCStreamer &streamer, WinEH::FrameInfo *info) {
  141. // If this UNWIND_INFO already has a symbol, it's already been emitted.
  142. if (info->Symbol)
  143. return;
  144. MCContext &context = streamer.getContext();
  145. MCSymbol *Label = context.createTempSymbol();
  146. streamer.EmitValueToAlignment(4);
  147. streamer.EmitLabel(Label);
  148. info->Symbol = Label;
  149. // Upper 3 bits are the version number (currently 1).
  150. uint8_t flags = 0x01;
  151. if (info->ChainedParent)
  152. flags |= Win64EH::UNW_ChainInfo << 3;
  153. else {
  154. if (info->HandlesUnwind)
  155. flags |= Win64EH::UNW_TerminateHandler << 3;
  156. if (info->HandlesExceptions)
  157. flags |= Win64EH::UNW_ExceptionHandler << 3;
  158. }
  159. streamer.EmitIntValue(flags, 1);
  160. if (info->PrologEnd)
  161. EmitAbsDifference(streamer, info->PrologEnd, info->Begin);
  162. else
  163. streamer.EmitIntValue(0, 1);
  164. uint8_t numCodes = CountOfUnwindCodes(info->Instructions);
  165. streamer.EmitIntValue(numCodes, 1);
  166. uint8_t frame = 0;
  167. if (info->LastFrameInst >= 0) {
  168. WinEH::Instruction &frameInst = info->Instructions[info->LastFrameInst];
  169. assert(frameInst.Operation == Win64EH::UOP_SetFPReg);
  170. frame = (frameInst.Register & 0x0F) | (frameInst.Offset & 0xF0);
  171. }
  172. streamer.EmitIntValue(frame, 1);
  173. // Emit unwind instructions (in reverse order).
  174. uint8_t numInst = info->Instructions.size();
  175. for (uint8_t c = 0; c < numInst; ++c) {
  176. WinEH::Instruction inst = info->Instructions.back();
  177. info->Instructions.pop_back();
  178. EmitUnwindCode(streamer, info->Begin, inst);
  179. }
  180. // For alignment purposes, the instruction array will always have an even
  181. // number of entries, with the final entry potentially unused (in which case
  182. // the array will be one longer than indicated by the count of unwind codes
  183. // field).
  184. if (numCodes & 1) {
  185. streamer.EmitIntValue(0, 2);
  186. }
  187. if (flags & (Win64EH::UNW_ChainInfo << 3))
  188. EmitRuntimeFunction(streamer, info->ChainedParent);
  189. else if (flags &
  190. ((Win64EH::UNW_TerminateHandler|Win64EH::UNW_ExceptionHandler) << 3))
  191. streamer.EmitValue(MCSymbolRefExpr::create(info->ExceptionHandler,
  192. MCSymbolRefExpr::VK_COFF_IMGREL32,
  193. context), 4);
  194. else if (numCodes == 0) {
  195. // The minimum size of an UNWIND_INFO struct is 8 bytes. If we're not
  196. // a chained unwind info, if there is no handler, and if there are fewer
  197. // than 2 slots used in the unwind code array, we have to pad to 8 bytes.
  198. streamer.EmitIntValue(0, 4);
  199. }
  200. }
  201. namespace Win64EH {
  202. void UnwindEmitter::Emit(MCStreamer &Streamer) const {
  203. MCContext &Context = Streamer.getContext();
  204. // Emit the unwind info structs first.
  205. for (const auto &CFI : Streamer.getWinFrameInfos()) {
  206. MCSection *XData = getXDataSection(CFI->Function, Context);
  207. Streamer.SwitchSection(XData);
  208. EmitUnwindInfo(Streamer, CFI);
  209. }
  210. // Now emit RUNTIME_FUNCTION entries.
  211. for (const auto &CFI : Streamer.getWinFrameInfos()) {
  212. MCSection *PData = getPDataSection(CFI->Function, Context);
  213. Streamer.SwitchSection(PData);
  214. EmitRuntimeFunction(Streamer, CFI);
  215. }
  216. }
  217. void UnwindEmitter::EmitUnwindInfo(MCStreamer &Streamer,
  218. WinEH::FrameInfo *info) const {
  219. // Switch sections (the static function above is meant to be called from
  220. // here and from Emit().
  221. MCContext &context = Streamer.getContext();
  222. MCSection *xdataSect = getXDataSection(info->Function, context);
  223. Streamer.SwitchSection(xdataSect);
  224. llvm::EmitUnwindInfo(Streamer, info);
  225. }
  226. }
  227. } // End of namespace llvm