changeset 180:270d31c6c4cd

Add support for jmps and labels in x86 module
author Mike Pavone <pavone@retrodev.com>
date Sat, 24 Aug 2013 15:08:00 -0700
parents 75aca5f87969
children f188723c15b4
files modules/bytearray.tp modules/x86.tp
diffstat 2 files changed, 106 insertions(+), 19 deletions(-) [+]
line wrap: on
line diff
--- a/modules/bytearray.tp	Sat Aug 24 09:56:29 2013 -0700
+++ b/modules/bytearray.tp	Sat Aug 24 15:08:00 2013 -0700
@@ -59,10 +59,7 @@
 		}
 		ba <- executable: totalSize
 		bytes fold: 0 with: :idx el {
-			el fold: idx with: :idx byte {
-				ba set: idx byte
-				idx + 1
-			}
+			el flattenTo: ba at: idx
 		}
 		ba
 	}
--- a/modules/x86.tp	Sat Aug 24 09:56:29 2013 -0700
+++ b/modules/x86.tp	Sat Aug 24 15:08:00 2013 -0700
@@ -10,6 +10,7 @@
 			validforSize? <- :size { true }
 			isInteger? <- { false }
 			register? <- { true }
+			localLabel? <- { false }
 			upper? <- { true }
 			needsRex? <- { regnum >= 8u8 }
 			rexBitReg <- {
@@ -43,6 +44,7 @@
 			}
 			isInteger? <- { false }
 			register? <- { true }
+			localLabel? <- { false }
 			upper? <- { true }
 			needsRex? <- { false }
 			= <- :other {
@@ -164,6 +166,18 @@
 	_dh <- upper: 6u8
 	_bh <- upper: 7u8
 
+	inst <- :ilist {
+		#{
+			length <- { ilist length }
+			flattenTo:at <- :dest :idx {
+				ilist fold: idx with: :idx byte {
+					dest set: idx byte
+					idx + 1
+				}
+			}
+		}
+	}
+
 	op:withCode:withImmed:withOpEx <- :src dst size :normal :immed :myopex {
 		reg <- src
 		rm <- dst
@@ -179,7 +193,7 @@
 				(size_bit: normal or 0x02u8 size) | (mod_rm: dst src)
 			}
 		}
-		prefix: reg rm size withInstruction: base
+		inst: (prefix: reg rm size withInstruction: base)
 	}
 
 	op:withCode:withImmed:withImmedRax:withOpEx:withByteExtend <- :src dst size :normal :immed :immedRax :myopex :byteExt {
@@ -196,11 +210,10 @@
 					(size_bit: immed size) | (mod_rm: (opex: myopex) dst withTail: (int_op: src size))
 				}
 			}
-			prefix: reg rm size withInstruction: base
+			inst: (prefix: reg rm size withInstruction: base)
 		} else: {
 			op: src dst size withCode: normal withImmed: immed withOpEx: myopex
 		}
-
 	}
 
 	#{
@@ -244,32 +257,109 @@
 			if: (src isInteger?) && (dst register?) {
 				opval <- if: size = byte { 0xB0u8 } else: { 0xB8u8 }
 				base <- opval | (int_op64: src size)
-				prefix: fakesrc rm size withInstruction: base
+				inst: (prefix: fakesrc rm size withInstruction: base)
 			} else: {
 				op: src dst size withCode: 0x88u8 withImmed: 0xC6u8 withOpEx: 0u8
 			}
 		}
 
-		ret <- { [ 0xC3u8 ] }
+		ret <- { inst: [ 0xC3u8 ] }
+
+		label <- {
+			_offset <- -1
+			_forwardRefs <- #[]
+			#{
+				length <- { 0 }
+				hasOffset? <- { _offset >= 0 }
+				offset <- { _offset }
+				register? <- { false }
+				localLabel? <- { true }
+				flattenTo:at <- :dest :idx {
+					if: (not: hasOffset?) {
+						_offset <- idx
+						foreach: _forwardRefs :idx fun {
+							fun: _offset
+						}
+						_forwardRefs <- #[]
+					}
+					idx
+				}
+				withOffset:else <- :fun :elsefun {
+					if: hasOffset? {
+						fun: _offset
+					} else: {
+						_forwardRefs append: fun
+						elsefun:
+					}
+				}
+			}
+		}
+
+		jmp <- :jmpDest {
+			if: (jmpDest localLabel?) {
+				_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: {
+									rel <- rel - 2
+									if: rel < 32768 && rel >= -32768 {
+										_size <- 4
+									} else: {
+										_size <- 5
+									}
+								}
+							}
+							rel <- off - (idx + _size)
+							if: _size = 2 {
+								dest set: idx 0xEBu8
+								dest set: (idx + 1) (uint8: rel)
+							} else: {
+								if: _size = 4 {
+									dest set: idx 0x66u8
+									dest set: (idx + 1) 0xE9u8
+									dest set: (idx + 2) (uint8: rel)
+									dest set: (idx + 3) (uint8: (rshift: rel by: 8))
+								} else: {
+									dest set: idx 0xE9u8
+									dest set: (idx + 1) (uint8: rel)
+									dest set: (idx + 2) (uint8: (rshift: rel by: 8))
+									dest set: (idx + 3) (uint8: (rshift: rel by: 16))
+									dest set: (idx + 4) (uint8: (rshift: rel by: 24))
+								}
+							}
+						} else: {
+							_size <- 5
+						}
+						idx + _size
+					}
+				}
+			} else: {
+				inst: 0xFFu8 | (mod_rm: (opex: 5u8) jmpDest)
+			}
+		}
 
 
 		main <- {
-			print: ((add: rax r8 b) map: :el { hex: el })
-			print: "\n"
-			print: ((add: r9 rdx w) map: :el { hex: el })
-			print: "\n"
-			print: ((add: rax rbx q) map: :el { hex: el })
-			print: "\n"
-			print: ((add: 25 rax q) map: :el { hex: el })
-			print: "\n"
-			print: ((add: rcx rdx d) map: :el { hex: el })
-			print: "\n"
+			foo <- label:
+			bar <- label:
 			prog <- #[
 				mov: rdi rax q
 				sub: 1 rdi q
 				add: rdi rax q
+				jmp: bar
+				foo
 				ret:
+				bar
+				sub: 13 rax q
+				jmp: foo
 			]
+
 			ba <- bytearray executableFromBytes: prog
 			res <- ba runWithArg: 24u64
 			print: (string: res) . "\n"