PrologEncoder.h 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. #pragma once
  6. #define IS_UNIBBLE(x) (!(((size_t)x) & ~((size_t)0xF)))
  7. #define TO_UNIBBLE(x) (x & 0xF)
  8. #define IS_UINT16(x) (!(((size_t)x) & ~((size_t)0xFFFF)))
  9. #define TO_UINT16(x) (x & 0xFFFF)
  10. #define IS_UINT32(x) (!(((size_t)x) & ~((size_t)0xFFFFFFFF)))
  11. #define TO_UINT32(x) (x & 0xFFFFFFFF)
  12. enum UnwindOp : unsigned __int8 {
  13. UWOP_IGNORE = (unsigned __int8)-1,
  14. UWOP_PUSH_NONVOL = 0,
  15. UWOP_ALLOC_LARGE = 1,
  16. UWOP_ALLOC_SMALL = 2,
  17. UWOP_SAVE_XMM128 = 8
  18. };
  19. #ifdef _WIN32
  20. // ----------------------------------------------------------------------------
  21. // _WIN32 x64 unwind uses PDATA
  22. // ----------------------------------------------------------------------------
  23. class PrologEncoder
  24. {
  25. private:
  26. #pragma pack(push, 1)
  27. struct UNWIND_CODE
  28. {
  29. /*
  30. * ntdll!UNWIND_CODE
  31. * +0x000 CodeOffset : UChar
  32. * +0x001 UnwindOp : Pos 0, 4 Bits
  33. * +0x001 OpInfo : Pos 4, 4 Bits
  34. * +0x000 FrameOffset : Uint2B
  35. */
  36. union {
  37. struct {
  38. unsigned __int8 CodeOffset;
  39. unsigned __int8 UnwindOp : 4;
  40. unsigned __int8 OpInfo : 4;
  41. };
  42. unsigned __int16 FrameOffset;
  43. };
  44. void SetOffset(unsigned __int8 offset)
  45. {
  46. CodeOffset = offset;
  47. }
  48. void SetOp(unsigned __int8 op)
  49. {
  50. Assert(IS_UNIBBLE(op));
  51. UnwindOp = TO_UNIBBLE(op);
  52. }
  53. void SetOpInfo(unsigned __int8 info)
  54. {
  55. Assert(IS_UNIBBLE(info));
  56. OpInfo = TO_UNIBBLE(info);
  57. }
  58. };
  59. struct UNWIND_INFO
  60. {
  61. /*
  62. * ntdll!UNWIND_INFO
  63. * +0x000 Version : Pos 0, 3 Bits
  64. * +0x000 Flags : Pos 3, 5 Bits
  65. * +0x001 SizeOfProlog : UChar
  66. * +0x002 CountOfCodes : UChar
  67. * +0x003 FrameRegister : Pos 0, 4 Bits
  68. * +0x003 FrameOffset : Pos 4, 4 Bits
  69. * +0x004 UnwindCode : [1] _UNWIND_CODE
  70. */
  71. unsigned __int8 Version : 3;
  72. unsigned __int8 Flags : 5;
  73. unsigned __int8 SizeOfProlog;
  74. unsigned __int8 CountOfCodes;
  75. unsigned __int8 FrameRegister : 4;
  76. unsigned __int8 FrameOffset : 4;
  77. UNWIND_CODE unwindCodes[0];
  78. };
  79. struct UnwindCode : public UNWIND_CODE
  80. {
  81. private:
  82. union {
  83. unsigned __int16 uint16Val;
  84. unsigned __int32 uint32Val;
  85. } u;
  86. public:
  87. void SetValue(unsigned __int16 value)
  88. {
  89. Assert(UnwindOp && (UnwindOp == UWOP_ALLOC_LARGE));
  90. u.uint16Val = value;
  91. }
  92. void SetValue(unsigned __int32 value)
  93. {
  94. Assert(UnwindOp && (UnwindOp == UWOP_ALLOC_LARGE));
  95. // insert assert to check that value actually warrants the use of
  96. // 32 bits to encoder.
  97. u.uint32Val = value;
  98. }
  99. };
  100. struct PData
  101. {
  102. RUNTIME_FUNCTION runtimeFunction;
  103. UNWIND_INFO unwindInfo;
  104. };
  105. #pragma pack(pop)
  106. static const unsigned __int8 MaxRequiredUnwindCodeNodeCount = 34;
  107. static const size_t MaxPDataSize = sizeof(PData) + (sizeof(UNWIND_CODE) * MaxRequiredUnwindCodeNodeCount);
  108. union
  109. {
  110. PData pdata;
  111. BYTE pdataBuffer[MaxPDataSize];
  112. };
  113. unsigned __int8 currentUnwindCodeNodeIndex;
  114. unsigned __int8 requiredUnwindCodeNodeCount;
  115. unsigned __int8 currentInstrOffset;
  116. public:
  117. PrologEncoder()
  118. : requiredUnwindCodeNodeCount(0),
  119. currentUnwindCodeNodeIndex(0),
  120. currentInstrOffset(0)
  121. {
  122. }
  123. void RecordNonVolRegSave();
  124. void RecordXmmRegSave();
  125. void RecordAlloca(size_t size);
  126. void EncodeInstr(IR::Instr *instr, unsigned __int8 size);
  127. void EncodeSmallProlog(uint8 prologSize, size_t size);
  128. //
  129. // Pre-Win8 PDATA registration.
  130. //
  131. DWORD SizeOfPData();
  132. BYTE *Finalize(BYTE *functionStart,
  133. DWORD codeSize,
  134. BYTE *pdataBuffer);
  135. //
  136. // Win8 PDATA registration.
  137. //
  138. void Begin(size_t prologStartOffset) {} // No op on _WIN32
  139. void End() {} // No op on _WIN32
  140. DWORD SizeOfUnwindInfo();
  141. BYTE *GetUnwindInfo();
  142. void FinalizeUnwindInfo(BYTE *functionStart, DWORD codeSize);
  143. private:
  144. UnwindCode *GetUnwindCode(unsigned __int8 nodeCount);
  145. };
  146. #else // !_WIN32
  147. // ----------------------------------------------------------------------------
  148. // !_WIN32 x64 unwind uses .eh_frame
  149. // ----------------------------------------------------------------------------
  150. #include "EhFrame.h"
  151. class PrologEncoder
  152. {
  153. public:
  154. static const int SMALL_EHFRAME_SIZE = 0x40;
  155. static const int JIT_EHFRAME_SIZE = 0x80;
  156. private:
  157. EhFrame ehFrame;
  158. BYTE buffer[JIT_EHFRAME_SIZE];
  159. size_t cfiInstrOffset; // last cfi emit instr offset
  160. size_t currentInstrOffset; // current instr offset
  161. // currentInstrOffset - cfiInstrOffset == advance
  162. unsigned cfaWordOffset;
  163. public:
  164. PrologEncoder()
  165. :ehFrame(buffer, JIT_EHFRAME_SIZE),
  166. cfiInstrOffset(0), currentInstrOffset(0), cfaWordOffset(1)
  167. {}
  168. void RecordNonVolRegSave() {}
  169. void RecordXmmRegSave() {}
  170. void RecordAlloca(size_t size) {}
  171. void EncodeInstr(IR::Instr *instr, uint8 size);
  172. void EncodeSmallProlog(uint8 prologSize, size_t size);
  173. DWORD SizeOfPData();
  174. BYTE *Finalize(BYTE *functionStart, DWORD codeSize, BYTE *pdataBuffer);
  175. void Begin(size_t prologStartOffset);
  176. void End();
  177. DWORD SizeOfUnwindInfo() { return SizeOfPData(); }
  178. BYTE *GetUnwindInfo() { return ehFrame.Buffer(); }
  179. void FinalizeUnwindInfo(BYTE *functionStart, DWORD codeSize);
  180. };
  181. #endif // !_WIN32