about summary refs log tree commit diff stats
path: root/src/miasm/jitter/jitcore_gcc.py
diff options
context:
space:
mode:
authorTheofilos Augoustis <theofilos.augoustis@gmail.com>2025-10-14 09:09:29 +0000
committerTheofilos Augoustis <theofilos.augoustis@gmail.com>2025-10-14 09:09:29 +0000
commit579cf1d03fb932083e6317967d1613d5c2587fb6 (patch)
tree629f039935382a2a7391bce9253f6c9968159049 /src/miasm/jitter/jitcore_gcc.py
parent51c15d3ea2e16d4fc5f0f01a3b9befc66b1f982e (diff)
downloadfocaccia-miasm-579cf1d03fb932083e6317967d1613d5c2587fb6.tar.gz
focaccia-miasm-579cf1d03fb932083e6317967d1613d5c2587fb6.zip
Convert to src-layout ta/nix
Diffstat (limited to 'src/miasm/jitter/jitcore_gcc.py')
-rw-r--r--src/miasm/jitter/jitcore_gcc.py141
1 files changed, 141 insertions, 0 deletions
diff --git a/src/miasm/jitter/jitcore_gcc.py b/src/miasm/jitter/jitcore_gcc.py
new file mode 100644
index 00000000..958c9d13
--- /dev/null
+++ b/src/miasm/jitter/jitcore_gcc.py
@@ -0,0 +1,141 @@
+#-*- coding:utf-8 -*-
+
+import sys
+import os
+import tempfile
+import ctypes
+import _ctypes
+import platform
+import sysconfig
+from subprocess import check_call
+from miasm.jitter import Jitgcc
+from miasm.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"
+
+    def __init__(self, lifter, bin_stream):
+        super(JitCore_Gcc, self).__init__(lifter, bin_stream)
+        self.exec_wrapper = Jitgcc.gcc_exec_block
+
+    def deleteCB(self, offset):
+        """Free the state associated to @offset and delete it
+        @offset: gcc state offset
+        """
+        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):
+        lib = ctypes.cdll.LoadLibrary(fname_so)
+        func = getattr(lib, self.FUNCNAME)
+        addr = ctypes.cast(func, ctypes.c_void_p).value
+        offset = self.lifter.loc_db.get_location_offset(label)
+        self.offset_to_jitted_func[offset] = addr
+        self.states[offset] = lib
+
+    def add_block(self, block):
+        """Add a block to JiT and JiT it.
+        @block: block to jit
+        """
+        block_hash = self.hash_block(block)
+        ext = sysconfig.get_config_var('EXT_SUFFIX')
+        if ext is None:
+            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)
+
+            # Create unique C file
+            fdesc, fname_in = tempfile.mkstemp(suffix=".c")
+            os.write(fdesc, func_code.encode())
+            os.close(fdesc)
+
+            # Create unique SO file
+            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]
+            if is_win:
+                libs.append(
+                    os.path.join(
+                        sysconfig.get_paths()['include'],
+                        "..",
+                        "libs",
+                        "python%d%d.lib" % (sys.version_info.major, sys.version_info.minor)
+                    )
+                )
+                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
+            try:
+                os.rename(fname_tmp, fname_out)
+            except WindowsError as 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)
+
+    @staticmethod
+    def gen_C_source(lifter, func_code):
+        c_source = ""
+        c_source += "\n".join(func_code)
+
+        c_source = gen_core(lifter.arch, lifter.attrib) + c_source
+        c_source = "#define PARITY_IMPORT\n#include <Python.h>\n" + c_source
+        return c_source