formins.c

来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 511 行

C
511
字号
/****************************************************************************
*
*                            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 <stdlib.h>
#include "disasm.h"

static  const ins_name        PrefixName[] = {
    I_LOCK,
    0,
    I_REPNE,
    I_REPE
};


static  void            PadBlanks( char * );

#ifdef O2A
#define START_INDEX     (DO_UNIX ? '(' : '[')
#define END_INDEX       (DO_UNIX ? ')' : ']')
#else
#define START_INDEX     '['
#define END_INDEX       ']'
#endif


static  bool    IsJumpIns( uint_16 opcode )
/*****************************************/
{
    switch( opcode ) {
    case I_JMP:
    case I_JA:
    case I_JAE:
    case I_JB:
    case I_JBE:
    case I_JE:
    case I_JNE:
    case I_JG:
    case I_JGE:
    case I_JL:
    case I_JLE:
    case I_JO:
    case I_JNO:
    case I_JS:
    case I_JNS:
    case I_JP:
    case I_JPO:
        return( TRUE );
    }
    return( FALSE );
}


static void FormIndex( operand * op, char * buff )
/************************************************/

{
    const char        *src;

    if( op->mode != ADDR_INDEX ) {
        src = RegisterName[ op->base ];
#ifdef O2A
        if( *src  &&  DO_UNIX ) {       /* FORM_ASSMEBLER is implied */
            *buff++ = '%';
        }
#endif
        while( *src ) {
            *buff++ = *src++;
        }
    }
    if( op->mode != ADDR_BASE ) {
#ifdef O2A
            if( DO_UNIX ) {
                *buff++ = ',';
            } else /* note missing '{' -- don't change */
#endif
            if ( op->mode == ADDR_BASE_INDEX ) {
                *buff++ = '+';
            }
        src = RegisterName[ op->index ];
#ifdef O2A
        if( *src  &&  DO_UNIX ) {       /* FORM_ASSEMBLER is implied */
            *buff++ = '%';
        }
#endif
        while( *src ) {
            *buff++ = *src++;
        }
        if( op->scale != 1 ) {
#ifdef O2A
            if( DO_UNIX ) {
                *buff++ = ',';
            } else {
#endif
                *buff++ = '*';
#ifdef O2A
            }
#endif
            *buff++ = op->scale + '0';
        }
    }
    *buff = '\0';
}

/*
 * We've got a string instruction with a segment override, have to
 * fiddle things so that the override gets shown.
 */
static void FixStringIns( instruction *ins )
{
    operand     *op;
    unsigned    size;

    size = 0;
    switch( ins->opcode )
    {
        case I_MOVSD:
            ++size;
            /* fall through */
        case I_MOVSB:
            ++size;
            /* fall through */
        case I_MOVSW:
            ins->opcode = I_MOVS;
            ins->num_oper = 2;
            ins->mem_ref_op = OP_2;
            ins->op[ OP_1 ].mode = ADDR_ES_DI;
            if( ins->pref & ADDR_LONG ) {
                ins->op[ OP_1 ].mode++;
            }
            break;
        case I_CMPSD:
            ++size;
            /* fall through */
        case I_CMPSW:
            ++size;
            /* fall through */
        case I_CMPSB:
            ins->opcode = I_CMPS;
            ins->num_oper = 2;
            ins->mem_ref_op = OP_1;
            ins->op[ OP_2 ].mode = ADDR_ES_DI;
            if( ins->pref & ADDR_LONG ) {
                ins->op[ OP_2 ].mode++;
            }
            break;
        case I_LODSD:
            ++size;
            /* fall through */
        case I_LODSW:
            ++size;
            /* fall through */
        case I_LODSB:
            ins->opcode = I_LODS;
            ins->num_oper = 1;
            ins->mem_ref_op = OP_1;
            break;
        case I_OUTSD:
            ++size;
            /* fall through */
        case I_OUTSW:
            ++size;
            /* fall through */
        case I_OUTSB:
            ins->opcode = I_OUTS;
            ins->num_oper = 2;
            ins->mem_ref_op = OP_2;
            ins->op[ OP_1 ].mode = ADDR_REG;
            ins->op[ OP_1 ].base = DX_REG;
            break;
        default:
            return;
    }
    switch( size ) {
    case 0:
        ins->modifier = MOD_BYTE;
        break;
    case 1:
        ins->modifier = MOD_WORD;
        break;
    case 2:
        ins->modifier = MOD_LINT;
        break;
    }
    op = &ins->op[ ins->mem_ref_op ];
    op->mode = ADDR_BASE;
    op->disp = 0;
    op->scale = 1;
    op->size = 0;
    if( ins->pref & ADDR_LONG ) {
        op->base = ESI_REG;
    } else {
        op->base = SI_REG;
    }
}

