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:
David Anderson 2006-09-20 08:44:21 +00:00
parent 824beee935
commit 1577897925
6 changed files with 166 additions and 35 deletions

View File

@ -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_

View File

@ -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);

View File

@ -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_

View File

@ -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

View File

@ -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

View File

@ -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);