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
|
import os
import importlib
import hashlib
try:
from llvmconvert import *
except ImportError:
pass
import jitcore
import Jitllvm
class JitCore_LLVM(jitcore.JitCore):
"JiT management, using LLVM as backend"
# Architecture dependant libraries
arch_dependent_libs = {"x86": "JitCore_x86.so",
"arm": "JitCore_arm.so",
"msp430": "JitCore_msp430.so",
"mips32": "JitCore_mips32.so"}
def __init__(self, my_ir, bs=None):
super(JitCore_LLVM, self).__init__(my_ir, bs)
self.options.update({"safe_mode": False, # Verify each function
"optimise": False, # Optimise functions
"log_func": False, # Print LLVM functions
"log_assembly": False, # Print assembly executed
"cache_ir": None # SaveDir for cached .ll
})
self.exec_wrapper = Jitllvm.llvm_exec_bloc
self.exec_engines = []
def load(self, arch):
# Library to load within Jit context
libs_to_load = []
# Get architecture dependant Jitcore library (if any)
lib_dir = os.path.dirname(os.path.realpath(__file__))
lib_dir = os.path.join(lib_dir, 'arch')
try:
jit_lib = os.path.join(
lib_dir, self.arch_dependent_libs[arch.name])
libs_to_load.append(jit_lib)
except KeyError:
pass
# Create a context
self.context = LLVMContext_JIT(libs_to_load)
# Set the optimisation level
self.context.optimise_level()
# Save the current architecture parameters
self.arch = arch
# Get the correspondance between registers and vmcpu struct
mod_name = "miasm2.jitter.arch.JitCore_%s" % (arch.name)
mod = importlib.import_module(mod_name)
self.context.set_vmcpu(mod.get_gpreg_offset_all())
# Save module base
self.mod_base_str = str(self.context.mod)
# Set IRs transformation to apply
self.context.set_IR_transformation(self.my_ir.expr_fix_regs_for_mode)
def add_bloc(self, bloc):
# Search in IR cache
if self.options["cache_ir"] is not None:
# /!\ This part is under development
# Use it at your own risk
# Compute Hash : label + bloc binary
func_name = bloc.label.name
to_hash = func_name
# Get binary from bloc
for line in bloc.lines:
b = line.b
to_hash += b
# Compute Hash
md5 = hashlib.md5(to_hash).hexdigest()
# Try to load the function from cache
filename = self.options["cache_ir"] + md5 + ".ll"
try:
fcontent = open(filename)
content = fcontent.read()
fcontent.close()
except IOError:
content = None
if content is None:
# Compute the IR
super(JitCore_LLVM, self).add_bloc(bloc)
# Save it
fdest = open(filename, "w")
dump = str(self.context.mod.get_function_named(func_name))
my = "declare i16 @llvm.bswap.i16(i16) nounwind readnone\n"
fdest.write(self.mod_base_str + my + dump)
fdest.close()
else:
import llvm.core as llvm_c
import llvm.ee as llvm_e
my_mod = llvm_c.Module.from_assembly(content)
func = my_mod.get_function_named(func_name)
exec_en = llvm_e.ExecutionEngine.new(my_mod)
self.exec_engines.append(exec_en)
# We can use the same exec_engine
ptr = self.exec_engines[0].get_pointer_to_function(func)
# Store a pointer on the function jitted code
self.lbl2jitbloc[bloc.label.offset] = ptr
else:
super(JitCore_LLVM, self).add_bloc(bloc)
def jitirblocs(self, label, irblocs):
# Build a function in the context
func = LLVMFunction(self.context, label.name)
# Set log level
func.log_regs = self.log_regs
func.log_mn = self.log_mn
# Import irblocs
func.from_blocs(irblocs)
# 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()
# Store a pointer on the function jitted code
self.lbl2jitbloc[label.offset] = func.get_function_pointer()
|