comparison modules/x86.tp @ 183:97f107b9e8d3

Fix a few bugs in the x86 module and add jcc, push and pop instructions
author Mike Pavone <pavone@retrodev.com>
date Sat, 24 Aug 2013 19:03:18 -0700
parents f188723c15b4
children 4293c725394c
comparison
equal deleted inserted replaced
182:ab7c142090a0 183:97f107b9e8d3
88 byte <- size: 0 88 byte <- size: 0
89 word <- size: 1 89 word <- size: 1
90 dword <- size: 2 90 dword <- size: 2
91 qword <- size: 3 91 qword <- size: 3
92 92
93 condition <- :num {
94 #{
95 cc <- { num }
96 }
97 }
98 _o <- condition: 0u8
99 _no <- condition: 1u8
100 _c <- condition: 2u8
101 _nc <- condition: 3u8
102 _z <- condition: 4u8
103 _nz <- condition: 5u8
104 _be <- condition: 6u8
105 _nbe <- condition: 7u8
106 _s <- condition: 8u8
107 _ns <- condition: 9u8
108 _p <- condition: 10u8
109 _np <- condition: 11u8
110 _l <- condition: 12u8
111 _nl <- condition: 13u8
112 _le <- condition: 14u8
113 _nle <- condition: 15u8
114
115
93 size_bit <- :opcode size { 116 size_bit <- :opcode size {
94 if: size = byte { 117 if: size = byte {
95 opcode 118 opcode
96 } else: { 119 } else: {
97 opcode or 1u8 120 opcode or 1u8
126 int_op: value size withTail: [] 149 int_op: value size withTail: []
127 } 150 }
128 //used for mov instructions that support 64-bit immediate operands/offsets 151 //used for mov instructions that support 64-bit immediate operands/offsets
129 int_op64 <- :value size { 152 int_op64 <- :value size {
130 tail <- [] 153 tail <- []
154 value <- uint64: value
131 if: size = qword { 155 if: size = qword {
132 tail <- (uint8: (rshift: value by: 32u64)) | (uint8: (rshift: value by: 40u64)) | (uint8: (rshift: value by: 48u64)) | (uint8: (rshift: value by: 56u64)) | tail 156 tail <- (uint8: (rshift: value by: 32u64)) | (uint8: (rshift: value by: 40u64)) | (uint8: (rshift: value by: 48u64)) | (uint8: (rshift: value by: 56u64)) | tail
133 } 157 }
134 int_op: value size withTail: tail 158 int_op: value size withTail: tail
135 } 159 }
212 } 236 }
213 inst: (prefix: reg rm size withInstruction: base) 237 inst: (prefix: reg rm size withInstruction: base)
214 } else: { 238 } else: {
215 op: src dst size withCode: normal withImmed: immed withOpEx: myopex 239 op: src dst size withCode: normal withImmed: immed withOpEx: myopex
216 } 240 }
241 }
242
243 _jmprel <- :op jmpDest {
217 } 244 }
218 245
219 #{ 246 #{
220 rax <- { _rax } 247 rax <- { _rax }
221 rcx <- { _rcx } 248 rcx <- { _rcx }
241 b <- { byte } 268 b <- { byte }
242 w <- { word } 269 w <- { word }
243 d <- { dword } 270 d <- { dword }
244 q <- { qword } 271 q <- { qword }
245 272
273 o <- { _o }
274 no <- { _no }
275 c <- { _c }
276 nc <- { _nc }
277 ae <- { _nc }
278 z <- { _z }
279 e <- { _z }
280 nz <- { _nz }
281 ne <- { _nz }
282 be <- { _be }
283 nbe <- { _nbe }
284 a <- { _nbe }
285 s <- { _s }
286 ns <- { _ns }
287 p <- { _p }
288 pe <- { _p }
289 np <- { _np }
290 po <- { _np }
291 l <- { _l }
292 nl <- { _nl }
293 ge <- { _nl }
294 le <- { _le }
295 nle <- { _nle }
296 g <- { _nle }
297
246 add <- :src dst size { 298 add <- :src dst size {
247 op: src dst size withCode: 0u8 withImmed: 0x80u8 withImmedRax: 0x04u8 withOpEx: 0u8 withByteExtend: 0x83u8 299 op: src dst size withCode: 0u8 withImmed: 0x80u8 withImmedRax: 0x04u8 withOpEx: 0u8 withByteExtend: 0x83u8
248 } 300 }
249 301
250 sub <- :src dst size { 302 sub <- :src dst size {
251 op: src dst size withCode: 0x28u8 withImmed: 0x80u8 withImmedRax: 0x2Cu8 withOpEx: 5u8 withByteExtend: 0x83u8 303 op: src dst size withCode: 0x28u8 withImmed: 0x80u8 withImmedRax: 0x2Cu8 withOpEx: 5u8 withByteExtend: 0x83u8
252 } 304 }
253 305
254 mov <- :src dst size { 306 mov <- :src dst size {
255 reg <- src
256 rm <- dst 307 rm <- dst
257 if: (src isInteger?) && (dst register?) { 308 if: (src isInteger?) && (dst register?) {
258 opval <- if: size = byte { 0xB0u8 } else: { 0xB8u8 } 309 opval <- if: size = byte { 0xB0u8 } else: { 0xB8u8 }
259 base <- opval | (int_op64: src size) 310 base <- opval or (dst reg) | (int_op64: src size)
260 inst: (prefix: fakesrc rm size withInstruction: base) 311 inst: (prefix: fakesrc rm size withInstruction: base)
261 } else: { 312 } else: {
262 op: src dst size withCode: 0x88u8 withImmed: 0xC6u8 withOpEx: 0u8 313 op: src dst size withCode: 0x88u8 withImmed: 0xC6u8 withOpEx: 0u8
263 } 314 }
264 } 315 }
265 316
266 ret <- { inst: [ 0xC3u8 ] } 317 ret <- { inst: [ 0xC3u8 ] }
267 318
268 label <- { 319 label <- {
269 _offset <- -1 320 _offset <- -1
270 _address <- 0u64
271 _forwardRefs <- #[] 321 _forwardRefs <- #[]
272 #{ 322 #{
273 length <- { 0 } 323 length <- { 0 }
274 hasOffset? <- { _offset >= 0 } 324 hasOffset? <- { _offset >= 0 }
275 offset <- { _offset } 325 offset <- { _offset }
276 register? <- { false } 326 register? <- { false }
277 label? <- { true } 327 label? <- { true }
278 flattenTo:at <- :dest :idx { 328 flattenTo:at <- :dest :idx {
279 if: (not: hasOffset?) { 329 if: (not: hasOffset?) {
280 _offset <- idx 330 _offset <- idx
281 _address <- dest addressAt: idx
282 foreach: _forwardRefs :idx fun { 331 foreach: _forwardRefs :idx fun {
283 fun: _offset 332 fun: _offset
284 } 333 }
285 _forwardRefs <- #[] 334 _forwardRefs <- #[]
286 } 335 }
344 } else: { 393 } else: {
345 inst: 0xFFu8 | (mod_rm: (opex: 5u8) jmpDest) 394 inst: 0xFFu8 | (mod_rm: (opex: 5u8) jmpDest)
346 } 395 }
347 } 396 }
348 397
398 jcc <- :cond jmpDest {
399 _size <- -1
400 #{
401 length <- { if: _size < 0 { 5 } else: { _size } }
402 flattenTo:at <- :dest :idx {
403 jmpDest withOffset: :off {
404 if: _size < 0 {
405 rel <- off - (idx + 2)
406 if: rel < 128 && rel >= -128 {
407 _size <- 2
408 } else: {
409 _size <- 6
410 }
411 }
412 rel <- off - (idx + _size)
413 if: _size = 2 {
414 dest set: idx 0x70u8 or (cond cc)
415 dest set: (idx + 1) (uint8: rel)
416 } else: {
417 dest set: idx 0x0Fu8
418 dest set: (idx + 1) 0x80u8 or (cond cc)
419 dest set: (idx + 2) (uint8: rel)
420 dest set: (idx + 3) (uint8: (rshift: rel by: 8))
421 dest set: (idx + 4) (uint8: (rshift: rel by: 16))
422 dest set: (idx + 5) (uint8: (rshift: rel by: 24))
423 }
424 } else: {
425 _size <- 6
426 }
427 idx + _size
428 }
429 }
430 }
431
349 call <- :callDest { 432 call <- :callDest {
350 if: (callDest label?) { 433 if: (callDest label?) {
351 #{ 434 #{
352 length <- { 5 } 435 length <- { 5 }
353 flattenTo:at <- :dest :idx { 436 flattenTo:at <- :dest :idx {
366 } else: { 449 } else: {
367 inst: 0xFFu8 | (mod_rm: (opex: 2u8) callDest) 450 inst: 0xFFu8 | (mod_rm: (opex: 2u8) callDest)
368 } 451 }
369 } 452 }
370 453
454 push <- :src {
455 if: (src isInteger?) {
456 if: src < 128 && src > -128 {
457 inst: 0x6Au8 | (uint8: src)
458 } else: {
459 inst: 0x68u8 | (uint8: src) | (uint8: (rshift: src by: 8)) | (uint8: (rshift: src by: 16)) | (uint8: (rshift: src by: 24))
460 }
461 } else: {
462 base <- if: (src register?) {
463 [0x50u8 or (src reg)]
464 } else: {
465 0xFFu8 | (mod_rm: (opex: 6u8) src)
466 }
467 inst: (prefix: fakesrc src d withInstruction: base)
468 }
469 }
470
471 pop <- :dst {
472 base <- if: (dst register?) {
473 [0x58u8 or (dst reg)]
474 } else: {
475 0x8Fu8 | (mod_rm: (opex: 0u8) dst)
476 }
477 inst: (prefix: fakesrc dst d withInstruction: base)
478 }
479
371 main <- { 480 main <- {
372 foo <- label: 481 fib <- label:
373 bar <- label: 482 notbase <- label:
374 baz <- label:
375 prog <- #[ 483 prog <- #[
376 mov: rdi rax q 484 fib
377 sub: 1 rdi q 485 sub: 2 rdi q
486 jcc: ge notbase
487 mov: 1 rax q
488 ret:
489
490 notbase
491 push: rdi
492 call: fib
493 pop: rdi
494 push: rax
495 add: 1 rdi q
496 call: fib
497 pop: rdi
378 add: rdi rax q 498 add: rdi rax q
379 jmp: bar
380 foo
381 ret:
382 bar
383 sub: 13 rax q
384 call: baz
385 jmp: foo
386 baz
387 add: 1 rax q
388 ret: 499 ret:
389 ] 500 ]
390 501
391 ba <- bytearray executableFromBytes: prog 502 ba <- bytearray executableFromBytes: prog
392 res <- ba runWithArg: 24u64 503 res <- ba runWithArg: 30u64
393 print: (string: res) . "\n" 504 print: (string: res) . "\n"
394 0 505 0
395 } 506 }
396 } 507 }
397 } 508 }