Created
February 13, 2012 16:33
-
-
Save Zeex/1818028 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <assert.h> | |
#include <stddef.h> /* for size_t */ | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#if defined LINUX | |
#include <sys/mman.h> | |
#else | |
#include <Windows.h> | |
#endif | |
#if __STDC_VERSION__ >= 199901L | |
#define HAVE_STDINT_H 1 | |
#include <stdint.h> | |
#include <stdbool.h> | |
#else | |
typedef unsigned char bool; | |
enum { false, true }; | |
#endif | |
#if defined __GNUC__ | |
#if defined __CYGWIN__ || defined __MINGW32__ | |
#define PLUGIN_CALL __attribute__((stdcall)) | |
#else | |
#define PLUGIN_CALL __attribute__((cdecl)) | |
#endif | |
#define PLUGIN_EXPORT __attribute__((visibility("default"))) | |
#elif defined _MSC_VER | |
#define PLUGIN_CALL __stdcall | |
#define PLUGIN_EXPORT __declspec(dllexport) | |
#endif | |
#if !defined(__BYTE_ORDER) | |
/* we are targeting x86 which is Little Endian */ | |
#define __LITTLE_ENDIAN 1234 | |
#define __BYTE_ORDER __LITTLE_ENDIAN | |
#endif | |
#include <amx/amx.h> | |
#include <lightning.h> | |
#define NOT_IMPLEMENTED(op) \ | |
do { \ | |
logprintf("JIT: the " op " instruction is not implemented"); \ | |
abort(); \ | |
} while (false) | |
typedef void (*logprintf_t)(const char *format, ...); | |
/* maximum size of generated JIT code */ | |
#define MAX_JIT_SIZE 10240 | |
/* opcode list from amx.c */ | |
typedef enum { | |
OP_NONE, /* invalid opcode */ | |
OP_LOAD_PRI, | |
OP_LOAD_ALT, | |
OP_LOAD_S_PRI, | |
OP_LOAD_S_ALT, | |
OP_LREF_PRI, | |
OP_LREF_ALT, | |
OP_LREF_S_PRI, | |
OP_LREF_S_ALT, | |
OP_LOAD_I, | |
OP_LODB_I, | |
OP_CONST_PRI, | |
OP_CONST_ALT, | |
OP_ADDR_PRI, | |
OP_ADDR_ALT, | |
OP_STOR_PRI, | |
OP_STOR_ALT, | |
OP_STOR_S_PRI, | |
OP_STOR_S_ALT, | |
OP_SREF_PRI, | |
OP_SREF_ALT, | |
OP_SREF_S_PRI, | |
OP_SREF_S_ALT, | |
OP_STOR_I, | |
OP_STRB_I, | |
OP_LIDX, | |
OP_LIDX_B, | |
OP_IDXADDR, | |
OP_IDXADDR_B, | |
OP_ALIGN_PRI, | |
OP_ALIGN_ALT, | |
OP_LCTRL, | |
OP_SCTRL, | |
OP_MOVE_PRI, | |
OP_MOVE_ALT, | |
OP_XCHG, | |
OP_PUSH_PRI, | |
OP_PUSH_ALT, | |
OP_PUSH_R, | |
OP_PUSH_C, | |
OP_PUSH, | |
OP_PUSH_S, | |
OP_POP_PRI, | |
OP_POP_ALT, | |
OP_STACK, | |
OP_HEAP, | |
OP_PROC, | |
OP_RET, | |
OP_RETN, | |
OP_CALL, | |
OP_CALL_PRI, | |
OP_JUMP, | |
OP_JREL, | |
OP_JZER, | |
OP_JNZ, | |
OP_JEQ, | |
OP_JNEQ, | |
OP_JLESS, | |
OP_JLEQ, | |
OP_JGRTR, | |
OP_JGEQ, | |
OP_JSLESS, | |
OP_JSLEQ, | |
OP_JSGRTR, | |
OP_JSGEQ, | |
OP_SHL, | |
OP_SHR, | |
OP_SSHR, | |
OP_SHL_C_PRI, | |
OP_SHL_C_ALT, | |
OP_SHR_C_PRI, | |
OP_SHR_C_ALT, | |
OP_SMUL, | |
OP_SDIV, | |
OP_SDIV_ALT, | |
OP_UMUL, | |
OP_UDIV, | |
OP_UDIV_ALT, | |
OP_ADD, | |
OP_SUB, | |
OP_SUB_ALT, | |
OP_AND, | |
OP_OR, | |
OP_XOR, | |
OP_NOT, | |
OP_NEG, | |
OP_INVERT, | |
OP_ADD_C, | |
OP_SMUL_C, | |
OP_ZERO_PRI, | |
OP_ZERO_ALT, | |
OP_ZERO, | |
OP_ZERO_S, | |
OP_SIGN_PRI, | |
OP_SIGN_ALT, | |
OP_EQ, | |
OP_NEQ, | |
OP_LESS, | |
OP_LEQ, | |
OP_GRTR, | |
OP_GEQ, | |
OP_SLESS, | |
OP_SLEQ, | |
OP_SGRTR, | |
OP_SGEQ, | |
OP_EQ_C_PRI, | |
OP_EQ_C_ALT, | |
OP_INC_PRI, | |
OP_INC_ALT, | |
OP_INC, | |
OP_INC_S, | |
OP_INC_I, | |
OP_DEC_PRI, | |
OP_DEC_ALT, | |
OP_DEC, | |
OP_DEC_S, | |
OP_DEC_I, | |
OP_MOVS, | |
OP_CMPS, | |
OP_FILL, | |
OP_HALT, | |
OP_BOUNDS, | |
OP_SYSREQ_PRI, | |
OP_SYSREQ_C, | |
OP_FILE, /* obsolete */ | |
OP_LINE, /* obsolete */ | |
OP_SYMBOL, /* obsolete */ | |
OP_SRANGE, /* obsolete */ | |
OP_JUMP_PRI, | |
OP_SWITCH, | |
OP_CASETBL, | |
OP_SWAP_PRI, | |
OP_SWAP_ALT, | |
OP_PUSHADDR, | |
OP_NOP, | |
OP_SYSREQ_D, | |
OP_SYMTAG, /* obsolete */ | |
OP_BREAK, | |
/* ----- */ | |
NUM_OPCODES | |
} OPCODE; | |
static logprintf_t logprintf; | |
struct list { | |
int key; | |
void *value; | |
struct list *next; | |
}; | |
struct fn_info { | |
cell amx_address; | |
void *jit_address; | |
bool is_public; | |
struct list *refs; | |
}; | |
struct fn_ref { | |
void *where; | |
}; | |
struct amx_info { | |
jit_insn *jit_code; | |
size_t jit_code_size; | |
}; | |
static struct list *amx_list; | |
static void list_insert(struct list **root, int key, void *value) { | |
struct list *node; | |
node = malloc(sizeof(struct list)); | |
node->key = key; | |
node->value = value; | |
node->next = *root; | |
*root = node; | |
} | |
static void *list_get(struct list *root, int key) { | |
struct list *cur; | |
cur = root; | |
while (cur != NULL) { | |
if (cur->key == key) { | |
return cur->value; | |
} | |
cur = cur->next; | |
} | |
return NULL; | |
} | |
static void *list_remove(struct list *root, int key) { | |
struct list *cur; | |
struct list *prev; | |
void *value; | |
cur = root; | |
prev = NULL; | |
while (cur != NULL) { | |
if (cur->key == key) { | |
value = cur->value; | |
if (prev != NULL) { | |
prev->next = cur->next; | |
} | |
free(cur); | |
return value; | |
} | |
prev = cur; | |
cur = cur->next; | |
} | |
return NULL; | |
} | |
static void list_free(struct list **root) { | |
struct list *cur; | |
struct list *prev; | |
cur = *root; | |
prev = NULL; | |
while (cur != NULL) { | |
prev = cur; | |
cur = cur->next; | |
free(prev); | |
} | |
*root = NULL; | |
} | |
static int find_public(AMX *amx, cell address) { | |
AMX_HEADER *hdr; | |
AMX_FUNCSTUBNT *publics; | |
int index, num_publics; | |
hdr = (AMX_HEADER*)amx->base; | |
publics = (AMX_FUNCSTUBNT*)(amx->base + hdr->publics); | |
num_publics = (hdr->natives - hdr->publics) / hdr->defsize; | |
for (index = 0; index < num_publics; index++) { | |
if (publics[index].address == address) { | |
return index; | |
} | |
} | |
return -1; | |
} | |
static bool is_public(AMX *amx, cell address) { | |
AMX_HEADER *hdr; | |
hdr = (AMX_HEADER*)amx->base; | |
if (address == hdr->cip) { | |
/* main() */ | |
return true; | |
} | |
return find_public(amx, address) >= 0; | |
} | |
static int set_public_address(AMX *amx, int index, cell address) { | |
AMX_HEADER *hdr; | |
AMX_FUNCSTUBNT *publics; | |
hdr = (AMX_HEADER*)amx->base; | |
publics = (AMX_FUNCSTUBNT*)(amx->base + hdr->publics); | |
if (index >= 0) { | |
publics[index].address = address; | |
} | |
return index; | |
} | |
static void *get_public_address(AMX *amx, cell index) { | |
AMX_HEADER *hdr; | |
AMX_FUNCSTUBNT *publics; | |
hdr = (AMX_HEADER*)amx->base; | |
publics = (AMX_FUNCSTUBNT*)(amx->base + hdr->publics); | |
return (void*)publics[index].address; | |
} | |
static void *get_native_address(AMX *amx, cell index) { | |
AMX_HEADER *hdr; | |
AMX_FUNCSTUBNT *natives; | |
hdr = (AMX_HEADER*)amx->base; | |
natives = (AMX_FUNCSTUBNT*)(amx->base + hdr->natives); | |
return (void*)natives[index].address; | |
} | |
static void dump_jit_code(const char *filename, jit_insn *code, size_t size) { | |
FILE *stream; | |
if ((stream = fopen(filename, "w")) != NULL) { | |
fwrite(code, sizeof(jit_insn), size, stream); | |
fclose(stream); | |
} | |
} | |
static void jit_amx(AMX *amx, jit_insn *jitcode, size_t size) | |
{ | |
AMX_HEADER *hdr; | |
unsigned char *code, *data; | |
cell code_size, data_size; | |
cell *cip, opcode, arg; | |
struct list *fn_list = NULL; | |
struct fn_info *fn; | |
jit_insn **amx2jit; | |
jit_set_ip(jitcode); | |
hdr = (AMX_HEADER*)amx->base; | |
code = amx->base + hdr->cod; | |
code_size = hdr->dat - hdr->cod; | |
/* maps AMX code to JIT */ | |
amx2jit = malloc(sizeof(*amx2jit) * code_size); | |
data = (amx->data != 0) ? amx->data : amx->base + hdr->dat; | |
data_size = hdr->hea - hdr->dat; | |
cip = (cell*)(code + hdr->cip); | |
while ((int)cip < (int)(code + code_size)) { | |
amx2jit[(int)cip - (int)code] = jit_get_label(); | |
opcode = *cip++; | |
arg = *cip; | |
switch (opcode) { | |
case OP_LOAD_PRI: /* address */ | |
/* PRI = [address] */ | |
jit_movi_i(JIT_V0, (int)(data + arg)); | |
jit_ldr_i(JIT_R0, JIT_V0); | |
cip++; | |
break; | |
case OP_LOAD_ALT: /* address */ | |
/* PRI = [address] */ | |
jit_movi_i(JIT_V0, (int)(data + arg)); | |
jit_ldr_i(JIT_R1, JIT_V0); | |
cip++; | |
break; | |
case OP_LOAD_S_PRI: /* offset */ | |
/* PRI = [FRM + offset] */ | |
jit_addi_i(JIT_V0, JIT_FP, arg); | |
jit_ldr_i(JIT_R0, JIT_V0); | |
cip++; | |
break; | |
case OP_LOAD_S_ALT: /* offset */ | |
/* ALT = [FRM + offset] */ | |
jit_addi_i(JIT_V0, JIT_FP, arg); | |
jit_ldr_i(JIT_R1, JIT_V0); | |
cip++; | |
break; | |
case OP_LREF_PRI: /* address */ | |
/* PRI = [ [address] ] */ | |
jit_movi_i(JIT_V0, (int)(data + arg)); | |
jit_ldr_i(JIT_V0, JIT_V0); | |
jit_ldr_i(JIT_R0, JIT_V0); | |
cip++; | |
break; | |
case OP_LREF_ALT: /* address */ | |
/* ALT = [ [address] ] */ | |
jit_movi_i(JIT_V0, (int)(data + arg)); | |
jit_ldr_i(JIT_V0, JIT_V0); | |
jit_ldr_i(JIT_R1, JIT_V0); | |
cip++; | |
break; | |
case OP_LREF_S_PRI: /* offset */ | |
/* PRI = [ [FRM + offset] ] */ | |
jit_addi_i(JIT_V0, JIT_FP, arg); | |
jit_ldr_i(JIT_V0, JIT_V0); | |
jit_ldr_i(JIT_R0, JIT_V0); | |
cip++; | |
break; | |
case OP_LREF_S_ALT: /* offset */ | |
/* PRI = [ [FRM + offset] ] */ | |
jit_addi_i(JIT_V0, JIT_FP, arg); | |
jit_ldr_i(JIT_V0, JIT_V0); | |
jit_ldr_i(JIT_R1, JIT_V0); | |
cip++; | |
break; | |
case OP_LOAD_I: | |
/* PRI = [PRI] (full cell) */ | |
jit_ldr_i(JIT_R0, JIT_R0); | |
break; | |
case OP_LODB_I: /* number */ | |
/* PRI = “number” bytes from [PRI] (read 1/2/4 bytes) */ | |
switch (arg) { | |
case 1: | |
jit_ldr_c(JIT_R0, JIT_R0); | |
break; | |
case 2: | |
jit_ldr_s(JIT_R0, JIT_R0); | |
break; | |
default: | |
jit_ldr_i(JIT_R0, JIT_R0); | |
} | |
cip++; | |
break; | |
case OP_CONST_PRI: /* value */ | |
/* PRI = value */ | |
jit_movr_i(JIT_R0, arg); | |
cip++; | |
break; | |
case OP_CONST_ALT: /* value */ | |
/* ALT = value */ | |
jit_movr_i(JIT_R1, arg); | |
cip++; | |
break; | |
case OP_ADDR_PRI: /* offset */ | |
/* PRI = FRM + offset */ | |
jit_addi_i(JIT_R0, JIT_FP, arg); | |
cip++; | |
break; | |
case OP_ADDR_ALT: /* offset */ | |
/* ALT = FRM + offset */ | |
jit_addi_i(JIT_R1, JIT_FP, arg); | |
cip++; | |
break; | |
case OP_STOR_PRI: /* address */ | |
/* [address] = PRI */ | |
jit_sti_i((int)(data + arg), JIT_R0); | |
cip++; | |
break; | |
case OP_STOR_ALT: /* address */ | |
/* [address] = ALT */ | |
jit_sti_i((int)(data + arg), JIT_R1); | |
cip++; | |
break; | |
case OP_STOR_S_PRI: /* offset */ | |
/* [FRM + offset] = ALT */ | |
jit_addi_i(JIT_V0, JIT_FP, arg); | |
jit_str_i(JIT_V0, JIT_R0); | |
cip++; | |
break; | |
case OP_STOR_S_ALT: /* offset */ | |
/* [FRM + offset] = ALT */ | |
jit_addi_i(JIT_V0, JIT_FP, arg); | |
jit_str_i(JIT_V0, JIT_R1); | |
cip++; | |
break; | |
case OP_SREF_PRI: /* address */ | |
/* [ [address] ] = PRI */ | |
jit_movi_i(JIT_V0, (int)(data + arg)); | |
jit_ldr_i(JIT_V0, JIT_V0); | |
jit_str_i(JIT_V0, JIT_R0); | |
cip++; | |
break; | |
case OP_SREF_ALT: /* address */ | |
/* [ [address] ] = ALT */ | |
jit_movi_i(JIT_V0, (int)(data + arg)); | |
jit_ldr_i(JIT_V0, JIT_V0); | |
jit_str_i(JIT_V0, JIT_R1); | |
cip++; | |
break; | |
case OP_SREF_S_PRI: /* offset */ | |
/* [ [FRM + offset] ] = PRI */ | |
jit_addi_i(JIT_V0, JIT_FP, arg); | |
jit_ldr_i(JIT_V0, JIT_V0); | |
jit_str_i(JIT_V0, JIT_R0); | |
cip++; | |
break; | |
case OP_SREF_S_ALT: /* offset */ | |
/* [ [FRM + offset] ] = ALT */ | |
jit_addi_i(JIT_V0, JIT_FP, arg); | |
jit_ldr_i(JIT_V0, JIT_V0); | |
jit_str_i(JIT_V0, JIT_R1); | |
cip++; | |
break; | |
case OP_STOR_I: | |
/* [ALT] = PRI (full cell) */ | |
jit_ldr_i(JIT_R1, JIT_R0); | |
break; | |
case OP_STRB_I: /* number */ | |
/* “number” bytes at [ALT] = PRI (write 1/2/4 bytes) */ | |
switch (arg) { | |
case 1: | |
jit_str_c(JIT_R1, JIT_R0); | |
break; | |
case 2: | |
jit_str_s(JIT_R1, JIT_R0); | |
break; | |
default: | |
jit_str_i(JIT_R1, JIT_R0); | |
} | |
cip++; | |
break; | |
case OP_LIDX: | |
/* PRI = [ ALT + (PRI x cell size) ] */ | |
jit_muli_ui(JIT_V0, JIT_R0, sizeof(cell)); | |
jit_addr_i(JIT_V0, JIT_R1, JIT_V0); | |
jit_ldr_i(JIT_R0, JIT_V0); | |
break; | |
case OP_LIDX_B: /* shift */ | |
/* PRI = [ ALT + (PRI << shift) ] */ | |
jit_muli_ui(JIT_V0, JIT_R0, arg); | |
jit_addr_i(JIT_V0, JIT_R1, JIT_V0); | |
jit_ldr_i(JIT_R0, JIT_V0); | |
cip++; | |
break; | |
case OP_IDXADDR: | |
/* PRI = ALT + (PRI x cell size) (calculate indexed address) */ | |
jit_muli_ui(JIT_V0, JIT_R0, sizeof(cell)); | |
jit_addr_i(JIT_R0, JIT_R1, JIT_V0); | |
break; | |
case OP_IDXADDR_B: /* shift */ | |
/* PRI = ALT + (PRI << shift) (calculate indexed address) */ | |
jit_muli_ui(JIT_V0, JIT_R0, arg); | |
jit_addr_i(JIT_R0, JIT_R1, JIT_V0); | |
cip++; | |
break; | |
case OP_ALIGN_PRI: /* number */ | |
/* Little Endian: PRI ^= cell size - number */ | |
#if __BYTE_ORDER == __LITTLE_ENDIAN | |
jit_xori_i(JIT_R0, JIT_R0, sizeof(cell) - arg); | |
#endif | |
cip++; | |
break; | |
case OP_ALIGN_ALT: /* number */ | |
/* Little Endian: ALT ^= cell size - number */ | |
#if __BYTE_ORDER == __LITTLE_ENDIAN | |
jit_xori_i(JIT_R1, JIT_R0, sizeof(cell) - arg); | |
#endif | |
cip++; | |
break; | |
case OP_LCTRL: /* index */ | |
/* PRI is set to the current value of any of the special registers. | |
* The index parameter must be: 0=COD, 1=DAT, 2=HEA, | |
* 3=STP, 4=STK, 5=FRM, 6=CIP (of the next instruction) | |
*/ | |
NOT_IMPLEMENTED("LCTRL"); | |
break; | |
case OP_SCTRL: /* index */ | |
/* set the indexed special registers to the value in PRI. | |
* The index parameter must be: 2=HEA, 4=STK, 5=FRM, | |
* 6=CIP | |
*/ | |
NOT_IMPLEMENTED("SCTRL"); | |
break; | |
case OP_MOVE_PRI: | |
/* PRI = ALT */ | |
jit_movr_i(JIT_R0, JIT_R1); | |
break; | |
case OP_MOVE_ALT: | |
/* ALT = PRI */ | |
jit_movr_i(JIT_R1, JIT_R0); | |
break; | |
case OP_XCHG: | |
/* Exchange PRI and ALT */ | |
jit_movr_i(JIT_V0, JIT_R0); | |
jit_movr_i(JIT_R0, JIT_R1); | |
jit_movr_i(JIT_R1, JIT_V0); | |
break; | |
case OP_PUSH_PRI: | |
/* [STK] = PRI/ALT, STK = STK - cell size */ | |
jit_ldr_i(JIT_SP, JIT_R0); | |
jit_subi_i(JIT_SP, JIT_SP, (int)sizeof(int)); | |
break; | |
case OP_PUSH_ALT: | |
jit_ldr_i(JIT_SP, JIT_R1); | |
jit_subi_i(JIT_SP, JIT_SP, (int)sizeof(int)); | |
break; | |
case OP_PUSH_R: /* value */ | |
/* obsolete */ | |
break; | |
case OP_PUSH_C: /* value */ | |
/* [STK] = value, STK = STK - cell size */ | |
jit_movi_i(JIT_V0, arg); | |
jit_str_i(JIT_SP, JIT_V0); | |
jit_subi_i(JIT_SP, JIT_SP, (int)sizeof(int)); | |
cip++; | |
break; | |
case OP_PUSH: /* address */ | |
/* [STK] = [address], STK = STK - cell size */ | |
jit_ldi_i(JIT_V0, (int)(data + arg)); | |
jit_ldr_i(JIT_SP, JIT_V0); | |
jit_subi_i(JIT_SP, JIT_SP, (int)sizeof(int)); | |
cip++; | |
break; | |
case OP_PUSH_S: /* offset */ | |
/* [STK] = [FRM + offset], STK = STK - cell size */ | |
jit_ldxi_i(JIT_SP, JIT_FP, arg); | |
jit_subi_i(JIT_SP, JIT_SP, (int)sizeof(int)); | |
cip++; | |
break; | |
case OP_POP_PRI: | |
/* STK = STK + cell size, PRI = [STK] */ | |
jit_ldr_i(JIT_R0, JIT_SP); | |
jit_addi_i(JIT_SP, JIT_SP, (int)sizeof(int)); | |
break; | |
case OP_POP_ALT: | |
/* STK = STK + cell size, ALT = [STK] */ | |
jit_ldr_i(JIT_R1, JIT_SP); | |
jit_addi_i(JIT_SP, JIT_SP, (int)sizeof(int)); | |
break; | |
case OP_STACK: /* value */ | |
/* ALT = STK, STK = STK + value */ | |
jit_movr_i(JIT_R1, JIT_SP); | |
jit_addi_i(JIT_SP, JIT_SP, arg); | |
cip++; | |
break; | |
case OP_HEAP: | |
NOT_IMPLEMENTED("HEAP"); | |
break; | |
case OP_PROC: | |
/* [STK] = FRM, STK = STK - cell size, FRM = STK */ | |
fn = list_get(fn_list, (int)(cip - 1) - (int)code); | |
if (fn == NULL) { | |
fn = malloc(sizeof(*fn)); | |
fn->amx_address = (int)(cip - 1) - (int)code; | |
fn->jit_address = jit_get_ip().vptr; | |
fn->is_public = is_public(amx, fn->amx_address); | |
fn->refs = NULL; /* no references */ | |
if (fn->amx_address == hdr->cip) { | |
hdr->cod = (cell)fn->jit_address; | |
} else { | |
set_public_address(amx, find_public(amx, fn->amx_address), (cell)fn->jit_address); | |
} | |
list_insert(&fn_list, fn->amx_address, fn); | |
} else { | |
fn->jit_address = jit_get_ip().vptr; | |
} | |
if (fn->is_public) { | |
jit_prolog(0); | |
} else { | |
jit_str_i(JIT_SP, JIT_FP); | |
jit_subi_i(JIT_SP, JIT_SP, (int)sizeof(cell)); | |
jit_movr_i(JIT_FP, JIT_SP); | |
} | |
break; | |
case OP_RET: | |
/* STK = STK + cell size, FRM = [STK], | |
* STK = STK + cell size, CIP = [STK], | |
* The RET instruction cleans up the stack frame and returns | |
* from the function to the instruction after the call. | |
*/ | |
if (fn->is_public) { | |
jit_ret(); | |
} else { | |
jit_addi_i(JIT_SP, JIT_SP, sizeof(cell)); | |
jit_ldr_i(JIT_FP, JIT_SP); | |
jit_addi_i(JIT_SP, JIT_SP, sizeof(cell)); | |
jit_ldr_i(JIT_V0, JIT_SP); | |
jit_jmpr(JIT_V0); | |
} | |
break; | |
case OP_RETN: | |
/* FRM = [STK], STK = STK + cell size, | |
* CIP = [STK], STK = STK + cell size, | |
* STK = STK + [STK] | |
* The RETN instruction removes a specified number of bytes | |
* from the stack. The value to adjust STK with must be | |
* pushed prior to the call. | |
*/ | |
if (fn->is_public) { | |
jit_ret(); | |
} else { | |
jit_ldr_i(JIT_FP, JIT_SP); /* [SP] = FP */ | |
jit_addi_i(JIT_SP, JIT_SP, sizeof(cell)); /* SP += sizeof(cell) */ | |
jit_ldr_i(JIT_V0, JIT_SP); /* V0 = [SP] ; return address */ | |
jit_addi_i(JIT_SP, JIT_SP, sizeof(cell)); /* SP += sizeof(cell) */ | |
jit_ldr_i(JIT_V1, JIT_SP); /* V1 = [SP] ; number of bytes */ | |
jit_addr_i(JIT_SP, JIT_SP, JIT_V1); /* SP += V1 ; pop arguments */ | |
jit_jmpr(JIT_V0); /* JUMP [V0] */ | |
} | |
break; | |
case OP_CALL: { | |
/* [STK] = CIP + 5, STK = STK - cell size | |
* CIP = CIP + offset | |
* The CALL instruction jumps to an address after storing the | |
* address of the next sequential instruction on the stack. | |
* The address jumped to is relative to the current CIP, | |
* but the address on the stack is an absolute address. | |
*/ | |
struct fn_info *callee; | |
callee = list_get(fn_list, arg - (int)code); | |
if (callee == NULL) { | |
callee = malloc(sizeof(*callee)); | |
callee->amx_address = arg - (int)code; | |
callee->jit_address = NULL; /* don't know the address yet */ | |
callee->is_public = is_public(amx, callee->amx_address); | |
callee->refs = NULL; /* no references */ | |
list_insert(&fn_list, callee->amx_address, callee); | |
} | |
if (callee->is_public) { | |
list_insert(&(callee->refs), (int)jit_get_ip().ptr, NULL); | |
jit_calli(0); | |
} else { | |
jit_insn *ref; | |
jit_movi_i(JIT_V0, (int)jit_forward()); | |
ref = jit_forward(); | |
jit_str_i(JIT_SP, JIT_V0); | |
list_insert(&(callee->refs), (int)jit_get_ip().ptr, NULL); | |
jit_jmpr(0); | |
/* HACK: subtract "ref" from IP to make jit_patch() insert | |
* an absolute address. | |
*/ | |
jit_set_ip((jit_insn*)((int)jit_get_ip().ptr + (int)ref)); | |
jit_patch((int)ref); | |
jit_set_ip((jit_insn*)((int)jit_get_ip().ptr - (int)ref)); | |
} | |
cip++; | |
break; | |
} | |
case OP_CALL_PRI: | |
/* obsolete */ | |
break; | |
case OP_JUMP: /* offset */ | |
/* CIP = CIP + offset (jump to the address relative from | |
* the current position) | |
*/ | |
NOT_IMPLEMENTED("JUMP"); | |
break; | |
case OP_JREL: /* offset */ | |
/* obsolete */ | |
break; | |
case OP_JZER: /* offset */ | |
/* if PRI == 0 then CIP = CIP + offset */ | |
NOT_IMPLEMENTED("JZER"); | |
break; | |
case OP_JNZ: /* offset */ | |
/* if PRI != 0 then CIP = CIP + offset */ | |
NOT_IMPLEMENTED("JNZ"); | |
break; | |
case OP_JEQ: /* offset */ | |
/* if PRI == ALT then CIP = CIP + offset */ | |
NOT_IMPLEMENTED("JEQ"); | |
break; | |
case OP_JNEQ: /* offset */ | |
/* if PRI != ALT then CIP = CIP + offset */ | |
NOT_IMPLEMENTED("JNEQ"); | |
break; | |
case OP_JLESS: /* offset */ | |
/* if PRI < ALT then CIP = CIP + offset (unsigned) */ | |
NOT_IMPLEMENTED("JLESS"); | |
break; | |
case OP_JLEQ: /* offset */ | |
/* if PRI <= ALT then CIP = CIP + offset (unsigned) */ | |
NOT_IMPLEMENTED("JLEQ"); | |
break; | |
case OP_JGRTR: /* offset */ | |
/* if PRI > ALT then CIP = CIP + offset (unsigned) */ | |
NOT_IMPLEMENTED("JGRTR"); | |
break; | |
case OP_JGEQ: /* offset */ | |
/* if PRI >= ALT then CIP = CIP + offset (unsigned) */ | |
NOT_IMPLEMENTED("JGEQ"); | |
break; | |
case OP_JSLESS: /* offset */ | |
/* if PRI < ALT then CIP = CIP + offset (signed) */ | |
NOT_IMPLEMENTED("JLESS"); | |
break; | |
case OP_JSLEQ: /* offset */ | |
/* if PRI <= ALT then CIP = CIP + offset (signed) */ | |
NOT_IMPLEMENTED("JSLEQ"); | |
break; | |
case OP_JSGRTR: /* offset */ | |
/* if PRI > ALT then CIP = CIP + offset (signed) */ | |
NOT_IMPLEMENTED("JSGRTR"); | |
break; | |
case OP_JSGEQ: /* offset */ | |
/* if PRI >= ALT then CIP = CIP + offset (signed) */ | |
NOT_IMPLEMENTED("JSGEQ"); | |
break; | |
case OP_SHL: | |
/* PRI = PRI << ALT */ | |
jit_lshr_ui(JIT_R0, JIT_R0, JIT_R1); | |
break; | |
case OP_SHR: | |
/* PRI = PRI >> ALT (without sign extension) */ | |
jit_rshr_ui(JIT_R0, JIT_R0, JIT_R1); | |
break; | |
case OP_SSHR: | |
/* PRI = PRI >> ALT with sign extension */ | |
jit_rshr_i(JIT_R0, JIT_R0, JIT_R1); | |
break; | |
case OP_SHL_C_PRI: /* value */ | |
/* PRI = PRI << value */ | |
jit_lshi_ui(JIT_R0, JIT_R0, arg); | |
cip++; | |
break; | |
case OP_SHL_C_ALT: /* value */ | |
/* ALT = ALT << value */ | |
jit_lshi_ui(JIT_R1, JIT_R1, arg); | |
cip++; | |
break; | |
case OP_SHR_C_PRI: /* value */ | |
/* PRI = PRI >> value (without sign extension) */ | |
jit_rshr_ui(JIT_R0, JIT_R0, arg); | |
cip++; | |
break; | |
case OP_SHR_C_ALT: /* value */ | |
/* PRI = PRI >> value (without sign extension) */ | |
jit_rshr_ui(JIT_R1, JIT_R1, arg); | |
cip++; | |
break; | |
case OP_SMUL: | |
/* PRI = PRI * ALT (signed multiply) */ | |
jit_mulr_i(JIT_R0, JIT_R0, JIT_R1); | |
break; | |
case OP_SDIV: | |
/* PRI = PRI / ALT (signed divide), ALT = PRI mod ALT */ | |
jit_divr_i(JIT_R0, JIT_R0, JIT_R1); | |
jit_modr_i(JIT_R1, JIT_R0, JIT_R1); | |
break; | |
case OP_SDIV_ALT: | |
/* PRI = ALT / PRI (signed divide), ALT = ALT mod PRI */ | |
jit_divr_i(JIT_R0, JIT_R1, JIT_R0); | |
jit_modr_i(JIT_R1, JIT_R1, JIT_R0); | |
break; | |
case OP_UMUL: | |
/* PRI = PRI * ALT (unsigned multiply) */ | |
jit_mulr_ui(JIT_R0, JIT_R0, JIT_R1); | |
break; | |
case OP_UDIV: | |
/* PRI = PRI / ALT (unsigned divide), ALT = PRI mod ALT */ | |
jit_divr_ui(JIT_R0, JIT_R0, JIT_R1); | |
jit_modr_ui(JIT_R1, JIT_R0, JIT_R1); | |
break; | |
case OP_UDIV_ALT: | |
/* PRI = ALT / PRI (unsigned divide), ALT = ALT mod PRI */ | |
jit_divr_ui(JIT_R0, JIT_R1, JIT_R0); | |
jit_modr_ui(JIT_R1, JIT_R1, JIT_R0); | |
break; | |
case OP_ADD: | |
/* PRI = PRI + ALT */ | |
jit_addr_i(JIT_R0, JIT_R0, JIT_R1); | |
break; | |
case OP_SUB: | |
/* PRI = PRI - ALT */ | |
jit_subr_i(JIT_R0, JIT_R0, JIT_R1); | |
break; | |
case OP_SUB_ALT: | |
/* PRI = ALT - PRI */ | |
jit_subr_i(JIT_R0, JIT_R1, JIT_R0); | |
break; | |
case OP_AND: | |
/* PRI = PRI & ALT */ | |
jit_andr_i(JIT_R0, JIT_R0, JIT_R1); | |
break; | |
case OP_OR: | |
/* PRI = PRI | ALT */ | |
jit_orr_i(JIT_R0, JIT_R0, JIT_R1); | |
break; | |
case OP_XOR: | |
/* PRI = PRI ^ ALT */ | |
jit_xorr_i(JIT_R0, JIT_R0, JIT_R1); | |
break; | |
case OP_NOT: | |
/* PRI = !PRI */ | |
jit_eqi_i(JIT_R0, JIT_R0, 0); | |
break; | |
case OP_NEG: | |
/* PRI = -PRI */ | |
jit_negr_i(JIT_R0, JIT_R0); | |
break; | |
case OP_INVERT: | |
/* PRI = ~PRI */ | |
jit_notr_i(JIT_R0, JIT_R0); | |
break; | |
case OP_ADD_C: /* value */ | |
/* PRI = PRI + value */ | |
jit_addr_i(JIT_R0, JIT_R0, arg); | |
cip++; | |
break; | |
case OP_SMUL_C: /* value */ | |
/* PRI = PRI * value */ | |
jit_mulr_i(JIT_R0, JIT_R0, arg); | |
cip++; | |
break; | |
case OP_ZERO_PRI: | |
/* PRI = 0 */ | |
jit_movi_i(JIT_R0, 0); | |
break; | |
case OP_ZERO_ALT: | |
/* ALT = 0 */ | |
jit_movi_i(JIT_R1, 0); | |
break; | |
case OP_ZERO: /* address */ | |
/* [address] = 0 */ | |
jit_sti_i((int)(data + arg), 0); | |
cip++; | |
break; | |
case OP_ZERO_S: /* offset */ | |
/* [FRM + offset] = 0 */ | |
jit_addi_i(JIT_V0, JIT_FP, arg); | |
jit_sti_i(JIT_V0, 0); | |
cip++; | |
break; | |
case OP_SIGN_PRI: | |
/* sign extent the byte in PRI to a cell */ | |
jit_extr_c_i(JIT_R0, JIT_R0); | |
break; | |
case OP_SIGN_ALT: | |
/* sign extent the byte in ALT to a cell */ | |
jit_extr_c_i(JIT_R1, JIT_R1); | |
break; | |
case OP_EQ: | |
/* PRI = PRI == ALT ? 1 : 0 */ | |
jit_eqr_i(JIT_R0, JIT_R0, JIT_R1); | |
break; | |
case OP_NEQ: | |
/* PRI = PRI != ALT ? 1 : 0 */ | |
jit_ner_i(JIT_R0, JIT_R0, JIT_R1); | |
break; | |
case OP_LESS: | |
/* PRI = PRI < ALT ? 1 : 0 (unsigned) */ | |
jit_ltr_ui(JIT_R0, JIT_R0, JIT_R1); | |
break; | |
case OP_LEQ: | |
/* PRI = PRI <= ALT ? 1 : 0 (unsigned) */ | |
jit_ler_ui(JIT_R0, JIT_R0, JIT_R1); | |
break; | |
case OP_GRTR: | |
/* PRI = PRI > ALT ? 1 : 0 (unsigned) */ | |
jit_gtr_ui(JIT_R0, JIT_R0, JIT_R1); | |
break; | |
case OP_GEQ: | |
/* PRI = PRI >= ALT ? 1 : 0 (unsigned) */ | |
jit_ger_ui(JIT_R0, JIT_R0, JIT_R1); | |
break; | |
case OP_SLESS: | |
/* PRI = PRI < ALT ? 1 : 0 (signed) */ | |
jit_ltr_i(JIT_R0, JIT_R0, JIT_R1); | |
break; | |
case OP_SLEQ: | |
/* PRI = PRI <= ALT ? 1 : 0 (signed) */ | |
jit_ler_i(JIT_R0, JIT_R0, JIT_R1); | |
break; | |
case OP_SGRTR: | |
/* PRI = PRI > ALT ? 1 : 0 (signed) */ | |
jit_gtr_i(JIT_R0, JIT_R0, JIT_R1); | |
break; | |
case OP_SGEQ: | |
/* PRI = PRI >= ALT ? 1 : 0 (signed) */ | |
jit_ger_i(JIT_R0, JIT_R0, JIT_R1); | |
break; | |
case OP_EQ_C_PRI: /* value */ | |
/* PRI = PRI == value ? 1 : 0 */ | |
jit_eqi_i(JIT_R0, JIT_R0, arg); | |
cip++; | |
break; | |
case OP_EQ_C_ALT: /* value */ | |
/* PRI = ALT == value ? 1 : 0 */ | |
jit_eqi_i(JIT_R0, JIT_R1, arg); | |
cip++; | |
break; | |
case OP_INC_PRI: | |
/* PRI = PRI + 1 */ | |
jit_addi_i(JIT_R0, JIT_R0, 1); | |
break; | |
case OP_INC_ALT: | |
/* ALT = ALT + 1 */ | |
jit_addi_i(JIT_R1, JIT_R1, 1); | |
break; | |
case OP_INC: /* address */ | |
/* [address] = [address] + 1 */ | |
jit_ldi_i(JIT_V0, (int)(data + arg)); | |
jit_addi_i(JIT_V0, JIT_V0, 1); | |
jit_str_i((int)(data + arg), JIT_V0); | |
cip++; | |
break; | |
case OP_INC_S: /* offset */ | |
/* [FRM + offset] = [FRM + offset] + 1 */ | |
jit_addi_i(JIT_V0, JIT_FP, arg); | |
jit_ldr_i(JIT_V1, JIT_V0); | |
jit_addi_i(JIT_V1, JIT_V1, 1); | |
jit_str_i(JIT_V0, JIT_V1); | |
cip++; | |
break; | |
case OP_INC_I: | |
/* [PRI] = [PRI] + 1 */ | |
jit_ldr_i(JIT_V0, JIT_R0); | |
jit_addi_i(JIT_V0, JIT_V0, 1); | |
jit_str_i(JIT_R0, JIT_V0); | |
break; | |
case OP_DEC_PRI: | |
/* PRI = PRI - 1 */ | |
jit_subi_i(JIT_R0, JIT_R0, 1); | |
break; | |
case OP_DEC_ALT: | |
/* ALT = ALT - 1 */ | |
jit_subi_i(JIT_R1, JIT_R1, 1); | |
break; | |
case OP_DEC: /* address */ | |
/* [address] = [address] - 1 */ | |
jit_ldi_i(JIT_V0, (int)(data + arg)); | |
jit_subi_i(JIT_V0, JIT_V0, 1); | |
jit_str_i((int)(data + arg), JIT_V0); | |
cip++; | |
break; | |
case OP_DEC_S: /* offset */ | |
/* [FRM + offset] = [FRM + offset] - 1 */ | |
jit_addi_i(JIT_V0, JIT_FP, arg); | |
jit_ldr_i(JIT_V1, JIT_V0); | |
jit_subi_i(JIT_V1, JIT_V1, 1); | |
jit_str_i(JIT_V0, JIT_V1); | |
cip++; | |
break; | |
case OP_DEC_I: | |
/* [PRI] = [PRI] - 1 */ | |
jit_ldr_i(JIT_V0, JIT_R0); | |
jit_subi_i(JIT_V0, JIT_V0, 1); | |
jit_str_i(JIT_R0, JIT_V0); | |
break; | |
case OP_MOVS: /* number */ | |
/* Copy memory from [PRI] to [ALT]. The parameter | |
* specifies the number of bytes. The blocks should not | |
* overlap. | |
*/ | |
/*NOT_IMPLEMENTED("MOVS");*/ | |
cip++; | |
break; | |
case OP_CMPS: /* number */ | |
/* Compare memory blocks at [PRI] and [ALT]. The parameter | |
* specifies the number of bytes. The blocks should not | |
* overlap. | |
*/ | |
NOT_IMPLEMENTED("CMPS"); | |
break; | |
case OP_FILL: { | |
/* Fill memory at [ALT] with value in [PRI]. The parameter | |
* specifies the number of bytes, which must be a multiple | |
* of the cell size. | |
*/ | |
jit_insn *loop; | |
jit_addi_i(JIT_V0, JIT_R1, (int)data + arg); /* V0 = R1 + data + numbytes */ | |
jit_addi_i(JIT_V1, JIT_R1, (int)data); /* V1 = R1 + data */ | |
loop = jit_bger_i(jit_forward(), JIT_V1, JIT_V0); /* LOOP: if (V1 >= V0) go to END */ | |
jit_str_i(JIT_V1, JIT_R0); /* [V1] = R0 */ | |
jit_addi_i(JIT_V1, JIT_V1, sizeof(cell)); /* V1 = V1 + sizeof(cell) */ | |
jit_jmpi(loop); /* go to LOOP */ | |
jit_patch(loop); /* END: */ | |
cip++; | |
break; | |
} | |
case OP_HALT: /* number */ | |
/* Abort execution (exit value in PRI), parameters other than 0 | |
* have a special meaning. | |
*/ | |
NOT_IMPLEMENTED("HALT"); | |
break; | |
case OP_BOUNDS: /* value */ | |
/* Abort execution if PRI > value or if PRI < 0 */ | |
NOT_IMPLEMENTED("BOUNDS"); | |
break; | |
case OP_SYSREQ_PRI: | |
/* call system service, service number in PRI */ | |
NOT_IMPLEMENTED("SYSREQ.pri"); | |
break; | |
case OP_SYSREQ_C: /* value */ | |
/* call system service */ | |
jit_prepare(2); | |
jit_movr_i(JIT_V0, JIT_SP); | |
jit_pusharg_i(JIT_V0); | |
jit_movi_i(JIT_V0, (int)amx); | |
jit_pusharg_i(JIT_V0); | |
jit_calli(get_native_address(amx, arg)); | |
cip++; | |
break; | |
case OP_FILE: /* size ord name */ | |
/* obsolete */ | |
break; | |
case OP_LINE: /* line ord */ | |
/* obsolete */ | |
break; | |
case OP_SYMBOL: /* size offset flag name */ | |
/* obsolete */ | |
break; | |
case OP_SRANGE: /* level size */ | |
/* obsolete */ | |
break; | |
case OP_JUMP_PRI: | |
/* obsolete */ | |
break; | |
case OP_SWITCH: /* offset */ | |
/* Compare PRI to the values in the case table (whose address | |
* is passed as an offset from CIP) and jump to the associated | |
* the address in the matching record. | |
*/ | |
NOT_IMPLEMENTED("SWITCH"); | |
break; | |
case OP_CASETBL: /* ... */ | |
/* A variable number of case records follows this opcode, where | |
* each record takes two cells. See the notes below for details | |
* on the case table lay-out. | |
*/ | |
NOT_IMPLEMENTED("CASETBL"); | |
break; | |
case OP_SWAP_PRI: | |
/* [STK] = PRI and PRI = [STK] */ | |
jit_movr_i(JIT_V0, JIT_R0); | |
jit_ldr_i(JIT_R0, JIT_SP); | |
jit_str_i(JIT_SP, JIT_V0); | |
break; | |
case OP_SWAP_ALT: | |
/* [STK] = ALT and ALT = [STK] */ | |
jit_movr_i(JIT_V0, JIT_R1); | |
jit_ldr_i(JIT_R0, JIT_SP); | |
jit_str_i(JIT_SP, JIT_V0); | |
break; | |
case OP_PUSHADDR: /* offset */ | |
/* [STK] = FRM + offset, STK = STK - cell size */ | |
jit_addi_i(JIT_V0, JIT_FP, arg); | |
jit_str_i(JIT_SP, JIT_V0); | |
jit_subr_i(JIT_SP, JIT_SP, sizeof(int)); | |
cip++; | |
break; | |
case OP_NOP: | |
/* no-operation, for code alignment */ | |
break; | |
case OP_SYSREQ_D: /* address */ | |
/* call system service */ | |
NOT_IMPLEMENTED("SYSREQ.D"); | |
break; | |
case OP_SYMTAG: /* value */ | |
/* obsolete */ | |
break; | |
case OP_BREAK: | |
/* conditional breakpoint */ | |
NOT_IMPLEMENTED("BREAK"); | |
break; | |
default: | |
logprintf("opcode = %x, code = %x, cip = %x, code_size = %x", opcode, code, cip, code_size); | |
assert(0); | |
} | |
} | |
if (fn_list != NULL) { | |
struct list *cur_fn = fn_list; | |
struct list *cur_ref; | |
jit_insn *ip; | |
/* Save current instruction pointer. */ | |
ip = (jit_insn*)jit_get_ip().ptr; | |
while (cur_fn != NULL) { | |
fn = (struct fn_info*)cur_fn->value; | |
assert(fn->jit_address != NULL); | |
/* Find all references to this funciton and replace the | |
* empty (null) address with the real one. | |
*/ | |
cur_ref = fn->refs; | |
while (cur_ref != NULL) { | |
/*jit_set_ip((jit_insn*)fn->jit_address); | |
jit_patch((jit_insn*)(cur_ref->key));*/ | |
jit_set_ip((jit_insn*)(cur_ref->key)); | |
if (fn->is_public) { | |
jit_calli((int)fn->jit_address); | |
} else { | |
jit_jmpi((int)fn->jit_address); | |
} | |
cur_ref = cur_ref->next; | |
} | |
list_free(&fn->refs); | |
cur_fn = cur_fn->next; | |
} | |
/* Restore IP. */ | |
jit_set_ip(ip); | |
} | |
jit_flush_code(jitcode, jit_get_ip().ptr); | |
list_free(&fn_list); | |
free(amx2jit); | |
dump_jit_code("jitcode.bin", jitcode, (int)jit_get_ip().ptr - (int)jitcode); | |
} | |
#if defined WIN32 | |
#define PAGE_ALIGN(x) (x) | |
#define PROT_NONE 0x0 /* page can be executed */ | |
#define PROT_READ 0x1 /* page can be read */ | |
#define PROT_WRITE 0x2 /* page can be written */ | |
#define PROT_EXEC 0x4 /* page can't be accessed */ | |
static int mprotect(void *addr, size_t len, int prot) { | |
DWORD new_prot; | |
DWORD old_prot; | |
if (prot == PROT_NONE) { | |
new_prot = PAGE_NOACCESS; | |
} else if (prot == PROT_READ) { | |
new_prot = PAGE_READONLY; | |
} else if ((prot & PROT_WRITE) && (prot & PROT_READ)) { | |
new_prot = PAGE_EXECUTE_READWRITE; | |
} else if ((prot & PROT_READ)) { | |
new_prot = PAGE_EXECUTE_READ; | |
} else if ((prot & PROT_EXEC)) { | |
new_prot = PAGE_EXECUTE; | |
} | |
return !VirtualProtect((LPVOID)addr, (SIZE_T)len, new_prot, &old_prot); | |
} | |
#else | |
/* Linux alread has mprotect() */ | |
#define PAGE_ALIGN(x) (void*)(((int)x + sysconf(_SC_PAGESIZE) - 1) & ~(sysconf(_SC_PAGESIZE) - 1)) | |
#endif | |
typedef int (__stdcall *jitted_public)(); | |
static int AMXAPI amx_Exec_JIT(AMX *amx, cell *retval, int index) { | |
struct amx_info *info; | |
jitted_public function; | |
info = list_get(amx_list, (int)amx); | |
if (info == NULL) { | |
/* store this AMX in the global list */ | |
info = malloc(sizeof(*info)); | |
info->jit_code_size = MAX_JIT_SIZE; | |
info->jit_code = malloc(sizeof(jit_insn) * info->jit_code_size); | |
list_insert(&amx_list, (int)amx, info); | |
/* JIT the code */ | |
jit_amx(amx, info->jit_code, info->jit_code_size); | |
} | |
if (index == AMX_EXEC_MAIN) { | |
function = (jitted_public)((AMX_HEADER*)amx->base)->cod; | |
} else if (index >= 0) { | |
function = (jitted_public)get_public_address(amx, index); | |
} | |
function(); | |
return AMX_ERR_NONE; | |
} | |
static void install_jmp_hook(void *from, void *to) { | |
/* set write permission */ | |
mprotect(PAGE_ALIGN(from), PAGE_ALIGN(5), PROT_READ | PROT_WRITE | PROT_EXEC); | |
/* write the JMP opcode */ | |
*((unsigned char*)from) = 0xE9; | |
/* write the address (relative to the nex instruction) */ | |
*((int*)((int)from + 1)) = ((int)to - ((int)from + 5)); | |
} | |
#define SUPPORTS_VERSION 0x0200 | |
#define SUPPORTS_AMX_NATIVES 0x10000 | |
PLUGIN_EXPORT unsigned int PLUGIN_CALL Supports() { | |
return SUPPORTS_VERSION | SUPPORTS_AMX_NATIVES; | |
} | |
#define PLUGIN_DATA_LOGPRINTF 0x00 | |
#define PLUGIN_DATA_AXM_EXPORTS 0x10 | |
#define PLUGIN_AMX_EXPORT_EXEC 7 | |
PLUGIN_EXPORT bool PLUGIN_CALL Load(void **ppData) { | |
logprintf = (logprintf_t)ppData[PLUGIN_DATA_LOGPRINTF]; | |
/* redirect amx_Exec() calls to amx_Exec_JIT() */ | |
install_jmp_hook(((void**)ppData[PLUGIN_DATA_AXM_EXPORTS])[PLUGIN_AMX_EXPORT_EXEC], | |
(void*)amx_Exec_JIT); | |
return true; | |
} | |
PLUGIN_EXPORT void PLUGIN_CALL Unload() { | |
/* nothing */ | |
} | |
PLUGIN_EXPORT int PLUGIN_CALL AmxLoad(AMX *amx) { | |
return AMX_ERR_NONE; | |
} | |
PLUGIN_EXPORT int PLUGIN_CALL AmxUnload(AMX *amx) { | |
struct amx_info *info; | |
info = (struct amx_info*)list_remove(amx_list, (int)amx); | |
free(info->jit_code); | |
free(info); | |
return AMX_ERR_NONE; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment