470 lines
14 KiB
C
470 lines
14 KiB
C
/**
|
|
* vim: set ts=4 :
|
|
* =============================================================================
|
|
* SourcePawn JIT SDK
|
|
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
|
* =============================================================================
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it under
|
|
* the terms of the GNU General Public License, version 3.0, as published by the
|
|
* Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
* details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along with
|
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
* As a special exception, AlliedModders LLC gives you permission to link the
|
|
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
|
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
|
* by the Valve Corporation. You must obey the GNU General Public License in
|
|
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
|
* this exception to all derivative works. AlliedModders LLC defines further
|
|
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
|
* or <http://www.sourcemod.net/license.php>.
|
|
*
|
|
* Version: $Id$
|
|
*/
|
|
|
|
#ifndef _INCLUDE_JIT_X86_MACROS_H
|
|
#define _INCLUDE_JIT_X86_MACROS_H
|
|
|
|
// :XXX:
|
|
// :XXX: This file is deprecated. For new code, use assembler-x86.h.
|
|
// :XXX:
|
|
|
|
#include <limits.h>
|
|
|
|
//MOD R/M
|
|
#define MOD_MEM_REG 0
|
|
#define MOD_DISP8 1
|
|
#define MOD_DISP32 2
|
|
#define MOD_REG 3
|
|
|
|
//SIB
|
|
#define NOSCALE 0
|
|
#define SCALE2 1
|
|
#define SCALE4 2
|
|
#define SCALE8 3
|
|
|
|
//Register codes
|
|
const jit_uint8_t kREG_EAX = 0;
|
|
const jit_uint8_t kREG_ECX = 1;
|
|
const jit_uint8_t kREG_EDX = 2;
|
|
const jit_uint8_t kREG_EBX = 3;
|
|
const jit_uint8_t kREG_ESP = 4;
|
|
const jit_uint8_t kREG_SIB = 4;
|
|
const jit_uint8_t kREG_NOIDX = 4;
|
|
const jit_uint8_t kREG_IMM_BASE = 5;
|
|
const jit_uint8_t kREG_EBP = 5;
|
|
const jit_uint8_t kREG_ESI = 6;
|
|
const jit_uint8_t kREG_EDI = 7;
|
|
|
|
#define IA32_16BIT_PREFIX 0x66
|
|
|
|
//condition codes (for example, Jcc opcodes)
|
|
#define CC_B 0x2
|
|
#define CC_NAE CC_B
|
|
#define CC_NB 0x3
|
|
#define CC_AE CC_NB
|
|
#define CC_E 0x4
|
|
#define CC_Z CC_E
|
|
#define CC_NE 0x5
|
|
#define CC_NZ CC_NE
|
|
#define CC_NA 0x6
|
|
#define CC_BE CC_NA
|
|
#define CC_A 0x7
|
|
#define CC_NBE CC_A
|
|
#define CC_L 0xC
|
|
#define CC_NGE CC_L
|
|
#define CC_NL 0xD
|
|
#define CC_GE CC_NL
|
|
#define CC_NG 0xE
|
|
#define CC_LE CC_NG
|
|
#define CC_G 0xF
|
|
#define CC_NLE CC_G
|
|
|
|
#define IA32_MOVZX_R32_RM8_1 0x0F // opcode part 1
|
|
#define IA32_MOVZX_R32_RM16_1 0x0F // opcode part 1
|
|
#define IA32_PUSH_REG 0x50 // encoding is +r
|
|
#define IA32_POP_REG 0x58 // encoding is +r
|
|
#define IA32_PUSH_IMM32 0x68 // encoding is <imm32>
|
|
#define IA32_PUSH_IMM8 0x6A // encoding is <imm8>
|
|
#define IA32_ADD_RM_IMM32 0x81 // encoding is /0
|
|
#define IA32_SUB_RM_IMM32 0x81 // encoding is /5 <imm32>
|
|
#define IA32_ADD_RM_IMM8 0x83 // encoding is /0
|
|
#define IA32_AND_RM_IMM8 0x83 // encoding is /4
|
|
#define IA32_SUB_RM_IMM8 0x83 // encoding is /5 <imm8>
|
|
#define IA32_MOV_RM8_REG8 0x88 // encoding is /r
|
|
#define IA32_MOV_RM_REG 0x89 // encoding is /r
|
|
#define IA32_MOV_REG8_RM8 0x8A // encoding is /r
|
|
#define IA32_MOV_REG_RM 0x8B // encoding is /r
|
|
#define IA32_LEA_REG_MEM 0x8D // encoding is /r
|
|
#define IA32_MOVSB 0xA4 // no extra encoding
|
|
#define IA32_MOVSD 0xA5 // no extra encoding
|
|
#define IA32_MOVZX_R32_RM8_2 0xB6 // encoding is /r
|
|
#define IA32_MOVZX_R32_RM16_2 0xB7 // encoding is /r
|
|
#define IA32_MOV_REG_IMM 0xB8 // encoding is +r <imm32>
|
|
#define IA32_FLD_MEM32 0xD9 // encoding is /0
|
|
#define IA32_FSTP_MEM32 0xD9 // encoding is /3
|
|
#define IA32_FLD_MEM64 0xDD // encoding is /0
|
|
#define IA32_FSTP_MEM64 0xDD // encoding is /3
|
|
#define IA32_CALL_IMM32 0xE8 // relative call, <imm32>
|
|
#define IA32_JMP_IMM32 0xE9 // encoding is imm32
|
|
#define IA32_RETN 0xC2 // encoding is <imm16>
|
|
#define IA32_RET 0xC3 // no extra encoding
|
|
#define IA32_REP 0xF3 // no extra encoding
|
|
#define IA32_CLD 0xFC // no extra encoding
|
|
#define IA32_CALL_RM 0xFF // encoding is /2
|
|
|
|
inline jit_uint8_t ia32_modrm(jit_uint8_t mode, jit_uint8_t reg, jit_uint8_t rm)
|
|
{
|
|
jit_uint8_t modrm = (mode << 6);
|
|
|
|
modrm |= (reg << 3);
|
|
modrm |= (rm);
|
|
|
|
return modrm;
|
|
}
|
|
|
|
//mode is the scaling method - NOSCALE ... SCALE8
|
|
//index is the register that is scaled
|
|
//base is the base register
|
|
inline jit_uint8_t ia32_sib(jit_uint8_t mode, jit_uint8_t index, jit_uint8_t base)
|
|
{
|
|
jit_uint8_t sib = (mode << 6);
|
|
|
|
sib |= (index << 3);
|
|
sib |= (base);
|
|
|
|
return sib;
|
|
}
|
|
|
|
inline void IA32_Return(JitWriter *jit)
|
|
{
|
|
jit->write_ubyte(IA32_RET);
|
|
}
|
|
|
|
inline void IA32_Mov_Reg_Rm(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode)
|
|
{
|
|
jit->write_ubyte(IA32_MOV_REG_RM);
|
|
jit->write_ubyte(ia32_modrm(mode, dest, src));
|
|
}
|
|
|
|
inline void IA32_Movzx_Reg32_Rm8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode)
|
|
{
|
|
jit->write_ubyte(IA32_MOVZX_R32_RM8_1);
|
|
jit->write_ubyte(IA32_MOVZX_R32_RM8_2);
|
|
jit->write_ubyte(ia32_modrm(mode, dest, src));
|
|
}
|
|
|
|
inline void IA32_Movzx_Reg32_Rm8_Disp8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int8_t disp)
|
|
{
|
|
jit->write_ubyte(IA32_MOVZX_R32_RM8_1);
|
|
jit->write_ubyte(IA32_MOVZX_R32_RM8_2);
|
|
jit->write_ubyte(ia32_modrm(MOD_DISP8, dest, src));
|
|
jit->write_byte(disp);
|
|
}
|
|
|
|
inline void IA32_Movzx_Reg32_Rm8_Disp32(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int32_t disp)
|
|
{
|
|
jit->write_ubyte(IA32_MOVZX_R32_RM8_1);
|
|
jit->write_ubyte(IA32_MOVZX_R32_RM8_2);
|
|
jit->write_ubyte(ia32_modrm(MOD_DISP32, dest, src));
|
|
jit->write_int32(disp);
|
|
}
|
|
|
|
inline void IA32_Movzx_Reg32_Rm16(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode)
|
|
{
|
|
jit->write_ubyte(IA32_MOVZX_R32_RM16_1);
|
|
jit->write_ubyte(IA32_MOVZX_R32_RM16_2);
|
|
jit->write_ubyte(ia32_modrm(mode, dest, src));
|
|
}
|
|
|
|
inline void IA32_Movzx_Reg32_Rm16_Disp8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int8_t disp)
|
|
{
|
|
jit->write_ubyte(IA32_MOVZX_R32_RM16_1);
|
|
jit->write_ubyte(IA32_MOVZX_R32_RM16_2);
|
|
jit->write_ubyte(ia32_modrm(MOD_DISP8, dest, src));
|
|
jit->write_byte(disp);
|
|
}
|
|
|
|
inline void IA32_Movzx_Reg32_Rm16_Disp32(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int32_t disp)
|
|
{
|
|
jit->write_ubyte(IA32_MOVZX_R32_RM16_1);
|
|
jit->write_ubyte(IA32_MOVZX_R32_RM16_2);
|
|
jit->write_ubyte(ia32_modrm(MOD_DISP32, dest, src));
|
|
jit->write_int32(disp);
|
|
}
|
|
|
|
inline void IA32_Push_Reg(JitWriter *jit, jit_uint8_t reg)
|
|
{
|
|
jit->write_ubyte(IA32_PUSH_REG+reg);
|
|
}
|
|
|
|
inline void IA32_Pop_Reg(JitWriter *jit, jit_uint8_t reg)
|
|
{
|
|
jit->write_ubyte(IA32_POP_REG+reg);
|
|
}
|
|
|
|
inline void IA32_Lea_DispRegImm8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src_base, jit_int8_t val)
|
|
{
|
|
jit->write_ubyte(IA32_LEA_REG_MEM);
|
|
jit->write_ubyte(ia32_modrm(MOD_DISP8, dest, src_base));
|
|
jit->write_byte(val);
|
|
}
|
|
|
|
inline void IA32_Lea_DispRegImm32(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src_base, jit_int32_t val)
|
|
{
|
|
jit->write_ubyte(IA32_LEA_REG_MEM);
|
|
jit->write_ubyte(ia32_modrm(MOD_DISP32, dest, src_base));
|
|
jit->write_int32(val);
|
|
}
|
|
|
|
inline void IA32_Mov_Reg_Rm_Disp8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int8_t disp)
|
|
{
|
|
jit->write_ubyte(IA32_MOV_REG_RM);
|
|
jit->write_ubyte(ia32_modrm(MOD_DISP8, dest, src));
|
|
jit->write_byte(disp);
|
|
}
|
|
|
|
inline void IA32_Mov_Reg_Rm_Disp32(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int32_t disp)
|
|
{
|
|
jit->write_ubyte(IA32_MOV_REG_RM);
|
|
jit->write_ubyte(ia32_modrm(MOD_DISP32, dest, src));
|
|
jit->write_int32(disp);
|
|
}
|
|
|
|
inline void IA32_Sub_Rm_Imm8(JitWriter *jit, jit_uint8_t reg, jit_int8_t val, jit_uint8_t mode)
|
|
{
|
|
jit->write_ubyte(IA32_SUB_RM_IMM8);
|
|
jit->write_ubyte(ia32_modrm(mode, 5, reg));
|
|
jit->write_byte(val);
|
|
}
|
|
|
|
inline void IA32_Sub_Rm_Imm32(JitWriter *jit, jit_uint8_t reg, jit_int32_t val, jit_uint8_t mode)
|
|
{
|
|
jit->write_ubyte(IA32_SUB_RM_IMM32);
|
|
jit->write_ubyte(ia32_modrm(mode, 5, reg));
|
|
jit->write_int32(val);
|
|
}
|
|
|
|
inline void IA32_Cld(JitWriter *jit)
|
|
{
|
|
jit->write_ubyte(IA32_CLD);
|
|
}
|
|
|
|
inline void IA32_Rep(JitWriter *jit)
|
|
{
|
|
jit->write_ubyte(IA32_REP);
|
|
}
|
|
|
|
inline void IA32_Movsd(JitWriter *jit)
|
|
{
|
|
jit->write_ubyte(IA32_MOVSD);
|
|
}
|
|
|
|
inline void IA32_Movsb(JitWriter *jit)
|
|
{
|
|
jit->write_ubyte(IA32_MOVSB);
|
|
}
|
|
|
|
inline jitoffs_t IA32_Call_Imm32(JitWriter *jit, jit_int32_t disp)
|
|
{
|
|
jitoffs_t ptr;
|
|
jit->write_ubyte(IA32_CALL_IMM32);
|
|
ptr = jit->get_outputpos();
|
|
jit->write_int32(disp);
|
|
return ptr;
|
|
}
|
|
|
|
inline void IA32_Mov_Rm8_Reg8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode)
|
|
{
|
|
jit->write_ubyte(IA32_MOV_RM8_REG8);
|
|
jit->write_ubyte(ia32_modrm(mode, src, dest));
|
|
}
|
|
|
|
inline void IA32_Mov_Rm_Reg(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode)
|
|
{
|
|
jit->write_ubyte(IA32_MOV_RM_REG);
|
|
jit->write_ubyte(ia32_modrm(mode, src, dest));
|
|
}
|
|
|
|
/**
|
|
* Corrects a jump using an absolute offset, not a relative one.
|
|
*/
|
|
inline void IA32_Write_Jump32_Abs(JitWriter *jit, jitoffs_t jmp, void *target)
|
|
{
|
|
//save old ptr
|
|
jitcode_t oldptr = jit->outptr;
|
|
//get relative difference
|
|
long diff = ((long)target - ((long)jit->outbase + jmp + 4));
|
|
//overwrite old value
|
|
jit->outptr = jit->outbase + jmp;
|
|
jit->write_int32(diff);
|
|
//restore old ptr
|
|
jit->outptr = oldptr;
|
|
}
|
|
|
|
inline void IA32_Fstp_Mem32(JitWriter *jit, jit_uint8_t dest)
|
|
{
|
|
jit->write_ubyte(IA32_FSTP_MEM32);
|
|
jit->write_ubyte(ia32_modrm(MOD_MEM_REG, 3, dest));
|
|
}
|
|
|
|
inline void IA32_Fstp_Mem64(JitWriter *jit, jit_uint8_t dest)
|
|
{
|
|
jit->write_ubyte(IA32_FSTP_MEM64);
|
|
jit->write_ubyte(ia32_modrm(MOD_MEM_REG, 3, dest));
|
|
}
|
|
|
|
inline void IA32_Mov_Rm_Reg_Disp8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int8_t disp)
|
|
{
|
|
jit->write_ubyte(IA32_MOV_RM_REG);
|
|
jit->write_ubyte(ia32_modrm(MOD_DISP8, src, dest));
|
|
jit->write_byte(disp);
|
|
}
|
|
|
|
inline void IA32_Call_Reg(JitWriter *jit, jit_uint8_t reg)
|
|
{
|
|
jit->write_ubyte(IA32_CALL_RM);
|
|
jit->write_ubyte(ia32_modrm(MOD_REG, 2, reg));
|
|
}
|
|
|
|
inline jitoffs_t IA32_Mov_Reg_Imm32(JitWriter *jit, jit_uint8_t dest, jit_int32_t num)
|
|
{
|
|
jitoffs_t offs;
|
|
jit->write_ubyte(IA32_MOV_REG_IMM+dest);
|
|
offs = jit->get_outputpos();
|
|
jit->write_int32(num);
|
|
return offs;
|
|
}
|
|
|
|
inline void IA32_Add_Rm_Imm8(JitWriter *jit, jit_uint8_t reg, jit_int8_t value, jit_uint8_t mode)
|
|
{
|
|
jit->write_ubyte(IA32_ADD_RM_IMM8);
|
|
jit->write_ubyte(ia32_modrm(mode, 0, reg));
|
|
jit->write_byte(value);
|
|
}
|
|
|
|
inline void IA32_Add_Rm_Imm32(JitWriter *jit, jit_uint8_t reg, jit_int32_t value, jit_uint8_t mode)
|
|
{
|
|
jit->write_ubyte(IA32_ADD_RM_IMM32);
|
|
jit->write_ubyte(ia32_modrm(mode, 0, reg));
|
|
jit->write_int32(value);
|
|
}
|
|
|
|
inline void IA32_And_Rm_Imm8(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode, jit_int8_t value)
|
|
{
|
|
jit->write_ubyte(IA32_AND_RM_IMM8);
|
|
jit->write_ubyte(ia32_modrm(mode, 4, reg));
|
|
jit->write_byte(value);
|
|
}
|
|
|
|
inline void IA32_Lea_Reg_DispRegMultImm8(JitWriter *jit,
|
|
jit_uint8_t dest,
|
|
jit_uint8_t src_base,
|
|
jit_uint8_t src_index,
|
|
jit_uint8_t scale,
|
|
jit_int8_t val)
|
|
{
|
|
jit->write_ubyte(IA32_LEA_REG_MEM);
|
|
jit->write_ubyte(ia32_modrm(MOD_DISP8, dest, kREG_SIB));
|
|
jit->write_ubyte(ia32_sib(scale, src_index, src_base));
|
|
jit->write_byte(val);
|
|
}
|
|
|
|
inline void IA32_Fld_Mem32_Disp8(JitWriter *jit, jit_uint8_t src, jit_int8_t val)
|
|
{
|
|
jit->write_ubyte(IA32_FLD_MEM32);
|
|
jit->write_ubyte(ia32_modrm(MOD_DISP8, 0, src));
|
|
jit->write_byte(val);
|
|
}
|
|
|
|
inline void IA32_Fld_Mem64_Disp8(JitWriter *jit, jit_uint8_t src, jit_int8_t val)
|
|
{
|
|
jit->write_ubyte(IA32_FLD_MEM64);
|
|
jit->write_ubyte(ia32_modrm(MOD_DISP8, 0, src));
|
|
jit->write_byte(val);
|
|
}
|
|
|
|
inline void IA32_Fld_Mem32(JitWriter *jit, jit_uint8_t src)
|
|
{
|
|
jit->write_ubyte(IA32_FLD_MEM32);
|
|
jit->write_ubyte(ia32_modrm(MOD_MEM_REG, 0, src));
|
|
}
|
|
|
|
inline void IA32_Fld_Mem64(JitWriter *jit, jit_uint8_t src)
|
|
{
|
|
jit->write_ubyte(IA32_FLD_MEM64);
|
|
jit->write_ubyte(ia32_modrm(MOD_MEM_REG, 0, src));
|
|
}
|
|
|
|
inline void IA32_Fld_Mem32_Disp32(JitWriter *jit, jit_uint8_t src, jit_int32_t val)
|
|
{
|
|
jit->write_ubyte(IA32_FLD_MEM32);
|
|
jit->write_ubyte(ia32_modrm(MOD_DISP32, 0, src));
|
|
jit->write_int32(val);
|
|
}
|
|
|
|
inline void IA32_Fld_Mem64_Disp32(JitWriter *jit, jit_uint8_t src, jit_int32_t val)
|
|
{
|
|
jit->write_ubyte(IA32_FLD_MEM64);
|
|
jit->write_ubyte(ia32_modrm(MOD_DISP32, 0, src));
|
|
jit->write_int32(val);
|
|
}
|
|
|
|
inline void IA32_Fstp_Mem32_ESP(JitWriter *jit)
|
|
{
|
|
jit->write_ubyte(IA32_FSTP_MEM32);
|
|
jit->write_ubyte(ia32_modrm(MOD_MEM_REG, 3, kREG_SIB));
|
|
jit->write_ubyte(ia32_sib(NOSCALE, kREG_NOIDX, kREG_ESP));
|
|
}
|
|
|
|
inline void IA32_Fstp_Mem64_ESP(JitWriter *jit)
|
|
{
|
|
jit->write_ubyte(IA32_FSTP_MEM64);
|
|
jit->write_ubyte(ia32_modrm(MOD_MEM_REG, 3, kREG_SIB));
|
|
jit->write_ubyte(ia32_sib(NOSCALE, kREG_NOIDX, kREG_ESP));
|
|
}
|
|
|
|
inline void IA32_Return_Popstack(JitWriter *jit, unsigned short bytes)
|
|
{
|
|
jit->write_ubyte(IA32_RETN);
|
|
jit->write_ushort(bytes);
|
|
}
|
|
|
|
inline void IA32_Push_Imm8(JitWriter *jit, jit_int8_t val)
|
|
{
|
|
jit->write_ubyte(IA32_PUSH_IMM8);
|
|
jit->write_byte(val);
|
|
}
|
|
|
|
inline void IA32_Push_Imm32(JitWriter *jit, jit_int32_t val)
|
|
{
|
|
jit->write_ubyte(IA32_PUSH_IMM32);
|
|
jit->write_int32(val);
|
|
}
|
|
|
|
inline void IA32_Mov_Reg8_Rm8_Disp8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int8_t disp)
|
|
{
|
|
jit->write_ubyte(IA32_MOV_REG8_RM8);
|
|
jit->write_ubyte(ia32_modrm(MOD_DISP8, dest, src));
|
|
jit->write_byte(disp);
|
|
}
|
|
|
|
inline jitoffs_t IA32_Jump_Imm32(JitWriter *jit, jit_int32_t disp)
|
|
{
|
|
jitoffs_t ptr;
|
|
jit->write_ubyte(IA32_JMP_IMM32);
|
|
ptr = jit->get_outputpos();
|
|
jit->write_int32(disp);
|
|
return ptr;
|
|
}
|
|
|
|
#endif //_INCLUDE_JIT_X86_MACROS_H
|
|
|