packages feed

x86-64bit 0.1.3 → 0.1.4

raw patch · 7 files changed

+279/−222 lines, 7 files

Files

CHANGELOG.md view
@@ -1,3 +1,10 @@+# Version 0.1.4
+
+-   OS X operating system support (Balázs Kőműves)
+-   better show for db
+-   bugfix
+    -   save flags in traceReg
+
 # Version 0.1.3
 
 -   jmpq instruction support (George Stelle)
CodeGen/X86.hs view
@@ -1,4 +1,3 @@-{-# language CPP #-}
 {-# language PatternSynonyms #-}
 module CodeGen.X86
     (
@@ -58,9 +57,6 @@     , runTests
     , CString (..)
     , traceReg
-#ifdef linux_HOST_OS
-    , memalign
-#endif
     , printf
     ) where
 
CodeGen/X86/Asm.hs view
@@ -538,7 +538,11 @@     Std   -> showOp0 "std"      Align s -> codeLine $ ".align " ++ show s-    Data (Bytes x) -> showOp "db" $ intercalate ", " (showByte <$> x) ++ "  ; " ++ show (toEnum . fromIntegral <$> x :: String)+    Data (Bytes x)+        | 2 * length (filter isPrint x) > length x -> showOp "db" $ show (toEnum . fromIntegral <$> x :: String)+        | otherwise -> showOp "db" $ intercalate ", " (show <$> x)+      where+        isPrint c = c >= 32 && c <= 126  showOp0 s = codeLine s showOp s a = showOp0 $ s ++ " " ++ a
CodeGen/X86/CallConv.hs view
@@ -1,95 +1,112 @@-
--- | Calling conventions. There are basically only two: System V (Linux, OSX, BSD) and Win64\/fastcall
-
-{-# language CPP #-}
-{-# language BangPatterns #-}
-{-# language DataKinds #-}
-module CodeGen.X86.CallConv where
-
-import Foreign
-import Data.Monoid
-import CodeGen.X86.Asm
-
------------------------------------------------------------------------------- 
-
-#if defined (mingw32_HOST_OS) || defined (mingw64_HOST_OS)
-
--- On Win64 the caller have to reserve 32 byte "shadow space" on the stack (and clean up after)
-callFun :: Operand S64 RW -> FunPtr a -> Code
-callFun r p 
-  =  Sub rsp (imm 32) 
-  <> Mov r (imm $ fromIntegral $ ptrToIntPtr $ castFunPtrToPtr p) 
-  <> Call r 
-  <> Add rsp (imm 32)
-
-#else
-
--- helper to call a function
-callFun :: Operand S64 RW -> FunPtr a -> Code
-callFun r p = Mov r (imm $ fromIntegral $ ptrToIntPtr $ castFunPtrToPtr p) <> Call r
-
-#endif
-
------------------------------------------------------------------------------- 
-
--- | Save the non-volatile registers 
---
--- Note: R12..R15 should be preserved on both Windows and Linux.
--- This is the responsability of the user (this won't save them).
---
-saveNonVolatile :: Code -> Code
-saveNonVolatile code = prologue <> code <> epilogue <> Ret
-
------------------------------------------------------------------------------- 
--- calling conventions
-
-#if defined (mingw32_HOST_OS) || defined (mingw64_HOST_OS)
-
----------- Win64 calling convention ----------
-
-arg1 = rcx
-arg2 = rdx
-arg3 = r8
-arg4 = r9
--- rest of the arguments on the stack
-
-result = rax
-
-prologue 
-    =  Push rbp
-    <> Push rbx
-    <> Push rdi
-    <> Push rsi
-
-epilogue
-    =  Pop rsi
-    <> Pop rdi
-    <> Pop rbx
-    <> Pop rbp 
-
-#elif defined (linux_HOST_OS)
-
----------- System V calling convention ----------
-
-arg1 = rdi
-arg2 = rsi
-arg3 = rdx
-arg4 = rcx
-arg5 = r8
-arg6 = r9
--- rest of the arguments on the stack
-
-result = rax
-
-prologue 
-    =  Push rbp
-    <> Push rbx
-
-epilogue
-    =  Pop rbx
-    <> Pop rbp  
-
-#endif
-
------------------------------------------------------------------------------- 
-
++-- | Calling conventions. There are basically only two: System V (Linux, OSX, BSD) and Win64\/fastcall++{-# language CPP #-}+{-# language BangPatterns #-}+{-# language DataKinds #-}+module CodeGen.X86.CallConv where++import Foreign+import Data.Monoid+import CodeGen.X86.Asm++------------------------------------------------------------------------------ ++#if defined (mingw32_HOST_OS) || defined (mingw64_HOST_OS)++-- On Win64 the caller have to reserve 32 byte "shadow space" on the stack (and clean up after)+callFun :: Operand S64 RW -> FunPtr a -> Code+callFun r p +  =  Sub rsp (imm 32) +  <> Mov r (imm $ fromIntegral $ ptrToIntPtr $ castFunPtrToPtr p) +  <> Call r +  <> Add rsp (imm 32)++#elif defined (darwin_HOST_OS)++-- OSX requires 16 byte alignment of the stack...+callFun :: Operand S64 RW -> FunPtr a -> Code+callFun r p +  =  Push r15              -- we will use r15 (non-volatile) to store old rsp+  <> Mov r15 (imm 15)      -- 0xf+  <> Not r15               -- 0xffff ... fff0+  <> And r15 rsp           -- align rsp into r15+  <> Xchg r15 rsp          -- new rsp = aligned, r15 = old rsp+  <> Mov r (imm $ fromIntegral $ ptrToIntPtr $ castFunPtrToPtr p) +  <> Call r +  <> Mov rsp r15           -- restore rsp+  <> Pop r15               -- restore r15++#else++-- helper to call a function+callFun :: Operand S64 RW -> FunPtr a -> Code+callFun r p +  =  Mov r (imm $ fromIntegral $ ptrToIntPtr $ castFunPtrToPtr p) +  <> Call r++#endif++------------------------------------------------------------------------------ ++-- | Save the non-volatile registers +--+-- Note: R12..R15 should be preserved on both Windows and Linux.+-- This is the responsability of the user (this won't save them).+--+saveNonVolatile :: Code -> Code+saveNonVolatile code = prologue <> code <> epilogue <> Ret++------------------------------------------------------------------------------ +-- calling conventions++#if defined (mingw32_HOST_OS) || defined (mingw64_HOST_OS)++---------- Win64 calling convention ----------++arg1 = rcx+arg2 = rdx+arg3 = r8+arg4 = r9+-- rest of the arguments on the stack++result = rax++prologue +    =  Push rbp+    <> Push rbx+    <> Push rdi+    <> Push rsi++epilogue+    =  Pop rsi+    <> Pop rdi+    <> Pop rbx+    <> Pop rbp ++#else++---------- System V calling convention ----------++arg1 = rdi+arg2 = rsi+arg3 = rdx+arg4 = rcx+arg5 = r8+arg6 = r9+-- rest of the arguments on the stack++result = rax++prologue +    =  Push rbp+    <> Push rbx++epilogue+    =  Pop rbx+    <> Pop rbp  ++#endif++------------------------------------------------------------------------------ +
CodeGen/X86/FFI.hs view
@@ -1,119 +1,152 @@-{-# language CPP #-}
-{-# language ForeignFunctionInterface #-}
-{-# language BangPatterns #-}
-{-# language ViewPatterns #-}
-{-# language FlexibleInstances #-}
-module CodeGen.X86.FFI where
-
--------------------------------------------------------
-
-import Control.Monad
-import Control.Exception (evaluate)
-import Foreign
-import Foreign.C.Types
-import Foreign.ForeignPtr
-import Foreign.ForeignPtr.Unsafe
-import System.IO.Unsafe
-
-import CodeGen.X86.Asm
-import CodeGen.X86.CodeGen
-
--------------------------------------------------------
-
-#define PAGE_SIZE 4096
-
-#if defined (mingw32_HOST_OS) || defined (mingw64_HOST_OS) 
-
-import System.Win32.Types
-import System.Win32.Mem
-import Foreign.Marshal.Alloc
-
-#endif
-
--------------------------------------------------------
-
-foreign import ccall "dynamic" callWord64           :: FunPtr Word64                -> Word64
-foreign import ccall "dynamic" callWord32           :: FunPtr Word32                -> Word32
-foreign import ccall "dynamic" callWord16           :: FunPtr Word16                -> Word16
-foreign import ccall "dynamic" callWord8            :: FunPtr Word8                 -> Word8
-foreign import ccall "dynamic" callBool             :: FunPtr Bool                  -> Bool
-foreign import ccall "dynamic" callIOUnit           :: FunPtr (IO ())               -> IO ()
-foreign import ccall "dynamic" callWord64_Word64    :: FunPtr (Word64 -> Word64)    -> Word64 -> Word64
-foreign import ccall "dynamic" callPtr_Word64       :: FunPtr (Ptr a -> Word64)     -> Ptr a -> Word64
-
-unsafeCallForeignPtr0 call p = unsafePerformIO $ evaluate (call (castPtrToFunPtr $ unsafeForeignPtrToPtr p)) <* touchForeignPtr p
-
-unsafeCallForeignPtr1 call p a = unsafePerformIO $ evaluate (call (castPtrToFunPtr $ unsafeForeignPtrToPtr p) a) <* touchForeignPtr p
-
-unsafeCallForeignPtrIO0 call p = call (castPtrToFunPtr $ unsafeForeignPtrToPtr p) <* touchForeignPtr p
-
-
-class Callable a where unsafeCallForeignPtr :: ForeignPtr a -> a
-
-instance Callable Word64                where unsafeCallForeignPtr = unsafeCallForeignPtr0 callWord64
-instance Callable Word32                where unsafeCallForeignPtr = unsafeCallForeignPtr0 callWord32
-instance Callable Word16                where unsafeCallForeignPtr = unsafeCallForeignPtr0 callWord16
-instance Callable Word8                 where unsafeCallForeignPtr = unsafeCallForeignPtr0 callWord8
-instance Callable Bool                  where unsafeCallForeignPtr = unsafeCallForeignPtr0 callBool
-instance Callable (IO ())               where unsafeCallForeignPtr = unsafeCallForeignPtrIO0 callIOUnit
-instance Callable (Word64 -> Word64)    where unsafeCallForeignPtr = unsafeCallForeignPtr1 callWord64_Word64
-instance Callable (Ptr a -> Word64)     where unsafeCallForeignPtr = unsafeCallForeignPtr1 callPtr_Word64
-
--------------------------------------------------------
-
-#if defined (mingw32_HOST_OS) || defined (mingw64_HOST_OS) 
--- note: GHC 64 bit also defines mingw32 ...
-
-foreign import ccall "static malloc.h  _aligned_malloc" c_aligned_malloc :: CSize -> CSize -> IO (Ptr a)
-foreign import ccall "static malloc.h  _aligned_free"   c_aligned_free   :: Ptr a -> IO ()
-foreign import ccall "static malloc.h &_aligned_free"   ptr_aligned_free :: FunPtr (Ptr a -> IO ())
-
-#elif defined linux_HOST_OS
-
-foreign import ccall "static stdlib.h memalign"   memalign :: CUInt -> CUInt -> IO (Ptr a)
-foreign import ccall "static stdlib.h &free"      stdfree  :: FunPtr (Ptr a -> IO ())
-foreign import ccall "static sys/mman.h mprotect" mprotect :: Ptr a -> CUInt -> Int -> IO Int
-
-#endif
-
--------------------------------------------------------
-
-#if defined (mingw32_HOST_OS) || defined (mingw64_HOST_OS) 
-
-flag_PAGE_EXECUTE_READWRITE :: Word32
-flag_PAGE_EXECUTE_READWRITE = 0x40 
-
-{-# NOINLINE compile #-}
-compile :: Callable a => Code -> a
-compile x = unsafeCallForeignPtr $ unsafePerformIO $ do
-    let (bytes, fromIntegral -> size) = buildTheCode x
-    arr <- c_aligned_malloc (fromIntegral size) PAGE_SIZE
-    _ <- virtualProtect (castPtr arr) (fromIntegral size) flag_PAGE_EXECUTE_READWRITE
-    forM_ [p | Right p <- bytes] $ uncurry $ pokeByteOff arr    
-    newForeignPtr ptr_aligned_free arr 
-
-#elif defined linux_HOST_OS
-
-{-# NOINLINE compile #-}
-compile :: Callable a => Code -> a
-compile x = unsafeCallForeignPtr $ unsafePerformIO $ do
-    let (bytes, fromIntegral -> size) = buildTheCode x
-    arr <- memalign PAGE_SIZE size
-    _ <- mprotect arr size 0x7 -- READ, WRITE, EXEC
-    forM_ [p | Right p <- bytes] $ uncurry $ pokeByteOff arr
-    newForeignPtr stdfree arr
-
-#endif
-
--------------------------------------------------------
-
-foreign import ccall "wrapper" createPtrWord64_Word64 :: (Word64 -> Word64) -> IO (FunPtr (Word64 -> Word64))
-
-class CallableHs a where createHsPtr :: a -> IO (FunPtr a)
-
-instance CallableHs (Word64 -> Word64) where createHsPtr = createPtrWord64_Word64
-
-hsPtr :: CallableHs a => a -> FunPtr a
-hsPtr x = unsafePerformIO $ createHsPtr x
-
-
+{-# language CPP #-}+{-# language ForeignFunctionInterface #-}+{-# language BangPatterns #-}+{-# language ViewPatterns #-}+{-# language FlexibleInstances #-}+module CodeGen.X86.FFI where++-------------------------------------------------------++import Control.Monad+import Control.Exception (evaluate)+import Foreign+import Foreign.C.Types+import Foreign.ForeignPtr+import Foreign.ForeignPtr.Unsafe+import System.IO.Unsafe++import CodeGen.X86.Asm+import CodeGen.X86.CodeGen++-------------------------------------------------------++-- this should be queried from the OS dynamically...+#define PAGE_SIZE 4096++#if defined (mingw32_HOST_OS) || defined (mingw64_HOST_OS) ++import System.Win32.Types+import System.Win32.Mem+import Foreign.Marshal.Alloc++#endif++-------------------------------------------------------++foreign import ccall "dynamic" callWord64           :: FunPtr Word64                -> Word64+foreign import ccall "dynamic" callWord32           :: FunPtr Word32                -> Word32+foreign import ccall "dynamic" callWord16           :: FunPtr Word16                -> Word16+foreign import ccall "dynamic" callWord8            :: FunPtr Word8                 -> Word8+foreign import ccall "dynamic" callBool             :: FunPtr Bool                  -> Bool+foreign import ccall "dynamic" callIOUnit           :: FunPtr (IO ())               -> IO ()+foreign import ccall "dynamic" callWord64_Word64    :: FunPtr (Word64 -> Word64)    -> Word64 -> Word64+foreign import ccall "dynamic" callPtr_Word64       :: FunPtr (Ptr a -> Word64)     -> Ptr a -> Word64++unsafeCallForeignPtr0 call p = unsafePerformIO $ evaluate (call (castPtrToFunPtr $ unsafeForeignPtrToPtr p)) <* touchForeignPtr p++unsafeCallForeignPtr1 call p a = unsafePerformIO $ evaluate (call (castPtrToFunPtr $ unsafeForeignPtrToPtr p) a) <* touchForeignPtr p++unsafeCallForeignPtrIO0 call p = call (castPtrToFunPtr $ unsafeForeignPtrToPtr p) <* touchForeignPtr p+++class Callable a where unsafeCallForeignPtr :: ForeignPtr a -> a++instance Callable Word64                where unsafeCallForeignPtr = unsafeCallForeignPtr0 callWord64+instance Callable Word32                where unsafeCallForeignPtr = unsafeCallForeignPtr0 callWord32+instance Callable Word16                where unsafeCallForeignPtr = unsafeCallForeignPtr0 callWord16+instance Callable Word8                 where unsafeCallForeignPtr = unsafeCallForeignPtr0 callWord8+instance Callable Bool                  where unsafeCallForeignPtr = unsafeCallForeignPtr0 callBool+instance Callable (IO ())               where unsafeCallForeignPtr = unsafeCallForeignPtrIO0 callIOUnit+instance Callable (Word64 -> Word64)    where unsafeCallForeignPtr = unsafeCallForeignPtr1 callWord64_Word64+instance Callable (Ptr a -> Word64)     where unsafeCallForeignPtr = unsafeCallForeignPtr1 callPtr_Word64++-------------------------------------------------------++#if defined (mingw32_HOST_OS) || defined (mingw64_HOST_OS) +-- note: GHC 64 bit also defines mingw32 ...++foreign import ccall "static malloc.h  _aligned_malloc" c_aligned_malloc :: CSize -> CSize -> IO (Ptr a)+foreign import ccall "static malloc.h  _aligned_free"   c_aligned_free   :: Ptr a -> IO ()+foreign import ccall "static malloc.h &_aligned_free"   ptr_aligned_free :: FunPtr (Ptr a -> IO ())++#elif defined (linux_HOST_OS)++-- on Linux too, we should use posix_memalign...+foreign import ccall "static stdlib.h memalign"   memalign :: CSize -> CSize -> IO (Ptr a)+foreign import ccall "static stdlib.h &free"      stdfree  :: FunPtr (Ptr a -> IO ())+foreign import ccall "static sys/mman.h mprotect" mprotect :: Ptr a -> CSize -> CInt -> IO CInt++#elif defined (darwin_HOST_OS) || defined (freebsd_HOST_OS) || defined (openbsd_HOST_OS) || defined (netbsd_HOST_OS) ++foreign import ccall "static stdlib.h posix_memalign"   posix_memalign :: Ptr (Ptr a) -> CSize -> CSize -> IO CInt+foreign import ccall "static stdlib.h &free"            stdfree        :: FunPtr (Ptr a -> IO ())+foreign import ccall "static sys/mman.h mprotect"       mprotect       :: Ptr a -> CSize -> CInt -> IO CInt++#endif++-------------------------------------------------------++#if defined (mingw32_HOST_OS) || defined (mingw64_HOST_OS) ++flag_PAGE_EXECUTE_READWRITE :: Word32+flag_PAGE_EXECUTE_READWRITE = 0x40 ++{-# NOINLINE compile #-}+compile :: Callable a => Code -> a+compile x = unsafeCallForeignPtr $ unsafePerformIO $ do+    let (bytes, fromIntegral -> size) = buildTheCode x+    arr <- c_aligned_malloc (fromIntegral size) PAGE_SIZE+    _ <- virtualProtect (castPtr arr) (fromIntegral size) flag_PAGE_EXECUTE_READWRITE+    forM_ [p | Right p <- bytes] $ uncurry $ pokeByteOff arr    +    newForeignPtr ptr_aligned_free arr ++#elif defined linux_HOST_OS++{-# NOINLINE compile #-}+compile :: Callable a => Code -> a+compile x = unsafeCallForeignPtr $ unsafePerformIO $ do+    let (bytes, fromIntegral -> size) = buildTheCode x+    arr <- memalign PAGE_SIZE size+    _ <- mprotect arr size 0x7 -- READ, WRITE, EXEC+    forM_ [p | Right p <- bytes] $ uncurry $ pokeByteOff arr+    newForeignPtr stdfree arr++#elif defined (darwin_HOST_OS) || defined (freebsd_HOST_OS) || defined (openbsd_HOST_OS) || defined (netbsd_HOST_OS) ++-- | This calls @posix_memalign()@+posixMemAlign +  :: CSize               -- ^ alignment+  -> CSize               -- ^ size+  -> IO (Ptr a)+posixMemAlign alignment size0 =+  alloca $ \pp -> do+    let a    = max alignment 8+        size = mod (size0 + a - 1) a      -- size *must* be a multiple of both alignment and sizeof(void*)+    res <- posix_memalign pp alignment size+    case res of+      0 -> peek pp+      _ -> error "posix_memalign failed"+      +{-# NOINLINE compile #-}+compile :: Callable a => Code -> a+compile x = unsafeCallForeignPtr $ unsafePerformIO $ do+    let (bytes, fromIntegral -> size) = buildTheCode x+    arr <- posixMemAlign PAGE_SIZE size+    _ <- mprotect arr size 0x7 -- READ, WRITE, EXEC+    forM_ [p | Right p <- bytes] $ uncurry $ pokeByteOff arr+    newForeignPtr stdfree arr++#endif++-------------------------------------------------------++foreign import ccall "wrapper" createPtrWord64_Word64 :: (Word64 -> Word64) -> IO (FunPtr (Word64 -> Word64))++class CallableHs a where createHsPtr :: a -> IO (FunPtr a)++instance CallableHs (Word64 -> Word64) where createHsPtr = createPtrWord64_Word64++hsPtr :: CallableHs a => a -> FunPtr a+hsPtr x = unsafePerformIO $ createHsPtr x++
CodeGen/X86/Utils.hs view
@@ -74,9 +74,9 @@ 
 traceReg :: IsSize s => String -> Operand s RW -> Code
 traceReg d r = 
-       push_all
+       PushF <> push_all
     <> mov' arg2 r <> leaData arg1 (CString $ show r ++ " = %" ++ s ++ d ++ "\n") <> Xor rax rax <> callFun r11 printf
-    <> pop_all
+    <> pop_all <> PopF
   where
     s = case size r of
         S8  -> "hh"
x86-64bit.cabal view
@@ -1,5 +1,5 @@ name:                x86-64bit
-version:             0.1.3
+version:             0.1.4
 homepage:            https://github.com/divipp/x86-64
 synopsis:            Runtime code generation for x86 64 bit machine code
 description:         The primary goal of x86-64bit is to provide a lightweight assembler for machine generated 64 bit x86 assembly instructions. See README.md for further details.