📄 translate-copy.c
字号:
/* * i386 on i386 translation * * Copyright (c) 2003 Fabrice Bellard * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */#include "config.h"#include <stdarg.h>#include <stdlib.h>#include <stdio.h>#include <string.h>#include <inttypes.h>#include <assert.h>#include "cpu.h"#include "exec-all.h"#include "disas.h"#ifdef USE_CODE_COPY#include <signal.h>#include <sys/mman.h>#include <sys/ucontext.h>extern char exec_loop;/* operand size */enum { OT_BYTE = 0, OT_WORD, OT_LONG, OT_QUAD,};#define PREFIX_REPZ 0x01#define PREFIX_REPNZ 0x02#define PREFIX_LOCK 0x04#define PREFIX_DATA 0x08#define PREFIX_ADR 0x10typedef struct DisasContext { /* current insn context */ int override; /* -1 if no override */ int prefix; int aflag, dflag; target_ulong pc; /* pc = eip + cs_base */ int is_jmp; /* 1 = means jump (stop translation), 2 means CPU static state change (stop translation) */ /* code output */ uint8_t *gen_code_ptr; uint8_t *gen_code_start; /* current block context */ target_ulong cs_base; /* base of CS segment */ int pe; /* protected mode */ int code32; /* 32 bit code segment */ int f_st; /* currently unused */ int vm86; /* vm86 mode */ int cpl; int iopl; int flags; struct TranslationBlock *tb;} DisasContext;#define CPU_FIELD_OFFSET(field) offsetof(CPUState, field)#define CPU_SEG 0x64 /* fs override */static inline void gb(DisasContext *s, uint32_t val){ *s->gen_code_ptr++ = val;}static inline void gw(DisasContext *s, uint32_t val){ *s->gen_code_ptr++ = val; *s->gen_code_ptr++ = val >> 8;}static inline void gl(DisasContext *s, uint32_t val){ *s->gen_code_ptr++ = val; *s->gen_code_ptr++ = val >> 8; *s->gen_code_ptr++ = val >> 16; *s->gen_code_ptr++ = val >> 24;}static inline void gjmp(DisasContext *s, long val){ gb(s, 0xe9); /* jmp */ gl(s, val - (long)(s->gen_code_ptr + 4));}static inline void gen_movl_addr_im(DisasContext *s, uint32_t addr, uint32_t val){ gb(s, CPU_SEG); /* seg movl im, addr */ gb(s, 0xc7); gb(s, 0x05); gl(s, addr); gl(s, val);}static inline void gen_movw_addr_im(DisasContext *s, uint32_t addr, uint32_t val){ gb(s, CPU_SEG); /* seg movl im, addr */ gb(s, 0x66); gb(s, 0xc7); gb(s, 0x05); gl(s, addr); gw(s, val);}static void gen_jmp(DisasContext *s, uint32_t target_eip){ TranslationBlock *tb = s->tb; gb(s, 0xe9); /* jmp */ tb->tb_jmp_offset[0] = s->gen_code_ptr - s->gen_code_start; gl(s, 0); tb->tb_next_offset[0] = s->gen_code_ptr - s->gen_code_start; gen_movl_addr_im(s, CPU_FIELD_OFFSET(eip), target_eip); gen_movl_addr_im(s, CPU_FIELD_OFFSET(tmp0), (uint32_t)tb); gjmp(s, (long)&exec_loop); s->is_jmp = 1;}static void gen_jcc(DisasContext *s, int op, uint32_t target_eip, uint32_t next_eip){ TranslationBlock *tb = s->tb; gb(s, 0x0f); /* jcc */ gb(s, 0x80 + op); tb->tb_jmp_offset[0] = s->gen_code_ptr - s->gen_code_start; gl(s, 0); gb(s, 0xe9); /* jmp */ tb->tb_jmp_offset[1] = s->gen_code_ptr - s->gen_code_start; gl(s, 0); tb->tb_next_offset[0] = s->gen_code_ptr - s->gen_code_start; gen_movl_addr_im(s, CPU_FIELD_OFFSET(eip), target_eip); gen_movl_addr_im(s, CPU_FIELD_OFFSET(tmp0), (uint32_t)tb); gjmp(s, (long)&exec_loop); tb->tb_next_offset[1] = s->gen_code_ptr - s->gen_code_start; gen_movl_addr_im(s, CPU_FIELD_OFFSET(eip), next_eip); gen_movl_addr_im(s, CPU_FIELD_OFFSET(tmp0), (uint32_t)tb | 1); gjmp(s, (long)&exec_loop); s->is_jmp = 1;}static void gen_eob(DisasContext *s){ gen_movl_addr_im(s, CPU_FIELD_OFFSET(tmp0), 0); gjmp(s, (long)&exec_loop); s->is_jmp = 1;}static inline void gen_lea_modrm(DisasContext *s, int modrm){ int havesib; int base, disp; int index; int scale; int mod, rm, code; mod = (modrm >> 6) & 3; rm = modrm & 7; if (s->aflag) { havesib = 0; base = rm; index = 0; scale = 0; if (base == 4) { havesib = 1; code = ldub_code(s->pc++); scale = (code >> 6) & 3; index = (code >> 3) & 7; base = code & 7; } switch (mod) { case 0: if (base == 5) { base = -1; disp = ldl_code(s->pc); s->pc += 4; } else { disp = 0; } break; case 1: disp = (int8_t)ldub_code(s->pc++); break; default: case 2: disp = ldl_code(s->pc); s->pc += 4; break; } } else { switch (mod) { case 0: if (rm == 6) { disp = lduw_code(s->pc); s->pc += 2; } else { disp = 0; } break; case 1: disp = (int8_t)ldub_code(s->pc++); break; default: case 2: disp = lduw_code(s->pc); s->pc += 2; break; } }}static inline void parse_modrm(DisasContext *s, int modrm){ if ((modrm & 0xc0) != 0xc0) gen_lea_modrm(s, modrm); }static inline uint32_t insn_get(DisasContext *s, int ot){ uint32_t ret; switch(ot) { case OT_BYTE: ret = ldub_code(s->pc); s->pc++; break; case OT_WORD: ret = lduw_code(s->pc); s->pc += 2; break; default: case OT_LONG: ret = ldl_code(s->pc); s->pc += 4; break; } return ret;}/* convert one instruction. s->is_jmp is set if the translation must be stopped. */static int disas_insn(DisasContext *s){ target_ulong pc_start, pc_tmp, pc_start_insn; int b, prefixes, aflag, dflag, next_eip, val; int ot; int modrm, mod, op, rm; pc_start = s->pc; prefixes = 0; aflag = s->code32; dflag = s->code32; s->override = -1; next_byte: b = ldub_code(s->pc); s->pc++; /* check prefixes */ switch (b) { case 0xf3: prefixes |= PREFIX_REPZ; goto next_byte; case 0xf2: prefixes |= PREFIX_REPNZ; goto next_byte; case 0xf0: prefixes |= PREFIX_LOCK; goto next_byte; case 0x2e: s->override = R_CS; goto next_byte; case 0x36: s->override = R_SS; goto next_byte; case 0x3e: s->override = R_DS; goto next_byte; case 0x26: s->override = R_ES; goto next_byte; case 0x64: s->override = R_FS; goto next_byte; case 0x65: s->override = R_GS; goto next_byte; case 0x66: prefixes |= PREFIX_DATA; goto next_byte; case 0x67: prefixes |= PREFIX_ADR; goto next_byte; } if (prefixes & PREFIX_DATA) dflag ^= 1; if (prefixes & PREFIX_ADR) aflag ^= 1; s->prefix = prefixes; s->aflag = aflag; s->dflag = dflag; /* lock generation */ if (prefixes & PREFIX_LOCK) goto unsupported_op; if (s->override == R_FS || s->override == R_GS || s->override == R_CS) goto unsupported_op; pc_start_insn = s->pc - 1; /* now check op code */ reswitch: switch(b) { case 0x0f: /**************************/ /* extended op code */ b = ldub_code(s->pc++) | 0x100; goto reswitch; /**************************/ /* arith & logic */ case 0x00 ... 0x05: case 0x08 ... 0x0d: case 0x10 ... 0x15: case 0x18 ... 0x1d: case 0x20 ... 0x25: case 0x28 ... 0x2d: case 0x30 ... 0x35: case 0x38 ... 0x3d: { int f; f = (b >> 1) & 3; if ((b & 1) == 0) ot = OT_BYTE; else ot = dflag ? OT_LONG : OT_WORD; switch(f) { case 0: /* OP Ev, Gv */ modrm = ldub_code(s->pc++); parse_modrm(s, modrm); break; case 1: /* OP Gv, Ev */ modrm = ldub_code(s->pc++); parse_modrm(s, modrm); break; case 2: /* OP A, Iv */ insn_get(s, ot); break; } } break; case 0x80: /* GRP1 */ case 0x81: case 0x82: case 0x83: { if ((b & 1) == 0) ot = OT_BYTE; else ot = dflag ? OT_LONG : OT_WORD; modrm = ldub_code(s->pc++); parse_modrm(s, modrm); switch(b) { default: case 0x80: case 0x81: case 0x82: insn_get(s, ot); break; case 0x83: insn_get(s, OT_BYTE); break; } } break; /**************************/ /* inc, dec, and other misc arith */ case 0x40 ... 0x47: /* inc Gv */ break; case 0x48 ... 0x4f: /* dec Gv */ break; case 0xf6: /* GRP3 */ case 0xf7: if ((b & 1) == 0) ot = OT_BYTE; else ot = dflag ? OT_LONG : OT_WORD; modrm = ldub_code(s->pc++); op = (modrm >> 3) & 7; parse_modrm(s, modrm); switch(op) { case 0: /* test */ insn_get(s, ot); break; case 2: /* not */ break; case 3: /* neg */ break; case 4: /* mul */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -