about summary refs log tree commit diff stats
path: root/miasm2/jitter/jitcore_gcc.py
diff options
context:
space:
mode:
authorAxel Souchet <0vercl0k@tuxfamily.org>2018-09-09 06:11:00 -0700
committerserpilliere <serpilliere@users.noreply.github.com>2018-09-09 15:11:00 +0200
commit8e6b39d80e9f8db8389bd2a8106d0f64b91c19e9 (patch)
treedbf342089690704e89c10532b83d1d81709a49f4 /miasm2/jitter/jitcore_gcc.py
parente61116884ac7879db08313542c6c28a8b00297c5 (diff)
downloadmiasm-8e6b39d80e9f8db8389bd2a8106d0f64b91c19e9.tar.gz
miasm-8e6b39d80e9f8db8389bd2a8106d0f64b91c19e9.zip
Adds Windows support and AppVeyor CI (#835)
* Get miasm to work on Windows, also add AppVeyor CI

* Fix gcc jitter on Linux

* Make the dse_crackme tests work on Windows

* calling build and then install is less confusing than install twice

* fix os.rename race condition on Windows

* clean it up

* Clean up after the unused cl.exe's artifacts

* Use is_win instead of an additional check

* Fix issue on Windows where 'w' and 'wb' modes are different

* Address review feedback

* setuptools is actually not required, so reverting
Diffstat (limited to 'miasm2/jitter/jitcore_gcc.py')
-rw-r--r--miasm2/jitter/jitcore_gcc.py59
1 files changed, 50 insertions, 9 deletions
diff --git a/miasm2/jitter/jitcore_gcc.py b/miasm2/jitter/jitcore_gcc.py
index dbaa2a08..238f2239 100644
--- a/miasm2/jitter/jitcore_gcc.py
+++ b/miasm2/jitter/jitcore_gcc.py
@@ -4,11 +4,14 @@ import os
 import tempfile
 import ctypes
 import _ctypes
+import platform
 from subprocess import check_call
+from distutils.sysconfig import get_python_inc
 
 from miasm2.jitter import Jitgcc
 from miasm2.jitter.jitcore_cc_base import JitCore_Cc_Base, gen_core
 
+is_win = platform.system() == "Windows"
 
 class JitCore_Gcc(JitCore_Cc_Base):
     "JiT management, using a C compiler as backend"
@@ -21,7 +24,12 @@ class JitCore_Gcc(JitCore_Cc_Base):
         """Free the state associated to @offset and delete it
         @offset: gcc state offset
         """
-        _ctypes.dlclose(self.states[offset]._handle)
+        flib = None
+        if is_win:
+            flib = _ctypes.FreeLibrary
+        else:
+            flib = _ctypes.dlclose
+        flib(self.states[offset]._handle)
         del self.states[offset]
 
     def load_code(self, label, fname_so):
@@ -37,7 +45,8 @@ class JitCore_Gcc(JitCore_Cc_Base):
         @block: block to jit
         """
         block_hash = self.hash_block(block)
-        fname_out = os.path.join(self.tempdir, "%s.so" % block_hash)
+        ext = ".so" if not is_win else ".pyd"
+        fname_out = os.path.join(self.tempdir, "%s%s" % (block_hash, ext))
 
         if not os.access(fname_out, os.R_OK | os.X_OK):
             func_code = self.gen_c_code(block)
@@ -48,16 +57,49 @@ class JitCore_Gcc(JitCore_Cc_Base):
             os.close(fdesc)
 
             # Create unique SO file
-            fdesc, fname_tmp = tempfile.mkstemp(suffix=".so")
+            fdesc, fname_tmp = tempfile.mkstemp(suffix=ext)
             os.close(fdesc)
 
             inc_dir = ["-I%s" % inc for inc in self.include_files]
             libs = ["%s" % lib for lib in self.libs]
-            args = ["cc"] + ["-O3"] + [
-                "-shared", "-fPIC", fname_in, '-o', fname_tmp] + inc_dir + libs
-            check_call(args)
+            if is_win:
+                libs.append(os.path.join(get_python_inc(), "..", "libs", "python27.lib"))
+                cl = [
+                    "cl", "/nologo", "/W3", "/MP",
+                    "/Od", "/DNDEBUG", "/D_WINDOWS", "/Gm-", "/EHsc",
+                    "/RTC1", "/MD", "/GS",
+                    fname_in
+                ] + inc_dir + libs
+                cl += ["/link", "/DLL", "/OUT:" + fname_tmp]
+                out_dir, _ = os.path.split(fname_tmp)
+                check_call(cl, cwd = out_dir)
+                basename_out, _ = os.path.splitext(fname_tmp)
+                basename_in, _ = os.path.splitext(os.path.basename(fname_in))
+                for ext in ('.obj', '.exp', '.lib'):
+                    artifact_out_path = os.path.join(out_dir, basename_out + ext)
+                    if os.path.isfile(artifact_out_path):
+                        os.remove(artifact_out_path)
+                    artifact_in_path = os.path.join(out_dir, basename_in + ext)
+                    if os.path.isfile(artifact_in_path):
+                        os.remove(artifact_in_path)
+            else:
+                args = ["cc", "-O3", "-shared", "-fPIC", fname_in, "-o", fname_tmp] + inc_dir + libs
+                check_call(args)
+
             # Move temporary file to final file
-            os.rename(fname_tmp, fname_out)
+            try:
+                os.rename(fname_tmp, fname_out)
+            except WindowsError, e:
+                # On Windows, os.rename works slightly differently than on Linux; quoting the documentation:
+                # "On Unix, if dst exists and is a file, it will be replaced silently if the user has permission.
+                # The operation may fail on some Unix flavors if src and dst are on different filesystems.
+                # If successful, the renaming will be an atomic operation (this is a POSIX requirement).
+                # On Windows, if dst already exists, OSError will be raised even if it is a file; there may be no way
+                # to implement an atomic rename when dst names an existing file."
+                # [Error 183] Cannot create a file when that file already exists
+                if e.winerror != 183:
+                    raise
+                os.remove(fname_tmp)
             os.remove(fname_in)
 
         self.load_code(block.loc_key, fname_out)
@@ -68,6 +110,5 @@ class JitCore_Gcc(JitCore_Cc_Base):
         c_source += "\n".join(func_code)
 
         c_source = gen_core(ir_arch.arch, ir_arch.attrib) + c_source
-        c_source = "#include <Python.h>\n" + c_source
-
+        c_source = "#define PARITY_IMPORT\n#include <Python.h>\n" + c_source
         return c_source