/
x86.h
610 lines (524 loc) · 15.1 KB
/
x86.h
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
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
#ifndef __X86_H__
#define __X86_H__
/* compiled code buffer */
typedef uint8_t* ccbuff;
#define PREFIX_LOCK 0xF0
#define PREFIX_REPNZ 0xF2
#define PREFIX_REPZ 0xF3
#define PREFIX_SEG_CS 0x2E
#define PREFIX_SEG_SS 0x36
#define PREFIX_SEG_DS 0x3E
#define PREFIX_SEG_ES 0x26
#define PREFIX_SEG_FS 0x64
#define PREFIX_SEG_GS 0x65
#define PREFIX_OPSIZE 0x66
#define PREFIX_ADDRSIZE 0x67
#define MOD_INDIR 0x0
#define MOD_INDIR_DISP8 0x1
#define MOD_INDIR_DISP32 0x2
#define MOD_REG 0x3
#define SCALE_1 0x0
#define SCALE_2 0x1
#define SCALE_4 0x2
#define SCALE_8 0x3
/* overflow */
#define CC_O 0x0
#define CC_NO 0x1
/* unsigned comparisons */
#define CC_B 0x2
#define CC_AE 0x3
#define CC_BE 0x6
#define CC_A 0x7
/* zero */
#define CC_Z 0x4
#define CC_NZ 0x5
/* sign */
#define CC_S 0x8
#define CC_NS 0x9
/* parity */
#define CC_P 0xA
#define CC_NP 0xB
/* unsigned comparisons */
#define CC_L 0xC
#define CC_GE 0xD
#define CC_LE 0xE
#define CC_G 0xF
typedef uint8_t cc_t;
#define PFX_REX 0x40
#define REXW 0x08
#define REXR 0x04
#define REXX 0x02
#define REXB 0x01
/*
* Using this as a register argument in the r/m field indicates an SIB
* byte follows (with mod != 3)
*/
#define REG_SIB X86ESP.val
/*
* With mod = 0, this specifies a 32-bit displacement
*/
#define REG_DISP32 X86EBP.val
/* Begin C++ */
template<uint8_t opcode>
struct has_opcode {
const static uint8_t val = opcode;
};
struct none {};
struct true_type {
const static bool val = true;
};
struct false_type {
const static bool val = true;
};
struct no_opcode {
const static none val;
};
#include "instructions.h"
class X86Assembler;
class X86Register;
class X86Label8;
#define FOR_EACH_INT_TYPE(X) \
X(signed short) \
X(unsigned short) \
X(signed int) \
X(unsigned int) \
X(signed long) \
X(unsigned long)
template<class Inst>
class X86Emitter {
private:
static void emit_(X86Assembler *cc, uint32_t lhs, X86Register rhs);
public:
#define D(int_type) static void emit(X86Assembler *cc, int_type lhs, X86Register rhs);
FOR_EACH_INT_TYPE(D)
#undef D
static void emit_imm(X86Assembler *cc, X86Register rhs, none);
static void emit_imm(X86Assembler *cc, X86Register rhs, uint8_t);
template <class Mem>
static void emit(X86Assembler *cc, uint32_t lhs, Mem rhs);
static void emit(X86Assembler *cc, X86Register lhs, X86Register rhs);
static void emit_reg(X86Assembler *cc, X86Register lhs, X86Register rhs, none);
static void emit_reg(X86Assembler *cc, X86Register lhs, X86Register rhs, uint8_t);
template <class Mem>
static void emit(X86Assembler *cc, X86Register lhs, Mem rhs);
template <class Mem>
static void emit(X86Assembler *cc, Mem lhs, X86Register rhs);
};
template<class Inst>
class X86ShiftEmitter {
public:
template <class Mem>
static void emit(X86Assembler *cc, X86Register, Mem);
template <class Mem>
static void emit(X86Assembler *cc, uint8_t, Mem);
};
class X86Assembler {
private:
ccbuff out;
public:
X86Assembler(ccbuff buf) : out(buf) {}
ccbuff eip() {
return out;
}
template <class T>
void emit(T v) {
*((T*)out) = v;
out += sizeof v;
}
void byte(uint8_t b) {
emit(b);
}
void address(uint32_t w) {
emit(w);
}
void word(uint32_t w) {
emit(w);
}
void rel32(uintptr_t label) {
word(((uint8_t*)label) - out - 4);
}
void modrm(uint8_t mod, uint8_t reg, uint8_t rm) {
ASSERT(!(mod & (~0x3)));
ASSERT(!(reg & (~0x7)));
ASSERT(!(rm & (~0x7)));
byte((uint8_t)(mod << 6)|(reg << 3)|(rm));
}
void sib(uint8_t scale, uint8_t index, uint8_t base) {
modrm(scale, index, base);
}
#ifdef __x86_64__
void rex(bool w = 0, bool r = 0, bool x = 0, bool b = 0) {
if (w || r || x || b)
byte(PFX_REX | (!!w << 3) | (!!r << 2) | (!!x << 2) | !!b);
}
#else
void rex(bool w = 0, bool r = 0, bool x = 0, bool b = 0) {
ASSERT(!w && !r && !x & !b);
}
#endif
void rex(int lbits, int rbits, bool r = 0, bool x = 0, bool b = 0) {
ASSERT(lbits == rbits || !lbits || !rbits);
rex((lbits | rbits) == 64, r, x, b);
}
#define INSTRUCTION(fn, cls) \
template <class Tl, class Tr> \
void fn(Tl lhs, Tr rhs) { \
X86Emitter<X86##cls>::emit(this, lhs, rhs); \
}
INSTRUCTION(test, Test);
INSTRUCTION(add_, Add);
INSTRUCTION(mov, Mov);
INSTRUCTION(cmp, Cmp);
INSTRUCTION(xor_, Xor);
INSTRUCTION(or_, Or);
INSTRUCTION(sub_, Sub);
INSTRUCTION(lea, Lea);
INSTRUCTION(and_, And);
#define SHIFT(fn, cls) \
template <class Tl, class Tr> \
void fn(Tl lhs, Tr rhs) { \
X86ShiftEmitter<X86##cls>::emit(this, lhs, rhs); \
}
SHIFT(shl, SHL);
SHIFT(shr, SHR);
SHIFT(sar, SAR);
template<class Mem> void imul(Mem lhs, X86Register rhs);
template<class Mem> void imul(uint32_t lhs, Mem rhs, X86Register dst);
template<class Mem> void idiv(Mem rhs);
void cdq();
void call(uintptr_t addr);
template<class Mem> void call(Mem target);
template<class Mem> void inc(Mem target);
void jmp(int8_t off);
void jmp(X86Label8 &l);
void jmp(uint8_t *addr);
template<class Mem> void jmp(Mem target);
void jcc(cc_t cc, int8_t off);
void jcc(cc_t cc, uint8_t *addr);
void jcc(cc_t cc, X86Label8 &l);
template<class Mem> void setcc(cc_t cc, Mem target);
void bind(X86Label8 *l);
private:
template<class Mem> void call(Mem target, true_type);
template<class Mem> void call(Mem target, false_type);
};
class X86Label8 {
enum {
NEW,
REFERENCED,
BOUND
} state;
uint8_t *reference;
int8_t addend;
public:
X86Label8() : state(NEW) {};
void referenced(uint8_t *addr, int8_t addend) {
ASSERT(state == NEW);
state = REFERENCED;
reference = addr;
this->addend = addend;
}
void bind(uint8_t *addr) {
ASSERT(state == REFERENCED);
state = BOUND;
*reference = addr - reference + addend;
}
};
template <class T>
struct is_modrm { const static false_type val; };
class X86Register {
public:
int val;
int bits;
X86Register(int v, int b = 0) : val(v), bits(b) {};
void rex(X86Assembler *cc, X86Register other) {
cc->rex(bits, other.bits);
}
void emit(X86Assembler *cc, X86Register reg) {
ASSERT(bits == reg.bits);
cc->modrm(MOD_REG, reg.val, val);
}
};
#ifdef __x86_64__
#define R(name, v) \
static X86Register X86E##name(v, 32); \
static X86Register X86R##name(v, 64)
#else
#define R(name, v) \
static X86Register X86E##name(v, 32)
#endif
R(AX, 0x00);
R(CX, 0x01);
R(DX, 0x02);
R(BX, 0x03);
R(SP, 0x04);
R(BP, 0x05);
R(SI, 0x06);
R(DI, 0x07);
#undef R
template<> struct is_modrm<X86Register> { const static true_type val; };
struct X86ReferenceIndirect {
X86Register base;
void rex(X86Assembler *cc, X86Register other) {
cc->rex(other.bits == 64);
}
void emit(X86Assembler *cc, X86Register reg) {
ASSERT(base.val != REG_DISP32);
ASSERT(base.val != REG_SIB);
cc->modrm(MOD_INDIR, reg.val, base.val);
}
};
template<> struct is_modrm<X86ReferenceIndirect> { const static true_type val; };
struct X86ReferenceIndirect32 {
X86Register base;
uint32_t offset;
void rex(X86Assembler *cc, X86Register other) {
cc->rex(other.bits == 64);
}
void emit(X86Assembler *cc, X86Register reg) {
ASSERT(base.val != REG_SIB);
cc->modrm(MOD_INDIR_DISP32, reg.val, base.val);
cc->word(offset);
}
};
template<> struct is_modrm<X86ReferenceIndirect32> { const static true_type val; };
struct X86ReferenceIndirect8 {
X86Register base;
uint8_t offset;
void rex(X86Assembler *cc, X86Register other) {
cc->rex(other.bits == 64);
}
void emit(X86Assembler *cc, X86Register reg) {
ASSERT(base.val != REG_SIB);
cc->modrm(MOD_INDIR_DISP8, reg.val, base.val);
cc->byte(offset);
}
};
template<> struct is_modrm<X86ReferenceIndirect8> { const static true_type val; };
struct X86ReferenceAbs {
uint32_t address;
void rex(X86Assembler *cc, X86Register other) {
cc->rex(other.bits == 64);
}
void emit(X86Assembler *cc, X86Register reg) {
cc->modrm(MOD_INDIR, reg.val, REG_DISP32);
cc->word(address);
}
};
template<> struct is_modrm<X86ReferenceAbs> { const static true_type val; };
struct X86ReferenceSIB {
uint32_t offset;
X86Register base, index;
uint8_t scale;
void rex(X86Assembler *cc, X86Register other) {
cc->rex(other.bits == 64);
}
void emit(X86Assembler *cc, X86Register reg) {
uint8_t sv;
switch(scale) {
#define S(n) case n: sv = SCALE_##n
S(1); S(2); S(4); S(8);
#undef S
default:
panic("Illegal scale value: %d", scale);
}
cc->modrm(MOD_INDIR_DISP32, reg.val, REG_SIB);
cc->sib(sv, index.val, base.val);
cc->word(offset);
}
};
template<> struct is_modrm<X86ReferenceSIB> { const static true_type val; };
static inline X86ReferenceIndirect X86Mem(X86Register reg) {
X86ReferenceIndirect r = {reg};
return r;
}
static inline X86ReferenceIndirect32 X86Mem(X86Register base, uint32_t off) {
X86ReferenceIndirect32 r = {base, off};
return r;
}
static inline X86ReferenceIndirect8 X86Mem(X86Register base, uint8_t off) {
X86ReferenceIndirect8 r = {base, off};
return r;
}
static inline X86ReferenceAbs X86Mem(uint32_t addr) {
X86ReferenceAbs r = {addr};
return r;
}
static inline X86ReferenceSIB X86Mem(uint32_t off, X86Register base, X86Register index, uint8_t scale) {
X86ReferenceSIB r = {off, base, index, scale};
return r;
}
template<class Inst>
inline void X86Emitter<Inst>::emit_(X86Assembler *cc, uint32_t lhs, X86Register rhs) {
emit_imm(cc, rhs, Inst::op_imm_r::val);
cc->word(lhs);
}
#define D(int_type) \
template<class Inst> \
inline void X86Emitter<Inst>::emit(X86Assembler *cc, int_type lhs, \
X86Register rhs) { \
emit_(cc, (uint32_t)lhs, rhs); \
}
FOR_EACH_INT_TYPE(D)
#undef D
template<class Inst>
inline void X86Emitter<Inst>::emit_imm(X86Assembler *cc, X86Register rhs, none) {
cc->rex(rhs.bits == 64);
cc->byte(Inst::op_imm_rm::val);
cc->modrm(MOD_REG, Inst::subop_imm_rm::val, rhs.val);
}
template<class Inst>
inline void X86Emitter<Inst>::emit_imm(X86Assembler *cc, X86Register rhs, uint8_t op_imm_r) {
cc->rex(rhs.bits == 64);
cc->byte(Inst::op_imm_r::val + rhs.val);
}
template<class Inst>
template<class Mem>
inline void X86Emitter<Inst>::emit(X86Assembler *cc, uint32_t lhs, Mem rhs) {
rhs.rex(cc, X86Register(Inst::subop_imm_rm::val));
cc->byte(Inst::op_imm_rm::val);
rhs.emit(cc, X86Register(Inst::subop_imm_rm::val));
cc->word(lhs);
}
template<class Inst>
inline void X86Emitter<Inst>::emit(X86Assembler *cc, X86Register lhs, X86Register rhs) {
emit_reg(cc, lhs, rhs, Inst::op_r_rm::val);
}
template<class Inst>
inline void X86Emitter<Inst>::emit_reg(X86Assembler *cc, X86Register lhs, X86Register rhs,
none) {
lhs.rex(cc, rhs);
cc->byte(Inst::op_rm_r::val);
lhs.emit(cc, rhs);
}
template<class Inst>
inline void X86Emitter<Inst>::emit_reg(X86Assembler *cc, X86Register lhs, X86Register rhs,
uint8_t) {
rhs.rex(cc, lhs);
cc->byte(Inst::op_r_rm::val);
rhs.emit(cc, lhs);
}
/* reg, rm */
template<class Inst>
template<class Mem>
inline void X86Emitter<Inst>::emit(X86Assembler *cc, X86Register lhs, Mem rhs) {
rhs.rex(cc, lhs);
cc->byte(Inst::op_r_rm::val);
rhs.emit(cc, lhs);
}
/* rm, reg */
template<class Inst>
template<class Mem>
inline void X86Emitter<Inst>::emit(X86Assembler *cc, Mem lhs, X86Register rhs) {
rhs.rex(cc, rhs);
cc->byte(Inst::op_rm_r::val);
lhs.emit(cc, rhs);
}
template<class Inst>
template<class Mem>
inline void X86ShiftEmitter<Inst>::emit(X86Assembler *cc, X86Register lhs, Mem rhs) {
ASSERT(lhs.val == X86ECX.val);
rhs.rex(cc, X86Register(Inst::subop_cl::val));
cc->byte(Inst::op_cl::val);
rhs.emit(cc, X86Register(Inst::subop_cl::val));
}
template<class Inst>
template<class Mem>
inline void X86ShiftEmitter<Inst>::emit(X86Assembler *cc, uint8_t lhs, Mem rhs) {
rhs.rex(cc, X86Register(Inst::subop_cl::val));
cc->byte(Inst::op_imm::val);
rhs.emit(cc, X86Register(Inst::subop_imm::val));
cc->byte(lhs);
}
template <class Mem>
inline void X86Assembler::imul(Mem lhs, X86Register rhs)
{
lhs.rex(this, rhs);
byte(0x0f); byte(0xaf);
lhs.emit(this, rhs);
}
template <class Mem>
inline void X86Assembler::imul(uint32_t lhs, Mem rhs, X86Register dst)
{
rhs.rex(this, dst);
byte(0x69);
rhs.emit(this, dst);
word(lhs);
}
template<class Mem>
void X86Assembler::idiv(Mem rhs)
{
rhs.rex(this, X86Register(0x7));
byte(0xf7);
rhs.emit(this, X86Register(0x7));
}
inline void X86Assembler::cdq()
{
byte(0x99);
}
inline void X86Assembler::call(uintptr_t addr) {
byte(0xe8);
rel32(addr);
}
template<class Mem>
inline void X86Assembler::call(Mem target) {
call(target, is_modrm<Mem>::val);
}
template<class Mem>
inline void X86Assembler::call(Mem target, true_type) {
// No REX byte, operand is always 64 bits
byte(0xff);
target.emit(this, X86Register(0x2));
}
template<class Mem>
inline void X86Assembler::call(Mem target, false_type) {
call((uintptr_t)target);
}
template<class Mem>
inline void X86Assembler::inc(Mem target) {
target.rex(this, X86Register(0x0));
byte(0xff);
target.emit(this, X86Register(0x0));
}
inline void X86Assembler::jmp(int8_t off) {
byte(0xeb);
byte(off);
}
inline void X86Assembler::jmp(X86Label8 &label) {
jmp((int8_t)0);
label.referenced(eip() - 1, -1);
}
inline void X86Assembler::jmp(uint8_t *addr) {
byte(0xe9);
rel32((uintptr_t)addr);
}
template<class Mem>
inline void X86Assembler::jmp(Mem target) {
// No REX byte
byte(0xff);
target.emit(this, X86Register(0x4));
}
inline void X86Assembler::jcc(cc_t cc, int8_t off) {
byte(0x70 | cc);
byte(off);
}
inline void X86Assembler::jcc(cc_t cc, uint8_t *addr) {
byte(0x0f);
byte(0x80 | cc);
rel32((uintptr_t)addr);
}
inline void X86Assembler::jcc(cc_t cc, X86Label8 &label) {
jcc(cc, (int8_t)0);
label.referenced(eip() - 1, -1);
}
template<class Mem>
inline void X86Assembler::setcc(cc_t cc, Mem target) {
// No REX byte, always 8 bits
byte(0x0f);
byte(0x90 | cc);
target.emit(this, X86Register(0x0));
}
inline void X86Assembler::bind(X86Label8 *label) {
label->bind(eip());
}
#endif