asmmatch.c
来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 887 行 · 第 1/2 页
C
887 行
/****************************************************************************
*
* Open Watcom Project
*
* Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
*
* ========================================================================
*
* This file contains Original Code and/or Modifications of Original
* Code as defined in and that are subject to the Sybase Open Watcom
* Public License version 1.0 (the 'License'). You may not use this file
* except in compliance with the License. BY USING THIS FILE YOU AGREE TO
* ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is
* provided with the Original Code and Modifications, and is also
* available at www.sybase.com/developer/opensource.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM
* ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR
* NON-INFRINGEMENT. Please see the License for the specific language
* governing rights and limitations under the License.
*
* ========================================================================
*
* Description: WHEN YOU FIGURE OUT WHAT THIS FILE DOES, PLEASE
* DESCRIBE IT HERE!
*
****************************************************************************/
#include "asmglob.h"
#include "asmins.h"
#include "asmdefs.h"
#include "asmalloc.h"
#include "asmfixup.h"
#if defined( _STANDALONE_ )
#include "directiv.h"
extern void AddLinnumDataRef( void );
extern int AddFloatingPointEmulationFixup( const struct asm_ins ASMFAR *, bool );
#endif
static int match_phase_3( int *i, OPNDTYPE determinant );
static int output_3DNow( int i )
/******************************/
{
const struct asm_ins ASMFAR *ins = &AsmOpTable[i];
if( ins->byte1_info == F_0F0F ) {
AsmCodeByte( ins->opcode | Code->info.opcode );
}
return( NOT_ERROR );
}
static int output( int i )
/************************/
/*
- determine what code should be output and their order;
- output prefix bytes ( ADRSIZ, OPSIZ, LOCK, REPxx, segment override prefix, etc )
, opcode, "mod r/m" byte and "s-i-b" byte;
*/
{
const struct asm_ins ASMFAR *ins = &AsmOpTable[i];
struct asm_code *rCode = Code;
unsigned_8 tmp;
#if defined( _STANDALONE_ )
/*
* Output debug info - line numbers
*/
if( Options.debug_flag && !PhaseError && (Parse_Pass != PASS_1) ) {
AddLinnumDataRef();
}
/*
* Check if FP is valid
*/
if((( ins->cpu & P_FPU_MASK ) != P_NO87 ) && ( Options.floating_point == NO_FP_ALLOWED )) {
AsmError( NO_FP_WITH_FPC_SET );
return( ERROR );
}
/*
* Output FP fixup if required
*/
if(( Options.floating_point == DO_FP_EMULATION )
&& ( !rCode->use32 )
&& ( ins->allowed_prefix != NO_FWAIT )
&& (( ins->allowed_prefix == FWAIT ) || (( ins->cpu&P_FPU_MASK ) != P_NO87 ))) {
if( AddFloatingPointEmulationFixup( ins, FALSE ) == ERROR ) {
return( ERROR );
}
}
#endif
/*
* Check if CPU and FPU is valid for output code
*/
if( ( ins->cpu & P_CPU_MASK ) > ( rCode->info.cpu & P_CPU_MASK )
|| ( ins->cpu & P_FPU_MASK ) > ( rCode->info.cpu & P_FPU_MASK )
|| ( ins->cpu & P_EXT_MASK ) > ( ins->cpu & rCode->info.cpu & P_EXT_MASK ) ) {
AsmError( INVALID_INSTRUCTION_WITH_CURRENT_CPU_SETTING );
return( ERROR );
}
/*
* Output instruction prefix LOCK, REP or REPNE
*/
if( rCode->prefix.ins != EMPTY ) {
switch( rCode->prefix.ins ) {
case T_LOCK:
if( ins->allowed_prefix != LOCK ) {
AsmError( LOCK_PREFIX_IS_NOT_ALLOWED_ON_THIS_INSTRUCTION );
return( ERROR );
}
break;
case T_REP:
if( ins->allowed_prefix != REP ) {
AsmError( REP_PREFIX_IS_NOT_ALLOWED_ON_THIS_INSTRUCTION );
return( ERROR );
}
break;
case T_REPZ:
case T_REPE:
case T_REPNZ:
case T_REPNE:
if( ins->allowed_prefix != REPxx ) {
AsmError( REPX_PREFIX_IS_NOT_ALLOWED_ON_THIS_INSTRUCTION );
return( ERROR );
}
break;
default:
break;
}
AsmCodeByte( AsmOpTable[AsmOpcode[rCode->prefix.ins].position].opcode );
}
/*
* Output instruction prefix REP or REPNE for SSEx instructions
*/
switch( ins->byte1_info ) {
case F_F20F:
AsmCodeByte( 0xF2 );
break;
case F_F3:
case F_F30F:
AsmCodeByte( 0xF3 );
break;
case F_16:
case F_32:
case F_660F:
case F_0F:
case F_0F0F:
default:
break;
}
/*
* Output FP FWAIT if required
*/
if( ins->token == T_FWAIT ) {
if(( rCode->info.cpu&P_CPU_MASK ) < P_386 ) {
#if defined( _STANDALONE_ )
if(( Options.floating_point == DO_FP_EMULATION ) && ( !rCode->use32 )) {
AsmCodeByte( OP_NOP );
}
#else
AsmCodeByte( OP_NOP );
#endif
}
} else if( ins->allowed_prefix == FWAIT ) {
AsmCodeByte( OP_WAIT );
#if defined( _STANDALONE_ )
} else if(( Options.floating_point == DO_FP_EMULATION )
&& ( !rCode->use32 )
&& ( ins->allowed_prefix != NO_FWAIT )
&& (( ins->allowed_prefix == FWAIT ) || (( ins->cpu&P_FPU_MASK ) != P_NO87 ))) {
AsmCodeByte( OP_WAIT );
#endif
} else if( ins->allowed_prefix != NO_FWAIT ) {
// implicit FWAIT synchronization for 8087 (CPU 8086/80186)
if((( rCode->info.cpu&P_CPU_MASK ) < P_286 )
&& (( ins->cpu&P_FPU_MASK ) == P_87 )) {
AsmCodeByte( OP_WAIT );
}
}
#if defined( _STANDALONE_ )
/*
* Output FP fixup if required
*/
if(( Options.floating_point == DO_FP_EMULATION )
&& ( !rCode->use32 )
&& ( ins->allowed_prefix != NO_FWAIT )
&& (( ins->allowed_prefix == FWAIT ) || (( ins->cpu&P_FPU_MASK ) != P_NO87 ))) {
if( AddFloatingPointEmulationFixup( ins, TRUE ) == ERROR ) {
return( ERROR );
}
}
#endif
/*
* Output address size prefix
*/
if( rCode->prefix.adrsiz == TRUE ) {
AsmCodeByte( ADRSIZ );
}
/*
* Output operand size prefix
*/
if( ins->cpu & NO_OPPRFX )
rCode->prefix.opsiz = FALSE;
switch( ins->byte1_info ) {
case F_16:
if( rCode->use32 ) rCode->prefix.opsiz = TRUE;
break;
case F_32:
if( !rCode->use32 ) rCode->prefix.opsiz = TRUE;
break;
case F_660F:
rCode->prefix.opsiz = TRUE;
break;
case F_0F:
case F_0F0F:
case F_F20F:
case F_F30F:
default:
break;
}
if( rCode->prefix.opsiz == TRUE ) {
/*
Certain instructions use the ADDRSIZE prefix when they really
should use OPERSIZE prefix (well, I think so!). Stupid Intel.
*/
switch( ins->token ) {
case T_JCXZ:
case T_JECXZ:
case T_LOOPD:
case T_LOOPW:
case T_LOOPED:
case T_LOOPEW:
case T_LOOPNED:
case T_LOOPNEW:
case T_LOOPZD:
case T_LOOPZW:
case T_LOOPNZD:
case T_LOOPNZW:
AsmCodeByte( ADRSIZ );
break;
default:
AsmCodeByte( OPSIZ );
break;
}
}
/*
* Output segment prefix
*/
if( rCode->prefix.seg != EMPTY ) {
AsmCodeByte( rCode->prefix.seg );
}
/*
* Output extended opcode
* special case for some 286 and 386 instructions
* or 3DNow!, MMX and SSEx instructions
*/
switch( ins->byte1_info ) {
case F_0F0F:
AsmCodeByte( EXTENDED_OPCODE );
// no break
case F_0F:
case F_660F:
case F_F20F:
case F_F30F:
AsmCodeByte( EXTENDED_OPCODE );
break;
case F_F3:
default:
break;
}
if( ins->opnd_dir ) {
/* The reg and r/m fields are backwards */
tmp = rCode->info.rm_byte;
rCode->info.rm_byte = ( tmp & 0xc0 ) | ((tmp >> 3) & 0x7) | ((tmp << 3) & 0x38);
}
switch( ins->rm_info ) {
case R_in_OP:
AsmCodeByte( ins->opcode | ( rCode->info.rm_byte & NOT_BIT_67 ) );
break;
case no_RM:
AsmCodeByte( ins->opcode | rCode->info.opcode );
break;
case no_WDS:
rCode->info.opcode = 0;
// no break
default:
// don't output opcode for 3DNow! instructions
if( ins->byte1_info != F_0F0F ) {
AsmCodeByte( ins->opcode | rCode->info.opcode );
}
tmp = ins->rm_byte | rCode->info.rm_byte;
AsmCodeByte( tmp );
if( addr_32( rCode ) ) {
switch ( tmp & NOT_BIT_345 ) {
case 0x04:
// mod = 00, r/m = 100
// s-i-b is present
case 0x44:
// mod = 01, r/m = 100
// s-i-b is present
case 0x84:
// mod = 10, r/m = 100
// s-i-b is present
AsmCodeByte( rCode->sib );
}
}
break;
}
return( NOT_ERROR );
}
static int output_data( OPNDTYPE determinant, int index )
/*******************************************************/
/*
output address displacement and immediate data;
*/
{
int out = 0;
mark_fixupp( determinant, index );
switch( Code->info.token ) {
case T_CMPS:
case T_LODS:
case T_MOVS:
case T_OUTS:
case T_INS:
case T_SCAS:
case T_STOS:
case T_XLAT:
/* these instructions don't really want the memory operand */
return( NOT_ERROR );
}
#if defined( _STANDALONE_ )
store_fixup( index );
#endif
if( determinant & OP_I8 ) { // 8 bit
out = 1;
} else if( determinant & OP_I16 ) { // 16 bit
out = 2;
} else if( determinant & ( OP_I32 | OP_J32 ) ) { // 32 bit
out = 4;
} else if( determinant & OP_J48 ) {
out = 6;
} else if( determinant & OP_M_ANY ) {
// switch on the mode ( the leftmost 2 bits )
switch( Code->info.rm_byte & BIT_67 ) {
case MOD_01: // mode = 01
out = 1;
break;
case MOD_00:
if( !addr_32( Code ) ) {
if( ( Code->info.rm_byte & BIT_012 ) == D16 ) {
out = 2;
}
} else {
switch( Code->info.rm_byte & BIT_012 ) {
case S_I_B:
if( ( Code->sib & BIT_012 ) != D32 ) {
break; // out = 0
}
// no break
case D32:
out = 4;
}
}
break;
case MOD_10: // mode = 10
if( !addr_32( Code ) ) {
out = 2;
} else {
out = 4;
}
}
}
while( out > 0 ) {
AsmCodeByte( Code->data[index] );
Code->data[index] >>= 8;
out--;
}
return( NOT_ERROR );
}
static int match_phase_2( int *i )
/*********************************
- a routine used by match_phase_1() to determine whether both operands match
with that in the assembly instructions table;
- call by match_phase_1() only;
*/
{
if( Code->info.opnd_type[OPND2] != OP_NONE ) {
// 2 opnds instruction
return( match_phase_3( i, AsmOpTable[*i].opnd_type[OPND1] ) );
} else {
// 1 opnd instruction
// make sure the second opnd also match, i.e. has to be OP_NONE
if( AsmOpTable[*i].opnd_type[OPND2] == OP_NONE ) {
if( output( *i ) == ERROR ) {
return( ERROR );
}
// output idata or disp ( if first opnd is OP_M / OP_I )
return( output_data( Code->info.opnd_type[OPND1], OPND1 ) );
} else {
// still cannot find match
return( EMPTY );
}
}
}
int match_phase_1( void )
/************************
- this routine will look up the assembler opcode table and try to match
the first operand in table with what we get;
- if first operand match then it will call match_phase_2() to determine if the
second operand also match; if not, it must be error;
*/
{
int i;
int retcode;
signed char temp_opsiz = 0;
OPNDTYPE cur_opnd;
OPNDTYPE asm_op1;
// if nothing inside, no need to output anything
if( Code->info.token == T_NULL ) {
if( Code->prefix.seg != EMPTY ) {
/* we have: REG: on line */
AsmError( SYNTAX_ERROR );
return( ERROR );
} else if( Code->info.opnd_type[OPND1] == OP_NONE ) {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?