| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584 |
- // Copyright (C) 2012 Zeex
- //
- // Permission is hereby granted, free of charge, to any person obtaining a
- // copy of this software and associated documentation files (the "Software"),
- // to deal in the Software without restriction, including without limitation
- // the rights to use, copy, modify, merge, publish, distribute, sublicense,
- // and/or sell copies of the Software, and to permit persons to whom the
- // Software is furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- // DEALINGS IN THE SOFTWARE.
- #if defined DYNAMIC_CALL_INC
- #endinput
- #endif
- #define DYNAMIC_CALL_INC
- #include <a_samp>
- #include "amx_header"
- #include "amx_memory"
- #include "opcode"
- #if !defined DYNAMIC_CALL_MAX_ARGS
- #define DYNAMIC_CALL_MAX_ARGS 256
- #endif
- forward bool:Push(arg);
- forward bool:PushString(const string[]);
- forward bool:Pop(&arg = 0);
- forward Call(address, bool:auto_pop = true);
- forward SysreqC(index, bool:auto_pop = true);
- forward SysreqD(address, bool:auto_pop = true);
- forward CallN(address, args_to_push, bool:auto_pop = true);
- forward SysreqCN(index, args_to_push, bool:auto_pop = true);
- forward SysreqDN(address, args_to_push, bool:auto_pop = true);
- forward CallFunction(address, {Float,_}:...);
- forward CallNative(index, {Float,_}:...);
- forward CallNativeByAddress(address, {Float,_}:...);
- static stock g_nargs = 0;
- static stock g_args[DYNAMIC_CALL_MAX_ARGS];
- stock bool:Push(arg) {
- if (g_nargs < sizeof(g_args)) {
- g_args[g_nargs++] = arg;
- return true;
- }
- return false;
- }
- stock bool:PushString(const string[]) {
- new address;
- #emit load.s.pri string
- #emit stor.s.pri address
- return Push(address);
- }
- stock bool:Pop(&arg = 0) {
- if (g_nargs > 0) {
- arg = g_args[--g_nargs];
- return true;
- }
- return false;
- }
- stock Call(address, bool:auto_pop = true) {
- new arg = 0;
- new index = g_nargs;
- new bytes = g_nargs * 4;
- new retval;
- while (--index >= 0) {
- arg = g_args[index];
- #emit push.s arg
- }
- #emit load.s.pri bytes
- #emit push.pri
- #emit lctrl 6
- #emit add.c 0x1c
- #emit push.pri
- #emit load.s.pri address
- #emit sctrl 6
- #emit stor.s.pri retval
- if (auto_pop) {
- while (Pop()) {}
- }
- return retval;
- }
- stock CallN(address, args_to_push, bool:auto_pop = true) {
- // Like "Call", but doesn't pass all parameters.
- new arg = 0;
- new index = g_nargs;
- new bytes = args_to_push * 4;
- new end = g_nargs - args_to_push;
- new retval;
- if (end < 0) {
- return cellmin;
- }
- while (--index >= end) {
- arg = g_args[index];
- #emit push.s arg
- }
- #emit load.s.pri bytes
- #emit push.pri
- #emit lctrl 6
- #emit add.c 0x1c
- #emit push.pri
- #emit load.s.pri address
- #emit sctrl 6
- #emit stor.s.pri retval
- if (auto_pop) {
- while (args_to_push--) {
- Pop();
- }
- }
- return retval;
- }
- stock CallFunction(address, {Float,_}:...) {
- new arg_bytes, arg_begin, arg_end;
- // Get number of bytes passed.
- #emit load.s.pri 0x8
- #emit const.alt 4
- #emit sub
- #emit stor.s.pri arg_bytes
- #emit move.alt
- // Last argument is at FRM + 0x0C + arg_bytes (which is in ALT).
- #emit lctrl 5
- #emit add.c 0xc
- #emit add
- #emit stor.s.pri arg_end
- // Frist argument is at FRM + 0x10.
- #emit lctrl 5
- #emit add.c 0x10
- #emit stor.s.pri arg_begin
- new arg = arg_end;
- while (arg >= arg_begin) {
- #emit lref.s.pri arg
- #emit load.i
- #emit push.pri
- arg -= 4;
- }
- // Call the function
- #emit push.s arg_bytes
- #emit lctrl 6
- #emit add.c 0x1c
- #emit push.pri
- #emit load.s.pri address
- #emit sctrl 6
- // Arguments are popped by callee.
- // Pop locals and return.
- #emit stack 0x10
- #emit retn
- return 0; // make compiler happy
- }
- stock SysreqC(index, bool:auto_pop = true) {
- new arg = 0;
- new i = g_nargs;
- new bytes = g_nargs * 4;
- new tmp;
- new Opcode:sysreq_c = RelocateOpcode(OP_SYSREQ_C);
- new retval;
- while (--i >= 0) {
- arg = g_args[i];
- #emit push.s arg
- }
- #emit load.s.pri bytes
- #emit push.pri
- // tmp = cod + cip - dat + <distance to SYSREQ.C's operand>
- #emit lctrl 0 // COD
- #emit move.alt
- #emit lctrl 6 // CIP
- #emit add
- #emit move.alt
- #emit lctrl 1 // DAT
- #emit sub.alt
- #emit add.c 0x5c
- #emit stor.s.pri tmp
- // nop #1 = sysreq.c
- #emit load.s.pri sysreq_c
- #emit sref.s.pri tmp
- // tmp += 4
- #emit load.s.pri tmp
- #emit add.c 4
- #emit stor.s.pri tmp
- // nop #2 = index
- #emit load.s.pri index
- #emit sref.s.pri tmp
- #emit nop
- #emit nop
- #emit stor.s.pri retval
- // Pop native arguments.
- #emit lctrl 4
- #emit load.s.alt bytes
- #emit add
- #emit add.c 4
- #emit sctrl 4
- if (auto_pop) {
- while (Pop()) {}
- }
- return retval;
- }
- stock SysreqD(address, bool:auto_pop = true) {
- new arg = 0;
- new i = g_nargs;
- new bytes = g_nargs * 4;
- new tmp;
- new Opcode:sysreq_d = RelocateOpcode(OP_SYSREQ_D);
- new retval;
- while (--i >= 0) {
- arg = g_args[i];
- #emit push.s arg
- }
- #emit load.s.pri bytes
- #emit push.pri
- // tmp = cod + cip - dat + <distance to nop #1>
- #emit lctrl 0 // COD
- #emit move.alt
- #emit lctrl 6 // CIP
- #emit add
- #emit move.alt
- #emit lctrl 1 // DAT
- #emit sub.alt
- #emit add.c 0x5c
- #emit stor.s.pri tmp
- // nop #1 = sysreq.d
- #emit load.s.pri sysreq_d
- #emit sref.s.pri tmp
- // tmp += 4
- #emit load.s.pri tmp
- #emit add.c 4
- #emit stor.s.pri tmp
- // nop #2 = address
- #emit load.s.pri address
- #emit sref.s.pri tmp
- #emit nop
- #emit nop
- #emit stor.s.pri retval
- // Pop native arguments.
- #emit lctrl 4
- #emit load.s.alt bytes
- #emit add
- #emit add.c 4
- #emit sctrl 4
- if (auto_pop) {
- while (Pop()) {}
- }
- return retval;
- }
- stock SysreqCN(index, args_to_push, bool:auto_pop = true) {
- new arg = 0;
- new i = g_nargs;
- new bytes = args_to_push * 4;
- new tmp;
- new Opcode:sysreq_c = RelocateOpcode(OP_SYSREQ_C);
- new end = g_nargs - args_to_push;
- new retval;
- if (end < 0) {
- return cellmin;
- }
- while (--i >= end) {
- arg = g_args[i];
- #emit push.s arg
- }
- #emit load.s.pri bytes
- #emit push.pri
- // tmp = cod + cip - dat + <distance to SYSREQ.C's operand>
- #emit lctrl 0 // COD
- #emit move.alt
- #emit lctrl 6 // CIP
- #emit add
- #emit move.alt
- #emit lctrl 1 // DAT
- #emit sub.alt
- #emit add.c 0x5c
- #emit stor.s.pri tmp
- // nop #1 = sysreq.c
- #emit load.s.pri sysreq_c
- #emit sref.s.pri tmp
- // tmp += 4
- #emit load.s.pri tmp
- #emit add.c 4
- #emit stor.s.pri tmp
- // nop #2 = index
- #emit load.s.pri index
- #emit sref.s.pri tmp
- #emit nop
- #emit nop
- #emit stor.s.pri retval
- // Pop native arguments.
- #emit lctrl 4
- #emit load.s.alt bytes
- #emit add
- #emit add.c 4
- #emit sctrl 4
- if (auto_pop) {
- while (args_to_push--) {
- Pop();
- }
- }
- return retval;
- }
- stock SysreqDN(address, args_to_push, bool:auto_pop = true) {
- new arg = 0;
- new i = g_nargs;
- new bytes = args_to_push * 4;
- new tmp;
- new Opcode:sysreq_d = RelocateOpcode(OP_SYSREQ_D);
- new end = g_nargs - args_to_push;
- new retval;
- if (end < 0) {
- return cellmin;
- }
- while (--i >= end) {
- arg = g_args[i];
- #emit push.s arg
- }
- #emit load.s.pri bytes
- #emit push.pri
- // tmp = cod + cip - dat + <distance to nop #1>
- #emit lctrl 0 // COD
- #emit move.alt
- #emit lctrl 6 // CIP
- #emit add
- #emit move.alt
- #emit lctrl 1 // DAT
- #emit sub.alt
- #emit add.c 0x5c
- #emit stor.s.pri tmp
- // nop #1 = sysreq.d
- #emit load.s.pri sysreq_d
- #emit sref.s.pri tmp
- // tmp += 4
- #emit load.s.pri tmp
- #emit add.c 4
- #emit stor.s.pri tmp
- // nop #2 = address
- #emit load.s.pri address
- #emit sref.s.pri tmp
- #emit nop
- #emit nop
- #emit stor.s.pri retval
- // Pop native arguments.
- #emit lctrl 4
- #emit load.s.alt bytes
- #emit add
- #emit add.c 4
- #emit sctrl 4
- if (auto_pop) {
- while (args_to_push--) {
- Pop();
- }
- }
- return retval;
- }
- stock CallNative(index, {Float,_}:...) {
- new arg_bytes, arg_begin, arg_end;
- new Opcode:sysreq_c = RelocateOpcode(OP_SYSREQ_C);
- // Get number of bytes passed.
- #emit load.s.pri 0x8
- #emit const.alt 4
- #emit sub
- #emit stor.s.pri arg_bytes
- #emit move.alt
- // Last argument is at FRM + 0x0C + arg_bytes (which is in ALT).
- #emit lctrl 5
- #emit add.c 0xc
- #emit add
- #emit stor.s.pri arg_end
- // Frist argument is at FRM + 0x10.
- #emit lctrl 5
- #emit add.c 0x10
- #emit stor.s.pri arg_begin
- new arg = arg_end;
- new tmp;
- while (arg >= arg_begin) {
- #emit lref.s.pri arg
- #emit load.i
- #emit push.pri
- arg -= 4;
- }
- // Push number of arguments * 4 (which is params[0]).
- #emit push.s arg_bytes
- // tmp = cod + cip - dat + <distance to nop #1>
- #emit lctrl 0 // COD
- #emit move.alt
- #emit lctrl 6 // CIP
- #emit add
- #emit move.alt
- #emit lctrl 1 // DAT
- #emit sub.alt
- #emit add.c 0x5c
- #emit stor.s.pri tmp
- // nop #1 = sysreq.c
- #emit load.s.pri sysreq_c
- #emit sref.s.pri tmp
- // tmp += 4
- #emit load.s.pri tmp
- #emit add.c 4
- #emit stor.s.pri tmp
- // nop #2 = index
- #emit load.s.pri index
- #emit sref.s.pri tmp
- #emit nop
- #emit nop
- new retval;
- #emit stor.s.pri retval
- // Pop native arguments.
- #emit lctrl 4
- #emit load.s.alt arg_bytes
- #emit add
- #emit add.c 4
- #emit sctrl 4
- return retval;
- }
- // Unlike CallNative(), this function calls natives directly via SYSREQ.D.
- stock CallNativeByAddress(address, {Float,_}:...) {
- new arg_bytes, arg_begin, arg_end;
- new Opcode:sysreq_d = RelocateOpcode(OP_SYSREQ_D);
- // Get number of bytes passed.
- #emit load.s.pri 0x8
- #emit const.alt 4
- #emit sub
- #emit stor.s.pri arg_bytes
- #emit move.alt
- // Last argument is at FRM + 0x0C + arg_bytes (which is in ALT).
- #emit lctrl 5
- #emit add.c 0xc
- #emit add
- #emit stor.s.pri arg_end
- // Frist argument is at FRM + 0x10.
- #emit lctrl 5
- #emit add.c 0x10
- #emit stor.s.pri arg_begin
- new arg = arg_end;
- new tmp;
- while (arg >= arg_begin) {
- #emit lref.s.pri arg
- #emit load.i
- #emit push.pri
- arg -= 4;
- }
- // Push number of arguments * 4 (which is params[0]).
- #emit push.s arg_bytes
- // tmp = cod + cip - dat + <distance to nop #1>
- #emit lctrl 0 // COD
- #emit move.alt
- #emit lctrl 6 // CIP
- #emit add
- #emit move.alt
- #emit lctrl 1 // DAT
- #emit sub.alt
- #emit add.c 0x5c
- #emit stor.s.pri tmp
- // nop #1 = sysreq.d
- #emit load.s.pri sysreq_d
- #emit sref.s.pri tmp
- // tmp += 4
- #emit load.s.pri tmp
- #emit add.c 4
- #emit stor.s.pri tmp
- // nop #2 = address
- #emit load.s.pri address
- #emit sref.s.pri tmp
- #emit nop
- #emit nop
- new retval;
- #emit stor.s.pri retval
- // Pop native arguments.
- #emit lctrl 4
- #emit load.s.alt arg_bytes
- #emit add
- #emit add.c 4
- #emit sctrl 4
- return retval;
- }
|