// ALSO AN EXECUTE FUNCTION - REQUIRED!!! // PRE - Given an Arm pointer with loaded memory // An entry point from whence to begin the decode // DESC - Decode all encoded memory indexes from the entry // point to (and including) the next branch statement // POST - All decoded memory from the entry to the next branch will be // decoded, replaced with their BaseInstr representations static void decodeTillBranch(PtrToBeCast base) { // i will be the empty instruction pointer EmptyInstr* i = (EmptyInstr*) base; // j will be the iterative measure u32 j = i->entry; Arm *raspi = i->raspi; do decodeInstruction(raspi, j++); // while not a branch statement, or not 0x00u while (!IS_BRANCH(mem.e[j - 1]) * mem.e[j - 1]); raspi->pc = raspi->pc - 1; }
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 ); }
int MinBlkPtrUpdates(BBLOCK *blk, struct ptrinfo *pi0) { int k, inc; INSTQ *ip, *ip0, *ipn; short *sp; short reg, dt; struct ptrinfo *pi; ILIST *il; /*fprintf(stderr, "----------blk=%d\n", blk->bnum);*/ for (pi=pi0; pi; pi=pi->next) { /*fprintf(stderr, "%s : %d\n", STname[pi->ptr-1], pi->flag);*/ /* * assumption: ilist in ptrinfo is correctly populated and point sequential * from up to down */ #if 0 assert(pi->ilist); ip0 = pi->ilist->inst; assert(ip0->inst[2] == ip0->prev->inst[2]); assert(IS_CONST(STflag[ip0->prev->inst[3]-1])); pi->upst = SToff[ip0->prev->inst[3]-1].i; fprintf(stderr, "init inc=%d\n", pi->upst); inc = pi->upst; #endif assert(pi->ilist); reg = -(pi->ilist->inst->inst[2]); inc = 0; for (il=pi->ilist; il; il=il->next) { ip0 = il->inst; assert(ip0->inst[2] == ip0->prev->inst[2]); assert(IS_CONST(STflag[ip0->prev->inst[3]-1])); inc += SToff[ip0->prev->inst[3]-1].i; if (il->next) ipn = il->next->inst; ipn = NULL; /* * we assume only const inc of ptr */ for (ip = ip0; ip != ipn; ip=ip->next) { dt = 0; if (IS_LOAD(ip->inst[0]) && NonLocalDeref(ip->inst[2])) dt = ip->inst[2]; else if (IS_STORE(ip->inst[0]) && NonLocalDeref(ip->inst[1])) dt = ip->inst[1]; if (dt && STpts2[dt-1] == pi->ptr) { /* * NOTE: since we are considering only const inc now, we won't have * any load of index. this assertion is to protect this assumption */ assert( (ip->prev->inst[0] == LD) && (STpts2[ip->prev->inst[2]-1])==pi->ptr ); k = -ip->prev->inst[1]; sp = UpdateDeref(ip, k, inc); if (sp) { for (k=0; k < 4; k++) ip->inst[k] = sp[k]; } else { #if 1 fprintf(stderr, "DT: <%d, %d, %d, %d>\n", SToff[dt-1].sa[0], SToff[dt-1].sa[1], SToff[dt-1].sa[2], SToff[dt-1].sa[3] ); assert(0); #else InsNewInst(blk, NULL, ip, ADD, -k, -k, STiconstlookup(inc)); #endif } } #if 0 if (IS_LOAD(ip->inst[0]) && NonLocalDeref(ip->inst[2])) { k = STpts2[ip->inst[2]-1]; if (k != pi->ptr) continue; /* * since it's const inc, there is no load of index.. so, ip->prev * should be load of ptr */ assert( (ip->prev->inst[0] == LD) && (k==STpts2[ip->prev->inst[2]-1]) ); k = -ip->prev->inst[1]; sp = UpdateDeref(ip, k, inc); if (sp) { for (k=0; k < 4; k++) ip->inst[k] = sp[k]; } else { #if 1 fprintf(stderr, "DT: <%d, %d, %d, %d>\n", SToff[ip->inst[2]-1].sa[0], SToff[ip->inst[2]-1].sa[1], SToff[ip->inst[2]-1].sa[2], SToff[ip->inst[2]-1].sa[3] ); assert(0); #else InsNewInst(blk, NULL, ip, ADD, -k, -k, STiconstlookup(inc)); #endif } } else if (IS_STORE(ip->inst[0]) && NonLocalDeref(ip->inst[1])) { k = STpts2[ip->inst[1]-1]; if (k != pi->ptr) continue; assert( (ip->prev->inst[0] == LD) && (k==STpts2[ip->prev->inst[2]-1]) ); k = -ip->prev->inst[1]; sp = UpdateDeref(ip, k, inc); if (sp) { for (k=0; k < 4; k++) ip->inst[k] = sp[k]; } else { #if 1 fprintf(stderr, "DT: <%d, %d, %d, %d>\n", SToff[ip->inst[1]-1].sa[0], SToff[ip->inst[1]-1].sa[1], SToff[ip->inst[1]-1].sa[2], SToff[ip->inst[1]-1].sa[3] ); assert(0); #else InsNewInst(blk, NULL, ip, ADD, -k, -k, STiconstlookup(inc)); #endif } } #endif } /* * delete pointer update... */ ip = ip0->prev->prev; ip = DelInst(ip); ip = DelInst(ip); ip = DelInst(ip); il->inst = NULL; } /* * add pointer update at the end of the block before branch unless we have * loop cmpflags */ ip = FindCompilerFlag(blk, CF_LOOP_PTRUPDATE ); if (!ip) { ip = FindCompilerFlag(blk, CF_LOOP_UPDATE); if (!ip) { ip = FindCompilerFlag(blk, CF_LOOP_INIT); if (!ip) { ip = blk->instN; if (IS_BRANCH(ip->inst[0])) ip = ip->prev; while (ip && !IS_STORE(ip->inst[0]) && !IS_BRANCH(ip->inst[0]) && ip->inst[0] != LABEL) { ip = ip->prev; } ip = ip->next; } } else { ip = InsNewInst(blk, NULL, ip, CMPFLAG, CF_LOOP_PTRUPDATE, 0, 0 ); ip = ip->next; } } else { ip = ip->next; } /* * inst shouldn't have any access of ptr after this point * FIXME: do we need to place a checking in case CMPFLAG got displaced??? */ InsNewInst(blk, NULL, ip, LD, -reg, SToff[pi->ptr-1].sa[2], 0 ); if (pi->flag & PTRF_INC) InsNewInst(blk, NULL, ip, ADD, -reg, -reg, STiconstlookup(inc)); else assert(0); InsNewInst(blk, NULL, ip, ST, SToff[pi->ptr-1].sa[2], -reg, 0 ); INUSETU2D = CFUSETU2D = INDEADU2D = 0; } }