docode.c

来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 1,247 行 · 第 1/3 页

C
1,247
字号
/****************************************************************************
*
*                            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 <string.h>
#include "disasm.h"

instruction             CurrIns;

static  char            W_Bit;
static  char            D_Bit;

static const address_mode RMMode[] = {
    ADDR_BASE_INDEX, /* [BX+SI] */
    ADDR_BASE_INDEX, /* [BX+DI] */
    ADDR_BASE_INDEX, /* [BP+SI] */
    ADDR_BASE_INDEX, /* [BP+DI] */
    ADDR_INDEX,      /* [SI] */
    ADDR_INDEX,      /* [DI] */
    ADDR_BASE,       /* [BP] */
    ADDR_BASE        /* [BX] */
};

static const processor_reg RMBase[] = {
    BX_REG, /* [BX+SI] */
    BX_REG, /* [BX+DI] */
    BP_REG, /* [BP+SI] */
    BP_REG, /* [BP+DI] */
    0,      /* [SI] */
    0,      /* [DI] */
    BP_REG, /* [BP] */
    BX_REG  /* [BX] */
};

static const processor_reg RMIndex[] = {
    SI_REG, /* [BX+SI] */
    DI_REG, /* [BX+DI] */
    SI_REG, /* [BP+SI] */
    DI_REG, /* [BP+DI] */
    SI_REG, /* [SI] */
    DI_REG, /* [DI] */
    0,      /* [BP] */
    0,      /* [BX] */
};

static const processor_reg RMSeg[] = {
    DS_REG,         /* [BX+SI] */
    DS_REG,         /* [BX+DI] */
    SS_REG,         /* [BP+SI] */
    SS_REG,         /* [BP+DI] */
    DS_REG,         /* [SI] */
    DS_REG,         /* [DI] */
    SS_REG,         /* [BP] */
    DS_REG,         /* [BX] */
};

static const  processor_reg   RM32Reg[] = {
    EAX_REG,
    ECX_REG,
    EDX_REG,
    EBX_REG,
    ESP_REG,
    EBP_REG,
    ESI_REG,
    EDI_REG
};

static const processor_reg RM32Seg[] = {
    DS_REG,
    DS_REG,
    DS_REG,
    DS_REG,
    SS_REG,
    SS_REG,
    DS_REG,
    DS_REG
};


/*
 * Static function prototypes
 */
static  void            GetOperands( operand_type, char );
static  ins_name        GetInsName( ins_name );


static processor_reg VarReg( processor_reg reg )
/**********************************************/

{
    if( CurrIns.pref & OPND_LONG ) {
        reg +=  FIRST_DWORD_REG - FIRST_WORD_REG;
    }
    return( reg );
}

static uint_8 InsOffset( void )
/*****************************/

{
    return( GetOffset() - InsAddr );
}


#if !defined( O2A )
static int  LookFor87Emulation( void )
/************************************/

{
    char        second_byte;
    int         inssize;
    int         seg_reg;

    inssize = 0;
    if( Opcode == 0xCD ) {
        second_byte = GetNextByte();
        if( second_byte >= 0x34 && second_byte <= 0x3d ) {
            CurrIns.pref |= EMU_INTERRUPT;
            CurrIns.op[ OP_3 ].disp = second_byte;
            if( second_byte <= 0x3b ) {
                Opcode = GetDataByte() + 0xA4;
                ++inssize;
            } else if ( second_byte == 0x3D ) {
                GetDataByte();
                Opcode = 0x90;
                inssize++;
            } else {                            /* 0x3C */
                GetDataByte();
                Opcode = GetDataByte();
                seg_reg = ( ~Opcode >> 6 ) & 3;
                CurrIns.pref |= SegPrefixTab[ seg_reg ];
                CurrIns.seg_used = FIRST_SEG_REG + seg_reg;
                inssize += 2;
                Opcode |= 0xC0;
            }
        }
    }
    return( inssize );
}
#endif


