aboutsummaryrefslogtreecommitdiff
path: root/src/tilde/tb_x64.h
blob: 58b3d656cc04accd3dc3aafd5161bd761963616a (plain)
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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
#ifndef TB_X64_H
#define TB_X64_H

#include <stdint.h>
#include <stdbool.h>

typedef enum {
    // uses xmm registers for the reg array
    TB_X86_INSTR_XMMREG = (1u << 0u),

    // r/m is a memory operand
    TB_X86_INSTR_USE_MEMOP = (1u << 1u),

    // r/m is a rip-relative address (TB_X86_INSTR_USE_MEMOP is always set when this is set)
    TB_X86_INSTR_USE_RIPMEM = (1u << 2u),

    // LOCK prefix is present
    TB_X86_INSTR_LOCK = (1u << 3u),

    // uses a signed immediate
    TB_X86_INSTR_IMMEDIATE = (1u << 4u),

    // absolute means it's using the 64bit immediate (cannot be applied while a memory operand is active)
    TB_X86_INSTR_ABSOLUTE = (1u << 5u),

    // set if the r/m can be found on the right hand side
    TB_X86_INSTR_DIRECTION = (1u << 6u),

    // uses the second data type because the instruction is weird like MOVSX or MOVZX
    TB_X86_INSTR_TWO_DATA_TYPES = (1u << 7u),

    // REP prefix is present
    TB_X86_INSTR_REP = (1u << 8u),

    // REPNE prefix is present
    TB_X86_INSTR_REPNE = (1u << 9u),
} TB_X86_InstFlags;

typedef enum {
    TB_X86_RAX, TB_X86_RCX, TB_X86_RDX, TB_X86_RBX, TB_X86_RSP, TB_X86_RBP, TB_X86_RSI, TB_X86_RDI,
    TB_X86_R8,  TB_X86_R9,  TB_X86_R10, TB_X86_R11, TB_X86_R12, TB_X86_R13, TB_X86_R14, TB_X86_R15,
} TB_X86_GPR;

typedef enum {
    TB_X86_SEGMENT_DEFAULT = 0,

    TB_X86_SEGMENT_ES, TB_X86_SEGMENT_CS,
    TB_X86_SEGMENT_SS, TB_X86_SEGMENT_DS,
    TB_X86_SEGMENT_GS, TB_X86_SEGMENT_FS,
} TB_X86_Segment;

typedef enum {
    TB_X86_TYPE_NONE = 0,

    TB_X86_TYPE_BYTE,    // 1
    TB_X86_TYPE_WORD,    // 2
    TB_X86_TYPE_DWORD,   // 4
    TB_X86_TYPE_QWORD,   // 8

    TB_X86_TYPE_PBYTE,   // int8 x 16 = 16
    TB_X86_TYPE_PWORD,   // int16 x 8 = 16
    TB_X86_TYPE_PDWORD,  // int32 x 4 = 16
    TB_X86_TYPE_PQWORD,  // int64 x 2 = 16

    TB_X86_TYPE_SSE_SS,  // float32 x 1 = 4
    TB_X86_TYPE_SSE_SD,  // float64 x 1 = 8
    TB_X86_TYPE_SSE_PS,  // float32 x 4 = 16
    TB_X86_TYPE_SSE_PD,  // float64 x 2 = 16

    TB_X86_TYPE_XMMWORD, // the generic idea of them
} TB_X86_DataType;

typedef struct {
    int32_t opcode;

    // registers (there's 4 max taking up 8bit slots each)
    int8_t regs[4];
    uint16_t flags;

    // bitpacking amirite
    TB_X86_DataType data_type  : 8;
    TB_X86_DataType data_type2 : 8;
    TB_X86_Segment segment     : 4;
    uint8_t length             : 4;

    // memory operand
    //   X86_INSTR_USE_MEMOP
    uint8_t base, index, scale;
    int32_t disp;

    // immediate operand
    //   imm for INSTR_IMMEDIATE
    //   abs for INSTR_ABSOLUTE
    union {
        int32_t  imm;
        uint64_t abs;
    };
} TB_X86_Inst;

bool tb_x86_disasm(TB_X86_Inst* restrict inst, size_t length, const uint8_t* data);
const char* tb_x86_reg_name(int8_t reg, TB_X86_DataType dt);
const char* tb_x86_type_name(TB_X86_DataType dt);
const char* tb_x86_mnemonic(TB_X86_Inst* inst);

#endif /* TB_X64_H */