1 package x86_64
2
3 import (
4 "fmt"
5 "math"
6 "math/bits"
7
8 "github.com/chenzhuoyu/iasm/expr"
9 )
10
11 type (
12 _PseudoType int
13 _InstructionEncoder func(*Program, ...interface{}) *Instruction
14 )
15
16 const (
17 _PseudoNop _PseudoType = iota + 1
18 _PseudoByte
19 _PseudoWord
20 _PseudoLong
21 _PseudoQuad
22 _PseudoData
23 _PseudoAlign
24 )
25
26 func (self _PseudoType) String() string {
27 switch self {
28 case _PseudoNop:
29 return ".nop"
30 case _PseudoByte:
31 return ".byte"
32 case _PseudoWord:
33 return ".word"
34 case _PseudoLong:
35 return ".long"
36 case _PseudoQuad:
37 return ".quad"
38 case _PseudoData:
39 return ".data"
40 case _PseudoAlign:
41 return ".align"
42 default:
43 panic("unreachable")
44 }
45 }
46
47 type _Pseudo struct {
48 kind _PseudoType
49 data []byte
50 uint uint64
51 expr *expr.Expr
52 }
53
54 func (self *_Pseudo) free() {
55 if self.expr != nil {
56 self.expr.Free()
57 }
58 }
59
60 func (self *_Pseudo) encode(m *[]byte, pc uintptr) int {
61 switch self.kind {
62 case _PseudoNop:
63 return 0
64 case _PseudoByte:
65 self.encodeByte(m)
66 return 1
67 case _PseudoWord:
68 self.encodeWord(m)
69 return 2
70 case _PseudoLong:
71 self.encodeLong(m)
72 return 4
73 case _PseudoQuad:
74 self.encodeQuad(m)
75 return 8
76 case _PseudoData:
77 self.encodeData(m)
78 return len(self.data)
79 case _PseudoAlign:
80 self.encodeAlign(m, pc)
81 return self.alignSize(pc)
82 default:
83 panic("invalid pseudo instruction")
84 }
85 }
86
87 func (self *_Pseudo) evalExpr(low int64, high int64) int64 {
88 if v, err := self.expr.Evaluate(); err != nil {
89 panic(err)
90 } else if v < low || v > high {
91 panic(fmt.Sprintf("expression out of range [%d, %d]: %d", low, high, v))
92 } else {
93 return v
94 }
95 }
96
97 func (self *_Pseudo) alignSize(pc uintptr) int {
98 if !ispow2(self.uint) {
99 panic(fmt.Sprintf("aligment should be a power of 2, not %d", self.uint))
100 } else {
101 return align(int(pc), bits.TrailingZeros64(self.uint)) - int(pc)
102 }
103 }
104
105 func (self *_Pseudo) encodeData(m *[]byte) {
106 if m != nil {
107 *m = append(*m, self.data...)
108 }
109 }
110
111 func (self *_Pseudo) encodeByte(m *[]byte) {
112 if m != nil {
113 append8(m, byte(self.evalExpr(math.MinInt8, math.MaxUint8)))
114 }
115 }
116
117 func (self *_Pseudo) encodeWord(m *[]byte) {
118 if m != nil {
119 append16(m, uint16(self.evalExpr(math.MinInt16, math.MaxUint16)))
120 }
121 }
122
123 func (self *_Pseudo) encodeLong(m *[]byte) {
124 if m != nil {
125 append32(m, uint32(self.evalExpr(math.MinInt32, math.MaxUint32)))
126 }
127 }
128
129 func (self *_Pseudo) encodeQuad(m *[]byte) {
130 if m != nil {
131 if v, err := self.expr.Evaluate(); err != nil {
132 panic(err)
133 } else {
134 append64(m, uint64(v))
135 }
136 }
137 }
138
139 func (self *_Pseudo) encodeAlign(m *[]byte, pc uintptr) {
140 if m != nil {
141 if self.expr == nil {
142 expandmm(m, self.alignSize(pc), 0)
143 } else {
144 expandmm(m, self.alignSize(pc), byte(self.evalExpr(math.MinInt8, math.MaxUint8)))
145 }
146 }
147 }
148
149
150 type Operands [_N_args]interface{}
151
152
153 type InstructionDomain uint8
154
155 const (
156 DomainGeneric InstructionDomain = iota
157 DomainMMXSSE
158 DomainAVX
159 DomainFMA
160 DomainCrypto
161 DomainMask
162 DomainAMDSpecific
163 DomainMisc
164 DomainPseudo
165 )
166
167 type (
168 _BranchType uint8
169 )
170
171 const (
172 _B_none _BranchType = iota
173 _B_conditional
174 _B_unconditional
175 )
176
177
178 type Instruction struct {
179 next *Instruction
180 pc uintptr
181 nb int
182 len int
183 argc int
184 name string
185 argv Operands
186 forms [_N_forms]_Encoding
187 pseudo _Pseudo
188 branch _BranchType
189 domain InstructionDomain
190 prefix []byte
191 }
192
193 func (self *Instruction) add(flags int, encoder func(m *_Encoding, v []interface{})) {
194 self.forms[self.len].flags = flags
195 self.forms[self.len].encoder = encoder
196 self.len++
197 }
198
199 func (self *Instruction) free() {
200 self.clear()
201 self.pseudo.free()
202
203 }
204
205 func (self *Instruction) clear() {
206 for i := 0; i < self.argc; i++ {
207 if v, ok := self.argv[i].(Disposable); ok {
208 v.Free()
209 }
210 }
211 }
212
213 func (self *Instruction) check(e *_Encoding) bool {
214 if (e.flags & _F_rel1) != 0 {
215 return isRel8(self.argv[0])
216 } else if (e.flags & _F_rel4) != 0 {
217 return isRel32(self.argv[0]) || isLabel(self.argv[0])
218 } else {
219 return true
220 }
221 }
222
223 func (self *Instruction) encode(m *[]byte) int {
224 n := math.MaxInt64
225 p := (*_Encoding)(nil)
226
227
228 if self.nb = len(self.prefix); m != nil {
229 *m = append(*m, self.prefix...)
230 }
231
232
233 if self.pseudo.kind != 0 {
234 self.nb += self.pseudo.encode(m, self.pc)
235 return self.nb
236 }
237
238
239 for i := 0; i < self.len; i++ {
240 if e := &self.forms[i]; self.check(e) {
241 if v := e.encode(self.argv[:self.argc]); v < n {
242 n = v
243 p = e
244 }
245 }
246 }
247
248
249 if m != nil {
250 *m = append(*m, p.bytes[:n]...)
251 }
252
253
254 self.nb += n
255 return self.nb
256 }
257
258
259
260 const (
261 _P_cs = 0x2e
262 _P_ds = 0x3e
263 _P_es = 0x26
264 _P_fs = 0x64
265 _P_gs = 0x65
266 _P_ss = 0x36
267 _P_lock = 0xf0
268 )
269
270
271 func (self *Instruction) CS() *Instruction {
272 self.prefix = append(self.prefix, _P_cs)
273 return self
274 }
275
276
277
278 func (self *Instruction) DS() *Instruction {
279 self.prefix = append(self.prefix, _P_ds)
280 return self
281 }
282
283
284 func (self *Instruction) ES() *Instruction {
285 self.prefix = append(self.prefix, _P_es)
286 return self
287 }
288
289
290 func (self *Instruction) FS() *Instruction {
291 self.prefix = append(self.prefix, _P_fs)
292 return self
293 }
294
295
296 func (self *Instruction) GS() *Instruction {
297 self.prefix = append(self.prefix, _P_gs)
298 return self
299 }
300
301
302 func (self *Instruction) SS() *Instruction {
303 self.prefix = append(self.prefix, _P_ss)
304 return self
305 }
306
307
308
309
310
311 func (self *Instruction) LOCK() *Instruction {
312 self.prefix = append(self.prefix, _P_lock)
313 return self
314 }
315
316
317
318
319 func (self *Instruction) Name() string {
320 return self.name
321 }
322
323
324 func (self *Instruction) Domain() InstructionDomain {
325 return self.domain
326 }
327
328
329 func (self *Instruction) Operands() []interface{} {
330 return self.argv[:self.argc]
331 }
332
333
334 type Program struct {
335 arch *Arch
336 head *Instruction
337 tail *Instruction
338 }
339
340 const (
341 _N_near = 2
342 _N_far_cond = 6
343 _N_far_uncond = 5
344 )
345
346 func (self *Program) clear() {
347 for p, q := self.head, self.head; p != nil; p = q {
348 q = p.next
349 p.free()
350 }
351 }
352
353 func (self *Program) alloc(name string, argc int, argv Operands) *Instruction {
354 p := self.tail
355 q := newInstruction(name, argc, argv)
356
357
358 if p != nil {
359 p.next = q
360 } else {
361 self.head = q
362 }
363
364
365 self.tail = q
366 return q
367 }
368
369 func (self *Program) pseudo(kind _PseudoType) (p *Instruction) {
370 p = self.alloc(kind.String(), 0, Operands{})
371 p.domain = DomainPseudo
372 p.pseudo.kind = kind
373 return
374 }
375
376 func (self *Program) require(isa ISA) {
377 if !self.arch.HasISA(isa) {
378 panic("ISA '" + isa.String() + "' was not enabled")
379 }
380 }
381
382 func (self *Program) branchSize(p *Instruction) int {
383 switch p.branch {
384 case _B_none:
385 panic("p is not a branch")
386 case _B_conditional:
387 return _N_far_cond
388 case _B_unconditional:
389 return _N_far_uncond
390 default:
391 panic("invalid instruction")
392 }
393 }
394
395
396
397
398 func (self *Program) Byte(v *expr.Expr) (p *Instruction) {
399 p = self.pseudo(_PseudoByte)
400 p.pseudo.expr = v
401 return
402 }
403
404
405 func (self *Program) Word(v *expr.Expr) (p *Instruction) {
406 p = self.pseudo(_PseudoWord)
407 p.pseudo.expr = v
408 return
409 }
410
411
412 func (self *Program) Long(v *expr.Expr) (p *Instruction) {
413 p = self.pseudo(_PseudoLong)
414 p.pseudo.expr = v
415 return
416 }
417
418
419 func (self *Program) Quad(v *expr.Expr) (p *Instruction) {
420 p = self.pseudo(_PseudoQuad)
421 p.pseudo.expr = v
422 return
423 }
424
425
426 func (self *Program) Data(v []byte) (p *Instruction) {
427 p = self.pseudo(_PseudoData)
428 p.pseudo.data = v
429 return
430 }
431
432
433 func (self *Program) Align(align uint64, padding *expr.Expr) (p *Instruction) {
434 p = self.pseudo(_PseudoAlign)
435 p.pseudo.uint = align
436 p.pseudo.expr = padding
437 return
438 }
439
440
441
442
443
444
445
446
447
448 func (self *Program) Free() {
449 self.clear()
450
451 }
452
453
454 func (self *Program) Link(p *Label) {
455 if p.Dest != nil {
456 panic("lable was alreay linked")
457 } else {
458 p.Dest = self.pseudo(_PseudoNop)
459 }
460 }
461
462
463 func (self *Program) Assemble(pc uintptr) (ret []byte) {
464 orig := pc
465 next := true
466 offs := uintptr(0)
467
468
469 for p := self.head; p != nil; p = p.next {
470 if p.pc = pc; !isLabel(p.argv[0]) || p.branch == _B_none {
471 pc += uintptr(p.encode(nil))
472 } else {
473 pc += uintptr(self.branchSize(p))
474 }
475 }
476
477
478 nb := int(pc - orig)
479 ret = make([]byte, 0, nb)
480
481
482 for next {
483 next = false
484 offs = uintptr(0)
485
486
487 for p := self.head; p != nil; p = p.next {
488 var ok bool
489 var lb *Label
490
491
492 if nb = p.nb; p.pseudo.kind == _PseudoAlign {
493 p.pc -= offs
494 offs += uintptr(nb - p.encode(nil))
495 continue
496 }
497
498
499 p.pc -= offs
500 lb, ok = p.argv[0].(*Label)
501
502
503 if !ok || p.nb == _N_near || p.branch == _B_none {
504 continue
505 }
506
507
508 size := self.branchSize(p)
509 diff := lb.offset(p.pc, size)
510
511
512 if diff > 127 || diff < -128 {
513 p.nb = size
514 continue
515 }
516
517
519 next = true
520 p.nb = _N_near
521 offs += uintptr(size - _N_near)
522 }
523 }
524
525
526 for p := self.head; p != nil; p = p.next {
527 for i := 0; i < p.argc; i++ {
528 var ok bool
529 var lb *Label
530 var op *MemoryOperand
531
532
533 if lb, ok = p.argv[i].(*Label); ok {
534 p.argv[i] = lb.offset(p.pc, p.nb)
535 continue
536 }
537
538
539 if op, ok = p.argv[i].(*MemoryOperand); !ok {
540 continue
541 }
542
543
544 if op.Addr.Type != Reference {
545 continue
546 }
547
548
549 op.Addr.Type = Offset
550 op.Addr.Offset = op.Addr.Reference.offset(p.pc, p.nb)
551 }
552 }
553
554
555 for p := self.head; p != nil; p = p.next {
556 p.encode(&ret)
557 }
558
559
560 return ret
561 }
562
563
564 func (self *Program) AssembleAndFree(pc uintptr) (ret []byte) {
565 ret = self.Assemble(pc)
566 self.Free()
567 return
568 }
569
View as plain text