PrologEncoder.h 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  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. class PrologEncoder
  20. {
  21. private:
  22. #pragma pack(push, 1)
  23. struct UNWIND_CODE
  24. {
  25. /*
  26. * ntdll!UNWIND_CODE
  27. * +0x000 CodeOffset : UChar
  28. * +0x001 UnwindOp : Pos 0, 4 Bits
  29. * +0x001 OpInfo : Pos 4, 4 Bits
  30. * +0x000 FrameOffset : Uint2B
  31. */
  32. union {
  33. struct {
  34. unsigned __int8 CodeOffset;
  35. unsigned __int8 UnwindOp : 4;
  36. unsigned __int8 OpInfo : 4;
  37. };
  38. unsigned __int16 FrameOffset;
  39. };
  40. void SetOffset(unsigned __int8 offset)
  41. {
  42. CodeOffset = offset;
  43. }
  44. void SetOp(unsigned __int8 op)
  45. {
  46. Assert(IS_UNIBBLE(op));
  47. UnwindOp = TO_UNIBBLE(op);
  48. }
  49. void SetOpInfo(unsigned __int8 info)
  50. {
  51. Assert(IS_UNIBBLE(info));
  52. OpInfo = TO_UNIBBLE(info);
  53. }
  54. };
  55. struct UNWIND_INFO
  56. {
  57. /*
  58. * ntdll!UNWIND_INFO
  59. * +0x000 Version : Pos 0, 3 Bits
  60. * +0x000 Flags : Pos 3, 5 Bits
  61. * +0x001 SizeOfProlog : UChar
  62. * +0x002 CountOfCodes : UChar
  63. * +0x003 FrameRegister : Pos 0, 4 Bits
  64. * +0x003 FrameOffset : Pos 4, 4 Bits
  65. * +0x004 UnwindCode : [1] _UNWIND_CODE
  66. */
  67. unsigned __int8 Version : 3;
  68. unsigned __int8 Flags : 5;
  69. unsigned __int8 SizeOfProlog;
  70. unsigned __int8 CountOfCodes;
  71. unsigned __int8 FrameRegister : 4;
  72. unsigned __int8 FrameOffset : 4;
  73. UNWIND_CODE unwindCodes[0];
  74. };
  75. struct UnwindCode : public UNWIND_CODE
  76. {
  77. private:
  78. union {
  79. unsigned __int16 uint16Val;
  80. unsigned __int32 uint32Val;
  81. } u;
  82. public:
  83. void SetValue(unsigned __int16 value)
  84. {
  85. Assert(UnwindOp && (UnwindOp == UWOP_ALLOC_LARGE));
  86. u.uint16Val = value;
  87. }
  88. void SetValue(unsigned __int32 value)
  89. {
  90. Assert(UnwindOp && (UnwindOp == UWOP_ALLOC_LARGE));
  91. // insert assert to check that value actually warrants the use of
  92. // 32 bits to encoder.
  93. u.uint32Val = value;
  94. }
  95. };
  96. struct PData
  97. {
  98. RUNTIME_FUNCTION runtimeFunction;
  99. UNWIND_INFO unwindInfo;
  100. };
  101. #pragma pack(pop)
  102. PData *pdata;
  103. ArenaAllocator *alloc;
  104. unsigned __int8 currentUnwindCodeNodeIndex;
  105. unsigned __int8 requiredUnwindCodeNodeCount;
  106. unsigned __int8 currentInstrOffset;
  107. public:
  108. PrologEncoder(ArenaAllocator *alloc)
  109. : alloc(alloc),
  110. pdata(nullptr),
  111. requiredUnwindCodeNodeCount(0),
  112. currentUnwindCodeNodeIndex(0),
  113. currentInstrOffset(0)
  114. {
  115. }
  116. void RecordNonVolRegSave();
  117. void RecordXmmRegSave();
  118. void RecordAlloca(size_t size);
  119. void EncodeInstr(IR::Instr *instr, unsigned __int8 size);
  120. void EncodeSmallProlog(uint8 prologSize, size_t size);
  121. //
  122. // Pre-Win8 PDATA registration.
  123. //
  124. DWORD SizeOfPData();
  125. void SetPDataPtr(void *pdata);
  126. BYTE *Finalize(BYTE *functionStart,
  127. DWORD codeSize,
  128. BYTE *pdataBuffer);
  129. //
  130. // Win8 PDATA registration.
  131. //
  132. DWORD SizeOfUnwindInfo();
  133. BYTE *GetUnwindInfo();
  134. void FinalizeUnwindInfo();
  135. private:
  136. UnwindCode *GetUnwindCode(unsigned __int8 nodeCount);
  137. };