Y_Less

als2.inc

Jul 8th, 2012
449
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Pawn 18.78 KB | None | 0 0
  1. /*----------------------------------------------------------------------------*\
  2.                     ==============================
  3.                       y_als2 - Advanced hooking.
  4.                     ==============================
  5. Description:
  6.     This code uses code-rewriting to dynamically insert either a function call
  7.     or a constant value.  This code is called once when a callback chain point
  8.     is reached (i.e. when one callback wants to call the next callback of the
  9.     same type), and replaces its own call with the new call.
  10. Legal:
  11.     Version: MPL 1.1
  12.    
  13.     The contents of this file are subject to the Mozilla Public License Version
  14.     1.1 (the "License"); you may not use this file except in compliance with
  15.     the License. You may obtain a copy of the License at
  16.     http://www.mozilla.org/MPL/
  17.    
  18.     Software distributed under the License is distributed on an "AS IS" basis,
  19.     WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  20.     for the specific language governing rights and limitations under the
  21.     License.
  22.    
  23.     The Original Code is the YSI vararg include.
  24.    
  25.     The Initial Developer of the Original Code is Alex "Y_Less" Cole.
  26.     Portions created by the Initial Developer are Copyright (C) 2011
  27.     the Initial Developer. All Rights Reserved.
  28.    
  29.     Contributors:
  30.         ZeeX, koolk, JoeBullet/Google63, g_aSlice/Slice
  31.    
  32.     Thanks:
  33.         JoeBullet/Google63 - Handy arbitrary ASM jump code using SCTRL.
  34.         ZeeX - Very productive conversations.
  35.         koolk - IsPlayerinAreaEx code.
  36.         TheAlpha - Danish translation.
  37.         breadfish - German translation.
  38.         Fireburn - Dutch translation.
  39.         yom - French translation.
  40.         50p - Polish translation.
  41.         Zamaroht - Spanish translation.
  42.         Dracoblue, sintax, mabako, Xtreme, other coders - Producing other modes
  43.             for me to strive to better.
  44.         Pixels^ - Running XScripters where the idea was born.
  45.         Matite - Pestering me to release it and using it.
  46.    
  47.     Very special thanks to:
  48.         Thiadmer - PAWN, whose limits continue to amaze me!
  49.         Kye/Kalcor - SA:MP.
  50.         SA:MP Team past, present and future - SA:MP.
  51.    
  52. Version:
  53.     1.0
  54. Changelog:
  55.     02/05/11:
  56.         First version.
  57. Functions:
  58.     Public:
  59.         -
  60.     Core:
  61.         -
  62.     Stock:
  63.         -
  64.     Static:
  65.         -
  66.     Inline:
  67.         -
  68.     API:
  69.         -
  70. Callbacks:
  71.     -
  72. Definitions:
  73.     -
  74. Enums:
  75.     -
  76. Macros:
  77.     -
  78. Tags:
  79.     -
  80. Variables:
  81.     Global:
  82.         -
  83.     Static:
  84.         -
  85. Commands:
  86.     -
  87. Compile options:
  88.     -
  89. Operators:
  90.     -
  91. \*----------------------------------------------------------------------------*/
  92.  
  93. // Hooks version three.  This code HIGHLY optimises for return calls, and
  94. // slightly optimises for other calls.  Fake function calls are inserted in to
  95. // the code to pad out space, then replaced at run-time.
  96.  
  97. /*#if !defined ALS_PREFIX
  98. #endif
  99.  
  100. #include <YSI\y_als>
  101.  
  102. #if defined ALS_CALL
  103.     #undef ALS_CALL
  104. #endif
  105.  
  106.  
  107. #if defined ALS_GET
  108.     #undef ALS_GET
  109. #endif*/
  110.  
  111. #undef _inc_als2
  112.  
  113. #if !defined _ALS_2_INCLUDED
  114.     #define _ALS_2_INCLUDED
  115.    
  116.     #if defined ALS_PREFIX
  117.         #tryinclude <YSI\y_als>
  118.     #else
  119.         #define ALS_PREFIX
  120.         #tryinclude <YSI\y_als>
  121.         #undef ALS_PREFIX
  122.     #endif
  123.    
  124.     #if defined _Y_ALS_INCLUDED
  125.         #if defined _JIT
  126.             // Support the new extended syntex.
  127.            
  128.             //#undef ALS_CALL
  129.             //#undef ALS_GET
  130.            
  131.             //#define ALS_CALL<%0> ALS_DO:ALS_C_INT<%0>
  132.             //#define ALS_GET<%0> ALS_DO:_ALS_C_INT<%0>
  133.            
  134.             #endinput
  135.         #endif
  136.         // Don't remove ALS_FORWARD
  137.        
  138.         #undef ALS_CALL
  139.         #undef ALS_GET
  140.        
  141.         #undef ALS_DATA
  142.         #define ALS_DATA<>
  143.        
  144.         #undef ALS_DETECT
  145.         #define ALS_DETECT<%0>
  146.     #else
  147.         #if defined _JIT
  148.             #error _JIT requires YSI\y_als to work.
  149.         #endif
  150.     #endif
  151.    
  152.     #define string:
  153.    
  154.     //#define ALS_CALL<%0> return _:_ALS_WITH_ON:_ALS_NO_ON:_ALS_NOTHING:_ALS_NO_P:ALS_Chain(%0)
  155.     //#define ALS_CALL<%0> return _:_ALS_NOTHING:_ALS_NO_P:ALS_Chain(%0);
  156.     #define ALS_CALL<%0> return _:_ALS_WITH_ON:_ALS_NOTHING:_ALS_NO_P:ALS_Chain(%0);
  157.    
  158.     //#define ALS_GET<%0> _:_ALS_WITH_ON:_ALS_NO_ON:_ALS_NOTHING:ALS_Call(%0)
  159.     #define ALS_GET<%0> _:_ALS_WITH_ON:_ALS_NOTHING:ALS_Call(%0);
  160.     //#define ALS_GET<%0> _:_ALS_NOTHING:ALS_Call(%0);
  161.    
  162.     //#define _ALS_WITH_ON:_ALS_NO_ON:_ALS_NOTHING:%3(%0_On%1) _ALS_P_%1(%3)(#%0"_On"#%1, _ALS_R_%1)
  163.     #define _ALS_WITH_ON:_ALS_NOTHING:%3(%0_On%1) _ALS_P_%1(%3)(#%0"_On"#%1, _ALS_R_%1)
  164.     //#define _ALS_NO_ON:_ALS_NOTHING:%3(%0_%1) _ALS_P_%1(%3)(#%0"_On"#%1, _ALS_R_%1)
  165.     #define _ALS_NOTHING:%3(%1) _ALS_P_%1(%3)(#ALS_PREFIX"_On"#%1, _ALS_R_%1)
  166.    
  167.     #define _ALS_NO_P:%3ALS_%0_%1( %3ALS_%0(
  168.    
  169.     //#define _ALS_CALL ALS_Call
  170.     //#define _ALS_CHAIN _ALS_ONLY_2:ALS_Chain
  171.    
  172.     //#define _ALS_ONLY_2:ALS_Chain(%0,%1,%2) ALS_Chain(%0,%1)
  173.    
  174.     // Define the default return values for every callback.
  175.     #define _ALS_R_GameModeInit 1
  176.     #define _ALS_R_GameModeExit 1
  177.     #define _ALS_R_FilterScriptInit 1
  178.     #define _ALS_R_FilterScriptExit 1
  179.     #define _ALS_R_PlayerConnect 1
  180.     #define _ALS_R_PlayerDisconnect 1
  181.     #define _ALS_R_PlayerSpawn 1
  182.     #define _ALS_R_PlayerDeath 1
  183.     #define _ALS_R_VehicleSpawn 1
  184.     #define _ALS_R_VehicleDeath 1
  185.     #define _ALS_R_PlayerText 1
  186.     #define _ALS_R_PlayerCommandText 0
  187.     #define _ALS_R_PlayerRequestClass 1
  188.     #define _ALS_R_PlayerEnterVehicle 1
  189.     #define _ALS_R_PlayerExitVehicle 1
  190.     #define _ALS_R_PlayerStateChange 1
  191.     #define _ALS_R_PlayerEnterCheckpoint 1
  192.     #define _ALS_R_PlayerLeaveCheckpoint 1
  193.     #define _ALS_R_PlayerEnterRaceCP 1
  194.     #define _ALS_R_PlayerLeaveRaceCP 1
  195.     #define _ALS_R_RconCommand 1
  196.     #define _ALS_R_PlayerRequestSpawn 1
  197.     #define _ALS_R_ObjectMoved 1
  198.     #define _ALS_R_PlayerObjectMoved 1
  199.     #define _ALS_R_PlayerPickUpPickup 1
  200.     #define _ALS_R_VehicleMod 1
  201.     #define _ALS_R_EnterExitModShop 1
  202.     #define _ALS_R_VehiclePaintjob 1
  203.     #define _ALS_R_VehicleRespray 1
  204.     #define _ALS_R_VehicleDamageStatusUp 1
  205.     #define _ALS_R_PlayerSelectedMenuRow 1
  206.     #define _ALS_R_PlayerExitedMenu 1
  207.     #define _ALS_R_PlayerInteriorChange 1
  208.     #define _ALS_R_PlayerKeyStateChange 1
  209.     #define _ALS_R_RconLoginAttempt 1
  210.     #define _ALS_R_PlayerUpdate 1
  211.     #define _ALS_R_PlayerStreamIn 1
  212.     #define _ALS_R_PlayerStreamOut 1
  213.     #define _ALS_R_VehicleStreamIn 1
  214.     #define _ALS_R_VehicleStreamOut 1
  215.     #define _ALS_R_DialogResponse 1
  216.     #define _ALS_R_PlayerClickPlayer 1
  217.     #define _ALS_R_PlayerClickMap 1
  218.     #define _ALS_R_PlayerClickTextDraw 1
  219.     #define _ALS_R_PlayerClickPlayerTD 1
  220.     #define _ALS_R_PlayerEditObject 1
  221.     #define _ALS_R_PlayerEditAttachedObj 1
  222.     #define _ALS_R_PlayerSelectObject 1
  223.     #define _ALS_R_PlayerTakeDamage 1
  224.     #define _ALS_R_PlayerGiveDamage 1
  225.    
  226.     // Define the number of parameter for every callback.
  227.     #define _ALS_P_GameModeInit(%0) %0_0
  228.     #define _ALS_P_GameModeExit(%0) %0_0
  229.     #define _ALS_P_FilterScriptInit(%0) %0_0
  230.     #define _ALS_P_FilterScriptExit(%0) %0_0
  231.     #define _ALS_P_PlayerConnect(%0) %0_Def
  232.     #define _ALS_P_PlayerDisconnect(%0) %0_2
  233.     #define _ALS_P_PlayerSpawn(%0) %0_Def
  234.     #define _ALS_P_PlayerDeath(%0) %0_3
  235.     #define _ALS_P_VehicleSpawn(%0) %0_Def
  236.     #define _ALS_P_VehicleDeath(%0) %0_2
  237.     #define _ALS_P_PlayerText(%0) %0_2
  238.     #define _ALS_P_PlayerCommandText(%0) %0_2
  239.     #define _ALS_P_PlayerRequestClass(%0) %0_2
  240.     #define _ALS_P_PlayerEnterVehicle(%0) %0_3
  241.     #define _ALS_P_PlayerExitVehicle(%0) %0_2
  242.     #define _ALS_P_PlayerStateChange(%0) %0_3
  243.     #define _ALS_P_PlayerEnterCheckpoint(%0) %0_Def
  244.     #define _ALS_P_PlayerLeaveCheckpoint(%0) %0_Def
  245.     #define _ALS_P_PlayerEnterRaceCP(%0) %0_Def
  246.     #define _ALS_P_PlayerLeaveRaceCP(%0) %0_Def
  247.     #define _ALS_P_RconCommand(%0) %0_Def
  248.     #define _ALS_P_PlayerRequestSpawn(%0) %0_Def
  249.     #define _ALS_P_ObjectMoved(%0) %0_Def
  250.     #define _ALS_P_PlayerObjectMoved(%0) %0_2
  251.     #define _ALS_P_PlayerPickUpPickup(%0) %0_2
  252.     #define _ALS_P_VehicleMod(%0) %0_3
  253.     #define _ALS_P_EnterExitModShop(%0) %0_3
  254.     #define _ALS_P_VehiclePaintjob(%0) %0_3
  255.     #define _ALS_P_VehicleRespray(%0) %0_4
  256.     #define _ALS_P_VehicleDamageStatusUp(%0) %0_2
  257.     #define _ALS_P_PlayerSelectedMenuRow(%0) %0_2
  258.     #define _ALS_P_PlayerExitedMenu(%0) %0_Def
  259.     #define _ALS_P_PlayerInteriorChange(%0) %0_3
  260.     #define _ALS_P_PlayerKeyStateChange(%0) %0_3
  261.     #define _ALS_P_RconLoginAttempt(%0) %0_3
  262.     #define _ALS_P_PlayerUpdate(%0) %0_Def
  263.     #define _ALS_P_PlayerStreamIn(%0) %0_2
  264.     #define _ALS_P_PlayerStreamOut(%0) %0_2
  265.     #define _ALS_P_VehicleStreamIn(%0) %0_2
  266.     #define _ALS_P_VehicleStreamOut(%0) %0_2
  267.     #define _ALS_P_DialogResponse(%0) %0_5
  268.     #define _ALS_P_PlayerClickPlayer(%0) %0_3
  269.     #define _ALS_P_PlayerClickMap(%0) %0_4
  270.     #define _ALS_P_PlayerClickTextDraw(%0) %0_2
  271.     #define _ALS_P_PlayerClickPlayerTD(%0) %0_3
  272.     #define _ALS_P_PlayerEditObject(%0) %0_Def0
  273.     #define _ALS_P_PlayerEditAttachedObj(%0) %0_Def4
  274.     #define _ALS_P_PlayerSelectObject(%0) %0_7
  275.     #define _ALS_P_PlayerTakeDamage(%0) %0_4
  276.     #define _ALS_P_PlayerGiveDamage(%0) %0_4
  277.    
  278.     static
  279.         ALS_gsWriteOffset = -1,
  280.         ALS_gsJumpOffset = -1,
  281.         ALS_gsPublicOffset = -1;
  282.    
  283.     stock ALS_Call_Def(const string:func[])
  284.     {
  285.         // ALS_Call_Def is an optimised version for single parameter functions that
  286.         // return "1".
  287.         return ALS_Call(func, 1, 1, 1);
  288.     }
  289.    
  290.     stock ALS_Call_0(const string:func[], ret)
  291.     {
  292.         // We need to write the code this horrible way to avoid having parameters
  293.         // being allocated on the heap instead of the stack (as happens with "...").
  294.         return ALS_Call(func, ret, 0, 2);
  295.     }
  296.    
  297.     stock ALS_Call_1(const string:func[], ret)
  298.     {
  299.         return ALS_Call(func, ret, 1, 2);
  300.     }
  301.    
  302.     stock ALS_Call_2(const string:func[], ret)
  303.     {
  304.         return ALS_Call(func, ret, 2, 2);
  305.     }
  306.    
  307.     stock ALS_Call_3(const string:func[], ret, _p0 = 0)
  308.     {
  309.         // The fake parameters are just there to ensure we reserve enough code space
  310.         // to do all the pushing required.
  311.         #pragma unused _p0
  312.         return ALS_Call(func, ret, 3, 3);
  313.     }
  314.    
  315.     stock ALS_Call_4(const string:func[], ret, _p0 = 0, _p1 = 0)
  316.     {
  317.         #pragma unused _p0, _p1
  318.         return ALS_Call(func, ret, 4, 4);
  319.     }
  320.    
  321.     stock ALS_Call_5(const string:func[], ret, _p0 = 0, _p1 = 0, _p2 = 0)
  322.     {
  323.         #pragma unused _p0, _p1, _p2
  324.         return ALS_Call(func, ret, 5, 5);
  325.     }
  326.    
  327.     stock ALS_Call_6(const string:func[], ret, _p0 = 0, _p1 = 0, _p2 = 0, _p3 = 0)
  328.     {
  329.         #pragma unused _p0, _p1, _p2, _p3
  330.         return ALS_Call(func, ret, 6, 6);
  331.     }
  332.    
  333.     stock ALS_Call_7(const string:func[], ret, _p0 = 0, _p1 = 0, _p2 = 0, _p3 = 0, _p4 = 0)
  334.     {
  335.         #pragma unused _p0, _p1, _p2, _p3, _p4
  336.         return ALS_Call(func, ret, 7, 7);
  337.     }
  338.    
  339.     stock ALS_Call_8(const string:func[], ret, _p0 = 0, _p1 = 0, _p2 = 0, _p3 = 0, _p4 = 0, _p5 = 0)
  340.     {
  341.         #pragma unused _p0, _p1, _p2, _p3, _p4, _p5
  342.         return ALS_Call(func, ret, 8, 8);
  343.     }
  344.    
  345.     stock ALS_Call_9(const string:func[], ret, _p0 = 0, _p1 = 0, _p2 = 0, _p3 = 0, _p4 = 0, _p5 = 0, _p6 = 0)
  346.     {
  347.         #pragma unused _p0, _p1, _p2, _p3, _p4, _p5, _p6
  348.         return ALS_Call(func, ret, 9, 9);
  349.     }
  350.    
  351.     stock ALS_Call_10(const string:func[], ret, _p0 = 0, _p1 = 0, _p2 = 0, _p3 = 0, _p4 = 0, _p5 = 0, _p6 = 0, _p7 = 0)
  352.     {
  353.         #pragma unused _p0, _p1, _p2, _p3, _p4, _p5, _p6, _p7
  354.         return ALS_Call(func, ret, 10, 10);
  355.     }
  356.    
  357.     stock ALS_Call_11(const string:func[], ret, _p0 = 0, _p1 = 0, _p2 = 0, _p3 = 0, _p4 = 0, _p5 = 0, _p6 = 0, _p7 = 0, _p8 = 0)
  358.     {
  359.         #pragma unused _p0, _p1, _p2, _p3, _p4, _p5, _p6, _p7, _p8
  360.         return ALS_Call(func, ret, 11, 11);
  361.     }
  362.    
  363.     stock ALS_Call_12(const string:func[], ret, _p0 = 0, _p1 = 0, _p2 = 0, _p3 = 0, _p4 = 0, _p5 = 0, _p6 = 0, _p7 = 0, _p8 = 0, _p9 = 0)
  364.     {
  365.         #pragma unused _p0, _p1, _p2, _p3, _p4, _p5, _p6, _p7, _p8, _p9
  366.         return ALS_Call(func, ret, 12, 12);
  367.     }
  368.    
  369.     stock ALS_Call_13(const string:func[], ret, _p0 = 0, _p1 = 0, _p2 = 0, _p3 = 0, _p4 = 0, _p5 = 0, _p6 = 0, _p7 = 0, _p8 = 0, _p9 = 0, _p10 = 0)
  370.     {
  371.         #pragma unused _p0, _p1, _p2, _p3, _p4, _p5, _p6, _p7, _p8, _p9, _p10
  372.         return ALS_Call(func, ret, 13, 13);
  373.     }
  374.    
  375.     stock ALS_Call_14(const string:func[], ret, _p0 = 0, _p1 = 0, _p2 = 0, _p3 = 0, _p4 = 0, _p5 = 0, _p6 = 0, _p7 = 0, _p8 = 0, _p9 = 0, _p10 = 0, _p11 = 0)
  376.     {
  377.         #pragma unused _p0, _p1, _p2, _p3, _p4, _p5, _p6, _p7, _p8, _p9, _p10, _p11
  378.         return ALS_Call(func, ret, 14, 14);
  379.     }
  380.    
  381.     stock ALS_Call_15(const string:func[], ret, _p0 = 0, _p1 = 0, _p2 = 0, _p3 = 0, _p4 = 0, _p5 = 0, _p6 = 0, _p7 = 0, _p8 = 0, _p9 = 0, _p10 = 0, _p11 = 0, _p12 = 0)
  382.     {
  383.         #pragma unused _p0, _p1, _p2, _p3, _p4, _p5, _p6, _p7, _p8, _p9, _p10, _p11, _p12
  384.         return ALS_Call(func, ret, 15, 15);
  385.     }
  386.    
  387.     static stock ALS_DoNothing()
  388.     {
  389.         // New global base address code based on code by Zeex in YSI.  See:
  390.         // https://github.com/Y-Less/YSI/pull/14
  391.         return 0;
  392.     }
  393.    
  394.     static stock ALS_GetGlobal()
  395.     {
  396.         new
  397.             addr;
  398.         // Get the offset from "DAT" to "COD" for writing new code.
  399.         #emit LCTRL          0
  400.         #emit MOVE.alt
  401.         #emit LCTRL          1
  402.         #emit SUB.alt
  403.         #emit STOR.pri       ALS_gsWriteOffset
  404.         // Call dummy function and read its (absolute) address from code.
  405.         ALS_DoNothing();
  406.         #emit LCTRL          6
  407.         #emit ADD.C          0xFFFFFFF4
  408.         #emit LOAD.alt       ALS_gsWriteOffset
  409.         #emit ADD
  410.         #emit STOR.S.pri     addr
  411.         #emit LREF.S.pri     addr
  412.         // Get difference between absolute and relative addresses.
  413.         #emit CONST.alt      ALS_DoNothing
  414.         #emit SUB
  415.         #emit STOR.pri       ALS_gsJumpOffset
  416.         // Get the relative offset to the start of the publics table.
  417.         #emit LCTRL          1
  418.         #emit NEG
  419.         #emit MOVE.alt
  420.         #emit ADD.C          32
  421.         #emit STOR.S.pri     addr
  422.         #emit LREF.S.pri     addr
  423.         #emit ADD
  424.         #emit STOR.pri       ALS_gsPublicOffset
  425.     }
  426.    
  427.     stock ALS_Call(const string:func[], ret, count, clamped)
  428.     {
  429.         //printf("ret = %d", ret);
  430.         if (ALS_gsWriteOffset == -1)
  431.         {
  432.             ALS_GetGlobal();
  433.         }
  434.         // Put the address offset in to "addr".  Need code to handle the case where
  435.         // the callback has less parameters than this function.
  436.         new
  437.             end,
  438.             //clamped = ((count <= 2) ? (2) : (count)),
  439.             addr = clamped * 8 + 16,
  440.             idx = funcidx(func) * 8;
  441.         // Get the write address MANY bytes before the PREVIOUS function call.
  442.         #emit LOAD.S.pri         0
  443.         #emit ADD.C              4
  444.         #emit LOAD.I
  445.         #emit STOR.S.pri         end
  446.         #emit LOAD.S.alt         addr
  447.         #emit SUB
  448.         #emit MOVE.alt
  449.         // Store the new return to the previous function's stack.
  450.         #emit LOAD.S.pri         0
  451.         #emit ADD.C              4
  452.         #emit XCHG
  453.         #emit STOR.I
  454.         // Get the write offset to the function address.
  455.         #emit LOAD.alt           ALS_gsWriteOffset
  456.         #emit ADD
  457.         #emit STOR.S.pri         addr
  458.         // This version basically replaces itself with call to the next item in the
  459.         // chain if needed, or a CONST.pri if not to get the default return.
  460.         // Change "count" to an instruction length offset.
  461.         if (idx == -8)
  462.         {
  463.             // This writes code to return the value given in "ret" back in the
  464.             // calling function, then jumps to that new code.
  465.             #emit CONST.pri      11
  466.             #emit SREF.S.pri     addr
  467.             addr += 4;
  468.             #emit LOAD.S.pri     ret
  469.             #emit SREF.S.pri     addr
  470.             addr += 4;
  471.             // Now we need to jump over at least 4 cells.  Here the extra "2" in
  472.             // "clamped" account for the parameter count "push" and "call" opcodes.
  473.             #emit CONST.pri      51
  474.             #emit SREF.S.pri     addr
  475.             addr += 4;
  476.             // Calculate the absolute address.
  477.             #emit LOAD.S.pri     0
  478.             #emit ADD.C          4
  479.             #emit LOAD.I
  480.             #emit LOAD.alt       ALS_gsJumpOffset
  481.             #emit ADD
  482.             // Add on enough offsets to jump past the function call.
  483.             #emit ADD.C          16
  484.             #emit LOAD.S.alt     clamped
  485.             #emit XCHG
  486.             #emit SMUL.C         8
  487.             #emit ADD
  488.             #emit SREF.S.pri     addr
  489.             // NOP the remaining code.
  490.             addr += 4;
  491.             end += ALS_gsWriteOffset;
  492.             while (addr != end)
  493.             {
  494.                 #emit CONST.pri  134
  495.                 #emit SREF.S.pri addr
  496.                 addr += 4;
  497.             }
  498.             return 0;
  499.         }
  500.         else
  501.         {
  502.             while (clamped > count)
  503.             {
  504.                 // NOP NOP
  505.                 #emit CONST.pri  134
  506.                 #emit SREF.S.pri addr
  507.                 addr += 4;
  508.                 #emit CONST.pri  134
  509.                 #emit SREF.S.pri addr
  510.                 addr += 4;
  511.                 --clamped;
  512.             }
  513.             // Start writing code to push all the parameters.
  514.             clamped = clamped * 4 + 8;
  515.             while (clamped > 8)
  516.             {
  517.                 // PUSH.S <clamped>
  518.                 #emit CONST.pri  41
  519.                 #emit SREF.S.pri addr
  520.                 addr += 4;
  521.                 #emit LOAD.S.pri clamped
  522.                 #emit SREF.S.pri addr
  523.                 #emit ADD.C      0xFFFFFFFC
  524.                 #emit STOR.S.pri clamped
  525.                 addr += 4;
  526.             }
  527.             // PUSH.C <count * 4>
  528.             #emit CONST.pri  39
  529.             #emit SREF.S.pri addr
  530.             addr += 4;
  531.             #emit LOAD.S.pri count
  532.             #emit SMUL.C     4
  533.             #emit SREF.S.pri addr
  534.             addr += 4;
  535.             // Get the absolute address of the function to call.
  536.             idx += ALS_gsPublicOffset;
  537.             #emit LREF.S.pri     idx
  538.             #emit LOAD.alt       ALS_gsJumpOffset
  539.             #emit ADD
  540.             #emit STOR.S.pri     idx
  541.             // Write the new call code.
  542.             // CALL
  543.             #emit CONST.pri      49
  544.             #emit SREF.S.pri     addr
  545.             addr += 4;
  546.             #emit LOAD.S.pri     idx
  547.             #emit SREF.S.pri     addr
  548.             addr += 4;
  549.             end += ALS_gsWriteOffset;
  550.             while (addr != end)
  551.             {
  552.                 #emit CONST.pri  134
  553.                 #emit SREF.S.pri addr
  554.                 addr += 4;
  555.             }
  556.             return 0;
  557.         }
  558.     }
  559.    
  560.     stock ALS_Chain(const string:func[], ret)
  561.     {
  562.         if (ALS_gsWriteOffset == -1)
  563.         {
  564.             ALS_GetGlobal();
  565.         }
  566.         new
  567.             start,
  568.             end,
  569.             addr,
  570.             idx = funcidx(func) * 8;
  571.         // Get the original cleanup code.
  572.         #emit LOAD.S.pri         4
  573.         #emit LOAD.alt           ALS_gsWriteOffset
  574.         #emit ADD
  575.         #emit STOR.S.pri         start
  576.         #emit STOR.S.pri         end
  577.         do
  578.         {
  579.             #emit LREF.S.pri     end
  580.             #emit STOR.S.pri     addr
  581.             end += 4;
  582.             // Find "RETN".
  583.         }
  584.         while (addr != 48);
  585.         // Get the write address 32 bytes before this function call.
  586.         #emit LOAD.S.pri         4
  587.         #emit ADD.C              0xFFFFFFE0
  588.         // Store the new return.
  589.         #emit STOR.S.pri         4
  590.         #emit LOAD.alt           ALS_gsWriteOffset
  591.         #emit ADD
  592.         #emit STOR.S.pri         addr
  593.         if (idx == -8)
  594.         {
  595.             // This writes code to return the value given in "ret" back in the
  596.             // calling function, then jumps to that new code.
  597.             // "CONST.pri"
  598.             #emit CONST.pri      11
  599.             #emit SREF.S.pri     addr
  600.             addr += 4;
  601.             #emit LOAD.S.pri     ret
  602.             #emit SREF.S.pri     addr
  603.             addr += 4;
  604.             // Restore the existing cleanup code.  Should also manage the heap.
  605.             while (start != end)
  606.             {
  607.                 #emit LREF.S.pri start
  608.                 #emit SREF.S.pri addr
  609.                 start += 4;
  610.                 addr += 4;
  611.             }
  612.             // Make everything else "NOP".
  613.             while (addr != end)
  614.             {
  615.                 #emit CONST.pri  134
  616.                 #emit SREF.S.pri addr
  617.                 addr += 4;
  618.             }
  619.             return 0;
  620.         }
  621.         else
  622.         {
  623.             // Get the absolute address of the function to jump in to.
  624.             idx += ALS_gsPublicOffset;
  625.             #emit LREF.S.pri     idx
  626.             #emit LOAD.alt       ALS_gsJumpOffset
  627.             #emit ADD
  628.             #emit ADD.C          4
  629.             #emit STOR.S.pri     idx
  630.             // Write the new call code.
  631.             // First clean up the stack.
  632.             end -= 4;
  633.             while (start != end)
  634.             {
  635.                 #emit LREF.S.pri start
  636.                 #emit SREF.S.pri addr
  637.                 start += 4;
  638.                 addr += 4;
  639.             }
  640.             //end += 4;
  641.             // JUMP
  642.             #emit CONST.pri      51
  643.             #emit SREF.S.pri     addr
  644.             addr += 4;
  645.             #emit LOAD.S.pri     idx
  646.             #emit SREF.S.pri     addr
  647.             // Blank with NOPs.
  648.             while (addr != end)
  649.             {
  650.                 addr += 4;
  651.                 #emit CONST.pri  134
  652.                 #emit SREF.S.pri addr
  653.             }
  654.             return 0;
  655.         }
  656.     }
  657. #endif
  658.  
  659. #if !defined ALS_PREFIX
  660.     //#error You must define a callback prefix before including y_als.
  661.     #define ALS_PREFIX Mode
  662. #endif
Advertisement
Add Comment
Please, Sign In to add comment