diff options
author | comex | 2015-02-22 23:28:20 -0500 |
---|---|---|
committer | comex | 2015-02-23 00:54:13 -0500 |
commit | 6080774f1af3103be688941beb43174d69d60483 (patch) | |
tree | 76a32ee6c7a9dc66a7a6bbc508e33596f2991945 | |
parent | fix i386 manual syscall, mmap return check (diff) | |
download | substitute-6080774f1af3103be688941beb43174d69d60483.tar.gz |
fix some i386 stuff
-rw-r--r-- | lib/x86/arch-transform-dis.inc.h | 84 | ||||
-rw-r--r-- | lib/x86/dis-main.inc.h | 2 | ||||
-rw-r--r-- | lib/x86/jump-patch.h | 13 |
3 files changed, 56 insertions, 43 deletions
diff --git a/lib/x86/arch-transform-dis.inc.h b/lib/x86/arch-transform-dis.inc.h index bb18d7d..56e41eb 100644 --- a/lib/x86/arch-transform-dis.inc.h +++ b/lib/x86/arch-transform-dis.inc.h @@ -55,58 +55,66 @@ static void transform_dis_pcrel(struct transform_dis_ctx *ctx, uint64_t dpc, static void transform_dis_branch(struct transform_dis_ctx *ctx, uint_tptr dpc, int cc) { - if (dpc >= ctx->pc_patch_start && dpc < ctx->pc_patch_end) { - if (dpc == ctx->base.pc + ctx->base.op_size && (cc & CC_CALL)) { - /* Probably a poor man's PC-rel - 'call .; pop %some'. - * Push the original address. - * Max size: orig + 1 + 11 + 5 + 1 - * Minimum call size is 4 bytes; at most 2. */ - void *code = *ctx->rewritten_ptr_ptr; - ctx->write_newop_here = NULL; + if (dpc == ctx->base.pc + ctx->base.op_size && (cc & CC_CALL)) { + /* Probably a poor man's PC-rel - 'call .; pop %some'. + * Push the original address. + * Max size: orig + 1 + 11 + 5 + 1 + * Minimum call size is 4 bytes; at most 2. */ + void *code = *ctx->rewritten_ptr_ptr; + ctx->write_newop_here = NULL; - /* push %whatever */ - op8(&code, 0x50); - /* push %rax; mov $dpc, %rax */ - push_mov_head(&code, dpc, true); - /* mov %rax, 8(%rsp) / mov %eax, 4(%esp) */ + /* push %whatever */ + op8(&code, 0x50); + /* push %rax; mov $dpc, %rax */ + push_mov_head(&code, dpc, true); + /* mov %rax, 8(%rsp) / mov %eax, 4(%esp) */ #ifdef TARGET_x86_64 - memcpy(code, ((uint8_t[]) {0x48, 0x8b, 0x44, 0x24, 0x08}), 5); - code += 5; + memcpy(code, ((uint8_t[]) {0x48, 0x8b, 0x44, 0x24, 0x08}), 5); + code += 5; #else - memcpy(code, ((uint8_t[]) {0x89, 0x44, 0x24, 0x04}), 4); - code += 4; + memcpy(code, ((uint8_t[]) {0x89, 0x44, 0x24, 0x04}), 4); + code += 4; #endif - /* pop %rax */ - push_mov_tail(&code, true); + /* pop %rax */ + push_mov_tail(&code, true); - *ctx->rewritten_ptr_ptr = code; - return; - } + *ctx->rewritten_ptr_ptr = code; + return; + } + if (dpc >= ctx->pc_patch_start && dpc < ctx->pc_patch_end) { ctx->err = SUBSTITUTE_ERR_FUNC_BAD_INSN_AT_START; return; } void *code = *ctx->rewritten_ptr_ptr; + struct arch_dis_ctx arch; - ctx->write_newop_here = code; - code += ctx->base.op_size; + if (cc & CC_CONDITIONAL) { + ctx->write_newop_here = code; + code += ctx->base.op_size; - struct arch_dis_ctx arch; - uintptr_t source = ctx->pc_trampoline + ctx->base.op_size + 2; - int size = jump_patch_size(source, dpc, arch, true); - /* If not taken, jmp past the big jump - this is a bit suboptimal but not - * that bad. - * Max size: orig + 2 + 14 - * Minimum jump size is 2 bytes; at most 3. */ - op8(&code, 0xeb); - op8(&code, size); - make_jump_patch(&code, source, dpc, arch); + uintptr_t source = ctx->pc_trampoline + ctx->base.op_size + 2; + int size = jump_patch_size(source, dpc, arch, true); - *ctx->rewritten_ptr_ptr = code; - ctx->base.newval[0] = 2; - ctx->base.modify = true; + /* If not taken, jmp past the big jump - this is a bit suboptimal but not + * that bad. + * Max size: orig + 2 + 14 + * Minimum jump size is 2 bytes; at most 3. */ + op8(&code, 0xeb); + op8(&code, size); + + make_jump_patch(&code, source, dpc, arch); - if (!cc) + ctx->base.newval[0] = 2; + ctx->base.modify = true; transform_dis_ret(ctx); + } else { + ctx->write_newop_here = NULL; + make_jmp_or_call(&code, ctx->pc_trampoline, dpc, cc & CC_CALL); + + if (!(cc & CC_CALL)) + transform_dis_ret(ctx); + } + *ctx->rewritten_ptr_ptr = code; } static void transform_dis_pre_dis(UNUSED struct transform_dis_ctx *ctx) {} diff --git a/lib/x86/dis-main.inc.h b/lib/x86/dis-main.inc.h index 4be45d8..9959409 100644 --- a/lib/x86/dis-main.inc.h +++ b/lib/x86/dis-main.inc.h @@ -263,7 +263,7 @@ got_bits: UNUSED default: __builtin_abort(); } - bool cond = (byte1 & 0xf0) != 0xe0; + bool cond = !(byte1 == 0xe2 || (byte1 >= 0xe8 && byte1 <= 0xeb)); bool call = !(bits & I_JMP); P(branch)(ctx, ctx->base.pc + ctx->base.op_size + imm, cond * CC_CONDITIONAL | call * CC_CALL); diff --git a/lib/x86/jump-patch.h b/lib/x86/jump-patch.h index 569eb74..09554d1 100644 --- a/lib/x86/jump-patch.h +++ b/lib/x86/jump-patch.h @@ -13,19 +13,24 @@ static inline int jump_patch_size(uint_tptr pc, uint_tptr dpc, return force ? (2+4+8) : -1; } -static inline void make_jump_patch(void **codep, uint_tptr pc, uint_tptr dpc, - UNUSED struct arch_dis_ctx arch) { +static inline void make_jmp_or_call(void **codep, uint_tptr pc, uint_tptr dpc, + bool call) { uint_tptr diff = dpc - (pc + 5); void *code = *codep; if (diff == (uint_tptr) (int32_t) diff) { - op8(&code, 0xe9); + op8(&code, call ? 0xe8 : 0xe9); op32(&code, diff); } else { /* jmpq *(%rip) */ op8(&code, 0xff); - op8(&code, 0x25); + op8(&code, call ? 0x15 : 0x25); op32(&code, 0); op64(&code, dpc); } *codep = code; } + +static inline void make_jump_patch(void **codep, uint_tptr pc, uint_tptr dpc, + UNUSED struct arch_dis_ctx arch) { + make_jmp_or_call(codep, pc, dpc, false); +} |