cpragx86.c

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

C
1,416
字号
    doPragAux();
    PPState = PPS_EOL | PPS_NO_EXPAND;
}


typedef enum
{       FIXWORD_NONE
,       FIXWORD_FLOAT
,       FIXWORD_SEGMENT
,       FIXWORD_OFFSET
,       FIXWORD_RELOFF
} fix_words;


static fix_words FixupKeyword(
    void )
{
    fix_words retn;             // - return

    if( CurToken == T_FLOAT ) {
        NextToken();
        retn = FIXWORD_FLOAT;
    } else if( PragRecog( "seg" ) ) {
        retn = FIXWORD_SEGMENT;
    } else if( PragRecog( "offset" ) ) {
        retn = FIXWORD_OFFSET;
    } else if( PragRecog( "reloff" ) ) {
        retn = FIXWORD_RELOFF;
    } else {
        retn = FIXWORD_NONE;
    }
    return( retn );
}


enum sym_state AsmQueryExternal(
    char *name )
{
#if 1
    SYMBOL sym;
    enum sym_state state;

    state = SYM_UNDEFINED;
    sym = ScopeASMLookup( name );
    if( sym != NULL ) {
        if( SymIsAutomatic( sym ) ) {
            state = SYM_STACK;
        } else {
            state = SYM_EXTERNAL;
        }
    }
    return( state );
#else
    name = name;
    return( SYM_UNDEFINED );
#endif
}


#if _CPU == 8086
    #define SYM_INT     SYM_INT2
    #define SYM_FFAR    SYM_FAR2
    #define SYM_FNEAR   SYM_NEAR2
    #define SYM_DFAR    SYM_INT4
    #define SYM_DNEAR   SYM_INT2
#else
    #define SYM_INT     SYM_INT4
    #define SYM_FFAR    SYM_FAR4
    #define SYM_FNEAR   SYM_NEAR2
    #define SYM_DFAR    SYM_INT6
    #define SYM_DNEAR   SYM_INT4
#endif

#ifdef WCPP_ASM
static enum sym_type CodePtrType( type_flag flags )
{
    enum sym_type retn;

    if( flags & TF1_FAR ) {
        retn = SYM_FFAR;
    } else if( flags & TF1_NEAR ) {
        retn = SYM_FNEAR;
    } else if( TargetSwitches & BIG_CODE ) {
        retn = SYM_FFAR;
    } else {
        retn = SYM_FNEAR;
    }
    return retn;
}
#endif


static enum sym_type PtrType( type_flag flags )
{
    enum sym_type retn;

    if( flags & ( TF1_FAR | TF1_HUGE ) ) {
        retn = SYM_DFAR;
    } else if( flags & TF1_NEAR ) {
        retn = SYM_DNEAR;
    } else if( TargetSwitches & BIG_DATA ) {
        retn = SYM_DFAR;
    } else {
        retn = SYM_DNEAR;
    }
    return retn;
}


#ifdef WCPP_ASM

#define ENTRY_ERROR             0,
#define ENTRY_BOOL              SYM_INT1,
#define ENTRY_CHAR              SYM_INT1,
#define ENTRY_SCHAR             SYM_INT1,
#define ENTRY_UCHAR             SYM_INT1,
#define ENTRY_WCHAR             SYM_INT2,
#define ENTRY_SSHORT            SYM_INT2,
#define ENTRY_USHORT            SYM_INT2,
#define ENTRY_SINT              SYM_INT,
#define ENTRY_UINT              SYM_INT,
#define ENTRY_SLONG             SYM_INT4,
#define ENTRY_ULONG             SYM_INT4,
#define ENTRY_SLONG64           SYM_INT8,
#define ENTRY_ULONG64           SYM_INT8,
#define ENTRY_FLOAT             SYM_FLOAT4,
#define ENTRY_DOUBLE            SYM_FLOAT8,
#define ENTRY_LONG_DOUBLE       SYM_FLOAT8,
#define ENTRY_ENUM              0,
#define ENTRY_POINTER           0,
#define ENTRY_TYPEDEF           0,
#define ENTRY_CLASS             0,
#define ENTRY_BITFIELD          0,
#define ENTRY_FUNCTION          0,
#define ENTRY_ARRAY             0,
#define ENTRY_DOT_DOT_DOT       0,
#define ENTRY_VOID              SYM_INT1,
#define ENTRY_MODIFIER          0,
#define ENTRY_MEMBER_POINTER    0,
#define ENTRY_GENERIC           0,

static enum sym_type AsmDataType[] = {
    #include "type_arr.h"
};
#endif

#ifdef WCPP_ASM

#define ASM_BLOCK       (64)

