about summary refs log tree commit diff stats
path: root/src/miasm/jitter/jitcore_llvm.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_llvm.py
parent51c15d3ea2e16d4fc5f0f01a3b9befc66b1f982e (diff)
downloadfocaccia-miasm-ta/nix.tar.gz
focaccia-miasm-ta/nix.zip
Convert to src-layout ta/nix
Diffstat (limited to 'src/miasm/jitter/jitcore_llvm.py')
-rw-r--r--src/miasm/jitter/jitcore_llvm.py144
1 files changed, 144 insertions, 0 deletions
diff --git a/src/miasm/jitter/jitcore_llvm.py b/src/miasm/jitter/jitcore_llvm.py
new file mode 100644
index 00000000..4f1871b2
--- /dev/null
+++ b/src/miasm/jitter/jitcore_llvm.py
@@ -0,0 +1,144 @@
+from __future__ import print_function
+import os
+import glob
+import importlib
+import tempfile
+import sysconfig
+
+from miasm.jitter.llvmconvert import *
+import miasm.jitter.jitcore as jitcore
+from miasm.jitter import Jitllvm
+import platform
+
+import llvmlite
+llvmlite.binding.load_library_permanently(Jitllvm.__file__)
+
+is_win = platform.system() == "Windows"
+
+class JitCore_LLVM(jitcore.JitCore):
+    "JiT management, using LLVM as backend"
+
+    # Architecture dependent libraries
+    arch_dependent_libs = {
+        "x86": "JitCore_x86",
+        "arm": "JitCore_arm",
+        "msp430": "JitCore_msp430",
+        "mips32": "JitCore_mips32",
+        "aarch64": "JitCore_aarch64",
+        "ppc32": "JitCore_ppc32",
+    }
+
+    def __init__(self, lifter, bin_stream):
+        super(JitCore_LLVM, self).__init__(lifter, bin_stream)
+
+        self.options.update(
+            {
+                "safe_mode": True,   # Verify each function
+                "optimise": True,     # Optimise functions
+                "log_func": False,    # Print LLVM functions
+                "log_assembly": False,  # Print assembly executed
+            }
+        )
+
+        self.exec_wrapper = Jitllvm.llvm_exec_block
+        self.lifter = lifter
+
+        # Cache temporary dir
+        self.tempdir = os.path.join(tempfile.gettempdir(), "miasm_cache")
+        try:
+            os.mkdir(self.tempdir, 0o755)
+        except OSError:
+            pass
+        if not os.access(self.tempdir, os.R_OK | os.W_OK):
+            raise RuntimeError(
+                'Cannot access cache directory %s ' % self.tempdir)
+
+    def load(self):
+
+        # Library to load within Jit context
+        libs_to_load = []
+
+        # Get architecture dependent Jitcore library (if any)
+        lib_dir = os.path.dirname(os.path.realpath(__file__))
+        ext = sysconfig.get_config_var('EXT_SUFFIX')
+        if ext is None:
+            ext = ".so" if not is_win else ".pyd"
+        if is_win:
+            # sysconfig.get_config_var('EXT_SUFFIX') is .pyd on Windows and need to be forced to .lib
+            # Additionally windows built libraries may have a name like VmMngr.cp38-win_amd64.lib
+            ext_files = glob.glob(os.path.join(lib_dir, "VmMngr.*pyd"))
+            if len(ext_files) == 1:
+                ext = os.path.basename(ext_files[0]).replace("VmMngr", "")
+        lib_dir = os.path.join(lib_dir, 'arch')
+        try:
+            jit_lib = os.path.join(
+                lib_dir, self.arch_dependent_libs[self.lifter.arch.name] + ext
+            )
+            libs_to_load.append(jit_lib)
+        except KeyError:
+            pass
+
+        # Create a context
+        self.context = LLVMContext_JIT(libs_to_load, self.lifter)
+
+        # Set the optimisation level
+        self.context.optimise_level()
+
+        # Save the current architecture parameters
+        self.arch = self.lifter.arch
+
+        # Get the correspondence between registers and vmcpu struct
+        mod_name = "miasm.jitter.arch.JitCore_%s" % (self.lifter.arch.name)
+        mod = importlib.import_module(mod_name)
+        self.context.set_vmcpu(mod.get_gpreg_offset_all())
+
+        # Enable caching
+        self.context.enable_cache()
+
+    def add_block(self, block):
+        """Add a block to JiT and JiT it.
+        @block: the block to add
+        """
+
+        block_hash = self.hash_block(block)
+        fname_out = os.path.join(self.tempdir, "%s.bc" % block_hash)
+
+        if not os.access(fname_out, os.R_OK):
+            # Build a function in the context
+            func = LLVMFunction(self.context, self.FUNCNAME)
+
+            # Set log level
+            func.log_regs = self.log_regs
+            func.log_mn = self.log_mn
+
+            # Import asm block
+            func.from_asmblock(block)
+
+            # Verify
+            if self.options["safe_mode"] is True:
+                func.verify()
+
+            # Optimise
+            if self.options["optimise"] is True:
+                func.optimise()
+
+            # Log
+            if self.options["log_func"] is True:
+                print(func)
+            if self.options["log_assembly"] is True:
+                print(func.get_assembly())
+
+            # Use propagate the cache filename
+            self.context.set_cache_filename(func, fname_out)
+
+            # Get a pointer on the function for JiT
+            ptr = func.get_function_pointer()
+
+        else:
+            # The cache file exists: function can be loaded from cache
+            ptr = self.context.get_ptr_from_cache(fname_out, self.FUNCNAME)
+
+        # Store a pointer on the function jitted code
+        loc_key = block.loc_key
+        offset = self.lifter.loc_db.get_location_offset(loc_key)
+        self.offset_to_jitted_func[offset] = ptr