changeset 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 ab7c142090a0
children ca249978ae96
files modules/x86.tp
diffstat 1 files changed, 130 insertions(+), 19 deletions(-) [+]
line wrap: on
line diff
--- a/modules/x86.tp	Sat Aug 24 19:02:59 2013 -0700
+++ b/modules/x86.tp	Sat Aug 24 19:03:18 2013 -0700
@@ -90,6 +90,29 @@
 	dword <- size: 2
 	qword <- size: 3
 
+	condition <- :num {
+		#{
+			cc <- { num }
+		}
+	}
+	_o <- condition: 0u8
+	_no <- condition: 1u8
+	_c <- condition: 2u8
+	_nc <- condition: 3u8
+	_z <- condition: 4u8
+	_nz <- condition: 5u8
+	_be <- condition: 6u8
+	_nbe <- condition: 7u8
+	_s <- condition: 8u8
+	_ns <- condition: 9u8
+	_p <- condition: 10u8
+	_np <- condition: 11u8
+	_l <- condition: 12u8
+	_nl <- condition: 13u8
+	_le <- condition: 14u8
+	_nle <- condition: 15u8
+
+
 	size_bit <- :opcode size {
 		if: size = byte {
 			opcode
@@ -128,6 +151,7 @@
 	//used for mov instructions that support 64-bit immediate operands/offsets
 	int_op64 <- :value size {
 		tail <- []
+		value <- uint64: value
 		if: size = qword {
 			tail <- (uint8: (rshift: value by: 32u64)) | (uint8: (rshift: value by: 40u64)) | (uint8: (rshift: value by: 48u64)) | (uint8: (rshift: value by: 56u64)) | tail
 		}
@@ -216,6 +240,9 @@
 		}
 	}
 
+	_jmprel <- :op jmpDest {
+	}
+
 	#{
 		rax <- { _rax }
 		rcx <- { _rcx }
@@ -243,6 +270,31 @@
 		d <- { dword }
 		q <- { qword }
 
+		o <- { _o }
+		no <- { _no }
+		c <- { _c }
+		nc <- { _nc }
+		ae <- { _nc }
+		z <- { _z }
+		e <- { _z }
+		nz <- { _nz }
+		ne <- { _nz }
+		be <- { _be }
+		nbe <- { _nbe }
+		a <- { _nbe }
+		s <- { _s }
+		ns <- { _ns }
+		p <- { _p }
+		pe <- { _p }
+		np <- { _np }
+		po <- { _np }
+		l <- { _l }
+		nl <- { _nl }
+		ge <- { _nl }
+		le <- { _le }
+		nle <- { _nle }
+		g <- { _nle }
+
 		add <- :src dst size {
 			op: src dst size withCode: 0u8 withImmed: 0x80u8 withImmedRax: 0x04u8 withOpEx: 0u8 withByteExtend: 0x83u8
 		}
@@ -252,11 +304,10 @@
 		}
 
 		mov <- :src dst size {
-			reg <- src
 			rm <- dst
 			if: (src isInteger?) && (dst register?) {
 				opval <- if: size = byte { 0xB0u8 } else: { 0xB8u8 }
-				base <- opval | (int_op64: src size)
+				base <- opval or (dst reg) | (int_op64: src size)
 				inst: (prefix: fakesrc rm size withInstruction: base)
 			} else: {
 				op: src dst size withCode: 0x88u8 withImmed: 0xC6u8 withOpEx: 0u8
@@ -267,7 +318,6 @@
 
 		label <- {
 			_offset <- -1
-			_address <- 0u64
 			_forwardRefs <- #[]
 			#{
 				length <- { 0 }
@@ -278,7 +328,6 @@
 				flattenTo:at <- :dest :idx {
 					if: (not: hasOffset?) {
 						_offset <- idx
-						_address <- dest addressAt: idx
 						foreach: _forwardRefs :idx fun {
 							fun: _offset
 						}
@@ -346,6 +395,40 @@
 			}
 		}
 
+		jcc <- :cond jmpDest {
+			_size <- -1
+			#{
+				length <- { if: _size < 0 { 5 } else: { _size } }
+				flattenTo:at <- :dest :idx {
+					jmpDest withOffset: :off {
+						if: _size < 0 {
+							rel <- off - (idx + 2)
+							if: rel < 128 && rel >= -128 {
+								_size <- 2
+							} else: {
+								_size <- 6
+							}
+						}
+						rel <- off - (idx + _size)
+						if: _size = 2 {
+							dest set: idx 0x70u8 or (cond cc)
+							dest set: (idx + 1) (uint8: rel)
+						} else: {
+							dest set: idx 0x0Fu8
+							dest set: (idx + 1) 0x80u8 or (cond cc)
+							dest set: (idx + 2) (uint8: rel)
+							dest set: (idx + 3) (uint8: (rshift: rel by: 8))
+							dest set: (idx + 4) (uint8: (rshift: rel by: 16))
+							dest set: (idx + 5) (uint8: (rshift: rel by: 24))
+						}
+					} else: {
+						_size <- 6
+					}
+					idx + _size
+				}
+			}
+		}
+
 		call <- :callDest {
 			if: (callDest label?) {
 				#{
@@ -368,28 +451,56 @@
 			}
 		}
 
+		push <- :src {
+			if: (src isInteger?) {
+				if: src < 128 && src > -128 {
+					inst: 0x6Au8 | (uint8: src)
+				} else: {
+					inst: 0x68u8 | (uint8: src) | (uint8: (rshift: src by: 8)) | (uint8: (rshift: src by: 16)) | (uint8: (rshift: src by: 24))
+				}
+			} else: {
+				base <- if: (src register?) {
+					[0x50u8 or (src reg)]
+				} else: {
+					0xFFu8 | (mod_rm: (opex: 6u8) src)
+				}
+				inst: (prefix: fakesrc src d withInstruction: base)
+			}
+		}
+
+		pop <- :dst {
+			base <- if: (dst register?) {
+				[0x58u8 or (dst reg)]
+			} else: {
+				0x8Fu8 | (mod_rm: (opex: 0u8) dst)
+			}
+			inst: (prefix: fakesrc dst d withInstruction: base)
+		}
+
 		main <- {
-			foo <- label:
-			bar <- label:
-			baz <- label:
+			fib <- label:
+			notbase <- label:
 			prog <- #[
-				mov: rdi rax q
-				sub: 1 rdi q
+				fib
+				sub: 2 rdi q
+				jcc: ge notbase
+				mov: 1 rax q
+				ret:
+
+				notbase
+				push: rdi
+				call: fib
+				pop: rdi
+				push: rax
+				add: 1 rdi q
+				call: fib
+				pop: rdi
 				add: rdi rax q
-				jmp: bar
-				foo
-				ret:
-				bar
-				sub: 13 rax q
-				call: baz
-				jmp: foo
-				baz
-				add: 1 rax q
 				ret:
 			]
 
 			ba <- bytearray executableFromBytes: prog
-			res <- ba runWithArg: 24u64
+			res <- ba runWithArg: 30u64
 			print: (string: res) . "\n"
 			0
 		}