static enum sym_type AsmType(
    TYPE type )
{
    type_flag mod_flags;

    type = TypeModFlags( type, &mod_flags );
    switch( type->id ) {
      case TYP_POINTER :
        type = TypeModFlags( type->of, &mod_flags );
        if( type->id == TYP_FUNCTION ) {
            return( CodePtrType( mod_flags ) );
        } else {
            return( PtrType( mod_flags ) );
        }
        break;
      case TYP_ARRAY :
      case TYP_BITFIELD :
      case TYP_ENUM :
        return( AsmType( type->of ) );
        break;
      case TYP_CLASS :
        return( SYM_INT1 );
        break;
      case TYP_FUNCTION :
        return( CodePtrType( mod_flags ) );
        break;
      default:
        return( AsmDataType[ type->id ] );
        break;
    }
}
#endif


enum sym_type AsmQueryType( char *name )
{
#if 1
    SYMBOL sym;
    enum sym_type type;

    sym = ScopeASMLookup( name );
    if( sym != NULL ) {
        type = AsmType( sym->sym_type );
    } else {
        type = SYM_INT1;
    }
    return( type );
#else
    name = name;
    return( SYM_INT1 );
#endif
}


static int insertFixups( VBUF *code_buffer, unsigned char *buff, unsigned i )
{
    struct asmfixup     *fix;
    struct asmfixup     *head;
    struct asmfixup     *chk;
    struct asmfixup     *next;
    struct asmfixup     **owner;
    unsigned char       *src;
    unsigned char       *end;
    unsigned char       cg_fix;
    unsigned long       perform_fixups;
    byte_seq            *seq;
    SYMBOL              sym;
    char                *name;
    unsigned            dst;
    unsigned            skip;
    int                 mutate_to_segment;
    boolean             uses_auto;
#if _CPU == 8086
    int                 fixup_padding;
#endif

    uses_auto = FALSE;
    perform_fixups = 0;
    head = FixupHead;
    if( head != NULL ) {
        FixupHead = NULL;
        /* sort the fixup list in increasing fixup_loc's */
        for( fix = head; fix != NULL; fix = next ) {
            owner = &FixupHead;
            for( ;; ) {
                chk = *owner;
                if( chk == NULL ) break;
                if( chk->fixup_loc > fix->fixup_loc ) break;
                owner = &chk->next;
            }
            next = fix->next;
            fix->next = *owner;
            *owner = fix;
        }
        dst = 0;
        src = buff;
        end = src + i;
        fix = FixupHead;
        owner = &FixupHead;
        /* insert fixup escape sequences */
        while( src < end ) {
            /* reserve at least ASM_BLOCK bytes in the buffer */
            VbufReqd( code_buffer, ( (dst+ASM_BLOCK) + (ASM_BLOCK-1) ) & ~(ASM_BLOCK-1) );
            if( fix != NULL && fix->fixup_loc == (src - buff) ) {
                name = fix->name;
                if( name != NULL ) {
                    sym = ScopeASMUseSymbol( name, &uses_auto );
                    if( sym == NULL ) {
                        return( 0 );
                    }
                }
                /* insert fixup information */
                skip = 0;
                code_buffer->buf[ dst++ ] = FLOATING_FIXUP_BYTE;
                mutate_to_segment = 0;
#if _CPU == 8086
                fixup_padding = 0;
#endif
                switch( fix->fixup_type ) {
                case FIX_SEG:
                    if( name == NULL ) {
                        /* special case for floating point fixup */
                        if( src[0] == 0x9b ) {
                           // FWAIT instruction as first byte
                        } else if( ( src[0] == 0x90 ) && ( src[1] == 0x9B ) ) {
                           // inline assembler FWAIT instruction 0x90, 0x9b
                        } else if( ( src[0] & 0xd8 ) == 0xd8 ) {
                           // FPU instruction, add FWAIT before it
                            code_buffer->buf[ dst++ ] = 0x9b;
                        } else {
                            // FIXME - probably wrong use of float !!!!
                        }
                    } else {
                        skip = 2;
                        cg_fix = FIX_SYM_SEGMENT;
                    }
                    break;
                case FIX_RELOFF8:
                    CErr2p( ERR_ASSEMBLER_ERROR, "cannot reach label with short jump" );
                    break;
                case FIX_RELOFF16:
                    skip = 2;
                    cg_fix = FIX_SYM_RELOFF;
                    break;
                case FIX_RELOFF32:
                    skip = 4;
                    cg_fix = FIX_SYM_RELOFF;
#if _CPU == 8086
                    fixup_padding = 1;
#endif
                    break;
                case FIX_PTR16:
                    mutate_to_segment = 1;
                    /* fall through */
                case FIX_OFF16:
                    skip = 2;
                    cg_fix = FIX_SYM_OFFSET;
                    break;
                case FIX_PTR32:
                    mutate_to_segment = 1;
                    /* fall through */
                case FIX_OFF32:
                    skip = 4;
                    cg_fix = FIX_SYM_OFFSET;
#if _CPU == 8086
                    fixup_padding = 1;
#endif
                    break;
                }
                if( skip != 0 ) {
                    code_buffer->buf[ dst++ ] = cg_fix;
                    *((unsigned long *)&code_buffer->buf[dst]) = (unsigned long)sym;
                    dst += sizeof( long );
                    *((unsigned long *)&code_buffer->buf[dst]) = fix->offset;
                    dst += sizeof( long );
                    src += skip;
                }
#if _CPU == 8086
                if( fixup_padding ) {
                    // add offset fixup padding to 32-bit
                    // cg create only 16-bit offset fixup
                    code_buffer->buf[ dst++ ] = 0;
                    code_buffer->buf[ dst++ ] = 0;
                    //
                }
#endif
                if( mutate_to_segment ) {
                    /*
                        Since the CG escape sequences don't allow for
                        FAR pointer fixups, we have to split them into two.
                        This is done by doing the offset fixup first, then
                        mutating the fixup structure to look like a segment
                        fixup one near pointer size later.
                    */
                    fix->fixup_type = FIX_SEG;
                    fix->fixup_loc += skip;
                    fix->offset = 0;
                } else {
                    head = fix;
                    fix = fix->next;
                    if( head->external ) {
                        *owner = fix;
                        CMemFree( head->name );
                        CMemFree( head );
                    } else {
                        owner = &head->next;
                    }
                }
            } else {
                if( *src == FLOATING_FIXUP_BYTE ) {
                    code_buffer->buf[ dst++ ] = FLOATING_FIXUP_BYTE;
                }
                code_buffer->buf[ dst++ ] = *src++;
            }
            VbufUsed( code_buffer, dst );
        }
        buff = code_buffer->buf;
        i = dst;
        perform_fixups = DO_FLOATING_FIXUPS;
    }
    seq = CMemAlloc( offsetof( byte_seq, data ) + i );
    seq->length = i | perform_fixups;
    memcpy( seq->data, buff, i );
    CurrInfo->code = seq;
    return( uses_auto );
}


