PrologEncoder.cpp 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  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. #include "Backend.h"
  6. #include "PrologEncoderMD.h"
  7. #ifdef _WIN32
  8. // ----------------------------------------------------------------------------
  9. // _WIN32 x64 unwind uses PDATA
  10. // ----------------------------------------------------------------------------
  11. void PrologEncoder::RecordNonVolRegSave()
  12. {
  13. requiredUnwindCodeNodeCount++;
  14. }
  15. void PrologEncoder::RecordXmmRegSave()
  16. {
  17. requiredUnwindCodeNodeCount += 2;
  18. }
  19. void PrologEncoder::RecordAlloca(size_t size)
  20. {
  21. Assert(size);
  22. requiredUnwindCodeNodeCount += PrologEncoderMD::GetRequiredNodeCountForAlloca(size);
  23. }
  24. DWORD PrologEncoder::SizeOfPData()
  25. {
  26. return sizeof(PData) + (sizeof(UNWIND_CODE) * requiredUnwindCodeNodeCount);
  27. }
  28. void PrologEncoder::EncodeSmallProlog(uint8 prologSize, size_t allocaSize)
  29. {
  30. Assert(allocaSize <= 128);
  31. Assert(requiredUnwindCodeNodeCount == 0);
  32. // Increment requiredUnwindCodeNodeCount to ensure we do the Alloc for the correct size
  33. currentUnwindCodeNodeIndex = ++requiredUnwindCodeNodeCount;
  34. currentInstrOffset = prologSize;
  35. UnwindCode* unwindCode = GetUnwindCode(1);
  36. size_t slots = (allocaSize - MachPtr) / MachPtr;
  37. uint8 unwindCodeOpInfo = TO_UNIBBLE(slots);
  38. unwindCode->SetOffset(prologSize);
  39. unwindCode->SetOp(TO_UNIBBLE(UWOP_ALLOC_SMALL));
  40. unwindCode->SetOpInfo(unwindCodeOpInfo);
  41. }
  42. void PrologEncoder::EncodeInstr(IR::Instr *instr, unsigned __int8 size)
  43. {
  44. Assert(instr);
  45. Assert(size);
  46. UnwindCode *unwindCode = nullptr;
  47. unsigned __int8 unwindCodeOp = PrologEncoderMD::GetOp(instr);
  48. unsigned __int8 unwindCodeOpInfo = 0;
  49. unsigned __int16 uint16Val = 0;
  50. unsigned __int32 uint32Val = 0;
  51. if (!currentInstrOffset)
  52. currentUnwindCodeNodeIndex = requiredUnwindCodeNodeCount;
  53. Assert((currentInstrOffset + size) > currentInstrOffset);
  54. currentInstrOffset += size;
  55. switch (unwindCodeOp)
  56. {
  57. case UWOP_PUSH_NONVOL:
  58. {
  59. unwindCode = GetUnwindCode(1);
  60. unwindCodeOpInfo = PrologEncoderMD::GetNonVolRegToSave(instr);
  61. break;
  62. }
  63. case UWOP_SAVE_XMM128:
  64. {
  65. unwindCode = GetUnwindCode(2);
  66. unwindCodeOpInfo = PrologEncoderMD::GetXmmRegToSave(instr, &uint16Val);
  67. *((unsigned __int16 *)&((UNWIND_CODE *)unwindCode)[1]) = uint16Val;
  68. break;
  69. }
  70. case UWOP_ALLOC_SMALL:
  71. {
  72. unwindCode = GetUnwindCode(1);
  73. size_t allocaSize = PrologEncoderMD::GetAllocaSize(instr);
  74. Assert((allocaSize - MachPtr) % MachPtr == 0);
  75. size_t slots = (allocaSize - MachPtr) / MachPtr;
  76. Assert(IS_UNIBBLE(slots));
  77. unwindCodeOpInfo = TO_UNIBBLE(slots);
  78. break;
  79. }
  80. case UWOP_ALLOC_LARGE:
  81. {
  82. size_t allocaSize = PrologEncoderMD::GetAllocaSize(instr);
  83. Assert(allocaSize > 0x80);
  84. Assert(allocaSize % 8 == 0);
  85. Assert(IS_UNIBBLE(unwindCodeOp));
  86. size_t slots = allocaSize / MachPtr;
  87. if (allocaSize > 0x7FF8)
  88. {
  89. unwindCode = GetUnwindCode(3);
  90. uint32Val = TO_UINT32(allocaSize);
  91. unwindCodeOpInfo = 1;
  92. unwindCode->SetOp(TO_UNIBBLE(unwindCodeOp));
  93. *((unsigned __int32 *)&((UNWIND_CODE *)unwindCode)[1]) = uint32Val;
  94. }
  95. else
  96. {
  97. unwindCode = GetUnwindCode(2);
  98. uint16Val = TO_UINT16(slots);
  99. unwindCodeOpInfo = 0;
  100. unwindCode->SetOp(TO_UNIBBLE(unwindCodeOp));
  101. *((unsigned __int16 *)&((UNWIND_CODE *)unwindCode)[1]) = uint16Val;
  102. }
  103. break;
  104. }
  105. case UWOP_IGNORE:
  106. {
  107. return;
  108. }
  109. default:
  110. {
  111. AssertMsg(false, "PrologEncoderMD returned unsupported UnwindCodeOp.");
  112. }
  113. }
  114. Assert(unwindCode);
  115. unwindCode->SetOffset(currentInstrOffset);
  116. Assert(IS_UNIBBLE(unwindCodeOp));
  117. unwindCode->SetOp(TO_UNIBBLE(unwindCodeOp));
  118. Assert(IS_UNIBBLE(unwindCodeOpInfo));
  119. unwindCode->SetOpInfo(TO_UNIBBLE(unwindCodeOpInfo));
  120. }
  121. BYTE *PrologEncoder::Finalize(BYTE *functionStart,
  122. DWORD codeSize,
  123. BYTE *pdataBuffer)
  124. {
  125. Assert(pdataBuffer > functionStart);
  126. Assert((size_t)pdataBuffer % sizeof(DWORD) == 0);
  127. pdata.runtimeFunction.BeginAddress = 0;
  128. pdata.runtimeFunction.EndAddress = codeSize;
  129. pdata.runtimeFunction.UnwindData = (DWORD)((pdataBuffer + sizeof(RUNTIME_FUNCTION)) - functionStart);
  130. FinalizeUnwindInfo(functionStart, codeSize);
  131. return (BYTE *)&pdata.runtimeFunction;
  132. }
  133. void PrologEncoder::FinalizeUnwindInfo(BYTE *functionStart, DWORD codeSize)
  134. {
  135. pdata.unwindInfo.Version = 1;
  136. pdata.unwindInfo.Flags = 0;
  137. pdata.unwindInfo.SizeOfProlog = currentInstrOffset;
  138. pdata.unwindInfo.CountOfCodes = requiredUnwindCodeNodeCount;
  139. // We don't use the frame pointer in the standard way, and since we don't do dynamic stack allocation, we don't change the
  140. // stack pointer except during calls. From the perspective of the unwind info, it needs to restore information relative to
  141. // the stack pointer, so don't register the frame pointer.
  142. pdata.unwindInfo.FrameRegister = 0;
  143. pdata.unwindInfo.FrameOffset = 0;
  144. AssertMsg(requiredUnwindCodeNodeCount <= MaxRequiredUnwindCodeNodeCount, "We allocate 72 bytes for xdata - 34 (UnwindCodes) * 2 + 4 (UnwindInfo)");
  145. }
  146. PrologEncoder::UnwindCode *PrologEncoder::GetUnwindCode(unsigned __int8 nodeCount)
  147. {
  148. Assert(nodeCount && ((currentUnwindCodeNodeIndex - nodeCount) >= 0));
  149. currentUnwindCodeNodeIndex -= nodeCount;
  150. return static_cast<UnwindCode *>(&pdata.unwindInfo.unwindCodes[currentUnwindCodeNodeIndex]);
  151. }
  152. DWORD PrologEncoder::SizeOfUnwindInfo()
  153. {
  154. return (sizeof(UNWIND_INFO) + (sizeof(UNWIND_CODE) * requiredUnwindCodeNodeCount));
  155. }
  156. BYTE *PrologEncoder::GetUnwindInfo()
  157. {
  158. return (BYTE *)&pdata.unwindInfo;
  159. }
  160. #else // !_WIN32
  161. // ----------------------------------------------------------------------------
  162. // !_WIN32 x64 unwind uses .eh_frame
  163. // ----------------------------------------------------------------------------
  164. void PrologEncoder::EncodeSmallProlog(uint8 prologSize, size_t size)
  165. {
  166. auto fde = ehFrame.GetFDE();
  167. // prolog: push rbp
  168. fde->cfi_advance_loc(1); // DW_CFA_advance_loc: 1
  169. fde->cfi_def_cfa_offset(MachPtr * 2); // DW_CFA_def_cfa_offset: 16
  170. fde->cfi_offset(GetDwarfRegNum(LowererMDArch::GetRegFramePointer()), 2); // DW_CFA_offset: r6 (rbp) at cfa-16
  171. ehFrame.End();
  172. }
  173. DWORD PrologEncoder::SizeOfPData()
  174. {
  175. return ehFrame.Count();
  176. }
  177. BYTE* PrologEncoder::Finalize(BYTE *functionStart, DWORD codeSize, BYTE *pdataBuffer)
  178. {
  179. auto fde = ehFrame.GetFDE();
  180. fde->UpdateAddressRange(functionStart, codeSize);
  181. return ehFrame.Buffer();
  182. }
  183. void PrologEncoder::Begin(size_t prologStartOffset)
  184. {
  185. Assert(currentInstrOffset == 0);
  186. currentInstrOffset = prologStartOffset;
  187. }
  188. void PrologEncoder::End()
  189. {
  190. ehFrame.End();
  191. }
  192. void PrologEncoder::FinalizeUnwindInfo(BYTE *functionStart, DWORD codeSize)
  193. {
  194. auto fde = ehFrame.GetFDE();
  195. fde->UpdateAddressRange(functionStart, codeSize);
  196. }
  197. void PrologEncoder::EncodeInstr(IR::Instr *instr, unsigned __int8 size)
  198. {
  199. auto fde = ehFrame.GetFDE();
  200. uint8 unwindCodeOp = PrologEncoderMD::GetOp(instr);
  201. Assert((currentInstrOffset + size) > currentInstrOffset);
  202. currentInstrOffset += size;
  203. switch (unwindCodeOp)
  204. {
  205. case UWOP_PUSH_NONVOL:
  206. {
  207. const uword advance = currentInstrOffset - cfiInstrOffset;
  208. cfiInstrOffset = currentInstrOffset;
  209. cfaWordOffset++;
  210. fde->cfi_advance(advance); // DW_CFA_advance_loc: ?
  211. fde->cfi_def_cfa_offset(cfaWordOffset * MachPtr); // DW_CFA_def_cfa_offset: ??
  212. const ubyte reg = PrologEncoderMD::GetNonVolRegToSave(instr) + 1;
  213. fde->cfi_offset(GetDwarfRegNum(reg), cfaWordOffset); // DW_CFA_offset: r? at cfa-??
  214. break;
  215. }
  216. case UWOP_SAVE_XMM128:
  217. {
  218. // TODO
  219. break;
  220. }
  221. case UWOP_ALLOC_SMALL:
  222. case UWOP_ALLOC_LARGE:
  223. {
  224. size_t allocaSize = PrologEncoderMD::GetAllocaSize(instr);
  225. Assert(allocaSize % MachPtr == 0);
  226. size_t slots = allocaSize / MachPtr;
  227. Assert(cfaWordOffset + slots > cfaWordOffset);
  228. const uword advance = currentInstrOffset - cfiInstrOffset;
  229. cfiInstrOffset = currentInstrOffset;
  230. cfaWordOffset += slots;
  231. fde->cfi_advance(advance); // DW_CFA_advance_loc: ?
  232. fde->cfi_def_cfa_offset(cfaWordOffset * MachPtr); // DW_CFA_def_cfa_offset: ??
  233. break;
  234. }
  235. case UWOP_IGNORE:
  236. {
  237. return;
  238. }
  239. default:
  240. {
  241. AssertMsg(false, "PrologEncoderMD returned unsupported UnwindCodeOp.");
  242. }
  243. }
  244. }
  245. #endif // !_WIN32