1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
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
|