static  void    SetOperands( char opcode )
/****************************************/
{
    W_Bit = opcode & 1;
    if( CurrIns.opcode == I_BOUND ) {
        W_Bit = 1;
    }
    if( W_Bit ) {
        if( CurrIns.pref & OPND_LONG ) {
            CurrIns.mem_ref_size = 4;
        } else {
            CurrIns.mem_ref_size = 2;
        }
    } else {
        CurrIns.mem_ref_size = 1;
    }
    if( CurrIns.opcode == I_ARPL ) {
        D_Bit = 0;
    } else {
        D_Bit = opcode & 2;
    }
}


void  DoCode( instruction *curr, char use_32 )
/*******************************************/

{
    operand_type        op_type;
    ins_name            instr_name;
    int                 seg_reg;
#if defined( O2A )
    int                 i;
    operand             *op;
#endif

    memset( &CurrIns, 0, sizeof( instruction ) );
    CurrIns.modifier = MOD_NONE;
    CurrIns.mem_ref_op = NULL_OP;
    for( ;; ) {                 /* collect prefix */
        if( EndOfSegment() ) {
            if( instr_name == I_WAIT ) {
                instr_name = I_NULL;
            } else {
                instr_name = I_INVALID;
            }
            break;
        }
        Opcode = GetDataByte();
#if !defined( O2A )
        LookFor87Emulation();
#endif
        instr_name = InsTab[ Opcode ].name;
        op_type = InsTab[ Opcode ].op_type;
        if( op_type == OT_PREFIX ) {
            if( CurrIns.pref & PrefixTab[ Opcode - 0xf0 ] ) {
                break;
            }
            CurrIns.pref |= PrefixTab[ Opcode - 0xf0 ]; /* 0xf0 == LOCK */
        } else if( op_type == OT_SEG_REG ) {
            seg_reg = _SegReg2Field( Opcode );
            if( CurrIns.pref & SegPrefixTab[ seg_reg ] ) {
                break;
            }
            CurrIns.pref |= SegPrefixTab[ seg_reg ];
            CurrIns.seg_used = FIRST_SEG_REG + seg_reg;
        } else if( op_type == OT_FS ) {
            CurrIns.pref |= PREF_FS;
            CurrIns.seg_used = FS_REG;
        } else if( op_type == OT_GS ) {
            CurrIns.pref |= PREF_GS;
            CurrIns.seg_used = GS_REG;
        } else if( op_type == OT_OPND_SIZE ) {
            CurrIns.pref |= PREF_OPND_SIZE;
        } else if( op_type == OT_ADDR_SIZE ) {
            CurrIns.pref |= PREF_ADDR_SIZE;
        } else if( instr_name == I_WAIT ) {
            /* any prefixes collected so far will apply to the WAIT instruction
               so decode it separately */
            if( CurrIns.pref != 0 ) {
                break;
            }
            CurrIns.pref |= PREF_FWAIT;
        } else {
            break;
        }
    }
    if( CurrIns.pref & PREF_OPND_SIZE ) {
        if( !use_32 ) CurrIns.pref |= OPND_LONG;
    } else {
        if( use_32 ) CurrIns.pref |= OPND_LONG;
    }
    if( CurrIns.pref & PREF_ADDR_SIZE ) {
        if( !use_32 ) CurrIns.pref |= ADDR_LONG;
    } else {
        if( use_32 ) CurrIns.pref |= ADDR_LONG;
    }
    SecondByte = GetNextByte();
    CurrIns.opcode = GetInsName( instr_name );
    if( CurrIns.opcode != I_INVALID ) {
        SetOperands( Opcode );
        GetOperands( op_type, use_32 );
        if( CurrIns.opcode != I_INVALID ) {
            if( CurrIns.seg_used == NULL_REG ) {
                CurrIns.seg_used = DS_REG;
            }
#if defined( O2A )
            if( CurrIns.opcode == I_RET_FAR ) {
                RetFarUsed = TRUE;
            }
            for( i = 0; i < CurrIns.num_oper; ++i ) {     /* locate labels */
                op = &CurrIns.op[ i ];
                if( op->mode == ADDR_LABEL ) {
                    FindLabel( InsAddr + op->offset, op->disp, Segment );
                } else if( op->mode == ADDR_SEG_OFFSET ) {
                    FindSymbol( InsAddr + op->offset );
                } else if( op->offset != 0 ) {
                    FindSymbol( InsAddr + op->offset );
                }
            }
#endif
        }
    }
    if( IsWtk( &CurrIns ) ) {
        DoWtk( /*&CurrIns*/ );
    }
    CurrIns.ins_size = InsOffset();
    *curr = CurrIns;
}


static ins_name GetInsName( ins_name instr_name )
/***********************************************/

{
    int                 index;

    index = _RegField( SecondByte );
    switch( instr_name ) {
    case I_IMMED:
        instr_name = ImmedTable[ index ];
        break;
    case I_SHIFT:
        instr_name = ShiftTable[ index ];
        break;
    case I_GROUP1:
        instr_name = Group1Table[ index ];
        break;
    case I_GROUP2:
        instr_name = Group2Table[ index ];
        break;
    case I_GROUP3:
        instr_name = Group3Table[ index ];
        break;
    case I_ESC:
        instr_name = GetFppCode();
        if( instr_name != I_INVALID ) CurrIns.pref |= FP_INS;
        break;
    default:
        if( CurrIns.pref & OPND_LONG ) {
            switch( instr_name ) {
            case I_RET_FAR:
                /* change retf to retd only in use16 segment */
                if( !(CurrIns.pref & PREF_OPND_SIZE) ) break;
                /* fall through */
            case I_PUSHF:
            case I_POPF:
            case I_PUSHA:
            case I_POPA:
            case I_INSW:
            case I_OUTSW:
            case I_MOVSW:
            case I_CMPSW:
            case I_STOSW:
            case I_LODSW:
            case I_SCASW:
            case I_IRET:
            case I_CBW:
            case I_CWD:
                ++instr_name; /* ie: INSW -> INSD */
            }
        }
    }
    return( instr_name );
}


void DoControl( int base )
/************************/
{
    int op1,op2;

    if( D_Bit ) {
        op1 = OP_2;
        op2 = OP_1;
    } else {
        op1 = OP_1;
        op2 = OP_2;
    }
    CurrIns.op[ op1 ].mode = ADDR_REG;
    CurrIns.op[ op1 ].base = FIRST_DWORD_REG + ( SecondByte & 7 );
    CurrIns.op[ op2 ].mode = ADDR_REG;
    CurrIns.op[ op2 ].base = base + ( ( SecondByte >> 3 ) & 7 );
    CurrIns.num_oper = 2;
    GetDataByte();
}


void DoOTModRM( void )
/********************/
{
    int         reg;
    int         op1;
    int         op2;

    if( D_Bit ) {
        op1 = OP_2;
        op2 = OP_1;
    } else {
        op1 = OP_1;
        op2 = OP_2;
    }
    CurrIns.num_oper = 2;
    ModRMOp( op1, FALSE );
    CurrIns.op[ op2 ].mode = ADDR_REG;
    reg = _RegField( SecondByte );
    if( W_Bit ) {
        CurrIns.op[ op2 ].base = VarReg( FIRST_WORD_REG + reg );
    } else {
        CurrIns.op[ op2 ].base = FIRST_BYTE_REG + reg;
    }
}


static void SetPWord( void )
/**************************/
{
    if( CurrIns.pref & OPND_LONG ) {
        CurrIns.modifier = MOD_PWORD;
        CurrIns.mem_ref_size = 6;
    } else {
        CurrIns.modifier = MOD_LINT;
        CurrIns.mem_ref_size = 4;
    }
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?