static void AddAFix(
    unsigned i,
    char *name,
    unsigned type,
    unsigned long off )
{
    struct asmfixup        *fix;

    fix = (struct asmfixup *)CMemAlloc( sizeof( *fix ) );
    fix->external = 1;
    fix->fixup_loc = i;
    fix->name = name;
    fix->offset = off;
    fix->fixup_type = type;
    fix->next = FixupHead;
    FixupHead = fix;
}

static byte_seq *AuxCodeDup(        // DUPLICATE AUX CODE
    byte_seq *code )
{
    byte_seq *new_code;
    byte_seq_len code_length;
    byte_seq_len size;

    if( code == NULL ) {
        return( code );
    }
    code_length = code->length & MAX_BYTE_SEQ_LEN;
    size = offsetof( byte_seq, data ) + code_length;
    new_code = (byte_seq *)vctsave( (char *)code, size );
    return( new_code );
}

void AsmSysCopyCode( void )
/*************************/
{
    byte_seq *code;

    code = CurrInfo->code;
    if( code != NULL && code == CurrAlias->code ) {
        CurrInfo->code = AuxCodeDup( code );
    }
}

boolean AsmSysInsertFixups( VBUF *code )
/**************************************/
{
    boolean uses_auto;
    auto VBUF temp_buffer;

    VbufInit( &temp_buffer );
    VbufReqd( &temp_buffer, code->used );
    uses_auto = insertFixups( &temp_buffer, code->buf, code->used );
    VbufFree( &temp_buffer );
    AsmSymFini();
    return( uses_auto );
}

AUX_INFO *AsmSysCreateAux( char *name )
/*************************************/
{
    CreateAux( name );
    AuxCopy( CurrInfo, &WatcallInfo );
    CurrInfo->use = 1;
    CurrInfo->save = asmRegsSaved;
    CurrEntry->info = CurrInfo;
    return( CurrInfo );
}

void AsmSysUsesAuto( void )
/*************************/
{
    /*
       We want to force the calling routine to set up a [E]BP frame
       for the use of this pragma. This is done by saying the pragma
       modifies the [E]SP register. A kludge, but it works.
    */
    HW_CTurnOff( CurrInfo->save, HW_SP );
    ScopeASMUsesAuto();
}

char const *AsmSysDefineByte( void )
/**********************************/
{
    return( "db" );
}

void AsmSysDone( void )
/*********************/
{
    PragEnding( FALSE );
}

⌨️ 快捷键说明

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