Mercurial > repos > tabletprog
view modules/x86.tp @ 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 |
line wrap: on
line source
{ regnames <- #["rax" "rcx" "rdx" "rbx" "rsp" "rbp" "rsi" "rdi" "r8" "r9" "r10" "r11" "r12" "r13" "r14" "r15"] uppernames <- #["ah" "ch" "dh" "bh"] ireg <- :regnum { #{ num <- { regnum } reg <- { regnum and 7u8} string <- { regnames get: regnum } rm <- :tail { reg or 0xC0u8 | tail } validforSize? <- :size { true } isInteger? <- { false } register? <- { true } localLabel? <- { false } upper? <- { true } needsRex? <- { regnum >= 8u8 } rexBitReg <- { if: needsRex? { 4u8 } else: { 0u8 } } rexBitRM <- { if: needsRex? { 1u8 } else: { 0u8 } } = <- :other { (not: (other isInteger?)) && (other register?) && (not: (other upper?)) && regnum = (other num) } } } upper <- :regnum { #{ num <- { regnum } reg <- { regnum } string <- { uppernames get: regnum - 4 } rm <- :tail { regnum or 0xC0u8 | tail } validforSize? <- :size { size = byte } isInteger? <- { false } register? <- { true } localLabel? <- { false } upper? <- { true } needsRex? <- { false } = <- :other { (not: (other isInteger?)) && (other register?) && (other upper?) && regnum = (other num) } } } fakesrc <- #{ needsRex? <- { false } rexBitReg <- { 0u8 } rexBitRM <- { 0u8 } } size <- :s { #{ num <- { s } = <- :other { s = (other num) } > <- :other { s > (other num) } >= <- :other { s >= (other num) } < <- :other { s < (other num) } <= <- :other { s <= (other num) } needsRex? <- { s = 3 } rexBit <- { if: needsRex? { 0x08u8 } else: { 0u8 } } } } byte <- size: 0 word <- size: 1 dword <- size: 2 qword <- size: 3 size_bit <- :opcode size { if: size = byte { opcode } else: { opcode or 1u8 } } opex <- :val { #{ reg <- { val } string <- { "opex " . val} } } mod_rm:withTail <- :register regmem :end { l <- regmem rm: end (l value) or ( lshift: (register reg) by: 3u8) | (l tail) } mod_rm <- :reg rm { mod_rm: reg rm withTail: [] } int_op:withTail <- :value size :tail { if: size >= dword { tail <- (uint8: (rshift: value by: 16u64)) | (uint8: (rshift: value by: 24u64)) | tail } if: size >= word { tail <- (uint8: (rshift: value by: 8u64)) | tail } (uint8: value) | tail } int_op <- :value size { int_op: value size withTail: [] } //used for mov instructions that support 64-bit immediate operands/offsets int_op64 <- :value size { tail <- [] 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 } int_op: value size withTail: tail } prefix:withInstruction <- :reg rm size :inst { if: size = word { inst <- 0x66u8 | inst } if: (size needsRex?) || (reg needsRex?) || (rm needsRex?) { rex <- 0x40u8 or (size rexBit) or (reg rexBitReg) or (rm rexBitRM) inst <- rex | inst } inst } _rax <- ireg: 0u8 _rcx <- ireg: 1u8 _rdx <- ireg: 2u8 _rbx <- ireg: 3u8 _rsp <- ireg: 4u8 _rbp <- ireg: 5u8 _rsi <- ireg: 6u8 _rdi <- ireg: 7u8 _r8 <- ireg: 8u8 _r9 <- ireg: 9u8 _r10 <- ireg: 10u8 _r11 <- ireg: 11u8 _r12 <- ireg: 12u8 _r13 <- ireg: 13u8 _r14 <- ireg: 14u8 _r15 <- ireg: 15u8 _ah <- upper: 4u8 _ch <- upper: 5u8 _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 base <- if: (src isInteger?) { reg <- fakesrc (size_bit: immed size) | (mod_rm: (opex: myopex) dst withTail: (int_op: src size)) } else: { if: (src register?) { (size_bit: normal size) | (mod_rm: src dst) } else: { reg <- dst rm <- src (size_bit: normal or 0x02u8 size) | (mod_rm: dst src) } } inst: (prefix: reg rm size withInstruction: base) } op:withCode:withImmed:withImmedRax:withOpEx:withByteExtend <- :src dst size :normal :immed :immedRax :myopex :byteExt { reg <- src rm <- dst if: (src isInteger?) { reg <- fakesrc base <- if: size > byte && (((src signed?) && src < 128 && src >= -128) || ((not: (src signed?)) && src < 256)) { byteExt | (mod_rm: (opex: myopex) dst withTail: [(uint8: src)]) } else: { if: dst = _rax { (size_bit: immedRax size) | (int_op: src size) } else: { (size_bit: immed size) | (mod_rm: (opex: myopex) dst withTail: (int_op: src size)) } } inst: (prefix: reg rm size withInstruction: base) } else: { op: src dst size withCode: normal withImmed: immed withOpEx: myopex } } #{ rax <- { _rax } rcx <- { _rcx } rdx <- { _rdx } rbx <- { _rbx } rsp <- { _rsp } rbp <- { _rbp } rsi <- { _rsi } rdi <- { _rdi } r8 <- { _r8 } r9 <- { _r9 } r10 <- { _r10 } r11 <- { _r11 } r12 <- { _r12 } r13 <- { _r13 } r14 <- { _r14 } r15 <- { _r15 } ah <- { _ah } ch <- { _ch } dh <- { _dh } bh <- { _bh } b <- { byte } w <- { word } d <- { dword } q <- { qword } add <- :src dst size { op: src dst size withCode: 0u8 withImmed: 0x80u8 withImmedRax: 0x04u8 withOpEx: 0u8 withByteExtend: 0x83u8 } sub <- :src dst size { op: src dst size withCode: 0x28u8 withImmed: 0x80u8 withImmedRax: 0x2Cu8 withOpEx: 5u8 withByteExtend: 0x83u8 } 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) inst: (prefix: fakesrc rm size withInstruction: base) } else: { op: src dst size withCode: 0x88u8 withImmed: 0xC6u8 withOpEx: 0u8 } } 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 <- { 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" 0 } } }