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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
|
#ifndef INSTRUCTIONS_H
#define INSTRUCTIONS_H
// Prefixes
// Prefix groups are mutually exclusive
// Prefix group 1
#define PREFIX_LOCK 0xf0
#define PREFIX_REPNE 0xf2
#define PREFIX_REPNZ PREFIX_REPNE
#define PREFIX_REP 0xf3
#define PREFIX_REPE PREFIX_REP
#define PREFIX_REPZ PREFIX_REP
// Prefix group 2
#define PREFIX_OVERRIDE_SEGMENT_CS 0x2e
#define PREFIX_OVERRIDE_SEGMENT_SS 0x36
#define PREFIX_OVERRIDE_SEGMENT_DS 0x3e
#define PREFIX_OVERRIDE_SEGMENT_ES 0x26
#define PREFIX_OVERRIDE_SEGMENT_FS 0x64
#define PREFIX_OVERRIDE_SEGMENT_GS 0x65
#define PREFIX_BRANCH_NOT_TAKEN PREFIX_OVERRIDE_SEGMENT_CS
#define PREFIX_BRANCH_TAKEN PREFIX_OVERRIDE_SEGMENT_DS
// Prefix group 3
// sets opsize to 16 bit,
// if combined with REX.w, set opsize to 64,
// if only REX.w, then both opsize and address is 64 bit.
#define PREFIX_OVERRIDE_OPSIZE 0x66
// Prefix group 4
// sets address size to 32 bit.
#define PREFIX_OVERRIDE_ADDRESSSIZE 0x67
// Rex prefixes are used when
// - Using 64-bit operand sizes when default is not 64 bit (eg. rax as opposed
// to eax),
// - Using extended registers (R8 to R15, XMM8 to XMM15, YMM8 to YMM15, CR8 to
// CR15 and DR8 to DR15),
// - Using one of the uniform byte registers: SPL, BPL, SIL or DIL.
// Rex prefix
// [ 0 1 0 0 | W R X B ]
// W changes operand size to 64 bits
// R Extension to MODRM.reg field
// X Extension SIB.index field, 64-bit addressing
// B Extension to MODRM.rm or SIB.base fields, 64-bit addressing
#define REX(mode) (0b01000000 | mode)
#define REX_W 0b1000
#define REX_R 0b0100
#define REX_X 0b0010
#define REX_B 0b0001
// Rex2 prefix (2 bytes
// [ 1 1 0 1 | 0 1 0 1 ]
// [ M₀ R₄ X₄ B₄ | W R₃ X₃ B₃ ]
// W, R₃, X₃, and B₃ are the same as in REX
// R₄, X₄, and B₄ are used to encode 32 EGPR registers.
// M0 selects between legacy map 0 (1-byte opcodes, no escape) and legacy
// map 1 (2-byte opcodes, escape 0x0F).
//
// Opcodes that default to 64bit in long mode (and does therefore not need REX
// prefixes) are:
// CALL (near), ENTER, Jcc, JrCXZ, JMP (near), LEAVE, LGDT, LIDT, LLDT, LOOP,
// LOOPcc, LTR, MOV CR(n), MOV DR(n), POP reg/mem, POP reg, POP FS, POP GS,
// POPFQ, PUSH imm8, PUSH imm32, PUSH reg/mem, PUSH reg, PUSH FS, PUSH GS,
// PUSHFQ, and RET (near).
#define REX2(mode) REX(REX_R | REX_B), mode
#define REX2_W REX_W
#define REX2_R REX_R
#define REX2_R3 REX_R
#define REX2_X REX_X
#define REX2_X3 REX_X
#define REX2_B REX_B
#define REX2_B3 REX_B
#define REX2_M 0b10000000
#define REX2_R4 0b01000000
#define REX2_X4 0b00100000
#define REX2_B4 0b00010000
// MODR/M
// MOD REG RM (r/m = register/memory)
// [ 1 1 | 1 0 1 | 1 0 1 ]
// if mod == 0b11, then treat r/m as register,
// (examples in OP SRC DST ordering (same as the reg-rm order)
// gas/at&t ASM => op reg-idx reg-idx => MOD | REG | RM
// --------------------+----------------------+---------------------
// ie "xor %rcx, %rcx" => XOR 1 1 => [ 1 1 | 0 0 1 | 0 0 1 ]
// ie "xor %rsi, %rbp" => XOR 6 5 => [ 1 1 | 1 0 1 | 1 1 0 ]
//
// Other combinations of MOD means RM specifies an addressing mode.
// For 64bit systems:
//
// "disp" is displacement specified in `mod` bits.
#define MODRM(mod, reg, rm) (((mod & 3) << 6) | ((reg & 7) << 3) | (rm & 7))
// SIB (Scale, Index, Base)
// [ S S | I I I | B B B ]
// S S: equals 2^SIB.index, eg. 1, 2, 4, 8
// I I I: index register to use. REX.X, VEX.~X, and XOP.~X expands this with 1
// most significant bit. B B B: base register to use. REX.B, VEX.~B, and XOP.~B
// expands this with 1 most significant bit. Same layout as MODRM, could as well
// as define it as MODRM(scale, index, base)
#define SIB(scale, index, base) \
(((scale & 3) << 6) | ((index & 7) << 3) | (base & 7))
// Opcode encoding
// <op>
// 0x0F <op>
// 0x0F 0x38 <op>
// 0x0F 0x3A <op>
// Instructions
// Move immediates
#define MOVBI(reg, imm) (0xb0 + reg), (imm & 0xff)
#define MOVWI(reg, imm) \
PREFIX_OVERRIDE_OPSIZE, (0xb8 + reg), (imm & 0xff), ((imm >> 8) & 0xff)
#define MOVDI(reg, imm) \
(0xb8 + reg), (imm & 0xff), ((imm >> 8) & 0xff), ((imm >> 16) & 0xff), \
((imm >> 24) & 0xff)
#define MOVQI(reg, imm) \
REX(REX_W), MOVDI(reg, imm), ((imm >> 32) & 0xff), ((imm >> 40) & 0xff), \
((imm >> 48) & 0xff), ((imm >> 56) & 0xff)
#define MOVABS(reg, imm) MOVQI(reg, imm)
// Move registers
#define MOVB(src, dst) (0x88), MODRM(0b11, src, dst)
#define MOVW(src, dst) PREFIX_OVERRIDE_OPSIZE, (0x89), MODRM(0b11, src, dst)
#define MOVD(src, dst) (0x89), MODRM(0b11, src, dst)
#define MOVQ(src, dst) REX(REX_W), MOVD(src, dst)
#define ADDBIC(reg, imm) (0x10 + reg), (imm & 0xff)
#define ADDBIC(reg, imm) (0x10 + reg), (imm & 0xff)
#define ADD
#define CALL
#define CMP
#define DEC
#define DIV
#define HLT
#define IDIV
#define IMUL
#define INC
#define INT
#define INTO
#define IRET
#define JNZ
#define JMP
#define LEA
#define POP
#define PUSH
#define RET 0xc3
#define RETN
#define SUB
#define XOR /*TODO*/
#define SYSCALL 0x0f, 0x05
#endif
|