aboutsummaryrefslogtreecommitdiff
path: root/lib/x86/arch-transform-dis.inc.h
blob: ffb95603963273beff31b7b00443eb5335f3ca77 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
/* Pretty trivial, but in its own file to match the other architectures. */
#include "x86/jump-patch.h"

UNUSED
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) {}