I'm proud to present the first non-backpatched error checking routine!
all of this is untested --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%4080
This commit is contained in:
parent
824beee935
commit
1577897925
@ -2,6 +2,7 @@
|
||||
#define _INCLUDE_SOURCEPAWN_JIT_HELPERS_H_
|
||||
|
||||
#include <sp_vm_types.h>
|
||||
#include <sp_vm_api.h>
|
||||
|
||||
#if defined HAVE_STDINT_H && !defined WIN32
|
||||
#include <stdint.h>
|
||||
@ -70,6 +71,7 @@ public:
|
||||
cell_t *inptr; /* input pointer */
|
||||
jitcode_t outbase; /* output pointer */
|
||||
jitcode_t outptr; /* output base */
|
||||
SourcePawn::ICompilation *data; /* compiler live info */
|
||||
};
|
||||
|
||||
#endif //_INCLUDE_SOURCEPAWN_JIT_HELPERS_H_
|
||||
|
@ -1,7 +1,6 @@
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "jit_x86.h"
|
||||
#include "..\jit_helpers.h"
|
||||
#include "opcode_helpers.h"
|
||||
#include "x86_macros.h"
|
||||
|
||||
@ -1001,6 +1000,13 @@ inline void WriteOp_Const_S(JitWriter *jit)
|
||||
}
|
||||
}
|
||||
|
||||
inline void WriteOp_Load_I(JitWriter *jit)
|
||||
{
|
||||
//mov eax, [edi+eax]
|
||||
Write_Check_VerifyAddr(jit, REG_EAX, false);
|
||||
IA32_Mov_Reg_Rm_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE);
|
||||
}
|
||||
|
||||
|
||||
/*************************************************
|
||||
*************************************************
|
||||
@ -1074,7 +1080,6 @@ IPluginContext *JITX86::CompileToContext(ICompilation *co, int *err)
|
||||
JitWriter writer;
|
||||
JitWriter *jit = &writer;
|
||||
cell_t *endptr = (cell_t *)(end_cip);
|
||||
jitoffs_t jit_return;
|
||||
|
||||
/* Initial code is written "blank,"
|
||||
* so we can check the exact memory usage.
|
||||
@ -1085,16 +1090,17 @@ IPluginContext *JITX86::CompileToContext(ICompilation *co, int *err)
|
||||
|
||||
/* Get inlining level */
|
||||
int inline_level = data->inline_level;
|
||||
bool never_inline = false;
|
||||
|
||||
if (inline_level == 0)
|
||||
{
|
||||
never_inline = true;
|
||||
}
|
||||
|
||||
//:TODO: Jump back here once finished!
|
||||
|
||||
/* Start writing the actual code */
|
||||
jit_return = Write_Execute_Function(jit, never_inline);
|
||||
data->jit_return = Write_Execute_Function(jit);
|
||||
|
||||
/* Write error checking routines in case they are needed */
|
||||
data->jit_verify_addr_eax = jit->jit_curpos();
|
||||
Write_Check_VerifyAddr(jit, REG_EAX, true);
|
||||
data->jit_verify_addr_edx = jit->jit_curpos();
|
||||
Write_Check_VerifyAddr(jit, REG_EDX, true);
|
||||
|
||||
for (; writer.inptr <= endptr;)
|
||||
{
|
||||
@ -1656,6 +1662,11 @@ IPluginContext *JITX86::CompileToContext(ICompilation *co, int *err)
|
||||
WriteOp_Const_S(jit);
|
||||
break;
|
||||
}
|
||||
case OP_LOAD_I:
|
||||
{
|
||||
WriteOp_Load_I(jit);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
AbortCompilation(co);
|
||||
|
@ -3,17 +3,24 @@
|
||||
|
||||
#include <sp_vm_types.h>
|
||||
#include <sp_vm_api.h>
|
||||
#include "..\jit_helpers.h"
|
||||
|
||||
using namespace SourcePawn;
|
||||
|
||||
#define JIT_INLINE_ERRORCHECKS (1<<0)
|
||||
#define JIT_INLINE_NATIVES (1<<1)
|
||||
|
||||
class CompData : public ICompilation
|
||||
{
|
||||
public:
|
||||
CompData() : plugin(NULL), debug(false), inline_level(2)
|
||||
CompData() : plugin(NULL), debug(false), inline_level(3)
|
||||
{
|
||||
};
|
||||
public:
|
||||
sp_plugin_t *plugin;
|
||||
jitoffs_t jit_return;
|
||||
jitoffs_t jit_verify_addr_eax;
|
||||
jitoffs_t jit_verify_addr_edx;
|
||||
int inline_level;
|
||||
bool debug;
|
||||
};
|
||||
@ -44,5 +51,6 @@ public:
|
||||
#define AMX_INFO_HEAP 4
|
||||
#define AMX_INFO_RETVAL 8
|
||||
#define AMX_INFO_CONTEXT 12
|
||||
#define AMX_INFO_STACKTOP 16
|
||||
|
||||
#endif //_INCLUDE_SOURCEPAWN_JIT_X86_H_
|
||||
|
@ -9,19 +9,6 @@ int OpAdvTable[OP_NUM_OPCODES];
|
||||
jitoffs_t Write_Execute_Function(JitWriter *jit, bool never_inline)
|
||||
{
|
||||
/**
|
||||
* The state expected by our plugin is:
|
||||
* #define AMX_REG_PRI REG_EAX (done)
|
||||
#define AMX_REG_ALT REG_EDX (done)
|
||||
#define AMX_REG_STK REG_EBP (done)
|
||||
#define AMX_REG_DAT REG_EDI (done)
|
||||
#define AMX_REG_TMP REG_ECX (nothing)
|
||||
#define AMX_REG_INFO REG_ESI (done)
|
||||
#define AMX_REG_FRM REG_EBX (done)
|
||||
#define AMX_INFO_FRM AMX_REG_INFO (done)
|
||||
#define AMX_INFO_HEAP 4 (done)
|
||||
#define AMX_INFO_RETVAL 8 (done)
|
||||
#define AMX_INFO_CONTEXT 12 (done)
|
||||
*
|
||||
* The variables we're passed in:
|
||||
* sp_context_t *ctx, uint32_t code_idx, cell_t *result
|
||||
*/
|
||||
@ -45,7 +32,7 @@ jitoffs_t Write_Execute_Function(JitWriter *jit, bool never_inline)
|
||||
IA32_Push_Reg(jit, REG_EDI);
|
||||
IA32_Push_Reg(jit, REG_EBX);
|
||||
|
||||
//sub esp, 4*4 - allocate info array
|
||||
//sub esp, 4*5 - allocate info array
|
||||
//mov esi, esp - save info pointer
|
||||
IA32_Sub_Rm_Imm8(jit, REG_ESP, 4*4, MOD_REG);
|
||||
IA32_Mov_Reg_Rm(jit, AMX_REG_INFO, REG_ESP, MOD_REG);
|
||||
@ -69,13 +56,21 @@ jitoffs_t Write_Execute_Function(JitWriter *jit, bool never_inline)
|
||||
//mov ebp, [eax+<offs>] - get stack pointer
|
||||
//add ebp, edi - relocate to data section
|
||||
//mov ebx, ebp - copy sp to frm
|
||||
IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_STK, REG_EAX, offsetof(sp_context_t, sp));
|
||||
IA32_Add_Rm_Reg(jit, REG_EBP, AMX_REG_STK, AMX_REG_DAT);
|
||||
IA32_Mov_Reg_Rm(jit, AMX_REG_FRM, AMX_REG_STK, MOD_REG);
|
||||
|
||||
//mov ecx, edi - copy base of data to temp var
|
||||
//add ecx, [eax+<offs>] - add memsize to get stack top
|
||||
//mov [esi+16], ecx - store stack top into info pointer
|
||||
IA32_Mov_Reg_Rm(jit, REG_ECX, AMX_REG_DAT, MOD_REG);
|
||||
IA32_Add_Reg_Rm_Disp8(jit, REG_ECX, REG_EAX, offsetof(sp_context_t, memory));
|
||||
IA32_Mov_Rm_Reg_Disp8(jit, REG_ESI, REG_ECX, AMX_INFO_STACKTOP);
|
||||
|
||||
//mov ecx, [ebp+12] - get code index
|
||||
//add ecx, [eax+<offs>] - add code base to index
|
||||
//mov edx, [eax+<offs>] - get alt
|
||||
//mov eax, [eax+<offs>] - get pri
|
||||
IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_STK, REG_EAX, offsetof(sp_context_t, sp));
|
||||
IA32_Add_Rm_Reg(jit, REG_EBP, AMX_REG_STK, AMX_REG_DAT);
|
||||
IA32_Mov_Reg_Rm(jit, AMX_REG_FRM, AMX_REG_STK, MOD_REG);
|
||||
IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, REG_EBP, 12);
|
||||
IA32_Add_Reg_Rm_Disp8(jit, REG_ECX, REG_EAX, offsetof(sp_context_t, base));
|
||||
IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_ALT, REG_EAX, offsetof(sp_context_t, alt));
|
||||
@ -94,9 +89,10 @@ jitoffs_t Write_Execute_Function(JitWriter *jit, bool never_inline)
|
||||
IA32_Mov_Rm_Reg(jit, REG_EBP, AMX_REG_PRI, MOD_MEM_REG);
|
||||
IA32_Mov_Reg_Imm32(jit, REG_EAX, SP_ERR_NONE);
|
||||
|
||||
/* where error checking/return functions should go to */
|
||||
/* save where error checking/halting functions should go to */
|
||||
jitoffs_t offs_return;
|
||||
if (never_inline)
|
||||
CompData *data = (CompData *)jit->data;
|
||||
if (!(data->inline_level & JIT_INLINE_ERRORCHECKS))
|
||||
{
|
||||
/* We have to write code assume we're breaking out of a call */
|
||||
//jmp [past the next instruction]
|
||||
@ -121,7 +117,7 @@ jitoffs_t Write_Execute_Function(JitWriter *jit, bool never_inline)
|
||||
//pop esi
|
||||
//pop ebp
|
||||
//ret
|
||||
IA32_Add_Rm_Imm8(jit, REG_ESP, 4*4, MOD_REG);
|
||||
IA32_Add_Rm_Imm8(jit, REG_ESP, 4*5, MOD_REG);
|
||||
IA32_Pop_Reg(jit, REG_EBX);
|
||||
IA32_Pop_Reg(jit, REG_EDI);
|
||||
IA32_Pop_Reg(jit, REG_ESI);
|
||||
@ -131,6 +127,75 @@ jitoffs_t Write_Execute_Function(JitWriter *jit, bool never_inline)
|
||||
return offs_return;
|
||||
}
|
||||
|
||||
void Write_Error(JitWriter *jit, int error)
|
||||
{
|
||||
CompData *data = (CompData *)jit->data;
|
||||
|
||||
/* These are so small that we always inline them! */
|
||||
//mov eax, <error>
|
||||
//jmp [...jit_return]
|
||||
IA32_Mov_Reg_Imm32(jit, REG_EAX, error);
|
||||
jitoffs_t jmp = IA32_Jump_Imm32(jit, 0);
|
||||
IA32_Write_Jump32(jit, jmp, data->jit_return);
|
||||
}
|
||||
|
||||
void Write_Check_VerifyAddr(JitWriter *jit, jit_uint8_t reg, bool firstcall)
|
||||
{
|
||||
CompData *data = (CompData *)jit->data;
|
||||
|
||||
/* :TODO: Should this be checking for below heaplow?
|
||||
* The old JIT did not.
|
||||
*/
|
||||
|
||||
bool call = false;
|
||||
if (!(data->inline_level & JIT_INLINE_ERRORCHECKS))
|
||||
{
|
||||
/* If we're not in the initial generation phase,
|
||||
* Write a call to the actual routine instead.
|
||||
*/
|
||||
if (!firstcall)
|
||||
{
|
||||
jitoffs_t call = IA32_Call_Imm32(jit, 0);
|
||||
if (reg == REG_EAX)
|
||||
{
|
||||
IA32_Write_Jump32(jit, call, data->jit_verify_addr_eax);
|
||||
} else if (reg == REG_EDX) {
|
||||
IA32_Write_Jump32(jit, call, data->jit_verify_addr_edx);
|
||||
}
|
||||
return;
|
||||
}
|
||||
call = true;
|
||||
} else if (firstcall) {
|
||||
/* Inline + initial gen == no code */
|
||||
return;
|
||||
}
|
||||
|
||||
//cmp reg, [stp]
|
||||
//jae memaccess
|
||||
//cmp reg, [hea]
|
||||
//jb continue
|
||||
//lea ecx, [reg+edi]
|
||||
//cmp ecx, ebp
|
||||
//jae continue
|
||||
//memaccess: (write error)
|
||||
//continue:
|
||||
IA32_Cmp_Reg_Rm_Disp8(jit, reg, AMX_REG_INFO, AMX_INFO_STACKTOP);
|
||||
jitoffs_t jmp1 = IA32_Jump_Cond_Imm8(jit, CC_AE, 0);
|
||||
IA32_Cmp_Reg_Rm_Disp8(jit, reg, AMX_REG_INFO, AMX_INFO_HEAP);
|
||||
jitoffs_t jmp2 = IA32_Jump_Cond_Imm8(jit, CC_B, 0);
|
||||
IA32_Lea_DispRegReg(jit, REG_ECX, reg, REG_EDI);
|
||||
IA32_Cmp_Rm_Reg(jit, REG_ECX, AMX_REG_STK, MOD_REG);
|
||||
jitoffs_t jmp3 = IA32_Jump_Cond_Imm8(jit, CC_AE, 0);
|
||||
IA32_Send_Jump8_Here(jit, jmp1);
|
||||
Write_Error(jit, SP_ERR_MEMACCESS);
|
||||
IA32_Send_Jump8_Here(jit, jmp2);
|
||||
IA32_Send_Jump8_Here(jit, jmp3);
|
||||
if (call)
|
||||
{
|
||||
IA32_Return(jit);
|
||||
}
|
||||
}
|
||||
|
||||
void Macro_PushN_Addr(JitWriter *jit, int i)
|
||||
{
|
||||
//push eax
|
||||
|
@ -7,11 +7,20 @@
|
||||
* This outputs the execution function for a plugin.
|
||||
* It also returns the 'return' offset, which is used for
|
||||
* breaking out of the JIT during runtime.
|
||||
*
|
||||
* If 'never_inline' is true, it outputs slightly different code used for
|
||||
* inlining the error checking routines.
|
||||
*/
|
||||
jitoffs_t Write_Execute_Function(JitWriter *jit, bool never_inline);
|
||||
jitoffs_t Write_Execute_Function(JitWriter *jit);
|
||||
|
||||
/**
|
||||
* Generates code to set an error state in the VM and return.
|
||||
* Note that this should only be called from inside an error
|
||||
* checking function.
|
||||
*/
|
||||
void Write_Error(JitWriter *jit, int error);
|
||||
|
||||
/**
|
||||
* Verifies an address by register.
|
||||
*/
|
||||
void Write_Check_VerifyAddr(JitWriter *jit, jit_uint8_t reg, bool firstcall);
|
||||
|
||||
/**
|
||||
* These are for writing the PushN opcodes.
|
||||
@ -32,7 +41,7 @@ typedef enum
|
||||
OP_LREF_ALT, //DONE
|
||||
OP_LREF_S_PRI, //DONE
|
||||
OP_LREF_S_ALT, //DONE
|
||||
OP_LOAD_I,
|
||||
OP_LOAD_I, //DONE
|
||||
OP_LODB_I,
|
||||
OP_CONST_PRI, //DONE
|
||||
OP_CONST_ALT, //DONE
|
||||
|
@ -97,6 +97,7 @@
|
||||
#define IA32_SHL_RM_CL 0xD3 // encoding is /4
|
||||
#define IA32_SAR_RM_IMM8 0xC1 // encoding is /7 <ib>
|
||||
#define IA32_CMP_RM_REG 0x39 // encoding is /r
|
||||
#define IA32_CMP_REG_RM 0x3B // encoding is /r
|
||||
#define IA32_SETCC_RM8_1 0x0F // opcode part 1
|
||||
#define IA32_SETCC_RM8_2 0x90 // encoding is +cc /0 (8bits)
|
||||
#define IA32_XCHG_EAX_REG 0x90 // encoding is +r
|
||||
@ -498,8 +499,16 @@ inline void IA32_Lea_Reg_DispRegMultImm8(JitWriter *jit,
|
||||
jit->write_byte(val);
|
||||
}
|
||||
|
||||
inline void IA32_Lea_DispRegReg(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src_base, jit_uint8_t dispreg)
|
||||
{
|
||||
jit->write_ubyte(IA32_LEA_REG_MEM);
|
||||
jit->write_ubyte(ia32_modrm(MOD_MEM_REG, dest, REG_SIB));
|
||||
jit->write_ubyte(ia32_sib(NOSCALE, dispreg, src_base));
|
||||
}
|
||||
|
||||
inline void IA32_Lea_DispRegImm8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src_base, jit_int8_t val)
|
||||
{
|
||||
/* :TODO: - why does this take in src_base? */
|
||||
jit->write_ubyte(IA32_LEA_REG_MEM);
|
||||
jit->write_ubyte(ia32_modrm(MOD_DISP8, dest, MOD_MEM_REG));
|
||||
jit->write_byte(val);
|
||||
@ -507,6 +516,7 @@ inline void IA32_Lea_DispRegImm8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t s
|
||||
|
||||
inline void IA32_Lea_DispRegImm32(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src_base, jit_int32_t val)
|
||||
{
|
||||
/* :TODO: - why does this take in src_base? */
|
||||
jit->write_ubyte(IA32_LEA_REG_MEM);
|
||||
jit->write_ubyte(ia32_modrm(MOD_DISP32, dest, MOD_MEM_REG));
|
||||
jit->write_int32(val);
|
||||
@ -709,12 +719,31 @@ inline void IA32_Write_Jump8(JitWriter *jit, jitoffs_t jmp, jitoffs_t target)
|
||||
jit->outptr = oldptr;
|
||||
}
|
||||
|
||||
inline void IA32_Write_Jump32(JitWriter *jit, jitoffs_t jmp, jitoffs_t target)
|
||||
{
|
||||
//save old ptr
|
||||
jitcode_t oldptr = jit->outptr;
|
||||
//get relative difference
|
||||
jit_int32_t diff = (target - (jmp + 1));
|
||||
//overwrite old value
|
||||
jit->outptr = jit->outbase + jmp;
|
||||
jit->write_int32(diff);
|
||||
//restore old ptr
|
||||
jit->outptr = oldptr;
|
||||
}
|
||||
|
||||
inline void IA32_Send_Jump8_Here(JitWriter *jit, jitoffs_t jmp)
|
||||
{
|
||||
jitoffs_t curptr = jit->jit_curpos();
|
||||
IA32_Write_Jump8(jit, jmp, curptr);
|
||||
}
|
||||
|
||||
inline void IA32_Send_Jump32_Here(JitWriter *jit, jitoffs_t jmp)
|
||||
{
|
||||
jitoffs_t curptr = jit->jit_curpos();
|
||||
IA32_Write_Jump32(jit, jmp, curptr);
|
||||
}
|
||||
|
||||
inline void IA32_Return(JitWriter *jit)
|
||||
{
|
||||
jit->write_ubyte(IA32_RET);
|
||||
@ -732,6 +761,13 @@ inline void IA32_Cmp_Rm_Reg(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, j
|
||||
jit->write_ubyte(ia32_modrm(mode, src, dest));
|
||||
}
|
||||
|
||||
inline void IA32_Cmp_Reg_Rm_Disp8(JitWriter *jit, jit_uint8_t reg1, jit_uint8_t reg2, jit_int8_t disp8)
|
||||
{
|
||||
jit->write_ubyte(IA32_CMP_REG_RM);
|
||||
jit->write_ubyte(ia32_modrm(MOD_DISP8, reg1, reg2));
|
||||
jit->write_byte(disp8);
|
||||
}
|
||||
|
||||
inline void IA32_Cmp_Rm_Imm8(JitWriter *jit, jit_uint8_t mode, jit_uint8_t rm, jit_int8_t imm8)
|
||||
{
|
||||
jit->write_ubyte(IA32_CMP_RM_IMM8);
|
||||
|
Loading…
Reference in New Issue
Block a user