x86_emulate.c
来自「xen虚拟机源代码安装包」· C语言 代码 · 共 1,781 行 · 第 1/5 页
C
1,781 行
{ src.reg = decode_register(modrm_reg, &_regs, 0); switch ( (src.bytes = op_bytes) ) { case 2: src.val = *(uint16_t *)src.reg; break; case 4: src.val = *(uint32_t *)src.reg; break; case 8: src.val = *(uint64_t *)src.reg; break; } } break; case SrcMem16: ea.bytes = 2; goto srcmem_common; case SrcMem: ea.bytes = (d & ByteOp) ? 1 : op_bytes; srcmem_common: src = ea; if ( src.type == OP_REG ) { switch ( src.bytes ) { case 1: src.val = *(uint8_t *)src.reg; break; case 2: src.val = *(uint16_t *)src.reg; break; case 4: src.val = *(uint32_t *)src.reg; break; case 8: src.val = *(uint64_t *)src.reg; break; } } else if ( (rc = read_ulong(src.mem.seg, src.mem.off, &src.val, src.bytes, ctxt, ops)) ) goto done; break; case SrcImm: src.type = OP_IMM; src.bytes = (d & ByteOp) ? 1 : op_bytes; if ( src.bytes == 8 ) src.bytes = 4; /* NB. Immediates are sign-extended as necessary. */ switch ( src.bytes ) { case 1: src.val = insn_fetch_type(int8_t); break; case 2: src.val = insn_fetch_type(int16_t); break; case 4: src.val = insn_fetch_type(int32_t); break; } break; case SrcImmByte: src.type = OP_IMM; src.bytes = 1; src.val = insn_fetch_type(int8_t); break; } /* Decode and fetch the destination operand: register or memory. */ switch ( d & DstMask ) { case DstReg: dst.type = OP_REG; if ( d & ByteOp ) { dst.reg = decode_register(modrm_reg, &_regs, (rex_prefix == 0)); dst.val = *(uint8_t *)dst.reg; dst.bytes = 1; } else { dst.reg = decode_register(modrm_reg, &_regs, 0); switch ( (dst.bytes = op_bytes) ) { case 2: dst.val = *(uint16_t *)dst.reg; break; case 4: dst.val = *(uint32_t *)dst.reg; break; case 8: dst.val = *(uint64_t *)dst.reg; break; } } break; case DstBitBase: if ( ((d & SrcMask) == SrcImmByte) || (ea.type == OP_REG) ) { src.val &= (op_bytes << 3) - 1; } else { /* * EA += BitOffset DIV op_bytes*8 * BitOffset = BitOffset MOD op_bytes*8 * DIV truncates towards negative infinity. * MOD always produces a positive result. */ if ( op_bytes == 2 ) src.val = (int16_t)src.val; else if ( op_bytes == 4 ) src.val = (int32_t)src.val; if ( (long)src.val < 0 ) { unsigned long byte_offset; byte_offset = op_bytes + (((-src.val-1) >> 3) & ~(op_bytes-1)); ea.mem.off -= byte_offset; src.val = (byte_offset << 3) + src.val; } else { ea.mem.off += (src.val >> 3) & ~(op_bytes - 1); src.val &= (op_bytes << 3) - 1; } } /* Becomes a normal DstMem operation from here on. */ d = (d & ~DstMask) | DstMem; case DstMem: ea.bytes = (d & ByteOp) ? 1 : op_bytes; dst = ea; if ( dst.type == OP_REG ) { switch ( dst.bytes ) { case 1: dst.val = *(uint8_t *)dst.reg; break; case 2: dst.val = *(uint16_t *)dst.reg; break; case 4: dst.val = *(uint32_t *)dst.reg; break; case 8: dst.val = *(uint64_t *)dst.reg; break; } } else if ( !(d & Mov) ) /* optimisation - avoid slow emulated read */ { if ( (rc = read_ulong(dst.mem.seg, dst.mem.off, &dst.val, dst.bytes, ctxt, ops)) ) goto done; dst.orig_val = dst.val; } break; } /* LOCK prefix allowed only on instructions with memory destination. */ generate_exception_if(lock_prefix && (dst.type != OP_MEM), EXC_GP, 0); if ( twobyte ) goto twobyte_insn; switch ( b ) { case 0x04 ... 0x05: /* add imm,%%eax */ dst.reg = (unsigned long *)&_regs.eax; dst.val = _regs.eax; case 0x00 ... 0x03: add: /* add */ emulate_2op_SrcV("add", src, dst, _regs.eflags); break; case 0x0c ... 0x0d: /* or imm,%%eax */ dst.reg = (unsigned long *)&_regs.eax; dst.val = _regs.eax; case 0x08 ... 0x0b: or: /* or */ emulate_2op_SrcV("or", src, dst, _regs.eflags); break; case 0x14 ... 0x15: /* adc imm,%%eax */ dst.reg = (unsigned long *)&_regs.eax; dst.val = _regs.eax; case 0x10 ... 0x13: adc: /* adc */ emulate_2op_SrcV("adc", src, dst, _regs.eflags); break; case 0x1c ... 0x1d: /* sbb imm,%%eax */ dst.reg = (unsigned long *)&_regs.eax; dst.val = _regs.eax; case 0x18 ... 0x1b: sbb: /* sbb */ emulate_2op_SrcV("sbb", src, dst, _regs.eflags); break; case 0x24 ... 0x25: /* and imm,%%eax */ dst.reg = (unsigned long *)&_regs.eax; dst.val = _regs.eax; case 0x20 ... 0x23: and: /* and */ emulate_2op_SrcV("and", src, dst, _regs.eflags); break; case 0x2c ... 0x2d: /* sub imm,%%eax */ dst.reg = (unsigned long *)&_regs.eax; dst.val = _regs.eax; case 0x28 ... 0x2b: sub: /* sub */ emulate_2op_SrcV("sub", src, dst, _regs.eflags); break; case 0x34 ... 0x35: /* xor imm,%%eax */ dst.reg = (unsigned long *)&_regs.eax; dst.val = _regs.eax; case 0x30 ... 0x33: xor: /* xor */ emulate_2op_SrcV("xor", src, dst, _regs.eflags); break; case 0x3c ... 0x3d: /* cmp imm,%%eax */ dst.reg = (unsigned long *)&_regs.eax; dst.val = _regs.eax; case 0x38 ... 0x3b: cmp: /* cmp */ emulate_2op_SrcV("cmp", src, dst, _regs.eflags); dst.type = OP_NONE; break; case 0x62: /* bound */ { unsigned long src_val2; int lb, ub, idx; generate_exception_if(mode_64bit() || (src.type != OP_MEM), EXC_UD, -1); if ( (rc = read_ulong(src.mem.seg, src.mem.off + op_bytes, &src_val2, op_bytes, ctxt, ops)) ) goto done; ub = (op_bytes == 2) ? (int16_t)src_val2 : (int32_t)src_val2; lb = (op_bytes == 2) ? (int16_t)src.val : (int32_t)src.val; idx = (op_bytes == 2) ? (int16_t)dst.val : (int32_t)dst.val; generate_exception_if((idx < lb) || (idx > ub), EXC_BR, -1); dst.type = OP_NONE; break; } case 0x63: /* movsxd (x86/64) / arpl (x86/32) */ if ( mode_64bit() ) { /* movsxd */ if ( src.type == OP_REG ) src.val = *(int32_t *)src.reg; else if ( (rc = read_ulong(src.mem.seg, src.mem.off, &src.val, 4, ctxt, ops)) ) goto done; dst.val = (int32_t)src.val; } else { /* arpl */ uint16_t src_val = dst.val; dst = src; _regs.eflags &= ~EFLG_ZF; _regs.eflags |= ((src_val & 3) > (dst.val & 3)) ? EFLG_ZF : 0; if ( _regs.eflags & EFLG_ZF ) dst.val = (dst.val & ~3) | (src_val & 3); else dst.type = OP_NONE; generate_exception_if(!in_protmode(ctxt, ops), EXC_UD, -1); } break; case 0x69: /* imul imm16/32 */ case 0x6b: /* imul imm8 */ { unsigned long src1; /* ModR/M source operand */ if ( ea.type == OP_REG ) src1 = *ea.reg; else if ( (rc = read_ulong(ea.mem.seg, ea.mem.off, &src1, op_bytes, ctxt, ops)) ) goto done; _regs.eflags &= ~(EFLG_OF|EFLG_CF); switch ( dst.bytes ) { case 2: dst.val = ((uint32_t)(int16_t)src.val * (uint32_t)(int16_t)src1); if ( (int16_t)dst.val != (uint32_t)dst.val ) _regs.eflags |= EFLG_OF|EFLG_CF; break;#ifdef __x86_64__ case 4: dst.val = ((uint64_t)(int32_t)src.val * (uint64_t)(int32_t)src1); if ( (int32_t)dst.val != dst.val ) _regs.eflags |= EFLG_OF|EFLG_CF; break;#endif default: { unsigned long m[2] = { src.val, src1 }; if ( imul_dbl(m) ) _regs.eflags |= EFLG_OF|EFLG_CF; dst.val = m[0]; break; } } break; } case 0x82: /* Grp1 (x86/32 only) */ generate_exception_if(mode_64bit(), EXC_UD, -1); case 0x80: case 0x81: case 0x83: /* Grp1 */ switch ( modrm_reg & 7 ) { case 0: goto add; case 1: goto or; case 2: goto adc; case 3: goto sbb; case 4: goto and; case 5: goto sub; case 6: goto xor; case 7: goto cmp; } break; case 0xa8 ... 0xa9: /* test imm,%%eax */ dst.reg = (unsigned long *)&_regs.eax; dst.val = _regs.eax; case 0x84 ... 0x85: test: /* test */ emulate_2op_SrcV("test", src, dst, _regs.eflags); dst.type = OP_NONE; break; case 0x86 ... 0x87: xchg: /* xchg */ /* Write back the register source. */ switch ( dst.bytes ) { case 1: *(uint8_t *)src.reg = (uint8_t)dst.val; break; case 2: *(uint16_t *)src.reg = (uint16_t)dst.val; break; case 4: *src.reg = (uint32_t)dst.val; break; /* 64b reg: zero-extend */ case 8: *src.reg = dst.val; break; } /* Write back the memory destination with implicit LOCK prefix. */ dst.val = src.val; lock_prefix = 1; break; case 0xc6 ... 0xc7: /* mov (sole member of Grp11) */ generate_exception_if((modrm_reg & 7) != 0, EXC_UD, -1); case 0x88 ... 0x8b: /* mov */ dst.val = src.val; break; case 0x8c: /* mov Sreg,r/m */ { struct segment_register reg; enum x86_segment seg = decode_segment(modrm_reg); generate_exception_if(seg == decode_segment_failed, EXC_UD, -1); fail_if(ops->read_segment == NULL); if ( (rc = ops->read_segment(seg, ®, ctxt)) != 0 ) goto done; dst.val = reg.sel; if ( dst.type == OP_MEM ) dst.bytes = 2; break; } case 0x8e: /* mov r/m,Sreg */ { enum x86_segment seg = decode_segment(modrm_reg); generate_exception_if(seg == decode_segment_failed, EXC_UD, -1); if ( (rc = load_seg(seg, (uint16_t)src.val, ctxt, ops)) != 0 ) goto done; if ( seg == x86_seg_ss ) ctxt->retire.flags.mov_ss = 1; dst.type = OP_NONE; break; } case 0x8d: /* lea */ dst.val = ea.mem.off; break; case 0x8f: /* pop (sole member of Grp1a) */ generate_exception_if((modrm_reg & 7) != 0, EXC_UD, -1); /* 64-bit mode: POP defaults to a 64-bit operand. */ if ( mode_64bit() && (dst.bytes == 4) ) dst.bytes = 8; if ( (rc = read_ulong(x86_seg_ss, sp_post_inc(dst.bytes), &dst.val, dst.bytes, ctxt, ops)) != 0 ) goto done; break; case
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?