static int first_nibble_is_4(RAnal* anal, RAnalOp* op, ut16 code){ switch (code & 0xF0FF) { //todo: implement case 0x4020: //shal op->type = R_ANAL_OP_TYPE_SAL; break; case 0x4021: //shar op->type = R_ANAL_OP_TYPE_SAR; break; case 0x4000: //shll case 0x4008: //shll2 case 0x4018: //shll8 case 0x4028: //shll16 op->type = R_ANAL_OP_TYPE_SHL; break; case 0x4001: //shlr case 0x4009: //shlr2 case 0x4019: //shlr8 case 0x4029: //shlr16 op->type = R_ANAL_OP_TYPE_SHR; break; default: break; } if (IS_JSR(code)) { op->type = R_ANAL_OP_TYPE_UCALL; //call to reg op->delay = 1; op->dst = anal_fill_ai_rg (anal, GET_TARGET_REG(code)); } else if ( IS_JMP(code) ) { op->type = R_ANAL_OP_TYPE_UJMP; //jmp to reg op->dst = anal_fill_ai_rg (anal, GET_TARGET_REG(code)); op->delay = 1; op->eob = true; } else if (IS_CMPPL(code) || IS_CMPPZ(code)) { op->type = R_ANAL_OP_TYPE_CMP; //todo: implement } else if (IS_LDCLSR1(code) || IS_LDSLMAC(code) || IS_LDSLPR(code)) { op->type = R_ANAL_OP_TYPE_POP; //todo: implement } else if (IS_LDCSR1(code) || IS_LDSMAC(code) || IS_LDSPR(code)) { op->type = R_ANAL_OP_TYPE_MOV; //todo: implement } else if (IS_ROT(code)) { op->type = (code&1)? R_ANAL_OP_TYPE_ROR:R_ANAL_OP_TYPE_ROL; //todo: implement rot* vs rotc* } else if (IS_STCLSR1(code) || IS_STSLMAC(code) || IS_STSLPR(code)) { op->type = R_ANAL_OP_TYPE_PUSH; //todo: implement st*.l *,@-Rn } else if (IS_TASB(code)) { op->type = R_ANAL_OP_TYPE_UNK; //todo: implement } else if (IS_DT(code)) { op->type = R_ANAL_OP_TYPE_UNK; //todo: implement } return op->size; }
static int first_nibble_is_4(RAnal* anal, RAnalOp* op, ut16 code){ if(IS_JSR(code)){ op->type = R_ANAL_OP_TYPE_UCALL; //call to reg op->delay = 1; op->dst = anal_fill_ai_rg(anal,GET_TARGET_REG(code)); } else if ( IS_JMP(code) ){ op->type = R_ANAL_OP_TYPE_UJMP; //jmp to reg op->dst = anal_fill_ai_rg(anal,GET_TARGET_REG(code)); op->delay = 1; op->eob = R_TRUE; } //TODO shifts + many system insns + CMP/P[L|Z]?? return op->size; }
bool jmp( expr_list *opndx, int *flags ) /* determine the displacement of jmp; */ { int_32 addr; enum fixup_types fixup_type; enum fixup_options fixup_option; enum sym_state state; struct asm_sym *sym; #if defined( _STANDALONE_ ) dir_node *seg; #endif *flags = 0; Code->data[Opnd_Count] = opndx->value; sym = opndx->sym; if( sym == NULL ) { if( Code->info.token == T_CALL ) { Code->info.token = T_CALLF; } else if( Code->info.token == T_JMP ) { Code->info.token = T_JMPF; } if( Code->data[Opnd_Count] > USHRT_MAX ) Code->info.opnd_type[Opnd_Count] = OP_I32; else Code->info.opnd_type[Opnd_Count] = OP_I16; return( RC_OK ); } #if defined( _STANDALONE_ ) if( sym->mem_type == MT_ERROR ) { AsmError( LABEL_NOT_DEFINED ); return( RC_ERROR ); } #endif state = sym->state; #if defined( _STANDALONE_ ) seg = GetSeg( sym ); if( seg == NULL || CurrSeg == NULL || CurrSeg->seg != seg ) { /* jumps to another segment are just like to another file */ state = SYM_EXTERNAL; } #endif if( !Code->mem_type_fixed ) { Code->mem_type = MT_EMPTY; } fixup_option = OPTJ_NONE; fixup_type = FIX_RELOFF8; switch( state ) { case SYM_INTERNAL: #if defined( _STANDALONE_ ) case SYM_PROC: #endif if( ( Code->mem_type == MT_EMPTY || Code->mem_type == MT_SHORT || Code->mem_type == MT_NEAR ) && sym->mem_type != MT_WORD && sym->mem_type != MT_DWORD && sym->mem_type != MT_FWORD && !IS_JMPCALLF( Code->info.token ) ) { #if defined( _STANDALONE_ ) if( ( Code->info.token == T_CALL ) && ( Code->mem_type == MT_EMPTY ) && ( sym->mem_type == MT_FAR ) ) { FarCallToNear(); *flags = SCRAP_INSTRUCTION; return( RC_OK ); } addr = sym->offset; #else addr = sym->addr; #endif addr -= ( AsmCodeAddress + 2 ); // calculate the displacement addr += Code->data[Opnd_Count]; switch( Code->info.token ) { case T_JCXZ: case T_LOOPW: case T_LOOPEW: case T_LOOPZW: case T_LOOPNEW: case T_LOOPNZW: if( Code->use32 ) { // 1 extra byte for OPNSIZ addr--; } break; case T_JECXZ: case T_LOOPD: case T_LOOPED: case T_LOOPZD: case T_LOOPNED: case T_LOOPNZD: if( !Code->use32 ) { // 1 extra byte for OPNSIZ addr--; } break; } if( Code->info.token == T_CALL && Code->mem_type == MT_EMPTY ) { Code->mem_type = MT_NEAR; } if( Code->mem_type != MT_NEAR && Code->info.token != T_CALL && ( addr >= SCHAR_MIN && addr <= SCHAR_MAX ) ) { Code->info.opnd_type[Opnd_Count] = OP_I8; } else { /* near jmp */ if( Code->use32 ) { Code->info.opnd_type[Opnd_Count] = OP_I32; addr -= 3; // 32 bit displacement } else { Code->info.opnd_type[Opnd_Count] = OP_I16; addr -= 1; // 16 bit displacement } if( IS_JMP( Code->info.token ) ) { switch( Code->info.token ) { case T_JMP: case T_JMPF: case T_JCXZ: case T_JECXZ: break; default: // 1 extra byte for opcode ( 0F ) addr--; break; } } } /* store the displacement */ Code->data[Opnd_Count] = addr; switch( Code->info.token ) { case T_JCXZ: case T_JECXZ: case T_LOOP: case T_LOOPE: case T_LOOPNE: case T_LOOPNZ: case T_LOOPZ: case T_LOOPD: case T_LOOPED: case T_LOOPNED: case T_LOOPNZD: case T_LOOPZD: case T_LOOPW: case T_LOOPEW: case T_LOOPNEW: case T_LOOPNZW: case T_LOOPZW: #if defined( _STANDALONE_ ) if( !PhaseError && (Code->info.opnd_type[Opnd_Count] != OP_I8) ) { #else if( (Code->info.opnd_type[Opnd_Count] != OP_I8) ) { #endif AsmError( JUMP_OUT_OF_RANGE ); return( RC_ERROR ); } Code->info.opnd_type[Opnd_Count] = OP_I8; break; } if( (Code->info.cpu&P_CPU_MASK) < P_386 && IS_JMP( Code->info.token ) ) { /* look into jump extension */ switch( Code->info.token ) { case T_JMP: case T_JMPF: break; default: if( Code->info.opnd_type[Opnd_Count] != OP_I8 ) { #if defined( _STANDALONE_ ) if( Code->mem_type == MT_EMPTY ) { jumpExtend( 0 ); *flags = SCRAP_INSTRUCTION; return( RC_OK ); } else if( !PhaseError ) { AsmError( JUMP_OUT_OF_RANGE ); return( RC_ERROR ); } #else AsmError( JUMP_OUT_OF_RANGE ); return( RC_ERROR ); #endif } } } break; } /* otherwise fall through & get handled like external symbols */ case SYM_UNDEFINED: case SYM_EXTERNAL: /* forward ref, or external symbol */ if( Code->mem_type == MT_EMPTY && sym->mem_type != MT_EMPTY ) { switch( sym->mem_type ) { case MT_FAR: if( Code->info.token == T_CALL ) { Code->info.token = T_CALLF; } else if( Code->info.token == T_JMP ) { Code->info.token = T_JMPF; } // fall through case MT_SHORT: case MT_NEAR: Code->mem_type = sym->mem_type; break; #if defined( _STANDALONE_ ) case MT_PROC: if( IS_PROC_FAR() ) { Code->mem_type = MT_FAR; if( Code->info.token == T_CALL ) { Code->info.token = T_CALLF; } else if( Code->info.token == T_JMP ) { Code->info.token = T_JMPF; } } else { Code->mem_type = MT_NEAR; } break; #endif case MT_FWORD: if( ptr_operator( MT_FWORD, true ) ) return( RC_ERROR ); break; default: Code->mem_type = sym->mem_type; } } if( Code->mem_type == MT_FAR ) { if( Code->info.token == T_CALL ) { Code->info.token = T_CALLF; } else if( Code->info.token == T_JMP ) { Code->info.token = T_JMPF; } } switch( Code->info.token ) { case T_CALLF: case T_JMPF: switch( Code->mem_type ) { case MT_SHORT: case MT_NEAR: if( Opnd_Count == OPND1 && Code->mem_type_fixed ) { AsmError( CANNOT_USE_SHORT_OR_NEAR ); return( RC_ERROR ); } /* fall through */ case MT_FAR: case MT_EMPTY: #if defined( _STANDALONE_ ) SET_OPSIZ( Code, SymIs32( sym )); find_frame( sym ); #endif if( Opnd_Count == OPND2 ) { if( IS_OPSIZ_32( Code ) ) { fixup_type = FIX_OFF32; Code->info.opnd_type[Opnd_Count] = OP_I32; } else { fixup_type = FIX_OFF16; Code->info.opnd_type[Opnd_Count] = OP_I16; } } else { if( IS_OPSIZ_32( Code ) ) { fixup_type = FIX_PTR32; Code->info.opnd_type[Opnd_Count] = OP_J48; } else { fixup_type = FIX_PTR16; Code->info.opnd_type[Opnd_Count] = OP_J32; } } break; case MT_BYTE: case MT_WORD: #if defined( _STANDALONE_ ) case MT_SBYTE: case MT_SWORD: #endif AsmError( INVALID_SIZE ); return( RC_ERROR ); case MT_DWORD: case MT_FWORD: #if defined( _STANDALONE_ ) case MT_SDWORD: #endif *flags = INDIRECT_JUMP; return( RC_OK ); case MT_QWORD: case MT_TBYTE: case MT_OWORD: AsmError( INVALID_SIZE ); return( RC_ERROR ); } break; case T_CALL: if( Code->mem_type == MT_SHORT ) { AsmError( CANNOT_USE_SHORT_WITH_CALL ); return( RC_ERROR ); } else if( Code->mem_type == MT_EMPTY ) { #if defined( _STANDALONE_ ) fixup_option = OPTJ_CALL; #else fixup_option = OPTJ_NONE; #endif if( Code->use32 ) { fixup_type = FIX_RELOFF32; Code->info.opnd_type[Opnd_Count] = OP_I32; } else { fixup_type = FIX_RELOFF16; Code->info.opnd_type[Opnd_Count] = OP_I16; } break; } /* fall through */ case T_JMP: switch( Code->mem_type ) { case MT_SHORT: fixup_option = OPTJ_EXPLICIT; fixup_type = FIX_RELOFF8; Code->info.opnd_type[Opnd_Count] = OP_I8; break; case MT_FAR: AsmError( SYNTAX_ERROR ); break; case MT_EMPTY: // forward reference // inline assembler jmp default distance is near // stand-alone assembler jmp default distance is short fixup_option = OPTJ_NONE; #if defined( _STANDALONE_ ) /* guess short if JMP, we will expand later if needed */ fixup_type = FIX_RELOFF8; Code->info.opnd_type[Opnd_Count] = OP_I8; #else if( Code->use32 ) { fixup_type = FIX_RELOFF32; Code->info.opnd_type[Opnd_Count] = OP_I32; } else { fixup_type = FIX_RELOFF16; Code->info.opnd_type[Opnd_Count] = OP_I16; } #endif break; case MT_NEAR: fixup_option = OPTJ_EXPLICIT; if( Code->use32 ) { fixup_type = FIX_RELOFF32; Code->info.opnd_type[Opnd_Count] = OP_I32; } else { fixup_type = FIX_RELOFF16; Code->info.opnd_type[Opnd_Count] = OP_I16; } break; case MT_DWORD: case MT_WORD: #if defined( _STANDALONE_ ) case MT_SDWORD: case MT_SWORD: #endif *flags = INDIRECT_JUMP; return( RC_OK ); #if defined( _STANDALONE_ ) case MT_SBYTE: #endif case MT_BYTE: case MT_FWORD: case MT_QWORD: case MT_TBYTE: case MT_OWORD: AsmError( INVALID_SIZE ); return( RC_ERROR ); } // check_assume( sym, PREFIX_EMPTY ); break; case T_JCXZ: case T_JECXZ: // JCXZ and JECXZ always require SHORT label case T_LOOP: case T_LOOPE: case T_LOOPNE: case T_LOOPNZ: case T_LOOPZ: case T_LOOPD: case T_LOOPED: case T_LOOPNED: case T_LOOPNZD: case T_LOOPZD: case T_LOOPW: case T_LOOPEW: case T_LOOPNEW: case T_LOOPNZW: case T_LOOPZW: #if defined( _STANDALONE_ ) if( ( Code->mem_type != MT_EMPTY ) && ( Code->mem_type != MT_SHORT ) && ( (Options.mode & MODE_IDEAL) == 0 ) ) { #else if( ( Code->mem_type != MT_EMPTY ) && ( Code->mem_type != MT_SHORT ) ) { #endif AsmError( ONLY_SHORT_DISPLACEMENT_IS_ALLOWED ); return( RC_ERROR ); } Code->info.opnd_type[Opnd_Count] = OP_I8; fixup_option = OPTJ_EXPLICIT; fixup_type = FIX_RELOFF8; break; default: if( (Code->info.cpu&P_CPU_MASK) >= P_386 ) { switch( Code->mem_type ) { case MT_SHORT: fixup_option = OPTJ_EXPLICIT; fixup_type = FIX_RELOFF8; Code->info.opnd_type[Opnd_Count] = OP_I8; break; case MT_EMPTY: // forward reference // inline assembler default distance is near // stand-alone assembler default distance is short #if defined( _STANDALONE_ ) fixup_option = OPTJ_JXX; fixup_type = FIX_RELOFF8; Code->info.opnd_type[Opnd_Count] = OP_I8; break; #endif case MT_NEAR: fixup_option = OPTJ_EXPLICIT; if( Code->use32 ) { fixup_type = FIX_RELOFF32; Code->info.opnd_type[Opnd_Count] = OP_I32; } else { fixup_type = FIX_RELOFF16; Code->info.opnd_type[Opnd_Count] = OP_I16; } break; case MT_FAR: #if defined( _STANDALONE_ ) jumpExtend( 1 ); *flags = SCRAP_INSTRUCTION; return( RC_OK ); #endif default: AsmError( ONLY_SHORT_AND_NEAR_DISPLACEMENT_IS_ALLOWED ); return( RC_ERROR ); } } else { // the only mode in 8086, 80186, 80286 is // Jxx SHORT switch( Code->mem_type ) { case MT_EMPTY: #if defined( _STANDALONE_ ) fixup_option = OPTJ_EXTEND; fixup_type = FIX_RELOFF8; Code->info.opnd_type[Opnd_Count] = OP_I8; break; #endif case MT_SHORT: fixup_option = OPTJ_EXPLICIT; fixup_type = FIX_RELOFF8; Code->info.opnd_type[Opnd_Count] = OP_I8; break; default: AsmError( ONLY_SHORT_DISPLACEMENT_IS_ALLOWED ); return( RC_ERROR ); } } } AddFixup( sym, fixup_type, fixup_option ); break; default: /* SYM_STACK */ AsmError( NO_JUMP_TO_AUTO ); return( RC_ERROR ); } return( RC_OK ); } bool ptr_operator( memtype mem_type, bool fix_mem_type ) /******************************************************/ /* determine what should be done with SHORT, NEAR, FAR, BYTE, WORD, DWORD, PTR operator; */ { /* new idea: * when we get a near/far/dword/etc, just set distance / mem_type * operator will be called again with PTR, then we set the opsiz, etc. */ if( Code->info.token == T_LEA ) return( RC_OK ); if( Code->info.token == T_SMSW ) return( RC_OK ); if( mem_type == MT_PTR ) { /* finish deciding what type to make the inst NOW * ie: decide size overrides etc. */ if( Code->use32 && MEM_TYPE( Code->mem_type, WORD ) ) { // if we are in use32 mode, we have to add OPSIZ prefix for // most of the 386 instructions ( except MOVSX and MOVZX ) // when we find WORD PTR if( !IS_BRANCH( Code->info.token ) ) { if( Code->info.opnd_type[OPND1] == OP_MMX ) { /* JBS 2001/02/19 no WORD operands for MMX instructions, only 64-bit or 128-bit so no WORD override needed */ } else { switch( Code->info.token ) { case T_MOVSX: case T_MOVZX: break; default: SET_OPSIZ_ON( Code ); break; } } } } else if( !Code->use32 && MEM_TYPE( Code->mem_type, DWORD ) ) { /* if we are not in use32 mode, we have to add OPSIZ * when we find DWORD PTR * unless we have a LXS ins. * which moves a DWORD ptr into SR:word reg * fixme - can this be done by breaking up the LXS instructions in * asmins.h, and then putting F_32 or F_16 to append * opsize bytes when necessary ? */ if( !IS_BRANCH( Code->info.token ) ) { if( Code->info.opnd_type[OPND1] == OP_MMX ) { /* JBS 2001/02/19 no WORD operands for MMX instructions, only 64-bit or 128-bit so no DWORD override needed */ } else { switch( Code->info.token ) { case T_LDS: case T_LES: case T_LFS: case T_LGS: case T_LSS: /* in these cases, opsize does NOT need to be changed */ break; default: // OPSIZ prefix SET_OPSIZ_ON( Code ); } } } } } else { if( ( mem_type != MT_EMPTY ) && !Code->mem_type_fixed ) { #if defined( _STANDALONE_ ) if( mem_type != MT_STRUCT ) { #endif Code->mem_type = mem_type; if( fix_mem_type ) { Code->mem_type_fixed = true; if( mem_type == MT_FAR ) { if( Code->info.token == T_CALL ) { Code->info.token = T_CALLF; } else if( Code->info.token == T_JMP ) { Code->info.token = T_JMPF; } } } #if defined( _STANDALONE_ ) } #endif } } return( RC_OK ); }