aboutsummaryrefslogtreecommitdiff
path: root/lib/x86
diff options
context:
space:
mode:
authorcomex2015-02-22 23:28:20 -0500
committercomex2015-02-23 00:54:13 -0500
commit6080774f1af3103be688941beb43174d69d60483 (patch)
tree76a32ee6c7a9dc66a7a6bbc508e33596f2991945 /lib/x86
parentfix i386 manual syscall, mmap return check (diff)
downloadsubstitute-6080774f1af3103be688941beb43174d69d60483.tar.gz
fix some i386 stuff
Diffstat (limited to 'lib/x86')
-rw-r--r--lib/x86/arch-transform-dis.inc.h84
-rw-r--r--lib/x86/dis-main.inc.h2
-rw-r--r--lib/x86/jump-patch.h13
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);
+}