aboutsummaryrefslogtreecommitdiff
path: root/lib/x86/arch-transform-dis.inc.h
diff options
context:
space:
mode:
authorcomex2015-02-08 23:45:24 -0500
committercomex2015-02-08 23:45:24 -0500
commiteb93cee2a22cde812ccd6b9bd418d36185c058f5 (patch)
tree43a22ccf021a1513dba3a9c99f7b81822fe950fa /lib/x86/arch-transform-dis.inc.h
parentformatting (diff)
downloadsubstitute-eb93cee2a22cde812ccd6b9bd418d36185c058f5.tar.gz
Refactor disassembly so x86 works, and add x86 transform-dis.
This patch is a monolithic mess, because I was too lazy to do the refactor first (that would require some stash fun, since I wasn't actually sure before doing x86 transform-dis what would be needed). Anyway, the resulting code should be cleaner - less duplication. This breaks ARM/ARM64.
Diffstat (limited to 'lib/x86/arch-transform-dis.inc.h')
-rw-r--r--lib/x86/arch-transform-dis.inc.h58
1 files changed, 58 insertions, 0 deletions
diff --git a/lib/x86/arch-transform-dis.inc.h b/lib/x86/arch-transform-dis.inc.h
new file mode 100644
index 0000000..bb86cf9
--- /dev/null
+++ b/lib/x86/arch-transform-dis.inc.h
@@ -0,0 +1,58 @@
+/* Pretty trivial, but in its own file to match the other architectures. */
+#include "x86/jump-patch.h"
+
+static void transform_dis_pcrel(struct transform_dis_ctx *ctx, uint64_t dpc,
+ struct arch_pcrel_info info) {
+ /* push %reg; mov $dpc, %reg; <orig but with reg instead>; pop %reg */
+ /* reg is rcx, or rax if the instruction might be using rcx. */
+ int rax = info.reg == 1;
+ void *code = *ctx->rewritten_ptr_ptr;
+ /* push */
+ op8(&code, rax ? 0x50 : 0x51);
+ /* mov */
+#ifdef TARGET_x86_64
+ op8(&code, 0x48);
+ op8(&code, rax ? 0xb8 : 0xb9);
+ op64(&code, dpc);
+#else
+ op8(&code, rax ? 0xb8 : 0xb9);
+ op32(&code, dpc);
+#endif
+ ctx->write_newop_here = code;
+ code += ctx->base.op_size;
+ /* pop */
+ op8(&code, rax ? 0x58 : 0x59);
+ *ctx->rewritten_ptr_ptr = code;
+ ctx->base.newop[0] = rax ? 0 : 1;
+ ctx->base.modify = true;
+}
+
+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) {
+ ctx->err = SUBSTITUTE_ERR_FUNC_BAD_INSN_AT_START;
+ return;
+ }
+ void *code = *ctx->rewritten_ptr_ptr;
+
+ ctx->write_newop_here = code;
+ code += ctx->base.op_size;
+
+ struct arch_dis_ctx arch;
+ uintptr_t source = (uintptr_t) code + 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 */
+ op8(&code, 0xeb);
+ op8(&code, size);
+ make_jump_patch(&code, source, dpc, arch);
+
+ *ctx->rewritten_ptr_ptr = code;
+ ctx->base.newop[0] = 2;
+ ctx->base.modify = true;
+
+ if (!cc)
+ transform_dis_ret(ctx);
+}
+
+static void transform_dis_pre_dis(UNUSED struct transform_dis_ctx *ctx) {}
+static void transform_dis_post_dis(UNUSED struct transform_dis_ctx *ctx) {}