apple-0.3.0.0: src/Asm/X86/Byte.hs
-- https://defuse.ca/online-x86-assembler.htm
-- https://disasm.pro/
--
-- https://wiki.osdev.org/X86-64_Instruction_Encoding
{-# LANGUAGE TupleSections #-}
module Asm.X86.Byte ( allFp, assemble, assembleCtx, dbgFp ) where
import Asm.M
import Asm.X86
import Data.Bifunctor (second)
import Data.Bits (Bits, rotateR, shiftL, (.&.), (.|.))
import qualified Data.ByteString as BS
import Data.Functor (($>))
import Data.Int (Int32, Int64, Int8)
import qualified Data.IntMap as IM
import qualified Data.Map.Strict as M
import Data.Word
import Foreign.Ptr (FunPtr, IntPtr (..), Ptr, ptrToIntPtr)
import Foreign.Storable (Storable, sizeOf)
import Hs.FFI
import Sys.DL
pI :: Ptr a -> Int
pI = (\(IntPtr i) -> i) . ptrToIntPtr
prepAddrs :: [X86 reg freg f2reg a] -> IO (Maybe CCtx)
prepAddrs ss = if hasMa ss then Just <$> mem' else pure Nothing
dbgFp asmϵ = do
(bs, _, ps) <- allFp asmϵ
mFree ps $> bs
assembleCtx :: CCtx -> (IM.IntMap [Word64], [X86 X86Reg FX86Reg F2X86 a]) -> IO (BS.ByteString, FunPtr b, Maybe (Ptr Word64))
assembleCtx ctx (ds, isns) = do
let (sz, lbls) = mkIx 0 isns
p <- if hasMa isns then allocNear (fst4 ctx) (fromIntegral sz) else allocExec (fromIntegral sz)
arrs <- aArr ds
let b = BS.pack.concat$asm 0 (pI p, arrs, Just ctx, lbls) isns
mP = snd<$>IM.lookupMin arrs
(b,,mP)<$>finish b p
allFp :: (IM.IntMap [Word64], [X86 X86Reg FX86Reg F2X86 a]) -> IO ([BS.ByteString], FunPtr b, Maybe (Ptr Word64))
allFp (ds, instrs) = do
let (sz, lbls) = mkIx 0 instrs
(fn, p) <- do
res <- prepAddrs instrs
case res of
Just (m, _, _, _) -> (res,) <$> allocNear m (fromIntegral sz)
_ -> (res,) <$> allocExec (fromIntegral sz)
arrs <- aArr ds
let is = asm 0 (pI p, arrs, fn, lbls) instrs; b = BS.pack.concat$is; bs = BS.pack<$>is
mP = snd<$>IM.lookupMin arrs
(bs,,mP)<$>finish b p
assemble :: (IM.IntMap [Word64], [X86 X86Reg FX86Reg F2X86 a]) -> BS.ByteString
assemble (_, instrs) =
let (_, lbls) = mkIx 0 instrs in
BS.pack.concat$asm 0 (error "Internal error: no self", error "Arrays not allowed :(", Nothing, lbls) instrs
data VEXM = F | F38 | F3A
data PP = S6 | F3 | F2
rrNoPre :: RMB reg
=> [Word8]
-> reg -- ^ r/m
-> reg -- ^ reg
-> [Word8]
rrNoPre opc r0 r1 =
let (_, b0) = modRM r0
(_, b1) = modRM r1
modRMB = (0x3 `shiftL` 6) .|. (b1 `shiftL` 3) .|. b0
in opc++[modRMB]
mkRR opc = mkAR opc 3
mkAR :: (RMB reg0, RMB reg1)
=> [Word8]
-> Word8 -- ^ mod
-> reg0 -- ^ r/m
-> reg1 -- ^ reg
-> [Word8]
mkAR opc m r0 r1 =
let (e0, b0) = modRM r0
(e1, b1) = modRM r1
prefix = 0x48 .|. (e1 `shiftL` 2) .|. e0
modRMB = (m `shiftL` 6) .|. (b1 `shiftL` 3) .|. b0
in prefix:opc++[modRMB]
-- movapd xmm9, xmm5 -> 66 44 0f 28 cd
-- movapd xmm1, xmm5 -> 66 0f 28 cd
--
-- addsd xmm8,xmm10 -> f2 45 0f 58 c2
extSse :: Word8 -> Word8 -> FX86Reg -> FX86Reg -> [Word8]
extSse pre opc r0 r1 =
let (e0, b0) = modRM r0
(e1, b1) = modRM r1
b = 0x40 .|. (e1 `shiftL` 2) .|. e0
modRMB = (0x3 `shiftL` 6) .|. (b1 `shiftL` 3) .|. b0
in [pre,b,0xf,opc,modRMB]
vexV4 :: FX86Reg -> Word8
vexV4 XMM0 = 0xf
vexV4 XMM1 = 0xe
vexV4 XMM2 = 0xd
vexV4 XMM3 = 0xc
vexV4 XMM4 = 0xb
vexV4 XMM5 = 0xa
vexV4 XMM6 = 0x9
vexV4 XMM7 = 0x8
vexV4 XMM8 = 0x7
vexV4 XMM9 = 0x6
vexV4 XMM10 = 0x5
vexV4 XMM11 = 0x4
vexV4 XMM12 = 0x3
vexV4 XMM13 = 0x2
vexV4 XMM14 = 0x1
vexV4 XMM15 = 0x0
bitC :: Word8 -> Word8
bitC 0x0 = 0x1
bitC 0x1 = 0x0
bitsm :: VEXM -> Word8
bitsm F = 0x1
bitsm F38 = 0x2
bitsm F3A = 0x3
ppbits :: PP -> Word8
ppbits S6 = 0x1
ppbits F3 = 0x2
ppbits F2 = 0x3
mkVex :: Word8 -> PP -> FX86Reg -> FX86Reg -> FX86Reg -> [Word8]
mkVex opc pp r0 r1 r2 =
[0xc5,b,opc,modRMB]
where b = (bitC e0 `shiftL` 7) .|. (vexV4 r1 `shiftL` 3) .|. ppbits pp
(e0, b0) = modRM r0
(_, b2) = modRM r2
modRMB = (0x3 `shiftL` 6) .|. b0 `shiftL` 3 .|. b2
mkVex3 :: Word8 -> PP -> VEXM -> FX86Reg -> FX86Reg -> FX86Reg -> [Word8]
mkVex3 opc pp mm r0 r1 r2 =
[0xc4,by0,by1,opc,modRMB]
where by0 = (bitC e0 `shiftL` 7) .|. (0x1 `shiftL` 6) .|. (bitC e2 `shiftL` 5) .|. bitsm mm
by1 = 1 `shiftL` 7 .|. (vexV4 r1 `shiftL` 3) .|. ppbits pp
(e0, b0) = modRM r0
(e2, b2) = modRM r2
modRMB = (0x3 `shiftL` 6) .|. b0 `shiftL` 3 .|. b2
mkVexA :: Word8 -> PP -> VEXM -> FX86Reg -> FX86Reg -> Addr X86Reg -> [Word8]
mkVexA opc pp mm xr0 xr1 (RSD b s i d)=
[0xc4,by0,by1,opc,modRMB,sib]++le d
where by0 = (bitC e0 `shiftL` 7) .|. (bitC ei `shiftL` 6) .|. (bitC eb `shiftL` 5) .|. bitsm mm
by1 = 1 `shiftL` 7 .|. vexV4 xr1 `shiftL` 3 .|. ppbits pp
(e0, b0) = modRM xr0
(eb, bb) = modRM b
(ei, bi) = modRM i
modRMB = 0x1 `shiftL` 6 .|. b0 `shiftL` 3 .|. 0x4
sib = encS s `shiftL` 6 .|. bi `shiftL` 3 .|. bb
mkVexA opc pp mm xr0 xr1 (RC b@Rsp i) =
[0xc4,by0,by1,opc,modRMB,sib]++le i
where by0 = bitC e0 `shiftL` 7 .|. bitC eb `shiftL` 6 .|. bitC eb `shiftL` 5 .|. bitsm mm
by1 = 1 `shiftL` 7 .|. vexV4 xr1 `shiftL` 3 .|. ppbits pp
(e0,b0) = modRM xr0
(eb,bb) = modRM b
modRMB = 0x1 `shiftL` 6 .|. b0 `shiftL` 3 .|. 0x4
sib = bb `shiftL` 3 .|. bb
mkIx :: Int -> [X86 X86Reg FX86Reg F2X86 a] -> (Int, M.Map Label Int)
mkIx ix (Pop _ r:asms) | fits r = mkIx (ix+1) asms
| otherwise = mkIx (ix+2) asms
mkIx ix (Push _ r:asms) | fits r = mkIx (ix+1) asms
| otherwise = mkIx (ix+2) asms
mkIx ix (Label _ l:asms) = second (M.insert l ix) $ mkIx ix asms
mkIx ix (MovRR{}:asms) = mkIx (ix+3) asms
mkIx ix (Movapd _ r0 r1:asms) | fits r0 && fits r1 = mkIx (ix+4) asms
| otherwise = mkIx (ix+5) asms
mkIx ix (IAddRR{}:asms) = mkIx (ix+3) asms
mkIx ix (And{}:asms) = mkIx (ix+3) asms
mkIx ix (ISubRR{}:asms) = mkIx (ix+3) asms
mkIx ix (Addsd _ r0 r1:asms) | fits r0 && fits r1 = mkIx (ix+4) asms
| otherwise = mkIx (ix+5) asms
mkIx ix (Mulsd _ r0 r1:asms) | fits r0 && fits r1 = mkIx (ix+4) asms
| otherwise = mkIx (ix+5) asms
mkIx ix (Divsd _ r0 r1:asms) | fits r0 && fits r1 = mkIx (ix+4) asms
| otherwise = mkIx (ix+5) asms
mkIx ix (Vsubsd _ _ _ r:asms) | fits r = mkIx (ix+4) asms
| otherwise = mkIx (ix+5) asms
mkIx ix (Vaddsd _ _ _ r:asms) | fits r = mkIx (ix+4) asms
| otherwise = mkIx (ix+5) asms
mkIx ix (Vdivsd _ _ _ r:asms) | fits r = mkIx (ix+4) asms
| otherwise = mkIx (ix+5) asms
mkIx ix (Vmulsd _ _ _ r:asms) | fits r = mkIx (ix+4) asms
| otherwise = mkIx (ix+5) asms
mkIx ix (Vmaxsd _ _ _ r:asms) | fits r = mkIx (ix+4) asms
| otherwise = mkIx (ix+5) asms
mkIx ix (VaddsdA{}:asms) = mkIx (ix+7) asms
mkIx ix (VmaxsdA{}:asms) = mkIx (ix+7) asms
mkIx ix (Vcmppd _ _ _ r _ :asms) | fits r = mkIx (ix+5) asms
| otherwise = mkIx (ix+6) asms
mkIx ix (Vfmadd231sd{}:asms) = mkIx (ix+5) asms
mkIx ix (Vfmnadd231sd{}:asms) = mkIx (ix+5) asms
mkIx ix (Vfmadd213sd{}:asms) = mkIx (ix+5) asms
mkIx ix (Vfmsub213sd{}:asms) = mkIx (ix+5) asms
mkIx ix (Vfmsub231sd{}:asms) = mkIx (ix+5) asms
mkIx ix (Vfmsub132sd{}:asms) = mkIx (ix+5) asms
mkIx ix (Vfmadd231sdA{}:asms) = mkIx (ix+7) asms
mkIx ix (CmpRR{}:asms) = mkIx (ix+3) asms
mkIx ix (IMulRR{}:asms) = mkIx (ix+4) asms
mkIx ix (IMulRA{}:asms) = mkIx (ix+6) asms
mkIx ix (XorRR{}:asms) = mkIx (ix+3) asms
mkIx ix (MovqXR{}:asms) = mkIx (ix+5) asms
mkIx ix (MovqRX{}:asms) = mkIx (ix+5) asms
mkIx ix (TestI{}:asms) = mkIx (ix+7) asms
mkIx ix ((CmpRI _ _ i):asms) | Just{} <- mi64i8 (fromIntegral i) = mkIx (ix+4) asms
| otherwise = mkIx (ix+7) asms
mkIx ix ((IAddRI _ _ i):asms) | Just{} <- mi64i8 i = mkIx (ix+4) asms
mkIx ix ((IAddRI _ _ i):asms) | Just{} <- mi64i32 i = mkIx (ix+7) asms
mkIx ix ((ISubRI _ _ i):asms) | Just{} <- mi64i8 i = mkIx (ix+4) asms
| Just{} <- mi64i32 i = mkIx (ix+7) asms
mkIx ix (MovRI _ r i:asms) | Just{} <- mi64i32 i, i >= 0 && fits r = mkIx (ix+5) asms
mkIx ix (MovRI{}:asms) = mkIx (ix+10) asms
mkIx ix (MovRL{}:asms) = mkIx (ix+10) asms
mkIx ix (Roundsd _ r0 r1 _:asms) | fits r0 && fits r1 = mkIx (ix+6) asms
mkIx ix (Roundsd{}:asms) = mkIx (ix+7) asms
mkIx ix (Cvttsd2si{}:asms) = mkIx (ix+5) asms
mkIx ix (Cvtsi2sd{}:asms) = mkIx (ix+5) asms
mkIx ix (Ret{}:asms) = mkIx (ix+1) asms
mkIx ix (RetL{}:asms) = mkIx (ix+1) asms
mkIx ix (Je{}:asms) = mkIx (ix+6) asms
mkIx ix (Jne{}:asms) = mkIx (ix+6) asms
mkIx ix (Jg{}:asms) = mkIx (ix+6) asms
mkIx ix (Jge{}:asms) = mkIx (ix+6) asms
mkIx ix (Jl{}:asms) = mkIx (ix+6) asms
mkIx ix (Jle{}:asms) = mkIx (ix+6) asms
mkIx ix (J{}:asms) = mkIx (ix+5) asms
mkIx ix (C{}:asms) = mkIx (ix+5) asms
mkIx ix (MovqAX _ (R Rsp) r:asms) | fits r = mkIx (ix+5) asms
mkIx ix (MovqAX _ (R rb) r:asms) | fits rb && fits r = mkIx (ix+4) asms
| otherwise = mkIx (ix+5) asms
mkIx ix (MovqAX _ (RC Rsp _) r1:asms) | fits r1 = mkIx (ix+6) asms
mkIx ix (MovqAX _ (RC R12 _) _:asms) = mkIx (ix+7) asms
mkIx ix (MovqAX _ (RC rb _) r:asms) | fits rb && fits r = mkIx (ix+5) asms
| otherwise = mkIx (ix+6) asms
mkIx ix (MovqAX _ (RSD b _ i _) r:asms) | fits r && fits b && fits i = mkIx (ix+6) asms
mkIx ix (MovqAX _ RSD{} _:asms) = mkIx (ix+7) asms
mkIx ix (MovqXA _ _ (R R13):asms) = mkIx (ix+6) asms
mkIx ix (MovqXA _ r0 (R Rsp):asms) | fits r0 = mkIx (ix+5) asms
| otherwise = mkIx (ix+6) asms
mkIx ix (MovqXA _ r0 (R r1):asms) | fits r0 && fits r1 = mkIx (ix+4) asms
| otherwise = mkIx (ix+5) asms
mkIx ix (MovqXA _ _ (RS R13 _ _):asms) = mkIx (ix+7) asms
mkIx ix (MovqXA _ _ RSD{}:asms) = mkIx (ix+7) asms
mkIx ix (MovqXA _ _ RS{}:asms) = mkIx (ix+6) asms
mkIx ix (MovqXA _ r0 (RC Rsp _):asms) | fits r0 = mkIx (ix+6) asms
| otherwise = mkIx (ix+7) asms
mkIx ix (MovqXA _ xr (RC r _):asms) | fits xr && fits r = mkIx (ix+5) asms
mkIx ix (MovqXA _ _ (RC R12 _):asms) = mkIx (ix+7) asms
mkIx ix (MovqXA _ _ RC{}:asms) = mkIx (ix+6) asms
mkIx ix (Fldl2e{}:asms) = mkIx (ix+2) asms
mkIx ix (Fldln2{}:asms) = mkIx (ix+2) asms
mkIx ix (Fld1{}:asms) = mkIx (ix+2) asms
mkIx ix (Fsin{}:asms) = mkIx (ix+2) asms
mkIx ix (Fcos{}:asms) = mkIx (ix+2) asms
mkIx ix (FldS{}:asms) = mkIx (ix+2) asms
mkIx ix (Fld _ (RC Rsp _):asms) = mkIx (ix+4) asms
mkIx ix (Fyl2x{}:asms) = mkIx (ix+2) asms
mkIx ix (Fmulp{}:asms) = mkIx (ix+2) asms
mkIx ix (F2xm1{}:asms) = mkIx (ix+2) asms
mkIx ix (Fprem{}:asms) = mkIx (ix+2) asms
mkIx ix (Faddp{}:asms) = mkIx (ix+2) asms
mkIx ix (Fscale{}:asms) = mkIx (ix+2) asms
mkIx ix (Fxch{}:asms) = mkIx (ix+2) asms
mkIx ix (Fstp _ (RC Rsp _):asms) = mkIx (ix+4) asms
mkIx ix (Sal{}:asms) = mkIx (ix+4) asms
mkIx ix (Sar{}:asms) = mkIx (ix+4) asms
mkIx ix (Call{}:asms) = mkIx (ix+5) asms
mkIx ix (MovAI32 _ (R Rsp) _:asms) = mkIx (ix+8) asms
mkIx ix (MovAI32 _ (R Rbp) _:asms) = mkIx (ix+8) asms
mkIx ix (MovAI32 _ (R R13) _:asms) = mkIx (ix+8) asms
mkIx ix (MovAI32 _ (R R12) _:asms) = mkIx (ix+8) asms
mkIx ix (MovAI32 _ R{} _:asms) = mkIx (ix+7) asms
mkIx ix (MovAI32 _ RC{} _:asms) = mkIx (ix+8) asms
mkIx ix (MovAR _ (RC Rsp _) _:asms) = mkIx (ix+5) asms
mkIx ix (MovAR _ (RC R12 _) _:asms) = mkIx (ix+5) asms
mkIx ix (MovAR _ RC{} _:asms) = mkIx (ix+4) asms
mkIx ix (MovAR _ (RC32 Rsp _) _:asms) = mkIx (ix+8) asms
mkIx ix (MovAR _ RC32{} _:asms) = mkIx (ix+7) asms
mkIx ix (MovAR _ RSD{} _:asms) = mkIx (ix+5) asms
mkIx ix (MovAR _ RS{} _:asms) = mkIx (ix+4) asms
mkIx ix (MovAR _ (R Rsp) _:asms) = mkIx (ix+4) asms
mkIx ix (MovAR _ (R Rbp) _:asms) = mkIx (ix+4) asms
mkIx ix (MovAR _ (R R13) _:asms) = mkIx (ix+4) asms
mkIx ix (MovAR _ R{} _:asms) = mkIx (ix+3) asms
mkIx ix (MovRA _ _ (RS Rbp _ _):asms) = mkIx (ix+5) asms
mkIx ix (MovRA _ _ (RS R13 _ _):asms) = mkIx (ix+5) asms
mkIx ix (MovRA _ _ RS{}:asms) = mkIx (ix+4) asms
mkIx ix (MovRA _ _ RSD{}:asms) = mkIx (ix+5) asms
mkIx ix (MovRA _ _ (R Rsp):asms) = mkIx (ix+4) asms
mkIx ix (MovRA _ _ (R Rbp):asms) = mkIx (ix+4) asms
mkIx ix (MovRA _ _ (R R13):asms) = mkIx (ix+4) asms
mkIx ix (MovRA _ _ R{}:asms) = mkIx (ix+3) asms
mkIx ix (MovRA _ _ (RC Rsp _):asms) = mkIx (ix+5) asms
mkIx ix (MovRA _ _ (RC R12 _):asms) = mkIx (ix+5) asms
mkIx ix (MovRA _ _ RC{}:asms) = mkIx (ix+4) asms
mkIx ix (MovRA _ _ (RC32 Rsp _):asms) = mkIx (ix+8) asms
mkIx ix (MovRA _ _ RC32{}:asms) = mkIx (ix+7) asms
mkIx ix (Sqrtsd _ r0 r1:asms) | fits r0 && fits r1 = mkIx (ix+4) asms
| otherwise = mkIx (ix+5) asms
mkIx ix (Not{}:asms) = mkIx (ix+3) asms
mkIx ix (Rdrand{}:asms) = mkIx (ix+4) asms
mkIx ix (Cmovnle{}:asms) = mkIx (ix+4) asms
mkIx ix (Cmovnl{}:asms) = mkIx (ix+4) asms
mkIx ix (Cmovne{}:asms) = mkIx (ix+4) asms
mkIx ix (Cmove{}:asms) = mkIx (ix+4) asms
mkIx ix (Cmovl{}:asms) = mkIx (ix+4) asms
mkIx ix (Cmovle{}:asms) = mkIx (ix+4) asms
mkIx ix (Fninit{}:asms) = mkIx (ix+2) asms
mkIx ix (IDiv{}:asms) = mkIx (ix+3) asms
mkIx ix (Neg{}:asms) = mkIx (ix+3) asms
mkIx ix [] = (ix, M.empty)
mkIx _ (instr:_) = error (show instr)
fits :: RMB reg => reg -> Bool
fits r = let (e, _) = modRM r in e == 0
asm :: Int -> (Int, IM.IntMap (Ptr Word64), Maybe CCtx, M.Map Label Int) -> [X86 X86Reg FX86Reg F2X86 a] -> [[Word8]]
asm _ _ [] = []
asm ix st (Push _ r:asms) | fits r =
let (_, b0) = modRM r
isn = 0x50 .|. b0
in [isn]:asm (ix+1) st asms
| otherwise =
let (_, b0) = modRM r
instr = [0x41, 0x50 .|. b0]
in instr:asm (ix+2) st asms
asm ix st (Pop _ r:asms) | (0, b0) <- modRM r=
let isn = 0x58 .|. b0
in [isn]:asm (ix+1) st asms
| otherwise =
let (_, b0) = modRM r
instr = [0x41, 0x58 .|. b0]
in instr:asm (ix+2) st asms
asm ix st (Label{}:asms) =
asm ix st asms
asm ix st (MovRR _ r0 r1:asms) =
mkRR [0x89] r0 r1:asm (ix+3) st asms
asm ix st (MovRA _ r0 (RC r1@Rsp i8):asms) =
let (e0, b0) = modRM r0
(0, b1) = modRM r1
pref = 0x48 .|. e0 `shiftL` 2
modB = 0x1 `shiftL` 6 .|. b0 `shiftL` 3 .|. 4
sib = b1 `shiftL` 3 .|. b1
opc=0x8b; instr = pref:opc:modB:sib:le i8
in instr:asm (ix+5) st asms
asm ix st (MovRA _ r0 (RC r1@R12 i8):asms) =
let (e0, b0) = modRM r0
(e1, b1) = modRM r1
pref = 0x48 .|. e0 `shiftL` 2 .|. e1
modB = 0x1 `shiftL` 6 .|. b0 `shiftL` 3 .|. 4
sib = b1 `shiftL` 3 .|. b1
opc=0x8b; instr = pref:opc:modB:sib:le i8
in instr:asm (ix+5) st asms
asm ix st (MovRA _ r0 (RC32 r1@Rsp i32):asms) =
let (e0, b0) = modRM r0
(0, b1) = modRM r1
pref = 0x48 .|. e0 `shiftL` 2
modB = 0x2 `shiftL` 6 .|. b0 `shiftL` 3 .|. 4
sib = b1 `shiftL` 3 .|. b1
opc=0x8b; instr = pref:opc:modB:sib:le i32
in instr:asm (ix+8) st asms
asm ix st (MovRA _ r0 (RC r1 i8):asms) =
let (e0, b0) = modRM r0
(e1, b1) = modRM r1
pref = 0x48 .|. (e0 `shiftL` 2) .|. e1
modB = 0x1 `shiftL` 6 .|. (b0 `shiftL` 3) .|. b1
opc=0x8b; instr = pref:opc:modB:le i8
in instr:asm (ix+4) st asms
asm ix st (MovRA _ r0 (RC32 r1 i32):asms) =
let (e0, b0) = modRM r0
(e1, b1) = modRM r1
pref = 0x48 .|. (e0 `shiftL` 2) .|. e1
modB = 0x2 `shiftL` 6 .|. (b0 `shiftL` 3) .|. b1
opc=0x8b; instr = pref:opc:modB:le i32
in instr:asm (ix+7) st asms
asm ix st (MovqXA _ r0 (RC r1@Rsp i8):asms) | fits r0 =
let (_, b0) = modRM r0
(_, b1) = modRM r1
modB = 0x1 `shiftL` 6 .|. b0 `shiftL` 3 .|. 0x4
sib = b1 `shiftL` 3 .|. b1
instr = 0xf3:0xf:0x7e:modB:sib:le i8
in instr:asm (ix+6) st asms
-- https://stackoverflow.com/questions/52522544/rbp-not-allowed-as-sib-base
asm ix st (MovqXA l r0 (R R13):asms) = asm ix st (MovqXA l r0 (RC R13 0):asms)
asm ix st (MovqXA _ r0 (R r1@Rsp):asms) | (0, b0) <- modRM r0 =
let (0, b1) = modRM r1
modB = b0 `shiftL` 3 .|. 4
sib = b1 `shiftL` 3 .|. b1
isn = [0xf3,0x0f,0x7e,modB,sib]
in isn:asm (ix+5) st asms
asm ix st (MovqXA _ r0 (R r1):asms) | (0, b0) <- modRM r0, (0, b1) <- modRM r1 =
let modB = b0 `shiftL` 3 .|. b1
instr = [0xf3, 0x0f, 0x7e, modB]
in instr:asm (ix+4) st asms
asm ix st (MovqXA _ r0 (RC r1 i8):asms) | (0, b0) <- modRM r0, (0, b1) <- modRM r1 =
let modB = 0x1 `shiftL` 6 .|. b0 `shiftL` 3 .|. b1
instr = 0xf3:0x0f:0x7e:modB:le i8
in instr:asm (ix+5) st asms
asm ix st (MovqXA _ r (RC rb@R12 i8):asms) =
let (e, b) = modRM r
(eb, bb) = modRM rb
modB = 0x1 `shiftL` 6 .|. b `shiftL` 3 .|. 0x4
sib = 0x4 `shiftL` 3 .|. bb
pre = 0x48 .|. e `shiftL` 2 .|. eb
isn = 0x66:pre:0xf:0x6e:modB:sib:le i8
in isn:asm (ix+7) st asms
asm ix st (MovqXA _ r (RC rb@Rsp i8):asms) =
let (e, b) = modRM r
(eb, bb) = modRM rb
modB = 0x1 `shiftL` 6 .|. b `shiftL` 3 .|. 0x4
sib = 0x4 `shiftL` 3 .|. bb
pre = 0x48 .|. e `shiftL` 2 .|. eb
isn = 0x66:pre:0xf:0x6e:modB:sib:le i8
in isn:asm (ix+7) st asms
asm ix st (MovqXA _ r0 (RC r1 i8):asms) =
let (e0, b0) = modRM r0
(e1, b1) = modRM r1
modB = 0x1 `shiftL` 6 .|. b0 `shiftL` 3 .|. b1
pre = 0x48 .|. e0 `shiftL` 2 .|. e1
instr = 0x66:pre:0xf:0x6e:modB:le i8
in instr:asm (ix+6) st asms
asm ix st (MovqXA _ r0 (R r1@Rsp):asms) =
let (e0, b0) = modRM r0
(0, b1) = modRM r1
modB = b0 `shiftL` 3 .|. 4
pre = 0x48 .|. e0 `shiftL` 2
sib = b1 `shiftL` 3 .|. b1
instr = [0x66, pre, 0xf, 0x6e, modB, sib]
in instr:asm (ix+6) st asms
asm ix st (MovqXA _ r0 (R r1):asms) =
let (e0, b0) = modRM r0
(e1, b1) = modRM r1
modB = b0 `shiftL` 3 .|. b1
pre = 0x48 .|. e0 `shiftL` 2 .|. e1
instr = [0x66, pre, 0xf, 0x6e, modB]
in instr:asm (ix+5) st asms
-- https://stackoverflow.com/questions/52522544/rbp-not-allowed-as-sib-base
asm ix st (MovqAX _ (RC r0@Rsp i8) r1:asms) | (0, b1) <- modRM r1 =
let (0, b0) = modRM r0
modB = 0x1 `shiftL` 6 .|. b1 `shiftL` 3 .|. 0x4
sib = b0 `shiftL` 3 .|. b0
instr = 0x66:0x0f:0xd6:modB:sib:le i8
in instr:asm (ix+6) st asms
asm ix st (MovqAX _ (R rb@Rsp) r:asms) | (0, b) <- modRM r =
let (0, bb) = modRM rb
modB = b `shiftL` 3 .|. 0x4
sib = bb `shiftL` 3 .|. bb
isn = [0x66,0x0f,0xd6,modB,sib]
in isn:asm (ix+5) st asms
asm ix st (MovqAX _ (R rb) r:asms) | (0, bb) <- modRM rb, (0, b) <- modRM r =
let modB = b `shiftL` 3 .|. bb
isn = [0x66,0x0f,0xd6,modB]
in isn:asm (ix+4) st asms
asm ix st (MovqAX _ (R rb) r:asms) =
let (eb, bb) = modRM rb; (e, b) = modRM r
pre = 0x48 .|. e `shiftL` 3 .|. eb
modB = b `shiftL` 3 .|. bb
isn = [0x66,pre,0x0f,0xd6,modB]
in isn:asm (ix+5) st asms
asm ix st (MovqAX _ (RC rb i8) r:asms) | (0, bb) <- modRM rb, (0, b) <- modRM r =
let modB = 0x1 `shiftL` 6 .|. b `shiftL` 3 .|. bb
isn = 0x66:0x0f:0xd6:modB:le i8
in isn:asm (ix+5) st asms
asm ix st (MovqAX _ (RC rb@R12 i8) r:asms) =
let (eb, bb) = modRM rb
(e, b) = modRM r
modB = 0x1 `shiftL` 6 .|. b `shiftL` 3 .|. 0x4
pre = 0x48 .|. e `shiftL` 2 .|. eb
sib = 0x4 `shiftL` 3 .|. bb
isn = 0x66:pre:0x0f:0xd6:modB:sib:le i8
in isn:asm (ix+7) st asms
asm ix st (MovqAX _ (RC rb i8) r:asms) =
let (eb, bb) = modRM rb
(e, b) = modRM r
modB = 0x1 `shiftL` 6 .|. b `shiftL` 3 .|. bb
pre = 0x48 .|. e `shiftL` 2 .|. eb
isn = 0x66:pre:0x0f:0xd6:modB:le i8
in isn:asm (ix+6) st asms
asm ix st (MovqAX _ (RSD rb s ri d) r:asms) | (0, b) <- modRM r, (0, bi) <- modRM ri, (0, bb) <- modRM rb =
let modB = 0x1 `shiftL` 6 .|. b `shiftL` 3 .|. 0x4
sib = encS s `shiftL` 6 .|. bi `shiftL` 3 .|. bb
instr = 0x66:0x0f:0xd6:modB:sib:le d
in instr:asm (ix+6) st asms
asm ix st (MovqAX _ (RSD rb s ri d) r:asms) =
let (e, b) = modRM r; (eb, bb) = modRM rb; (ei, bi) = modRM ri
modB = 0x1 `shiftL` 6 .|. b `shiftL` 3 .|. 0x4
rex = 0x48 .|. e `shiftL` 2 .|. ei `shiftL` 1 .|. eb
sib = encS s `shiftL` 6 .|. bi `shiftL` 3 .|. bb
instr = 0x66:rex:0x0f:0x7e:modB:sib:le d
in instr:asm (ix+7) st asms
asm ix st (MovqXA l r (RS R13 s ri):asms) = asm ix st (MovqXA l r (RSD R13 s ri 0):asms)
asm ix st (MovqXA _ r (RS rb s ri):asms) =
let (e, b) = modRM r; (eb, bb) = modRM rb; (ei, bi) = modRM ri
modB = b `shiftL` 3 .|. 4
rex = 0x48 .|. e `shiftL` 2 .|. ei `shiftL` 1 .|. eb
sib = encS s `shiftL` 6 .|. bi `shiftL` 3 .|. bb
instr = [0x66,rex,0x0f,0x6e,modB,sib]
in instr:asm (ix+6) st asms
asm ix st (MovqXA _ r (RSD rb s ri d):asms) =
let (e, b) = modRM r; (eb, bb) = modRM rb; (ei, bi) = modRM ri
modB = 1 `shiftL` 6 .|. b `shiftL` 3 .|. 4
rex = 0x48 .|. e `shiftL` 2 .|. ei `shiftL` 1 .|. eb
sib = encS s `shiftL` 6 .|. bi `shiftL` 3 .|. bb
instr = 0x66:rex:0x0f:0x6e:modB:sib:le d
in instr:asm (ix+7) st asms
asm ix st (Movapd _ r0 r1:asms) | fits r0 && fits r1 =
rrNoPre [0x66,0x0f,0x28] r1 r0:asm (ix+4) st asms
| otherwise =
extSse 0x66 0x28 r1 r0:asm (ix+5) st asms
asm ix st (IAddRR _ r0 r1:asms) =
mkRR [0x01] r0 r1:asm (ix+3) st asms
asm ix st (And _ r0 r1:asms) =
mkRR [0x21] r0 r1:asm (ix+3) st asms
asm ix st (ISubRR _ r0 r1:asms) =
mkRR [0x29] r0 r1:asm (ix+3) st asms
asm ix st (IDiv _ r:asms) =
let (e, b) = modRM r
modB = 3 `shiftL` 6 .|. 7 `shiftL` 3 .|. b
pre = 0x48 .|. e
isn = [pre,0xf7,modB]
in isn:asm (ix+3) st asms
asm ix st (Addsd _ r0 r1:asms) | fits r0 && fits r1 =
rrNoPre [0xf2,0x0f,0x58] r1 r0:asm (ix+4) st asms
| otherwise =
extSse 0xf2 0x58 r1 r0:asm (ix+5) st asms
asm ix st (Mulsd _ r0 r1:asms) | fits r0 && fits r1 =
rrNoPre [0xf2,0x0f,0x59] r1 r0:asm (ix+4) st asms
| otherwise =
extSse 0xf2 0x59 r1 r0:asm (ix+5) st asms
asm ix st (Divsd _ r0 r1:asms) | fits r0 && fits r1 =
rrNoPre [0xf2,0x0f,0x5e] r1 r0:asm (ix+4) st asms
| otherwise =
extSse 0xf2 0x5e r1 r0:asm (ix+5) st asms
asm ix st (Vsubsd _ r0 r1 r2:asms) | fits r2 =
mkVex 0x5c F2 r0 r1 r2:asm (ix+4) st asms
| otherwise =
mkVex3 0x5c F2 F r0 r1 r2:asm (ix+5) st asms
asm ix st (Vaddsd _ r0 r1 r2:asms) | fits r2 =
mkVex 0x58 F2 r0 r1 r2:asm (ix+4) st asms
| otherwise =
mkVex3 0x58 F2 F r0 r1 r2:asm (ix+5) st asms
asm ix st (Vdivsd _ r0 r1 r2:asms) | fits r2 =
mkVex 0x5e F2 r0 r1 r2:asm (ix+4) st asms
| otherwise =
mkVex3 0x5e F2 F r0 r1 r2:asm (ix+5) st asms
asm ix st (Vmulsd _ r0 r1 r2:asms) | fits r2 =
mkVex 0x59 F2 r0 r1 r2:asm (ix+4) st asms
| otherwise =
mkVex3 0x59 F2 F r0 r1 r2:asm (ix+5) st asms
asm ix st (Vmaxsd _ r0 r1 r2:asms) | fits r2 =
mkVex 0x5f F2 r0 r1 r2:asm (ix+4) st asms
| otherwise =
mkVex3 0x5f F2 F r0 r1 r2:asm (ix+5) st asms
asm ix st (VaddsdA _ r0 r1 a:asms) =
mkVexA 0x58 F2 F r0 r1 a:asm (ix+7) st asms
asm ix st (VmaxsdA _ r0 r1 a:asms) =
mkVexA 0x5f F2 F r0 r1 a:asm (ix+7) st asms
asm ix st (Vcmppd _ r0 r1 r2 p:asms) | fits r2 =
(mkVex 0xc2 S6 r0 r1 r2 ++ le (imm8 p)):asm (ix+5) st asms
| otherwise =
(mkVex3 0xc2 S6 F r0 r1 r2 ++ le (imm8 p)):asm (ix+6) st asms
asm ix st (Vfmadd231sd _ r0 r1 r2:asms) =
mkVex3 0xb9 S6 F38 r0 r1 r2:asm (ix+5) st asms
asm ix st (Vfmnadd231sd _ r0 r1 r2:asms) =
mkVex3 0xbd S6 F38 r0 r1 r2:asm (ix+5) st asms
asm ix st (Vfmadd213sd _ r0 r1 r2:asms) =
mkVex3 0xa9 S6 F38 r0 r1 r2:asm (ix+5) st asms
asm ix st (Vfmsub132sd _ r0 r1 r2:asms) =
mkVex3 0x9b S6 F38 r0 r1 r2:asm (ix+5) st asms
asm ix st (Vfmsub213sd _ r0 r1 r2:asms) =
mkVex3 0xab S6 F38 r0 r1 r2:asm (ix+5) st asms
asm ix st (Vfmsub231sd _ r0 r1 r2:asms) =
mkVex3 0xbb S6 F38 r0 r1 r2:asm (ix+5) st asms
asm ix st (Vfmadd231sdA _ r0 r1 a:asms) =
mkVexA 0xb9 S6 F38 r0 r1 a:asm (ix+7) st asms
asm ix st (Roundsd _ r0 r1 i:asms) | fits r0 && fits r1 =
(rrNoPre [0x66,0x0f,0x3a,0x0b] r1 r0++le (roundMode i)):asm (ix+6) st asms
asm ix st (Roundsd _ r0 r1 i:asms) =
(0x66:mkAR [0xf,0x3a,0xb] 0 r1 r0++le (roundMode i)):asm (ix+7) st asms
asm ix st (Cvttsd2si _ r0 r1:asms) =
(0xf2:mkRR [0x0f,0x2c] r1 r0):asm (ix+5) st asms
asm ix st (Cvtsi2sd _ fr r:asms) =
(0xf2:mkRR [0x0f,0x2a] r fr):asm (ix+5) st asms
asm ix st (Sqrtsd _ r0 r1:asms) | fits r0 && fits r1 =
rrNoPre [0xf2,0x0f,0x51] r1 r0:asm (ix+4) st asms
| otherwise =
extSse 0xf2 0x51 r1 r0:asm (ix+5) st asms
asm ix st (CmpRR _ r0 r1:asms) =
mkRR [0x39] r0 r1:asm (ix+3) st asms
asm ix st (MovqXR _ fr r:asms) =
(0x66:mkRR [0x0f,0x6e] r fr):asm (ix+5) st asms
asm ix st (MovqRX _ r fr:asms) =
(0x66:mkRR [0x0f,0x7e] r fr):asm (ix+5) st asms
asm ix st (IMulRR _ r0 r1:asms) =
-- flip r0,r1 as instr. uses them differently from sub, etc.
mkRR [0x0f, 0xaf] r1 r0:asm (ix+4) st asms
asm ix st (IMulRA _ r (RSD rb s ri d):asms) =
let (e, b) = modRM r
(eb, bb) = modRM rb
(ei, bi) = modRM ri
pre = 0x48 .|. e `shiftL` 2 .|. ei `shiftL` 1 .|. eb
modB = 0x1 `shiftL` 6 .|. b `shiftL` 3 .|. 0x4
sib = encS s `shiftL` 6 .|. bi `shiftL` 3 .|. bb
in (pre:0x0f:0xaf:modB:sib:le d):asm (ix+6) st asms
asm ix st (XorRR _ r0 r1:asms) =
mkRR [0x31] r0 r1:asm (ix+3) st asms
asm ix st (TestI _ r i:asms) =
let (e, b) = modRM r
prefix = 0x48 .|. e
modB = 0x3 `shiftL` 6 .|. b
in (prefix:0xf7:modB:le i):asm (ix+7) st asms
asm ix st (CmpRI _ r i:asms) | Just i8 <- mi64i8 (fromIntegral i) =
let (e, b) = modRM r
prefix = 0x48 .|. e
modRMB = (0x3 `shiftL` 6) .|. (0o7 `shiftL` 3) .|. b
in (prefix:0x83:modRMB:le i8):asm (ix+4) st asms
asm ix st (CmpRI _ r i32:asms) =
let (e, b) = modRM r
prefix = 0x48 .|. e
modRMB = (0x3 `shiftL` 6) .|. (0o7 `shiftL` 3) .|. b
in (prefix:0x81:modRMB:le i32):asm (ix+7) st asms
asm ix st (IAddRI _ r i:asms) | Just i8 <- mi64i8 i =
let (e, b) = modRM r
prefix = 0x48 .|. e
modRMB = (0x3 `shiftL` 6) .|. b
in (prefix:0x83:modRMB:le i8):asm (ix+4) st asms
asm ix st (IAddRI _ r i:asms) | Just i32 <- mi64i32 i =
let (e, b) = modRM r
prefix = 0x48 .|. e
modRMB = (0x3 `shiftL` 6) .|. b
in (prefix:0x81:modRMB:le i32):asm (ix+7) st asms
asm ix st (ISubRI _ r i:asms) | Just i8 <- mi64i8 i =
let (e, b) = modRM r
prefix = 0x48 .|. e
modRMB = (0x3 `shiftL` 6) .|. (0x5 `shiftL` 3) .|. b
in (prefix:0x83:modRMB:le i8):asm (ix+4) st asms
asm ix st (ISubRI _ r i:asms) | Just i32 <- mi64i32 i =
let (e, b) = modRM r
prefix = 0x48 .|. e
modRMB = (0x3 `shiftL` 6) .|. (0x5 `shiftL` 3) .|. b
in (prefix:0x81:modRMB:le i32):asm (ix+7) st asms
| otherwise = error "Not implemented yet: handling 64-bit immediates"
-- TODO: r32<-i32 like nasm does (note r32<-i32 (zero-extended) vs.
-- sign-extended
-- https://stackoverflow.com/questions/40315803/difference-between-movq-and-movabsq-in-x86-64
asm ix st (MovRI _ r i:asms) | Just i32 <- mi64i32 i, i >= 0 && fits r =
let (_, b) = modRM r
opc = 0xb8 .|. b
in (opc:cd i32):asm (ix+5) st asms
-- TODO: 0xc7 for case i<0
asm ix st (MovRI _ r i:asms) =
let (e, b) = modRM r
pre = (0x48 .|. e:) . (0xB8 .|. b:)
in pre (le i):asm (ix+10) st asms
asm ix st (MovRL x r l:asms) =
let p=arr l st
in asm ix st (MovRI x r (fromIntegral$pI p):asms)
asm ix st (Ret{}:asms) =
[0xc3]:asm (ix+1) st asms
asm ix st (RetL{}:asms) =
[0xc3]:asm (ix+1) st asms
asm ix st (Je _ l:asms) =
let lIx = get l st
instr = let offs = lIx-ix-6 in 0x0f:0x84:cd (fromIntegral offs :: Int32)
in instr:asm (ix+6) st asms
asm ix st (Jne _ l:asms) =
let lIx = get l st
instr = let offs = lIx-ix-6 in 0x0f:0x85:cd (fromIntegral offs :: Int32)
in instr:asm (ix+6) st asms
asm ix st (Jg _ l:asms) =
let lIx = get l st
instr = let offs = lIx-ix-6 in 0x0f:0x8f:cd (fromIntegral offs :: Int32)
in instr:asm (ix+6) st asms
asm ix st (Jge _ l:asms) =
let lIx = get l st
instr = let offs = lIx-ix-6 in 0x0f:0x8d:cd (fromIntegral offs :: Int32)
in instr:asm (ix+6) st asms
asm ix st (Jl _ l:asms) =
let lIx = get l st
instr = let offs = lIx-ix-6 in 0x0f:0x8c:cd (fromIntegral offs :: Int32)
in instr:asm (ix+6) st asms
asm ix st (Jle _ l:asms) =
let lIx = get l st
instr = let offs = lIx-ix-6 in 0x0f:0x8e:cd (fromIntegral offs :: Int32)
in instr:asm (ix+6) st asms
asm ix st (J _ l:asms) =
let lIx = get l st
instr = let offs = lIx-ix-5 in 0xe9:cd (fromIntegral offs :: Int32)
in instr:asm (ix+5) st asms
asm ix st (C _ l:asms) =
let lIx = get l st
instr = let offs = lIx-ix-5 in 0xe8:cd (fromIntegral offs :: Int32)
in instr:asm (ix+5) st asms
asm ix st (Fmulp{}:asms) =
[0xde,0xc9]:asm (ix+2) st asms
asm ix st (F2xm1{}:asms) =
[0xd9,0xf0]:asm (ix+2) st asms
asm ix st (Fldl2e{}:asms) =
[0xd9,0xea]:asm (ix+2) st asms
asm ix st (Fldln2{}:asms) =
[0xd9,0xed]:asm (ix+2) st asms
asm ix st (Fld1{}:asms) =
[0xd9,0xe8]:asm (ix+2) st asms
asm ix st (Fsin{}:asms) =
[0xd9,0xfe]:asm (ix+2) st asms
asm ix st (Fcos{}:asms) =
[0xd9,0xff]:asm (ix+2) st asms
asm ix st (FldS _ (ST i):asms) =
let isn = [0xd9, 0xc0+fromIntegral i] in isn:asm (ix+2) st asms
asm ix st (Fprem{}:asms) =
[0xd9,0xf8]:asm (ix+2) st asms
asm ix st (Faddp{}:asms) =
[0xde,0xc1]:asm (ix+2) st asms
asm ix st (Fscale{}:asms) =
[0xd9,0xfd]:asm (ix+2) st asms
asm ix st (Fninit{}:asms) =
[0xdb,0xe3]:asm (ix+2) st asms
asm ix st (Fxch _ (ST i):asms) =
let isn = [0xd9, 0xc9+fromIntegral i] in isn:asm (ix+2) st asms
asm ix st (Fyl2x{}:asms) =
[0xd9,0xf1]:asm (ix+2) st asms
asm ix st (Fld _ (RC r@Rsp i8):asms) =
let (_, b) = modRM r
modB = 0x1 `shiftL` 6 .|. 0x4
sib = b `shiftL` 3 .|. b
instr = 0xdd:modB:sib:le i8
in instr:asm (ix+4) st asms
asm ix st (Fstp _ (RC r@Rsp i8):asms) =
let (_, b) = modRM r
modB = 0x1 `shiftL` 6 .|. 0x3 `shiftL` 3 .|. 0x4
sib = b `shiftL` 3 .|. b
instr = 0xdd:modB:sib:le i8
in instr:asm (ix+4) st asms
asm ix st (Sal _ r i:asms) =
let (e, b) = modRM r
modRMB = (0x3 `shiftL` 6) .|. (0x4 `shiftL` 3) .|. b
pre = 0x48 .|. e
instr = pre:0xc1:modRMB:le i
in instr:asm (ix+4) st asms
asm ix st (Sar _ r i:asms) =
let (e, b) = modRM r
modRMB = (0x3 `shiftL` 6) .|. (0x7 `shiftL` 3) .|. b
pre = 0x48 .|. e
instr = pre:0xc1:modRMB:le i
in instr:asm (ix+4) st asms
asm ix st (MovAI32 l (R R13) i32:asms) = asm ix st (MovAI32 l (RC R13 0) i32:asms)
asm ix st (MovAI32 l (R Rbp) i32:asms) = asm ix st (MovAI32 l (RC Rbp 0) i32:asms)
asm ix st (MovAI32 _ (R Rsp) i32:asms) =
let (0, b) = modRM Rsp
modB = 0x4
sib = b `shiftL` 3 .|. b
instr = 0x48:0xc7:modB:sib:le i32
in instr:asm (ix+8) st asms
asm ix st (MovAI32 _ (R R12) i32:asms) =
let (e, b) = modRM R12
modB = 0x4
sib = 0x4 `shiftL` 3 .|. b
pre = 0x48 .|. e
isn = pre:0xc7:modB:sib:le i32
in isn:asm (ix+8) st asms
asm ix st (MovAI32 _ (R r) i32:asms) =
let (e, b) = modRM r
modRMB = b
pre = 0x48 .|. e
instr = pre:0xc7:modRMB:le i32
in instr:asm (ix+7) st asms
asm ix st (MovAI32 _ (RC r i8) i32:asms) =
let (e, b) = modRM r
modB = 0x1 `shiftL` 6 .|. b
pre = 0x48 .|. e
isn = pre:0xc7:modB:le i8 ++ le i32
in isn:asm (ix+8) st asms
asm ix st (MovAR _ (RC Rsp i8) r:asms) =
let (e, b) = modRM r
(0, bi) = modRM Rsp
pre = 0x48 .|. e `shiftL` 2
modB = 0x1 `shiftL` 6 .|. b `shiftL` 3 .|. 0x4
sib = bi `shiftL` 3 .|. bi
instr = pre:0x89:modB:sib:le i8
in instr:asm (ix+5) st asms
asm ix st (MovAR _ (RC32 Rsp i32) r:asms) =
let (e, b) = modRM r
(0, bi) = modRM Rsp
pre = 0x48 .|. e `shiftL` 2
modB = 0x2 `shiftL` 6 .|. b `shiftL` 3 .|. 0x4
sib = bi `shiftL` 3 .|. bi
instr = pre:0x89:modB:sib:le i32
in instr:asm (ix+8) st asms
asm ix st (MovAR _ (RC R12 i8) r:asms) =
let (e, b) = modRM r
(ei, bi) = modRM R12
pre = 0x48 .|. e `shiftL` 2 .|. ei
modB = 0x1 `shiftL` 6 .|. b `shiftL` 3 .|. 0x4
sib = bi `shiftL` 3 .|. bi
instr = pre:0x89:modB:sib:le i8
in instr:asm (ix+5) st asms
asm ix st (MovAR _ (RC ar i8) r:asms) =
(mkAR [0x89] 1 ar r++le i8):asm (ix+4) st asms
asm ix st (MovAR _ (RC32 ar i32) r:asms) =
(mkAR [0x89] 2 ar r++le i32):asm (ix+7) st asms
asm ix st (MovRA l r (RS b@Rbp s i):asms) = asm ix st (MovRA l r (RSD b s i 0):asms)
asm ix st (MovRA l r (RS b@R13 s i):asms) = asm ix st (MovRA l r (RSD b s i 0):asms)
asm ix st (MovRA _ r (RS b s i):asms) =
let (e0, b0) = modRM r
(eb, bb) = modRM b
(ei, bi) = modRM i
pre = 0x48 .|. e0 `shiftL` 2 .|. ei `shiftL` 1 .|. eb
modB = b0 `shiftL` 3 .|. 4
sib = encS s `shiftL` 6 .|. bi `shiftL` 3 .|. bb
instr = [pre,0x8b,modB,sib]
in instr:asm (ix+4) st asms
asm ix st (MovAR _ (RSD b s i i8) r:asms) =
let (eb, bb) = modRM b
(ei, bi) = modRM i
(e0, b0) = modRM r
pre = 0x48 .|. e0 `shiftL` 2 .|. ei `shiftL` 1 .|. eb
modRMB = 1 `shiftL` 6 .|. b0 `shiftL` 3 .|. 4
sib = encS s `shiftL` 6 .|. bi `shiftL` 3 .|. bb
instr = pre:0x89:modRMB:sib:le i8
in instr:asm (ix+5) st asms
asm ix st (MovRA _ r (RSD b s i i8):asms) =
let (eb, bb) = modRM b
(ei, bi) = modRM i
(e0, b0) = modRM r
pre = 0x48 .|. e0 `shiftL` 2 .|. ei `shiftL` 1 .|. eb
modRMB = 1 `shiftL` 6 .|. b0 `shiftL` 3 .|. 4
sib = encS s `shiftL` 6 .|. bi `shiftL` 3 .|. bb
instr = pre:0x8b:modRMB:sib:le i8
in instr:asm (ix+5) st asms
asm ix st (MovAR l (R Rbp) r:asms) = asm ix st (MovAR l (RC Rbp 0) r:asms)
asm ix st (MovAR l (R R13) r:asms) = asm ix st (MovAR l (RC R13 0) r:asms)
asm ix st (MovAR _ (R ar@Rsp) r:asms) =
let (0, bi) = modRM ar
(e0, b0) = modRM r
pre = 0x48 .|. e0 `shiftL` 2
modRMB = b0 `shiftL` 3 .|. 4; sib = bi `shiftL` 3 .|. bi
isn = [pre,0x89,modRMB,sib]
in isn:asm (ix+4) st asms
asm ix st (MovRA _ r (R ar@Rsp):asms) =
let (0, bi) = modRM ar
(e0, b0) = modRM r
pre = 0x48 .|. e0 `shiftL` 2
modRMB = b0 `shiftL` 3 .|. 4; sib = bi `shiftL` 3 .|. bi
isn = [pre,0x8b,modRMB,sib]
in isn:asm (ix+4) st asms
asm ix st (MovAR _ (R ar) r:asms) =
mkAR [0x89] 0 ar r:asm (ix+3) st asms
asm ix st (MovRA l r (R Rbp):asms) = asm ix st (MovRA l r (RC Rbp 0):asms)
asm ix st (MovRA l r (R R13):asms) = asm ix st (MovRA l r (RC R13 0):asms)
asm ix st (MovRA _ r (R ar):asms) =
mkAR [0x8b] 0 ar r:asm (ix+3) st asms
asm ix st (Cmovne _ r0 r1:asms) =
mkRR [0xf,0x45] r1 r0:asm (ix+4) st asms
asm ix st (Cmovnle _ r0 r1:asms) =
mkRR [0xf,0x4f] r1 r0:asm (ix+4) st asms
asm ix st (Cmovnl _ r0 r1:asms) =
mkRR [0xf,0x4d] r1 r0:asm (ix+4) st asms
asm ix st (Cmovle _ r0 r1:asms) =
mkRR [0xf,0x4e] r1 r0:asm (ix+4) st asms
asm ix st (Cmovl _ r0 r1:asms) =
mkRR [0xf,0x4c] r1 r0:asm (ix+4) st asms
asm ix st (Cmove _ r0 r1:asms) =
mkRR [0xf,0x44] r1 r0:asm (ix+4) st asms
asm ix st (MovAR _ (RS rb s ri) r:asms) =
let (eb, bb) = modRM rb
(ei, bi) = modRM ri
(e, b) = modRM r
modRMB = b `shiftL` 3 .|. 4
sib = encS s `shiftL` 6 .|. bi `shiftL` 3 .|. bb
pre = 0x48 .|. e `shiftL` 2 .|. ei `shiftL` 1 .|. eb
in [pre,0x89,modRMB,sib]:asm (ix+4) st asms
asm ix st (Not _ r:asms) =
let (e, b) = modRM r
pre = 0x48 .|. e
modB = 3 `shiftL` 6 .|. 2 `shiftL` 3 .|. b
in [pre,0xf7,modB]:asm (ix+3) st asms
asm ix st (Neg _ r:asms) =
let (e, b) = modRM r
pre = 0x48 .|. e
modB = 3 `shiftL` 6 .|. 3 `shiftL` 3 .|. b
in [pre,0xf7,modB]:asm(ix+3) st asms
asm ix st (Rdrand _ r:asms) =
let (e, b) = modRM r
pre = 0x48 .|. e
modB = 3 `shiftL` 6 .|. 6 `shiftL` 3 .|. b
in [pre,0xf,0xc7,modB]:asm(ix+4) st asms
asm ix st@(self, _, Just (m, _, _, _), _) (Call _ Malloc:asms) | Just i32 <- mi32 (m-(self+ix+5)) =
let instr = 0xe8:le i32
in instr:asm (ix+5) st asms
asm ix st@(self, _, Just (_, f, _, _), _) (Call _ Free:asms) | Just i32 <- mi32 (f-(self+ix+5)) =
let instr = 0xe8:le i32
in instr:asm (ix+5) st asms
asm ix st@(self, _, Just (_, _, d, _), _) (Call _ DR:asms) | Just i32 <- mi32 (d-(self+ix+5)) =
let isn=0xe8:le i32
in isn:asm (ix+5) st asms
asm _ (_, _, Nothing, _) (Call{}:_) = error "Internal error? no dynlibs"
asm _ _ (instr:_) = error (show instr)
encS :: Scale -> Word8
encS One = 0
encS Two = 1
encS Four = 2
encS Eight = 3
get :: Label -> (Int, IM.IntMap (Ptr Word64), Maybe CCtx, M.Map Label Int) -> Int
get l =
M.findWithDefault (error "Internal error: label not found") l . fth where fth (_,_,_,z) = z
arr :: Int -> (Int, IM.IntMap (Ptr Word64), Maybe CCtx, M.Map Label Int) -> Ptr Word64
arr n = IM.findWithDefault (error "Internal error: array not found during assembler stage") n . snd4 where snd4 (_,y,_,_) = y
mi64i8 :: Int64 -> Maybe Int8
mi64i8 i | i > fromIntegral (maxBound :: Int8) || i < fromIntegral (minBound :: Int8) = Nothing
| otherwise = Just $ fromIntegral i
mi32 :: Int -> Maybe Int32
mi32 i | i > fromIntegral (maxBound :: Int32) || i < fromIntegral (minBound :: Int32) = Nothing
| otherwise = Just $ fromIntegral i
mi64i32 :: Int64 -> Maybe Int32
mi64i32 i | i > fromIntegral (maxBound :: Int32) || i < fromIntegral (minBound :: Int32) = Nothing
| otherwise = Just $ fromIntegral i
class RMB a where
-- extra is 1 bit, ModR/M is 3 bits; I store them as bytes for ease of
-- manipulation
modRM :: a -> (Word8, Word8)
instance RMB X86Reg where
modRM Rax = (0, 0o0)
modRM Rcx = (0, 0o1)
modRM Rdx = (0, 0o2)
modRM Rbx = (0, 0o3)
modRM Rsp = (0, 0o4)
modRM Rbp = (0, 0o5)
modRM Rsi = (0, 0o6)
modRM Rdi = (0, 0o7)
modRM R8 = (1, 0o0)
modRM R9 = (1, 0o1)
modRM R10 = (1, 0o2)
modRM R11 = (1, 0o3)
modRM R12 = (1, 0o4)
modRM R13 = (1, 0o5)
modRM R14 = (1, 0o6)
modRM R15 = (1, 0o7)
instance RMB FX86Reg where
modRM XMM0 = (0, 0o0)
modRM XMM1 = (0, 0o1)
modRM XMM2 = (0, 0o2)
modRM XMM3 = (0, 0o3)
modRM XMM4 = (0, 0o4)
modRM XMM5 = (0, 0o5)
modRM XMM6 = (0, 0o6)
modRM XMM7 = (0, 0o7)
modRM XMM8 = (1, 0o0)
modRM XMM9 = (1, 0o1)
modRM XMM10 = (1, 0o2)
modRM XMM11 = (1, 0o3)
modRM XMM12 = (1, 0o4)
modRM XMM13 = (1, 0o5)
modRM XMM14 = (1, 0o6)
modRM XMM15 = (1, 0o7)
cd :: (Integral a) => a -> [Word8]
cd x = le (fromIntegral x :: Word32)
-- little endian
le :: (Storable a, Integral a, Bits a) => a -> [Word8]
le x = fromIntegral <$> zipWith (\m e -> (x .&. m) `rotateR` e) masks ee
where ee = [0,8..(8*(sizeOf x-1))]
masks = iterate (*0x100) 0xff
fst4 :: (a, b, c, d) -> a
fst4 (x, _, _, _) = x