diff options
| author | Theofilos Augoustis <theofilos.augoustis@gmail.com> | 2025-10-14 09:09:29 +0000 |
|---|---|---|
| committer | Theofilos Augoustis <theofilos.augoustis@gmail.com> | 2025-10-14 09:09:29 +0000 |
| commit | 579cf1d03fb932083e6317967d1613d5c2587fb6 (patch) | |
| tree | 629f039935382a2a7391bce9253f6c9968159049 /src/miasm/jitter/jitcore_gcc.py | |
| parent | 51c15d3ea2e16d4fc5f0f01a3b9befc66b1f982e (diff) | |
| download | focaccia-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.py | 141 |
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 |