mirror of
https://github.com/NishiOwO/JWasm.git
synced 2025-04-21 08:44:38 +00:00
865 lines
30 KiB
C
865 lines
30 KiB
C
/****************************************************************************
|
|
*
|
|
* This code is Public Domain.
|
|
*
|
|
* ========================================================================
|
|
*
|
|
* Description: reserved word handling, including hash table access
|
|
*
|
|
****************************************************************************/
|
|
|
|
#include "globals.h"
|
|
#include "memalloc.h"
|
|
#include "parser.h"
|
|
#include "reswords.h"
|
|
#include "expreval.h"
|
|
#include "condasm.h"
|
|
#include "codegen.h"
|
|
#ifdef __I86__
|
|
#include "i86.h"
|
|
#endif
|
|
|
|
//#define HASH_TABITEMS 211
|
|
#if AVXSUPP
|
|
#define HASH_TABITEMS 811
|
|
#else
|
|
#define HASH_TABITEMS 599
|
|
#endif
|
|
|
|
#if 0 // def __I86__
|
|
/* optionally, for JWASMR, use a void based pointer for the name field.
|
|
* However, this requires to deactivate the RENAMEKEYWORD option!
|
|
*/
|
|
#define GetPtr( x, y ) seg:>x->y
|
|
#define BASEPTR
|
|
#else
|
|
#define GetPtr( x, y ) x->y
|
|
#endif
|
|
|
|
/* reserved words hash table */
|
|
static uint_16 resw_table[ HASH_TABITEMS ];
|
|
|
|
/* define unary operand (LOW, HIGH, OFFSET, ...) type flags */
|
|
enum unary_operand_types {
|
|
#define res( value, func ) UOT_ ## value,
|
|
#include "unaryop.h"
|
|
#undef res
|
|
};
|
|
|
|
/* v2.06: the following operand combinations are used
|
|
* inside InstrTable[] only, they don't need to be known
|
|
* by the parser.
|
|
*/
|
|
enum operand_sets {
|
|
OP_R_MS = ( OP_R | OP_MS ),
|
|
OP_R8_M08 = ( OP_R8 | OP_M08 ),
|
|
OP_RGT8_MS = ( OP_RGT8 | OP_MS ),
|
|
OP_RGT8_MGT8 = ( OP_RGT8 | OP_MGT8 ),
|
|
OP_RMGT16 = ( OP_RGT16 | OP_MGT16 ),
|
|
OP_RGT16_M08 = ( OP_RGT16 | OP_M08 ),
|
|
OP_R16_R32 = ( OP_R16 | OP_R32 ),
|
|
OP_R16_M16 = ( OP_R16 | OP_M16 ),
|
|
OP_R32_M08 = ( OP_R32 | OP_M08 ),
|
|
OP_R32_M16 = ( OP_R32 | OP_M16 ),
|
|
OP_R32_M32 = ( OP_R32 | OP_M32 ),
|
|
#if AMD64_SUPPORT
|
|
OP_R16_R64 = ( OP_R16 | OP_R64 ),
|
|
OP_R64_M64 = ( OP_R64 | OP_M64 ),
|
|
OP_M16_M64 = ( OP_M16 | OP_M64 ),
|
|
#endif
|
|
OP_M16_M32 = ( OP_M16 | OP_M32 ),
|
|
OP_MMX_M64 = ( OP_MMX | OP_M64 ),
|
|
OP_XMM_M16 = ( OP_XMM | OP_M16 ),
|
|
OP_XMM_M32 = ( OP_XMM | OP_M32 ),
|
|
OP_XMM_M64 = ( OP_XMM | OP_M64 ),
|
|
OP_XMM_M128 = ( OP_XMM | OP_M128 ),
|
|
#if MASM_SSE_MEMX
|
|
/* extended Masm syntax: sometimes Masm accepts 2 mem types
|
|
* for the memory operand, although the mem access will always
|
|
* be QWORD/OWORD.
|
|
*/
|
|
OP_MMX_M64_08 = ( OP_MMX | OP_M64 | OP_M08 ),
|
|
OP_MMX_M64_16 = ( OP_MMX | OP_M64 | OP_M16 ),
|
|
OP_MMX_M64_32 = ( OP_MMX | OP_M64 | OP_M32 ),
|
|
|
|
OP_XMM_M128_08 = ( OP_XMM | OP_M128 | OP_M08 ),
|
|
OP_XMM_M128_16 = ( OP_XMM | OP_M128 | OP_M16 ),
|
|
OP_XMM_M128_32 = ( OP_XMM | OP_M128 | OP_M32 ),
|
|
OP_XMM_M128_64 = ( OP_XMM | OP_M128 | OP_M64 ),
|
|
#else
|
|
/* see macro OpCls() below */
|
|
#define OPC_MMXMMX_M64_08NONE OPC_MMXMMX_M64NONE
|
|
#define OPC_MMXMMX_M64_16NONE OPC_MMXMMX_M64NONE
|
|
#define OPC_MMXMMX_M64_32NONE OPC_MMXMMX_M64NONE
|
|
|
|
#define OPC_XMMXMM_M128_08NONE OPC_XMMXMM_M128NONE
|
|
#define OPC_XMMXMM_M128_16NONE OPC_XMMXMM_M128NONE
|
|
#define OPC_XMMXMM_M128_32NONE OPC_XMMXMM_M128NONE
|
|
#define OPC_XMMXMM_M128_64NONE OPC_XMMXMM_M128NONE
|
|
#endif
|
|
#if AVXSUPP
|
|
OP_YMM_M256 = ( OP_YMM | OP_M256 ),
|
|
#endif
|
|
};
|
|
|
|
/* v2.06: operand types have been removed from InstrTable[], they
|
|
* are stored now in their own table, opnd_clstab[], below.
|
|
* This will allow to add a 4th operand ( AVX ) more effectively.
|
|
*/
|
|
enum opnd_variants {
|
|
#define OpCls( op1, op2, op3 ) OPC_ ## op1 ## op2 ## op3,
|
|
#include "opndcls.h"
|
|
#undef OpCls
|
|
};
|
|
|
|
/* the tables to handle "reserved words" are now generated:
|
|
* 1. InstrTable: contains info for instructions.
|
|
* instructions may need multiple rows!
|
|
* 2. SpecialTable: contains info for reserved words which are
|
|
* NOT instructions. One row each.
|
|
* 3. optable_idx: array of indices for InstrTable.
|
|
* 4. resw_strings: strings of reserved words. No terminating x'00'!
|
|
* 5. ResWordTable: array of reserved words (name, name length, flags).
|
|
*
|
|
* Each reserved word has a "token" value assigned, which is a short integer.
|
|
* This integer can be used as index for:
|
|
* - SpecialTable
|
|
* - optable_idx ( needs adjustment, better use macro IndexFromToken() )
|
|
* - ResWordTable
|
|
*/
|
|
|
|
/* create InstrTable. */
|
|
|
|
#define OpCls( op1, op2, op3 ) OPC_ ## op1 ## op2 ## op3
|
|
|
|
const struct instr_item InstrTable[] = {
|
|
#define ins(tok, string, opcls, byte1_info,op_dir,rm_info,opcode,rm_byte,cpu,prefix) \
|
|
{ opcls, byte1_info, prefix, 1, rm_info, op_dir, 0, cpu, opcode, rm_byte },
|
|
#define insx(tok,string, opcls, byte1_info,op_dir,rm_info,opcode,rm_byte,cpu,prefix,flgs) \
|
|
{ opcls, byte1_info, prefix, 1, rm_info, op_dir, 0, cpu, opcode, rm_byte },
|
|
#define insn(tok,suffix, opcls, byte1_info,op_dir,rm_info,opcode,rm_byte,cpu,prefix) \
|
|
{ opcls, byte1_info, prefix, 0, rm_info, op_dir, 0, cpu, opcode, rm_byte },
|
|
#define insm(tok,suffix, opcls, byte1_info,op_dir,rm_info,opcode,rm_byte,cpu,prefix) \
|
|
{ opcls, byte1_info, prefix, 1, rm_info, op_dir, 0, cpu, opcode, rm_byte },
|
|
#include "instruct.h"
|
|
#include "instr64.h"
|
|
ins (NULL,0,OpCls(NONE,NONE,NONE),0,0,0,0,0,0,0) /* last entry - needed for its ".first" (=1) field */
|
|
#undef insm
|
|
#undef insn
|
|
#undef insx
|
|
#undef ins
|
|
};
|
|
#undef OpCls
|
|
|
|
/* create SpecialTable. */
|
|
|
|
const struct special_item SpecialTable[] = {
|
|
{ 0, 0, 0, 0, 0 }, /* dummy entry for T_NULL */
|
|
#define res(tok, string, type, value, bytval, flags, cpu, sflags ) \
|
|
{ value, sflags, cpu, bytval, type },
|
|
#include "special.h"
|
|
#undef res
|
|
#define res(tok, string, value, bytval, flags, cpu, sflags ) \
|
|
{ value, sflags, cpu, bytval, RWT_DIRECTIVE },
|
|
#include "directve.h"
|
|
#undef res
|
|
};
|
|
|
|
/* define symbolic indices for InstrTable[] */
|
|
|
|
enum res_idx {
|
|
#define ins(tok, string, opcls, byte1_info, op_dir, rm_info, opcode, rm_byte, cpu, prefix) T_ ## tok ## _I,
|
|
#define insx(tok, string, opcls, byte1_info, op_dir, rm_info, opcode, rm_byte, cpu, prefix,flgs) T_ ## tok ## _I,
|
|
#define insn(tok, suffix, opcls, byte1_info, op_dir, rm_info, opcode, rm_byte, cpu, prefix) T_ ## tok ## _ ## suffix,
|
|
#define insm(tok, suffix, opcls, byte1_info, op_dir, rm_info, opcode, rm_byte, cpu, prefix) T_ ## tok ## _ ## suffix,
|
|
#include "instruct.h"
|
|
#undef insm
|
|
#undef insn
|
|
#undef ins
|
|
|
|
#define ins(tok, string, opcls, byte1_info, op_dir, rm_info, opcode, rm_byte, cpu, prefix) T_ ## tok ## _I64,
|
|
#define insn(tok, suffix, opcls, byte1_info, op_dir, rm_info, opcode, rm_byte, cpu, prefix) T_ ## tok ## _ ## suffix ## _I64,
|
|
#define insm(tok, suffix, opcls, byte1_info, op_dir, rm_info, opcode, rm_byte, cpu, prefix) T_ ## tok ## _ ## suffix ## _I64,
|
|
#include "instr64.h"
|
|
#undef insm
|
|
#undef insn
|
|
#undef insx
|
|
#undef ins
|
|
//T_NULL_I /* v2.06: removed */
|
|
};
|
|
|
|
/* create optable_idx, the index array for InstrTable.
|
|
* This is needed because instructions often need more than
|
|
* one entry in InstrTable.
|
|
*/
|
|
|
|
uint_16 optable_idx[] = {
|
|
|
|
#define ins( tok, string, opcls, byte1_info, op_dir, rm_info, opcode, rm_byte, cpu, prefix) T_ ## tok ## _I,
|
|
#define insx( tok, string, opcls, byte1_info, op_dir, rm_info, opcode, rm_byte, cpu, prefix,flgs) T_ ## tok ## _I,
|
|
#define insn( tok, suffix, opcls, byte1_info, op_dir, rm_info, opcode, rm_byte, cpu, prefix)
|
|
#define insm( tok, suffix, opcls, byte1_info, op_dir, rm_info, opcode, rm_byte, cpu, prefix)
|
|
#include "instruct.h"
|
|
#undef insm
|
|
#undef insn
|
|
#undef insx
|
|
#undef ins
|
|
|
|
/* v2.06: this was superfluous, because the additional entries for
|
|
* 64-bit are only needed in InstrTable[]. For optable_idx[], a
|
|
* patch is done (see patchtabr[])
|
|
*/
|
|
//#define ins(tok,string, op1,op2,op3, byte1_info,op_dir,rm_info,opcode,rm_byte,cpu,prefix) T_ ## tok ## _I64,
|
|
//#define insn(tok,suffix, op1,op2,op3, byte1_info,op_dir,rm_info,opcode,rm_byte,cpu,prefix) T_ ## tok ## _ ## suffix ## _I64,
|
|
//#define insm(tok,suffix, op1,op2,op3, byte1_info,op_dir,rm_info,opcode,rm_byte,cpu,prefix) T_ ## tok ## _ ## suffix ## _I64,
|
|
//#include "instr64.h"
|
|
//#undef insm
|
|
//#undef insn
|
|
//#undef ins
|
|
|
|
#if AVXSUPP
|
|
#define avxins( tok, string, cpu, flgs ) T_ ## tok ## _I,
|
|
#include "instravx.h"
|
|
#undef avxins
|
|
#endif
|
|
//T_NULL_I /* v2.06: also not needed */
|
|
};
|
|
|
|
/* table of instruction operand classes
|
|
*/
|
|
const struct opnd_class opnd_clstab[] = {
|
|
#define OpCls( op1, op2, op3 ) { { OP_ ## op1, OP_ ## op2 }, OP3_ ## op3 },
|
|
#include "opndcls.h"
|
|
#undef OpCls
|
|
};
|
|
|
|
/* create the strings for all reserved words */
|
|
|
|
static const char resw_strings[] = {
|
|
#define res(tok, string, type, value, bytval, flags, cpu, sflags) \
|
|
# string
|
|
#include "special.h"
|
|
#undef res
|
|
#define res(tok, string, value, bytval, flags, cpu, sflags) \
|
|
# string
|
|
#include "directve.h"
|
|
#undef res
|
|
|
|
#define ins(tok,string, opcls, byte1_info,op_dir,rm_info,opcode,rm_byte,cpu,prefix) \
|
|
# string
|
|
#define insn(tok,suffix, opcls, byte1_info,op_dir,rm_info,opcode,rm_byte,cpu,prefix)
|
|
#define insm(tok,suffix, opcls, byte1_info,op_dir,rm_info,opcode,rm_byte,cpu,prefix)
|
|
#define insx(tok,string, opcls, byte1_info,op_dir,rm_info,opcode,rm_byte,cpu,prefix,flgs) \
|
|
# string
|
|
#include "instruct.h"
|
|
#if AVXSUPP
|
|
#define avxins( tok, string, cpu, flgs ) # string
|
|
#include "instravx.h"
|
|
#undef avxins
|
|
#endif
|
|
"syscall_" /* replacement for "syscall" language type in 64-bit */
|
|
};
|
|
#define strSyscall_ &resw_strings[sizeof(resw_strings)-9]
|
|
#undef insx
|
|
#undef insm
|
|
#undef insn
|
|
#undef ins
|
|
|
|
/* create the 'reserved words' table (ResWordTable).
|
|
* this table's entries will be used to create the instruction hash table.
|
|
* v2.11: RWF_SPECIAL flag removed:
|
|
* { 0, sizeof(#string)-1, RWF_SPECIAL | flags, NULL },
|
|
*/
|
|
struct ReservedWord ResWordTable[] = {
|
|
{ 0, 0, 0, NULL }, /* dummy entry for T_NULL */
|
|
#define res(tok, string, type, value, bytval, flags, cpu, sflags) \
|
|
{ 0, sizeof(#string)-1, flags, NULL },
|
|
#include "special.h"
|
|
#undef res
|
|
#define res(tok, string, value, bytval, flags, cpu, sflags) \
|
|
{ 0, sizeof(#string)-1, flags, NULL },
|
|
#include "directve.h"
|
|
#undef res
|
|
|
|
#define ins(tok,string, opcls, byte1_info,op_dir,rm_info,opcode,rm_byte,cpu,prefix) \
|
|
{ 0, sizeof(#string)-1, 0, NULL },
|
|
#define insn(tok,suffix, opcls, byte1_info,op_dir,rm_info,opcode,rm_byte,cpu,prefix)
|
|
#define insm(tok,suffix, opcls, byte1_info,op_dir,rm_info,opcode,rm_byte,cpu,prefix)
|
|
#define insx(tok,string, opcls, byte1_info,op_dir,rm_info,opcode,rm_byte,cpu,prefix,flags) \
|
|
{ 0, sizeof(#string)-1, flags, NULL },
|
|
#include "instruct.h"
|
|
#undef insx
|
|
#undef insm
|
|
#undef insn
|
|
#undef ins
|
|
#if AVXSUPP
|
|
#define avxins( tok, string, cpu, flgs ) \
|
|
{ 0, sizeof(#string)-1, RWF_VEX, NULL },
|
|
#include "instravx.h"
|
|
#undef avxins
|
|
#endif
|
|
};
|
|
|
|
#if AVXSUPP
|
|
/* these is a special 1-byte array for vex-encoded instructions.
|
|
* it could probably be moved to InstrTable[] (there is an unused byte),
|
|
* but in fact it's the wrong place, since the content of vex_flags[]
|
|
* are associated with opcodes, not with instruction variants.
|
|
*/
|
|
const uint_8 vex_flags[] = {
|
|
/* flags for the AVX instructions in instruct.h. The order must
|
|
* be equal to the one in instruct.h! ( this is to be improved.)
|
|
* For a description of the VX_ flags see codegen.h
|
|
*/
|
|
VX_NND, /* VBROADCASTSS */
|
|
VX_NND, /* VBROADCASTSD */
|
|
VX_NND, /* VBROADCASTF128 */
|
|
VX_L, /* VBLENDVPD */
|
|
VX_L, /* VBLENDVPS */
|
|
0, /* VINSERTF128 */
|
|
VX_NND, /* VEXTRACTF128 */
|
|
VX_L, /* VMASKMOVPS */
|
|
VX_L, /* VMASKMOVPD */
|
|
0, /* VPBLENDVB */
|
|
VX_L|VX_IMM, /* VPERMILPD */
|
|
VX_L|VX_IMM, /* VPERMILPS */
|
|
/* VPERMIL2xx has been dropped */
|
|
//VX_L, /* VPERMIL2PD */
|
|
//VX_L, /* VPERMIL2PS */
|
|
0, /* VPERM2F128 */
|
|
VX_L|VX_NND, /* VTESTPS */
|
|
VX_L|VX_NND, /* VTESTPD */
|
|
VX_L, /* VZEROALL */
|
|
0, /* VZEROUPPER */
|
|
VX_NND, /* VCVTPD2DQ */
|
|
VX_NND, /* VCVTTPD2DQ */
|
|
VX_NND, /* VCVTPD2PS */
|
|
VX_NND, /* VMOVDDUP */
|
|
VX_L|VX_NND, /* VMOVMSKPD */ /* v2.11 */
|
|
VX_L|VX_NND, /* VMOVMSKPS */ /* v2.11 */
|
|
#define avxins( tok, string, cpu, flgs ) flgs,
|
|
#include "instravx.h"
|
|
#undef avxins
|
|
};
|
|
#endif
|
|
|
|
#if AMD64_SUPPORT
|
|
|
|
/* keywords to be added for 64-bit */
|
|
static const enum instr_token patchtab64[] = {
|
|
T_SPL, /* add x64 register part of special.h */
|
|
T_FRAME, /* add x64 reserved word part of special.h */
|
|
T_DOT_ALLOCSTACK, /* add x64 directive part of directve.h (win64) */
|
|
T_JRCXZ, /* branch instructions must be grouped together */
|
|
T_CDQE, /* add x64 part of instruct.h */
|
|
#if AVXSUPP
|
|
T_VPEXTRQ, /* add x64 part of instravx.h */
|
|
#endif
|
|
};
|
|
|
|
/* keywords to be removed for 64-bit */
|
|
static const enum instr_token patchtab32[] = {
|
|
T_TR3, /* registers invalid for IA32+ */
|
|
T_DOT_SAFESEH, /* directives invalid for IA32+ */
|
|
T_AAA, /* instructions invalid for IA32+ */
|
|
T_JCXZ, /* 1. branch instructions invalid for IA32+ */
|
|
T_LOOPW /* 2. branch instructions invalid for IA32+ */
|
|
};
|
|
|
|
struct replace_ins {
|
|
uint_16 tok; /* is an optable_idx[] index */
|
|
enum res_idx idx32;
|
|
enum res_idx idx64;
|
|
};
|
|
|
|
/* keyword entries to be changed for 64-bit (see instr64.h) */
|
|
static const struct replace_ins patchtabr[] = {
|
|
{ T_LGDT - SPECIAL_LAST, T_LGDT_I, T_LGDT_I64 },
|
|
{ T_LIDT - SPECIAL_LAST, T_LIDT_I, T_LIDT_I64 },
|
|
{ T_CALL - SPECIAL_LAST, T_CALL_I, T_CALL_I64 },
|
|
{ T_JMP - SPECIAL_LAST, T_JMP_I, T_JMP_I64 },
|
|
{ T_POP - SPECIAL_LAST, T_POP_I, T_POP_I64 }, /* v2.06: added */
|
|
{ T_PUSH - SPECIAL_LAST, T_PUSH_I, T_PUSH_I64 }, /* v2.06: added */
|
|
#if 1
|
|
/* with Masm, in 16/32-bit SLDT|SMSW|STR accept a WORD argument only -
|
|
* in 64-bit (ML64), 32- and 64-bit registers are also accepted!
|
|
*/
|
|
{ T_SLDT - SPECIAL_LAST, T_SLDT_I, T_SLDT_I64 },
|
|
{ T_SMSW - SPECIAL_LAST, T_SMSW_I, T_SMSW_I64 },
|
|
{ T_STR - SPECIAL_LAST, T_STR_I, T_STR_I64 },
|
|
#endif
|
|
#if VMXSUPP /* v2.09: added */
|
|
{ T_VMREAD - SPECIAL_LAST, T_VMREAD_I, T_VMREAD_I64 },
|
|
{ T_VMWRITE - SPECIAL_LAST, T_VMWRITE_I, T_VMWRITE_I64 },
|
|
#endif
|
|
};
|
|
|
|
#endif
|
|
|
|
#if RENAMEKEY
|
|
static struct qdesc renamed_keys = { NULL, NULL };
|
|
#endif
|
|
|
|
/* global queue of "disabled" reserved words.
|
|
* just indices of ResWordTable[] are used.
|
|
*/
|
|
static struct {
|
|
uint_16 Head;
|
|
uint_16 Tail;
|
|
} Removed = { 0, 0 };
|
|
|
|
#if AMD64_SUPPORT
|
|
static bool b64bit = FALSE; /* resw tables in 64bit mode? */
|
|
#endif
|
|
|
|
static unsigned get_hash( const char *s, unsigned char size )
|
|
/***********************************************************/
|
|
{
|
|
uint_32 h;
|
|
uint_32 g;
|
|
|
|
for( h = 0; size; size-- ) {
|
|
/* ( h & ~0x0fff ) == 0 is always true here */
|
|
h = (h << 3) + (*s++ | ' ');
|
|
g = h & ~0x1fff;
|
|
h ^= g;
|
|
h ^= g >> 13;
|
|
}
|
|
return( h % HASH_TABITEMS );
|
|
}
|
|
|
|
unsigned FindResWord( const char *name, unsigned char size )
|
|
/**********************************************************/
|
|
/* search reserved word in hash table */
|
|
{
|
|
struct ReservedWord *inst;
|
|
unsigned i;
|
|
#ifdef BASEPTR
|
|
__segment seg = FP_SEG( resw_strings );
|
|
#endif
|
|
|
|
for( i = resw_table[ get_hash( name, size ) ]; i != 0; i = inst->next ) {
|
|
inst = &ResWordTable[i];
|
|
/* check if the name matches the entry for this inst in AsmChars */
|
|
//if( name[ inst->len ] == NULLC && _strnicmp( name, inst->name, inst->len ) == 0) {
|
|
if( inst->len == size && _memicmp( name, GetPtr( inst, name ), inst->len ) == 0 ) {
|
|
return( i );
|
|
}
|
|
}
|
|
return( 0 );
|
|
}
|
|
|
|
/* add reserved word to hash table */
|
|
|
|
static void AddResWord( int token )
|
|
/*********************************/
|
|
{
|
|
int i;
|
|
int old;
|
|
int curr;
|
|
#ifdef BASEPTR
|
|
__segment seg = FP_SEG( resw_strings );
|
|
#endif
|
|
|
|
i = get_hash( ResWordTable[token].name, ResWordTable[token].len );
|
|
|
|
/* sort the items of a line by length! */
|
|
|
|
for( curr = resw_table[i], old = 0; curr != 0 && ResWordTable[curr].len <= ResWordTable[token].len; old = curr, curr = ResWordTable[curr].next );
|
|
|
|
if ( old == 0 ) {
|
|
ResWordTable[token].next = resw_table[i];
|
|
resw_table[i] = token;
|
|
} else {
|
|
ResWordTable[token].next = ResWordTable[old].next;
|
|
ResWordTable[old].next = token;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/* remove a reserved word from the hash table. */
|
|
|
|
static int RemoveResWord( int token )
|
|
/***********************************/
|
|
{
|
|
int i;
|
|
int old;
|
|
int curr;
|
|
#ifdef BASEPTR
|
|
__segment seg = FP_SEG( resw_strings );
|
|
#endif
|
|
|
|
i = get_hash( ResWordTable[token].name, ResWordTable[token].len );
|
|
|
|
for( curr = resw_table[i], old = 0 ; curr != 0 ; old = curr, curr = ResWordTable[curr].next ) {
|
|
if( curr == token ) {
|
|
if ( old != 0 )
|
|
ResWordTable[old].next = ResWordTable[curr].next;
|
|
else
|
|
resw_table[i] = ResWordTable[curr].next;
|
|
return( TRUE );
|
|
}
|
|
}
|
|
return( FALSE );
|
|
}
|
|
|
|
#if RENAMEKEY
|
|
|
|
struct rename_node {
|
|
struct rename_node *next;
|
|
const char *name; /* the original name in resw_strings[] */
|
|
uint_16 token; /* is either enum instr_token or enum special_token */
|
|
uint_8 length;
|
|
};
|
|
|
|
/* Rename a keyword - used by OPTION RENAMEKEYWORD.
|
|
* - token: keyword to rename
|
|
* - newname: new name of keyword
|
|
* - length: length of new name
|
|
*/
|
|
|
|
void RenameKeyword( unsigned token, const char *newname, uint_8 length )
|
|
/**********************************************************************/
|
|
{
|
|
struct rename_node *curr;
|
|
struct rename_node *prev;
|
|
|
|
/* v2.11: do nothing if new name matches current name */
|
|
if ( ResWordTable[token].len == length && !_memicmp( newname, ResWordTable[token].name, length ) )
|
|
return;
|
|
|
|
RemoveResWord( token );
|
|
/* if it is the first rename action for this keyword,
|
|
* the original name must be saved.
|
|
*/
|
|
if ( ResWordTable[token].name >= resw_strings &&
|
|
ResWordTable[token].name < ( resw_strings + sizeof( resw_strings ) ) ) {
|
|
curr = LclAlloc( sizeof( struct rename_node ) );
|
|
curr->next = NULL;
|
|
curr->name = ResWordTable[token].name;
|
|
curr->token = token;
|
|
curr->length = ResWordTable[token].len;
|
|
if ( renamed_keys.head == NULL ) {
|
|
renamed_keys.head = renamed_keys.tail = curr;
|
|
} else {
|
|
((struct rename_node *)renamed_keys.tail)->next = curr;
|
|
renamed_keys.tail = curr;
|
|
}
|
|
} else {
|
|
LclFree( (void *)ResWordTable[token].name );
|
|
#if 1
|
|
/* v2.11: search the original name. if the "new" names matches
|
|
* the original name, restore the name pointer */
|
|
for ( curr = renamed_keys.head, prev = NULL; curr; prev = curr ) {
|
|
if ( curr->token == token ) {
|
|
if ( curr->length == length && !memcmp( newname, curr->name, length ) ) {
|
|
if ( prev )
|
|
prev->next = curr->next;
|
|
else
|
|
renamed_keys.head = curr->next;
|
|
if ( renamed_keys.tail == curr )
|
|
renamed_keys.tail = prev;
|
|
ResWordTable[token].name = curr->name;
|
|
ResWordTable[token].len = curr->length;
|
|
AddResWord( token );
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
ResWordTable[token].name = LclAlloc( length );
|
|
/* convert to lowercase? */
|
|
memcpy( (void *)ResWordTable[token].name, newname, length );
|
|
ResWordTable[token].len = length;
|
|
AddResWord( token );
|
|
}
|
|
|
|
#endif
|
|
|
|
#if AMD64_SUPPORT
|
|
|
|
/* depending on 64bit on or off, some instructions must be added,
|
|
* some removed. Currently this is a bit hackish.
|
|
*/
|
|
void Set64Bit( bool newmode )
|
|
/***************************/
|
|
{
|
|
static const char *syscallname; /* "true" syscall name stored here */
|
|
int token;
|
|
int i;
|
|
|
|
if ( newmode != b64bit ) {
|
|
DebugMsg1(("Set64Bit(%u): mode is to change\n", newmode ));
|
|
if ( newmode != FALSE ) {
|
|
optable_idx[ T_INC - SPECIAL_LAST ]++; /* skip the one-byte register INC */
|
|
optable_idx[ T_DEC - SPECIAL_LAST ]++; /* skip the one-byte register DEC */
|
|
/*
|
|
* change SYSCALL to SYSCALL_ language in long mode.
|
|
* one cannot just change the name, since the hash value
|
|
* will differ!
|
|
*/
|
|
RemoveResWord( T_SYSCALL );
|
|
syscallname = ResWordTable[T_SYSCALL].name; /* save the "true" name */
|
|
ResWordTable[T_SYSCALL].name = strSyscall_;
|
|
ResWordTable[T_SYSCALL].len++;
|
|
AddResWord( T_SYSCALL );
|
|
|
|
for ( i = 0; i < sizeof( patchtab64 ) / sizeof( patchtab64[0] ); i++ )
|
|
for( token = patchtab64[i]; ResWordTable[token].flags & RWF_X64; token++ )
|
|
if ( !( ResWordTable[token].flags & RWF_DISABLED ) )
|
|
AddResWord( token );
|
|
for ( i = 0; i < sizeof( patchtab32 ) / sizeof( patchtab32[0] ); i++ )
|
|
for( token = patchtab32[i]; ResWordTable[token].flags & RWF_IA32; token++ )
|
|
if ( !( ResWordTable[token].flags & RWF_DISABLED ) )
|
|
RemoveResWord( token );
|
|
for ( i = 0; i < sizeof( patchtabr) / sizeof( patchtabr[0] ); i++ ) {
|
|
optable_idx[ patchtabr[i].tok] = patchtabr[i].idx64;
|
|
}
|
|
} else {
|
|
optable_idx[T_INC - SPECIAL_LAST]--; /* restore the one-byte register INC */
|
|
optable_idx[T_DEC - SPECIAL_LAST]--; /* restore the one-byte register DEC */
|
|
|
|
for ( i = 0; i < sizeof( patchtab64 ) / sizeof( patchtab64[0] ); i++ )
|
|
for( token = patchtab64[i]; ResWordTable[token].flags & RWF_X64; token++ )
|
|
if ( !( ResWordTable[token].flags & RWF_DISABLED ) )
|
|
RemoveResWord( token );
|
|
for ( i = 0; i < sizeof( patchtab32 ) / sizeof( patchtab32[0] ); i++ )
|
|
for( token = patchtab32[i]; ResWordTable[token].flags & RWF_IA32; token++ )
|
|
if ( !( ResWordTable[token].flags & RWF_DISABLED ) )
|
|
AddResWord( token );
|
|
for ( i = 0; i < sizeof( patchtabr) / sizeof( patchtabr[0] ); i++ ) {
|
|
optable_idx[patchtabr[i].tok] = patchtabr[i].idx32;
|
|
}
|
|
|
|
/* change calling convention syscall_ back to syscall */
|
|
RemoveResWord( T_SYSCALL );
|
|
ResWordTable[T_SYSCALL].name = syscallname; /* restore "true" name */
|
|
ResWordTable[T_SYSCALL].len--;
|
|
AddResWord( T_SYSCALL );
|
|
}
|
|
b64bit = newmode;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
void DisableKeyword( unsigned token )
|
|
/***********************************/
|
|
{
|
|
if ( !( ResWordTable[token].flags & RWF_DISABLED ) ) {
|
|
RemoveResWord( token );
|
|
ResWordTable[token].next = 0;
|
|
ResWordTable[token].flags |= RWF_DISABLED;
|
|
if ( Removed.Head == 0 )
|
|
Removed.Head = Removed.Tail = token;
|
|
else {
|
|
ResWordTable[Removed.Tail].next = token;
|
|
Removed.Tail = token;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* check if a keyword is in the list of disabled words.
|
|
*/
|
|
|
|
bool IsKeywordDisabled( const char *name, int len )
|
|
/*************************************************/
|
|
{
|
|
unsigned token;
|
|
for ( token = Removed.Head; token != 0; token = ResWordTable[token].next )
|
|
if( ResWordTable[token].name[ len ] == NULLC && _memicmp( name, ResWordTable[token].name, len ) == 0 )
|
|
return( TRUE );
|
|
return( FALSE );
|
|
}
|
|
|
|
/* get current name of a reserved word.
|
|
* max size is 255.
|
|
*/
|
|
|
|
char *GetResWName( unsigned resword, char *buff )
|
|
/***********************************************/
|
|
{
|
|
#ifdef __I86__
|
|
static char intbuff[32];
|
|
#else
|
|
static char intbuff[256];
|
|
#endif
|
|
if ( !buff )
|
|
buff = intbuff;
|
|
memcpy( buff, ResWordTable[resword].name, ResWordTable[resword].len );
|
|
buff[ResWordTable[resword].len] = NULLC;
|
|
return( buff );
|
|
}
|
|
|
|
/* ResWordsInit() initializes the reserved words hash array ( resw_table[] )
|
|
* and also the reserved words string pointers ( ResWordTable[].name + ResWordTable[].len )
|
|
*/
|
|
|
|
void ResWordsInit( void )
|
|
/***********************/
|
|
{
|
|
int i;
|
|
const char *p = resw_strings;
|
|
|
|
/* exit immediately if table is already initialized */
|
|
if ( ResWordTable[1].name )
|
|
return;
|
|
|
|
DebugMsg(("ResWordsInit() enter\n"));
|
|
|
|
/* clear hash table */
|
|
memset( &resw_table, 0, sizeof( resw_table ) );
|
|
|
|
#if AVXSUPP && AMD64_SUPPORT
|
|
/* currently these flags must be set manually, since the
|
|
* RWF_ flags aren't contained in instravx.h */
|
|
ResWordTable[T_VPEXTRQ].flags |= RWF_X64;
|
|
ResWordTable[T_VPINSRQ].flags |= RWF_X64;
|
|
#endif
|
|
|
|
/* initialize ResWordTable[].name and .len.
|
|
* add keyword to hash table ( unless it is 64-bit only ).
|
|
* v2.09: start with index = 1, since index 0 is now T_NULL
|
|
*/
|
|
for( i = 1; i < sizeof( ResWordTable ) / sizeof( ResWordTable[0] ); i++ ) {
|
|
ResWordTable[i].name = p;
|
|
p += ResWordTable[i].len;
|
|
#if AMD64_SUPPORT /* don't add the words specific to x64 */
|
|
if ( !(ResWordTable[i].flags & RWF_X64 ) )
|
|
#endif
|
|
AddResWord( i );
|
|
}
|
|
DebugMsg(("ResWordsInit() exit\n"));
|
|
return;
|
|
}
|
|
|
|
/* ResWordsFini() is called once per module
|
|
* it restores the resword table
|
|
*/
|
|
|
|
void ResWordsFini( void )
|
|
/***********************/
|
|
{
|
|
int i;
|
|
int next;
|
|
#if RENAMEKEY
|
|
struct rename_node *rencurr;
|
|
#endif
|
|
|
|
DebugMsg(("ResWordsFini() enter\n"));
|
|
#if RENAMEKEY
|
|
/* restore renamed keywords.
|
|
* the keyword has to removed ( and readded ) from the hash table,
|
|
* since its position most likely will change.
|
|
*/
|
|
for ( rencurr = renamed_keys.head; rencurr; ) {
|
|
struct rename_node *tmp = rencurr->next;
|
|
RemoveResWord( rencurr->token );
|
|
/* v2.06: this is the correct name to free */
|
|
LclFree( (void *)ResWordTable[rencurr->token].name );
|
|
ResWordTable[rencurr->token].name = rencurr->name;
|
|
ResWordTable[rencurr->token].len = rencurr->length;
|
|
AddResWord( rencurr->token );
|
|
DebugMsg(("ResWordsFini(): %s restored\n", GetResWName( rencurr->token, NULL ) ));
|
|
//LclFree( (void *)rencurr->name ); /* v2.06: this was the wrong one */
|
|
LclFree( rencurr );
|
|
rencurr = tmp;
|
|
}
|
|
renamed_keys.head = NULL;
|
|
#endif
|
|
|
|
/* reenter disabled keywords */
|
|
for( i = Removed.Head; i != 0; i = next ) {
|
|
next = ResWordTable[i].next;
|
|
ResWordTable[i].flags &= ~RWF_DISABLED;
|
|
#if AMD64_SUPPORT /* don't add the words specific to x64 */
|
|
if ( !(ResWordTable[i].flags & RWF_X64 ) )
|
|
#endif
|
|
AddResWord( i );
|
|
DebugMsg(("ResWordsInit(): %s reenabled\n", GetResWName( i, NULL ) ));
|
|
}
|
|
Removed.Head = Removed.Tail = 0;
|
|
|
|
return;
|
|
}
|
|
|
|
#ifdef DEBUG_OUT
|
|
|
|
void DumpResWords( void )
|
|
/***********************/
|
|
{
|
|
int i;
|
|
|
|
printf("SpecialTable\n");
|
|
printf(" # keyword value sflags cpu val8 type flg len\n");
|
|
printf("--------------------------------------------------------------\n");
|
|
/* start with index 1 ( index 0 is T_NULL ) */
|
|
for ( i = 1; i < sizeof( SpecialTable ) / sizeof( SpecialTable[0] ); i++ ) {
|
|
printf("%4u %-16s %8X %8X %4X %4X %2X %2X %3u\n", i, GetResWName( i, NULL ),
|
|
SpecialTable[i].value, SpecialTable[i].sflags,
|
|
SpecialTable[i].cpu, SpecialTable[i].bytval,
|
|
SpecialTable[i].type, ResWordTable[i].flags, ResWordTable[i].len );
|
|
}
|
|
printf("--------------------------------------------------------------\n");
|
|
|
|
printf("\nitems in InstrTable[]: %u\n", sizeof( InstrTable ) / sizeof( InstrTable[0] ) );
|
|
printf("items in optable_idx[]: %u, used by ResWordTable items %u-%u\n",
|
|
sizeof( optable_idx ) / sizeof( optable_idx[0] ), INS_FIRST_1 + 1, sizeof( ResWordTable ) / sizeof( ResWordTable[0] ) - 1 );
|
|
|
|
printf("\nInstructionTable\n");
|
|
printf(" # keyword cls cpu opc rmb b1 rmi pfx fst idx flg len\n");
|
|
printf("----------------------------------------------------------------\n");
|
|
for ( i = INS_FIRST_1 + 1; i < sizeof( ResWordTable ) / sizeof( ResWordTable[0] ); i++ ) {
|
|
const struct instr_item *ins = &InstrTable[IndexFromToken( i )];
|
|
printf("%4u %-16s %02X %4X %02X %02X %2u %X %X %u %4u %3X %3u\n", i, GetResWName( i, NULL ),
|
|
ins->opclsidx,
|
|
ins->cpu, ins->opcode, ins->rm_byte, ins->byte1_info,
|
|
ins->rm_info, ins->allowed_prefix, ins->first,
|
|
IndexFromToken( i ), ResWordTable[i].flags, ResWordTable[i].len );
|
|
}
|
|
printf("----------------------------------------------------------------\n");
|
|
}
|
|
|
|
void DumpInstrStats( void )
|
|
/*************************/
|
|
{
|
|
unsigned i;
|
|
int inst;
|
|
unsigned count = 0;
|
|
unsigned max = 0;
|
|
unsigned curr = 0;
|
|
unsigned num[8] = {0,0,0,0,0,0,0,0};
|
|
|
|
if ( Options.dump_reswords_hash ) {
|
|
printf("\nReserved Word Hash Table\n");
|
|
printf("Idx keywords\n");
|
|
printf("---------------------------\n");
|
|
}
|
|
|
|
for( i = 0; i < HASH_TABITEMS; i++ ) {
|
|
if ( Options.dump_reswords_hash )
|
|
printf("%3u ", i );
|
|
for( inst = resw_table[i], curr = 0; inst != 0; inst = ResWordTable[inst].next ) {
|
|
if ( Options.dump_reswords_hash )
|
|
printf(" %-8s", GetResWName( inst, NULL ) );
|
|
curr++;
|
|
}
|
|
if ( Options.dump_reswords_hash )
|
|
printf("\n" );
|
|
count += curr;
|
|
if ( curr <= 7 )
|
|
num[curr]++;
|
|
if (max < curr)
|
|
max = curr;
|
|
}
|
|
if ( Options.dump_reswords_hash )
|
|
printf("---------------------------\n");
|
|
if ( Options.quiet == FALSE ) {
|
|
printf( "%u items in resw table, max items/line=%u ", count, max );
|
|
printf( "[0=%u 1=%u %u %u %u %u %u %u]\n", num[0], num[1], num[2], num[3], num[4], num[5], num[6], num[7] );
|
|
}
|
|
}
|
|
#endif
|