static char *DumpOverride( char *buff, int seg_override )
{
#ifdef O2A
    if( DO_UNIX ) {
        *buff++ = '%';
    }
#endif
    strcpy( buff, RegisterName[ seg_override ] );
    buff += strlen( buff );
    *buff++ = ':';
    *buff = '\0';
    return( buff );
}


void  FormatIns( char *buf, instruction *curr_ins, form_option format )
/*********************************************************************/

{
    const char          *name;
    int                 len;
    operand             *op;
    int                 i;
    int                 seg_override;
    char                prefix;
    char                tmp_buff[ 80 ];
    char                *ptr;

    if( curr_ins->opcode == I_INVALID ) {
        strcpy( buf, "?????" );
        return;
    }
    CurrIns = *curr_ins;
    prefix = FALSE;
    for( i = 0; i <= 3; ++i ) {
        if( CurrIns.pref & PrefixTab[ i ] ) {
            strcpy( tmp_buff, InsName[ PrefixName[ i ] ] );
            PadBlanks( tmp_buff );
            if( format & FORM_NAME_UPPER ) {
                ZapUpper( tmp_buff );
            }
            strcat( buf, tmp_buff );
            prefix = TRUE;
        }
    }
    seg_override = NULL_REG;
    if( CurrIns.pref & PREF_xS ) {
        seg_override = CurrIns.seg_used;
        FixStringIns( &CurrIns );
    }
    if( CurrIns.opcode < FIRST_WTK_INS ) {
        name = InsName[ CurrIns.opcode ];
    } else {
        name = GetWtkInsName( CurrIns.opcode - FIRST_WTK_INS );
    }
    strcpy( tmp_buff, name );
#ifdef O2A
    if( DO_UNIX ) {
        ToUnixInsName( tmp_buff, &CurrIns );
    }
#endif
    if( format & FORM_NAME_UPPER ) {
        ZapUpper( tmp_buff );
    }
    strcat( buf, tmp_buff );
    PadBlanks( buf );
    if( prefix ) {          /* if a prefix like 'lock', need space after name */
        strcat( buf, " " );
    }

    tmp_buff[ 0 ] = '\0';
#ifdef O2A
    if( !DO_UNIX ) {
#endif
        if( CurrIns.opcode == I_CALL_FAR || CurrIns.opcode == I_JMP_FAR ) {
            if( CurrIns.modifier == MOD_NONE ) {
                if( format & FORM_ASSEMBLER ) {
                    strcpy( tmp_buff, "far ptr " );
                } else {
                    strcpy( tmp_buff, "far " );
                }
            }
        } else if( CurrIns.opcode == I_CALL ||
                ( IsJumpIns( CurrIns.opcode ) && CurrIns.ins_size != 2 ) ) {
            if( CurrIns.modifier == MOD_NONE ) {
                if( format & FORM_ASSEMBLER ) {
                    strcpy( tmp_buff, "near ptr " );
                }
            }
        }
        if( format & FORM_NAME_UPPER ) {
            ZapUpper( tmp_buff );
        }
        strcat( buf, tmp_buff );

#ifdef O2A
    } else if( CurrIns.num_oper >= 2 ) { // swap operands
        operand tmp;
        int     last;

        last = CurrIns.num_oper - 1;
        tmp = CurrIns.op[ OP_1 ];
        CurrIns.op[ OP_1 ] = CurrIns.op[ last ];
        CurrIns.op[ last ] = tmp;
        if( CurrIns.mem_ref_op == 0 ) {
            CurrIns.mem_ref_op = last;
        } else if( CurrIns.mem_ref_op == last ) {
            CurrIns.mem_ref_op = 0;
        }
    }
#endif
    for( i = 0; i < CurrIns.num_oper; ++i ) {
        if( i > 0 ) {
            len = strlen( buf );
            buf[ len ] = ',';
            buf[ len + 1 ] = '\0';
        }
        op = &CurrIns.op[ i ];
        if( CurrIns.mem_ref_op == i ) {
            if(
#ifdef O2A
                !DO_UNIX  &&
#endif
                CurrIns.modifier != MOD_NONE ) {
                strcpy( tmp_buff, ModifierTab[ CurrIns.modifier ] );
                if( format & FORM_NAME_UPPER ) {
                    ZapUpper( tmp_buff );
                }
                strcat( buf, tmp_buff );
            }
            if( seg_override != NULL_REG ) {
                DumpOverride( tmp_buff, seg_override );
                if( format & FORM_REG_UPPER ) ZapUpper( tmp_buff );
                strcat( buf, tmp_buff );
            }
        }
        switch( op->mode ) {
        case ADDR_REG:
            ptr = tmp_buff;
#ifdef O2A
            if( DO_UNIX ) {
                *ptr++ = '%';
            }
#endif
            strcpy( ptr, RegisterName[ op->base ] );
            if( format & FORM_REG_UPPER ) ZapUpper( ptr );
            strcat( buf, tmp_buff );
            break;
        case ADDR_CONST:
#ifdef O2A
            if( DO_UNIX ) {
                strcat( buf, "$" );
            }
#endif
            if( op->size == 0 ) {
                len = strlen( buf );
                ltoa( op->disp, &buf[ len ], 10 );
            } else {
                strcat( buf, ToStr( op->disp, 2 * op->size, op->offset ) );
            }
            break;
        case ADDR_LABEL:
#ifdef O2A
            if( !DO_UNIX  &&
                ( format & FORM_ASSEMBLER && IsJumpIns( CurrIns.opcode ) ) ) {
                if( CurrIns.ins_size == 2 ) {
                    if( format & FORM_NAME_UPPER ) {
                        strcat( buf, "SHORT " );
                    } else {
                        strcat( buf, "short " );
                    }
                }
            }
#endif
            strcat( buf, JmpLabel( op->disp, op->offset ) );
            break;
        case ADDR_ABS:
            strcat( buf, ToBrStr( op->disp, op->offset ) );
            break;
        case ADDR_BASE:
        case ADDR_INDEX:
        case ADDR_BASE_INDEX:
            if(
#ifdef O2A
                DO_UNIX  ||
#endif
                ( format & FORM_INDEX_IN ) == 0 ) {
                if( op->size != 0 ) {
                    strcat( buf, ToIndex( op->disp, op->offset ) );
                }
            }
            len = strlen( buf );
            buf[ len ] = START_INDEX;
            FormIndex( op, tmp_buff );
            if( format & FORM_REG_UPPER ) {
                ZapUpper( tmp_buff );
            }
            strcpy( &buf[ len + 1 ], tmp_buff );
            if(
#ifdef O2A
                !DO_UNIX  &&
#endif
                ( format & FORM_INDEX_IN ) ) {
                if( op->size != 0 ) {
                    name = ToIndex( op->disp, op->offset );
                    if( *name != '+' && *name != '-' ) {
                        strcat( buf, "+" );
                    }
                    strcat( buf, name );
                }
            }
            len = strlen( buf );
            buf[ len ] = END_INDEX;
            buf[ len + 1 ] = '\0';
            break;
        case ADDR_SEG_OFFSET:
            /* modifier or seg override */
            strcat( buf, ToSegStr( op->disp, (op+1)->disp, op->offset ) );
            break;
        case ADDR_ES_DI:
        case ADDR_ES_EDI:
            /* we have an overridden string instruction */
            ptr = DumpOverride( tmp_buff, ES_REG );
            *ptr++ = START_INDEX;
            strcpy( ptr,
                RegisterName[ op->mode == ADDR_ES_DI ? DI_REG : EDI_REG ] );
            ptr += strlen( ptr );
            *ptr++ = END_INDEX;
            *ptr = '\0';
            if( format & FORM_REG_UPPER ) ZapUpper( tmp_buff );
            strcat( buf, tmp_buff );
            break;
        case ADDR_WTK:
            {
                char * tmpstr;
                wop_type tmptype = (wop_type)op->size;
                if( tmptype == WST  ||  tmptype == ANY_SINGLE ) {
                    tmpstr = "ws";
                } else {
                    tmpstr = "wd";
                }
                strcat( buf, tmpstr );
                itoa( (int)op->disp, &buf[ strlen( buf ) ], 10 );
            }
            break;
        case ADDR_WTK_OPCODE:
            strcat( buf, InsName[ op->disp ] );
            break;
        }
    }
    if( CurrIns.pref & EMU_INTERRUPT ) {
        strcat( buf, "; int " );
        strcat( buf, ToStr( CurrIns.op[ OP_3 ].disp, 2, -1 ) );
    }
}


#ifndef O2A
static
#endif
void  ZapUpper( char *str )
/*************************/

{
    while( *str != '\0' ) {
        if( *str >= 'a' ) {
            *str &= 0xdf;
        }
        ++str;
    }
}


static  void  PadBlanks( char *str )
/**********************************/

{
    int                 oldlen;
    int                 padlen;

    oldlen = strlen( str );
    padlen = OPCODE_LEN - oldlen % OPCODE_LEN;
    memset( &str[ oldlen ], ' ', padlen );
    str[ oldlen + padlen ] = '\0';
}

⌨️ 快捷键说明

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