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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
|
#!/usr/bin/env python
#-*- coding:utf-8 -*-
import os
from distutils.sysconfig import get_python_inc
from subprocess import Popen, PIPE
from hashlib import md5
import tempfile
from miasm2.jitter import jitcore, Jittcc
def jit_tcc_compil(func_name, func_code):
global Jittcc
c = Jittcc.tcc_compil(func_name, func_code)
return c
def gen_core(arch, attrib):
lib_dir = os.path.dirname(os.path.realpath(__file__))
txt = ""
txt += '#include "%s/queue.h"\n' % lib_dir
txt += '#include "%s/vm_mngr.h"\n' % lib_dir
txt += '#include "%s/vm_mngr_py.h"\n' % lib_dir
txt += '#include "%s/JitCore.h"\n' % lib_dir
txt += '#include "%s/arch/JitCore_%s.h"\n' % (lib_dir, arch.name)
txt += r'''
#define RAISE(errtype, msg) {PyObject* p; p = PyErr_Format( errtype, msg ); return p;}
'''
return txt
def gen_C_source(ir_arch, func_code):
c_source = ""
c_source += "\n".join(func_code)
c_source = gen_core(ir_arch.arch, ir_arch.attrib) + c_source
c_source = """
#ifdef __x86_64__
#ifndef __LP64__
/*
for ubuntu ?!? XXX TODO
/!\ force 64 bit system using 64 bits libc
change this to __ILP32__ to do so.
*/
#define __LP64__
#endif
#endif
""" + "#include <Python.h>\n" + c_source
return c_source
class myresolver:
def __init__(self, offset):
self.offset = offset
def ret(self):
return "return PyLong_FromUnsignedLongLong(0x%X);" % self.offset
from miasm2.core.utils import keydefaultdict
class resolver:
def __init__(self):
self.resolvers = keydefaultdict(myresolver)
def get_resolver(self, offset):
return self.resolvers[offset]
class JitCore_Tcc(jitcore.JitCore):
"JiT management, using LibTCC as backend"
def __init__(self, ir_arch, bs=None):
self.jitted_block_delete_cb = self.deleteCB
super(JitCore_Tcc, self).__init__(ir_arch, bs)
self.resolver = resolver()
self.exec_wrapper = Jittcc.tcc_exec_bloc
self.tcc_states = {}
self.ir_arch = ir_arch
self.tempdir = os.path.join(tempfile.gettempdir(), "miasm_gcc_cache")
try:
os.mkdir(self.tempdir, 0755)
except OSError:
pass
def deleteCB(self, offset):
"Free the TCCState corresponding to @offset"
if offset in self.tcc_states:
Jittcc.tcc_end(self.tcc_states[offset])
del self.tcc_states[offset]
def load(self):
# os.path.join(os.path.dirname(os.path.realpath(__file__)), "jitter")
lib_dir = os.path.dirname(os.path.realpath(__file__))
libs = []
libs.append(os.path.join(lib_dir, 'VmMngr.so'))
libs.append(
os.path.join(lib_dir, 'arch/JitCore_%s.so' % (self.ir_arch.arch.name)))
libs = ';'.join(libs)
jittcc_path = Jittcc.__file__
include_dir = os.path.dirname(jittcc_path)
include_dir += ";" + os.path.join(include_dir, "arch")
# print include_dir
# XXX HACK
# As debian/ubuntu have moved some include files using arch directory,
# TCC doesn't know them, so we get the info from GCC
# For example /usr/include/x86_64-linux-gnu which contains limits.h
p = Popen(["cc", "-Wp,-v", "-E", "-"],
stdout=PIPE, stderr=PIPE, stdin=PIPE)
p.stdin.close()
include_files = p.stderr.read().split('\n')
include_files = [x[1:]
for x in include_files if x.startswith(' /usr/include')]
include_files += [include_dir, get_python_inc()]
include_files = ";".join(include_files)
Jittcc.tcc_set_emul_lib_path(include_files, libs)
def init_codegen(self, codegen):
"""
Get the code generator @codegen
@codegen: an CGen instance
"""
self.codegen = codegen
def __del__(self):
for tcc_state in self.tcc_states.values():
Jittcc.tcc_end(tcc_state)
def label2fname(self, label):
"""
Generate function name from @label
@label: asm_label instance
"""
return "block_%s" % label.name
def compil_code(self, block, func_code):
"""
Compil the C code of @func_code from @block
@block: original asm_block
@func_code: C code of the block
"""
label = block.label
self.jitcount += 1
tcc_state, mcode = jit_tcc_compil(self.label2fname(label), func_code)
self.lbl2jitbloc[label.offset] = mcode
self.tcc_states[label.offset] = tcc_state
def gen_c_code(self, label, block):
"""
Return the C code corresponding to the @irblocks
@label: asm_label of the block to jit
@irblocks: list of irblocks
"""
f_name = self.label2fname(label)
f_declaration = 'int %s(block_id * BlockDst, JitCpu* jitcpu)' % f_name
out = self.codegen.gen_c(block, log_mn=self.log_mn, log_regs=self.log_regs)
out = [f_declaration + '{'] + out + ['}\n']
c_code = out
return gen_C_source(self.ir_arch, c_code)
def add_bloc(self, block):
"""Add a bloc to JiT and JiT it.
@block: block to jit
"""
block_raw = "".join(line.b for line in block.lines)
block_hash = md5("%X_%s_%s_%s" % (block.label.offset,
self.log_mn,
self.log_regs,
block_raw)).hexdigest()
fname_out = os.path.join(self.tempdir, "%s.c" % block_hash)
if os.access(fname_out, os.R_OK):
func_code = open(fname_out).read()
else:
func_code = self.gen_c_code(block.label, block)
# Create unique C file
fdesc, fname_tmp = tempfile.mkstemp(suffix=".c")
os.write(fdesc, func_code)
os.close(fdesc)
os.rename(fname_tmp, fname_out)
self.compil_code(block, func_code)
|