y_hooks_nps.inc 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678
  1. /*
  2. Legal:
  3. Version: MPL 1.1
  4. The contents of this file are subject to the Mozilla Public License Version
  5. 1.1 the "License"; you may not use this file except in compliance with
  6. the License. You may obtain a copy of the License at
  7. http://www.mozilla.org/MPL/
  8. Software distributed under the License is distributed on an "AS IS" basis,
  9. WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  10. for the specific language governing rights and limitations under the
  11. License.
  12. The Original Code is the YSI framework.
  13. The Initial Developer of the Original Code is Alex "Y_Less" Cole.
  14. Portions created by the Initial Developer are Copyright C 2011
  15. the Initial Developer. All Rights Reserved.
  16. Contributors:
  17. Y_Less
  18. koolk
  19. JoeBullet/Google63
  20. g_aSlice/Slice
  21. Misiur
  22. samphunter
  23. tianmeta
  24. maddinat0r
  25. spacemud
  26. Crayder
  27. Dayvison
  28. Ahmad45123
  29. Zeex
  30. irinel1996
  31. Yiin-
  32. Chaprnks
  33. Konstantinos
  34. Masterchen09
  35. Southclaws
  36. PatchwerkQWER
  37. m0k1
  38. paulommu
  39. udan111
  40. Thanks:
  41. JoeBullet/Google63 - Handy arbitrary ASM jump code using SCTRL.
  42. ZeeX - Very productive conversations.
  43. koolk - IsPlayerinAreaEx code.
  44. TheAlpha - Danish translation.
  45. breadfish - German translation.
  46. Fireburn - Dutch translation.
  47. yom - French translation.
  48. 50p - Polish translation.
  49. Zamaroht - Spanish translation.
  50. Los - Portuguese translation.
  51. Dracoblue, sintax, mabako, Xtreme, other coders - Producing other modes for
  52. me to strive to better.
  53. Pixels^ - Running XScripters where the idea was born.
  54. Matite - Pestering me to release it and using it.
  55. Very special thanks to:
  56. Thiadmer - PAWN, whose limits continue to amaze me!
  57. Kye/Kalcor - SA:MP.
  58. SA:MP Team past, present and future - SA:MP.
  59. Optional plugins:
  60. Gamer_Z - GPS.
  61. Incognito - Streamer.
  62. Me - sscanf2, fixes2, Whirlpool.
  63. */
  64. #define HOOK_STOCK__%0(%1) FUNC_PARSER(YHNPS,ARR_MUL_CST:STR_CST_DEF:NUM_CST_DEF:REF_DEF:EXT_TAG:)(%0(%1))()()(1,0)
  65. #define HOOK_NATIVE__ HOOK_STOCK__
  66. #define HOOK_native__ HOOK_STOCK__
  67. #define HOOK_stock__ HOOK_STOCK__
  68. #define HOOK_FUNCTION__ HOOK_STOCK__
  69. #define HOOK_function__ HOOK_STOCK__
  70. // Strip spaces from the generated function names.
  71. #define @yH_%0\32; @yH_ // hook
  72. #define @_Hy%0\32; @_Hy // extra stock/native info
  73. #define @Hy_%0\32; @Hy_ // hook stock/native
  74. #define @H_y%0\32; @H_y // hook public
  75. #define @y_H%0\32; @y_H // DEFINE_HOOK_RETURN
  76. #define @_yH%0\32; @_yH // DEFINE_HOOK_REPLACEMENT
  77. // Arrays.
  78. //
  79. // %0 = `const`
  80. // %1 = Tag (unused)
  81. // %2 = Name
  82. // %4+ = Dims
  83. #define YHNPS_ARR(%0,%1,%2,%4)%8$ YHNPS_BYREF(%0%2[%4],%2)%8$
  84. #define YHNPS_ARR_ARR(%0,%1,%2,%4,%5)%8$ YHNPS_BYREF(%0%2[%4][%5],%2)%8$
  85. #define YHNPS_ARR_ARR_ARR(%0,%1,%2,%4,%5,%6)%8$ YHNPS_BYREF(%0%2[%4][%5][%6],%2)%8$
  86. // Strings.
  87. //
  88. // %0 = `const`
  89. // %1 = Tag (unused)
  90. // %2 = Name
  91. // %4 = Size
  92. // %3 = Default (unused)
  93. #define YHNPS_STR(%0,%1,%2,%4)%8$ YHNPS_BYREF(%0%2[%4],%2)%8$
  94. #define YHNPS_STR_DEF(%0,%1,%2,%4,%3)%8$ YHNPS_BYREF(%0%2[%4],%2)%8$
  95. // Varargs.
  96. //
  97. // %0 = `const` (unused)
  98. // %1 = Tag
  99. // %2 = Name (unused)
  100. // %5 = Prototype parameters
  101. // %6 = Call parameters
  102. #define YHNPS_EXT(%0,%1,%2)%8$(%5)(%6)(%9,%4) %8$(%5,%1...)(%6)(%9,%4)
  103. // References.
  104. //
  105. // %0 = `const` (unused)
  106. // %1 = Tag (unused)
  107. // %2 = Name
  108. // %3 = Default (unused)
  109. #define YHNPS_REF(%0,%1,%2)%8$ YHNPS_BYREF(&%2,%2)%8$
  110. #define YHNPS_REF_DEF(%0,%1,%2,%3)%8$ YHNPS_BYREF(&%2,%2)%8$
  111. // Variables.
  112. //
  113. // %0 = `const`
  114. // %1 = Tag (unused)
  115. // %2 = Name
  116. // %3 = Default (unused)
  117. #define YHNPS_NUM(%0,%1,%2)%8$ YHNPS_BYVAL(%0%2,%2)%8$
  118. #define YHNPS_NUM_DEF(%0,%1,%2,%3)%8$ YHNPS_BYVAL(%0%2,%2)%8$
  119. // Generate the parameter descriptions.
  120. //
  121. // %0 = Name in prototype
  122. // %1 = Name in call
  123. // %5 = Prototype parameters
  124. // %6 = Call parameters
  125. // %9 = Shift
  126. // %4 = Existing values
  127. // %7 = Prefix
  128. #define YHNPS_BYREF(%0,%1)%8$(%5)(%6)(%9,%4) %8$(%5,%0)(%6,%1)(%9+1,%4)
  129. #define YHNPS_BYVAL(%0,%1)%8$(%5)(%6)(%9,%4) %8$(%5,%0)(%6,%1)(%9+1,1<<%9|%4)
  130. // End, generate the code.
  131. //
  132. // %0 = Name
  133. // %3 = Descriptor
  134. // %5 = Prototype parameters
  135. // %6 = Call parameters
  136. // %9 = Shift
  137. // %4 = Existing values
  138. // %7 = Prefix0
  139. // %1 = Prefix1
  140. #define YHNPS_END(%0)%8$(,%5)(,%6)(%9,%4) %8$forward YHNPS_U0<%0>(%5);YHNPS_U1<%0>(%5);YHNPS_U1<%0>(%5)_yH@(%4),%0(%6),_@yH();YHNPS_U0<%0>(%5)
  141. #define YHNPS_NUL(%0)%8$()() YHNPS_END(%0)%8$(,)(,)
  142. // Helper macro to generate the unique function name without bloating the
  143. // generated code multiple times.
  144. #define YHNPS_U0<%1> UNIQUE_FUNCTION<@Hy_%1@...>
  145. #define YHNPS_U1<%1> UNIQUE_FUNCTION<@_Hy%1@...>
  146. // Doing `hook native` instead of `HOOK_NATIVE__` attaches the `forward` and
  147. // unique value earlier. This just does all the same code, but with a reduced
  148. // ending name generation.
  149. #define HOOK_REDO__%0(%1) FUNC_PARSER(YHNPS2,ARR_MUL_CST:STR_CST_DEF:NUM_CST_DEF:REF_DEF:EXT_TAG:)(%0(%1))()()(1,0)
  150. #define YHNPS2_ARR YHNPS_ARR
  151. #define YHNPS2_ARR_ARR YHNPS_ARR_ARR
  152. #define YHNPS2_ARR_ARR_ARR YHNPS_ARR_ARR_ARR
  153. #define YHNPS2_STR YHNPS_STR
  154. #define YHNPS2_STR_DEF YHNPS_STR_DEF
  155. #define YHNPS2_EXT YHNPS_EXT
  156. #define YHNPS2_REF YHNPS_REF
  157. #define YHNPS2_REF_DEF YHNPS_REF_DEF
  158. #define YHNPS2_NUM YHNPS_NUM
  159. #define YHNPS2_NUM_DEF YHNPS_NUM_DEF
  160. #define YHNPS2_BYREF YHNPS_BYREF
  161. #define YHNPS2_BYVAL YHNPS_BYVAL
  162. #define YHNPS2_END(%0)%8$(,%5)(,%6)(%9,%4) %8$@Hy_%0(%5);@_Hy%0(%5);@_Hy%0(%5)_yH@(%4),%0(%6),_@yH();@Hy_%0(%5)
  163. #define YHNPS2_NUL(%0)%8$()() YHNPS2_END(%0)%8$(,)(,)
  164. // Remove specified priorities from the original call.
  165. #define _yH@(%0),%1@%2(%3),_@yH(); _yH@(%0),%1(%3),_@yH();
  166. new
  167. YSI_g_sNPSBaseCall,
  168. YSI_g_sNPSTrampoline,
  169. YSI_g_sNPSReplace,
  170. YSI_g_sNPSStack;
  171. static
  172. YSI_g_sTempRet;
  173. static stock YHNPS_Find(heap, end, value)
  174. {
  175. new
  176. start = 0,
  177. mid;
  178. --end;
  179. while (start <= end)
  180. {
  181. mid = (start + end) / 2;
  182. new
  183. diff = value - AMX_Read(heap + mid * 8);
  184. if (diff < 0)
  185. {
  186. start = mid + 1;
  187. }
  188. else if (diff > 0)
  189. {
  190. end = mid - 1;
  191. }
  192. else
  193. {
  194. return AMX_Read(heap + mid * 8 + 4);
  195. }
  196. }
  197. return cellmin;
  198. }
  199. static stock YHNPS_Insert(heap, count, value, ptr)
  200. {
  201. new
  202. start = 0,
  203. mid,
  204. end = count - 1;
  205. while (start <= end)
  206. {
  207. mid = (start + end) / 2;
  208. new
  209. diff = value - AMX_Read(heap + mid * 8);
  210. if (diff < 0)
  211. {
  212. start = mid + 1;
  213. }
  214. else if (diff > 0)
  215. {
  216. end = mid - 1;
  217. }
  218. else
  219. {
  220. return;
  221. }
  222. }
  223. if (start == count)
  224. {
  225. // Shift all the greater values up.
  226. AMX_Write(heap + count * 8, value);
  227. AMX_Write(heap + count * 8 + 4, ptr);
  228. }
  229. else
  230. {
  231. // Shift all the greater values up.
  232. rawMemcpy(heap + mid * 8 + 8, heap + mid * 8, (count - mid) * 8);
  233. AMX_Write(heap + mid * 8, value);
  234. AMX_Write(heap + mid * 8 + 4, ptr);
  235. }
  236. }
  237. Hooks_Continue_(GLOBAL_TAG_TYPES:...)
  238. {
  239. return 0;
  240. }
  241. static stock YHNPS_Push(heap, &allocated, &nativeCount, &stockCount, base, find, replace)
  242. {
  243. if (allocated == max(nativeCount, stockCount))
  244. {
  245. // Space to insert 32 new values for each hook type.
  246. HeapAllocCells(6 * 32);
  247. // Move the arrays up in memory.
  248. if (nativeCount)
  249. {
  250. rawMemcpy(heap + allocated * 16 + 32 * 16, heap + allocated * 16, nativeCount * 8);
  251. }
  252. if (stockCount)
  253. {
  254. rawMemcpy(heap + allocated * 8 + 32 * 8, heap + allocated * 8, stockCount * 8);
  255. }
  256. allocated += 32;
  257. }
  258. if (find < 0)
  259. {
  260. YHNPS_Insert(heap, nativeCount, -find, replace + base);
  261. YHNPS_Insert(heap + allocated * 16, nativeCount, GetNativeAddressFromIndex(-find), replace + base);
  262. ++nativeCount;
  263. }
  264. else
  265. {
  266. YHNPS_Insert(heap + allocated * 8, stockCount, find, replace + base);
  267. ++stockCount;
  268. }
  269. }
  270. _@yH(&a = 0, &b = 0, &c = 0, &d = 0, &e = 0, &f = 0)
  271. {
  272. #pragma unused a, b, c, d, e, f
  273. // This function does nothing. It merely exists to reserve space for
  274. // codegen. According to my experiments, just 4 parameters are enough to
  275. // reserve enough space (exactly) for the code generated below, even for a
  276. // function with no parameters. But better to be safe than sorry.
  277. }
  278. public OnCodeInit()
  279. {
  280. Indirect_Init();
  281. // Step 1:
  282. //
  283. // Read the AMX header to loop over all the `@_Hy` functions. These
  284. // contain the call to `_yH@` which generates the trambopoline code.
  285. //
  286. // From this data we build a list of all calls to replace.
  287. new
  288. heap = GetAmxHeapTop(),
  289. allocated = 0,
  290. nativeCount = 0,
  291. stockCount = 0,
  292. idx1,
  293. idx2,
  294. base;
  295. {
  296. new hdr[AMX_HDR];
  297. GetAmxHeader(hdr);
  298. base = GetAmxBaseAddress() + hdr[AMX_HDR_COD];
  299. }
  300. {
  301. YSI_g_sNPSBaseCall = cellmin;
  302. // Needs to be split over multiple lines because macros (`_A`).
  303. while (
  304. (idx1 = AMX_GetPublicPointerPrefix(idx1, YSI_g_sNPSReplace, _A<@Hy_>))
  305. &&
  306. (idx2 = AMX_GetPublicPointerPrefix(idx2, YSI_g_sNPSTrampoline, _A<@_Hy>))
  307. )
  308. {
  309. @.YSI_g_sNPSTrampoline();
  310. if (YSI_g_sNPSStack != YSI_g_sNPSTrampoline)
  311. {
  312. YHNPS_Push(heap, allocated, nativeCount, stockCount, base, YSI_g_sNPSReplace, YSI_g_sNPSStack);
  313. YSI_g_sNPSStack = YSI_g_sNPSTrampoline;
  314. }
  315. }
  316. }
  317. if (YSI_g_sNPSBaseCall != cellmin)
  318. {
  319. // Store the final chain.
  320. YHNPS_Push(heap, allocated, nativeCount, stockCount, base, YSI_g_sNPSBaseCall, YSI_g_sNPSTrampoline);
  321. }
  322. // Step 2:
  323. //
  324. // Iterate over the entire mode and replace all relevant calls.
  325. //
  326. new
  327. Opcode:call = RelocateOpcode(OP_CALL),
  328. Opcode:nop = RelocateOpcode(OP_NOP),
  329. Opcode:proc = RelocateOpcode(OP_PROC),
  330. dctx[DisasmContext];
  331. DisasmInit(dctx);
  332. for ( ; ; )
  333. {
  334. switch (DisasmNextInsn(dctx))
  335. {
  336. case OP_NONE:
  337. {
  338. break;
  339. }
  340. case OP_SYSREQ_C:
  341. {
  342. // Check that the previous OP is `PUSH.C`. That reqpresents a real native call, not our
  343. // wrapper.
  344. if (Opcode:AMX_Read(DisasmGetCurIp(dctx) - 8) == proc)
  345. {
  346. continue;
  347. }
  348. idx1 = YHNPS_Find(heap, nativeCount, DisasmGetOperand(dctx));
  349. }
  350. case OP_SYSREQ_D:
  351. {
  352. if (Opcode:AMX_Read(DisasmGetCurIp(dctx) - 8) == proc)
  353. {
  354. continue;
  355. }
  356. idx1 = YHNPS_Find(heap + allocated * 16, nativeCount, DisasmGetOperand(dctx));
  357. }
  358. case OP_CALL:
  359. {
  360. idx1 = YHNPS_Find(heap + allocated * 8, stockCount, DisasmGetOperandReloc(dctx));
  361. if (idx1 != cellmin)
  362. {
  363. // Write a different target address.
  364. AMX_Write(DisasmGetCurIp(dctx) + 4, idx1);
  365. }
  366. continue;
  367. }
  368. default:
  369. {
  370. continue;
  371. }
  372. }
  373. // `SYSREQ.C` is always followed by `STACK`, except with `#emit` usage.
  374. // We need to change the pair in to a single `CALL`. Don't forget
  375. // `SYSREQ.D`.
  376. if (idx1 != cellmin)
  377. {
  378. // Write a different target address.
  379. base = DisasmGetCurIp(dctx);
  380. AMX_Write(base, _:call);
  381. AMX_Write(base + 4, idx1);
  382. if (DisasmNextInsn(dctx) == OP_STACK)
  383. {
  384. AMX_Write(base + 8, _:nop);
  385. AMX_Write(base + 12, _:nop);
  386. }
  387. }
  388. }
  389. // Step 2:
  390. //
  391. // Generate `continue`.
  392. //
  393. Hooks_GenerateContinue();
  394. // Clear the stack.
  395. YSI_g_sNPSStack = 0;
  396. HeapRelease(heap);
  397. #if defined YHNPS_OnCodeInit
  398. YHNPS_OnCodeInit();
  399. #endif
  400. return 1;
  401. }
  402. #undef OnCodeInit
  403. #define OnCodeInit YHNPS_OnCodeInit
  404. #if defined YHNPS_OnCodeInit
  405. forward YHNPS_OnCodeInit();
  406. #endif
  407. /*
  408. Trampoline code, to add the indirection pattern to the start of the parameter
  409. list. I.e. change this:
  410. SetPlayerHealth(playerid, 5.5);
  411. To:
  412. SetPlayerHealth("if", playerid, 5.5);
  413. This function is called, and just needs to insert a new function.
  414. // No `PROC`, so no adjusted frame yet.
  415. #emit POP.alt // Store return address.
  416. #emit POP.pri // Store parameter count.
  417. #emit PUSH.C "param-string" // Pre-get the address.
  418. #emit ADD.C 4 // Increase the parameter count.
  419. #emit PUSH.pri
  420. #emit PUSH.alt
  421. #emit JUMP TrueFunction // Jump to the start of the implementation.
  422. */
  423. #define continue(%0) Hooks_Continue_(%0)
  424. stock _yH@(compressedFormat)
  425. {
  426. #pragma unused compressedFormat
  427. // Get the next function call address, being the original function. This
  428. // can also tell us if it is a native, public, or stock (which is a nice
  429. // side-effect I wasn't planning).
  430. new
  431. dctx[DisasmContext],
  432. ctx[AsmContext],
  433. addr,
  434. type = 0;
  435. DisasmInit(dctx, GetCurrentFrameReturn());
  436. while (DisasmNext(dctx))
  437. {
  438. switch (DisasmGetOpcode(dctx))
  439. {
  440. case OP_CALL:
  441. {
  442. addr = DisasmGetOperandReloc(dctx);
  443. type = 1;
  444. break;
  445. }
  446. case OP_SYSREQ_C:
  447. {
  448. addr = -DisasmGetOperand(dctx);
  449. type = -(YSI_g_sNPSTrampoline + 39 * cellbytes);
  450. break;
  451. }
  452. case OP_SYSREQ_D:
  453. {
  454. type = -(YSI_g_sNPSTrampoline + 39 * cellbytes);
  455. break;
  456. }
  457. }
  458. }
  459. //if (type < 0)
  460. //{
  461. // // Native function call.
  462. // addr = -addr;
  463. //}
  464. AsmInitPtr(ctx, YSI_g_sNPSTrampoline + AMX_HEADER_COD, YSI_g_sNPSReplace - YSI_g_sNPSTrampoline);
  465. // Forward the function, storing the chain data in the heap. Note that no
  466. // `PROC` is added to this new trambopoline:
  467. //
  468. // https://www.youtube.com/watch?v=geHqnV4Mk_4
  469. //
  470. // Build the structure in the stack first.
  471. @emit POP.pri // 1
  472. @emit PUSH.C compressedFormat // 3
  473. // Chain the functions.
  474. if (YSI_g_sNPSBaseCall == addr)
  475. {
  476. @emit PUSH.C YSI_g_sNPSStack // 5
  477. YSI_g_sNPSStack = YSI_g_sNPSTrampoline; // Replace.
  478. }
  479. else if (YSI_g_sNPSBaseCall == cellmin)
  480. {
  481. @emit PUSH.C (type < 0 ? type : addr) // 5
  482. YSI_g_sNPSStack = YSI_g_sNPSTrampoline;
  483. }
  484. else
  485. {
  486. @emit PUSH.C (type < 0 ? type : addr) // 5
  487. }
  488. @emit PUSH.C 8 // 7
  489. @emit PUSH.pri // Save the return address again. // 8
  490. @emit PUSH ref(YSI_g_sNPSStack) // 10
  491. // Copy 20 bytes over (includes the return address and fake param count).
  492. @emit HEAP 20 // 12
  493. @emit LCTRL 4 // 14
  494. @emit MOVS 20 // 16
  495. @emit STOR.alt ref(YSI_g_sNPSStack) // 18
  496. // Call, and return to here to clean up the heap.
  497. @emit STACK 20 // 20
  498. @emit CALL.abs YSI_g_sNPSReplace // 22
  499. // Put data (and return value) on the stack.
  500. @emit STACK -20 // 24
  501. @emit STACK 0 // 26
  502. @emit PUSH.pri // 27
  503. // Copy from the heap.
  504. @emit LOAD.pri ref(YSI_g_sNPSStack) // 29
  505. @emit MOVS 20 // 31
  506. // Restore the return address and `continue` stack.
  507. @emit POP.pri // 32
  508. @emit POP.alt // 33
  509. @emit STOR.alt ref(YSI_g_sNPSStack) // 35
  510. @emit HEAP -20 // 37
  511. // Return from this "function", with our fake parameters and return address.
  512. // We do this instead of using `SCTRL 6`, as is the normal way, to preserve
  513. // `pri` as the return value.
  514. @emit PROC // 38
  515. @emit RETN // 39
  516. if (type < 0)
  517. {
  518. // Missed this one apparently...
  519. @emit SYSREQ.C -addr
  520. //@emit SYSREQ.pri
  521. // Returns to here.
  522. @emit PUSH.alt
  523. @emit PUSH ref(YSI_g_sTempRet)
  524. @emit RETN
  525. }
  526. AsmEmitPadding(ctx);
  527. YSI_g_sNPSReplace = YSI_g_sNPSBaseCall; // Find
  528. YSI_g_sNPSBaseCall = addr;
  529. // Do a double return - exit the calling function as well as this function,
  530. // so that the next call is never actually made.
  531. #emit LOAD.S.pri 0
  532. #emit SCTRL 5
  533. #emit SCTRL 4
  534. // Clear faked parameter counts. The outer public (maybe) expects lots of
  535. // parameters. We call it with none.
  536. #emit ZERO.S 8
  537. #emit RETN
  538. }
  539. static stock Hooks_GenerateContinue(GLOBAL_TAG_TYPES:...)
  540. {
  541. // This generates new code in a given location. That location just happens
  542. // to entirely clobber `YHNPS_Push`, but we no longer need it.
  543. new
  544. ctx[AsmContext],
  545. ptr = _:addressof(Hooks_Continue_<>);
  546. AsmInitPtr(ctx, ptr + AMX_HEADER_COD, _:addressof(_@yH<>) - ptr);
  547. @emit PROC
  548. @emit ADDR.pri 8
  549. @emit PUSH.pri
  550. @emit LOAD.pri ref(YSI_g_sNPSStack)
  551. @emit ADD.C 16
  552. @emit LOAD.I
  553. @emit MOVE.alt
  554. @emit Hooks_Continue_loop:
  555. @emit POP.pri
  556. @emit ADD.C 4
  557. @emit PUSH.pri
  558. // Check if `alt` is `0` (no parameters) or odd (move this parameter).
  559. @emit CONST.pri 1
  560. @emit SHR.C.alt 1
  561. @emit JGRTR.label Hooks_Continue_done
  562. @emit AND
  563. @emit JZER.label Hooks_Continue_loop
  564. // Adjust the given parameter.
  565. @emit LREF.S.pri -4
  566. @emit LOAD.I
  567. @emit SREF.S.pri -4
  568. @emit JUMP.label Hooks_Continue_loop
  569. @emit Hooks_Continue_done:
  570. @emit POP.pri
  571. @emit LOAD.pri ref(YSI_g_sNPSStack)
  572. @emit ADD.C 12
  573. @emit LOAD.I
  574. // `alt` is `0` here, thanks to the loop above.
  575. @emit JSLEQ.label Hooks_Continue_native
  576. @emit MOVE.alt
  577. @emit POP.pri
  578. @emit SCTRL 5
  579. // Jump to the function.
  580. @emit MOVE.pri
  581. @emit LCTRL 8
  582. @emit SCTRL 6
  583. @emit Hooks_Continue_native:
  584. // Save the bottom of the stack.
  585. @emit POP.alt
  586. @emit STOR.alt ref(YSI_g_sTempRet)
  587. @emit POP.alt
  588. @emit NEG
  589. @emit LCTRL 8
  590. @emit SCTRL 6
  591. //// Missed this one apparently...
  592. //AsmEmitSysreqPri(ctx);
  593. ////@emit SYSREQ.pri
  594. //
  595. //// Returns to here.
  596. //@emit PUSH.alt
  597. //@emit PUSH ref(YSI_g_sTempRet)
  598. //@emit RETN
  599. AsmEmitPadding(ctx);
  600. }