Miasm2
 All Classes Namespaces Files Functions Variables Typedefs Properties Macros
jitcore_llvm.py
Go to the documentation of this file.
1 import os
2 import importlib
3 import hashlib
4 from miasm2.jitter.llvmconvert import *
5 import miasm2.jitter.jitcore as jitcore
6 import Jitllvm
7 
8 
10 
11  "JiT management, using LLVM as backend"
12 
13  # Architecture dependant libraries
14  arch_dependent_libs = {"x86": "JitCore_x86.so",
15  "arm": "JitCore_arm.so",
16  "msp430": "JitCore_msp430.so",
17  "mips32": "JitCore_mips32.so"}
18 
19  def __init__(self, ir_arch, bs=None):
20  super(JitCore_LLVM, self).__init__(ir_arch, bs)
21 
22  self.options.update({"safe_mode": False, # Verify each function
23  "optimise": False, # Optimise functions
24  "log_func": False, # Print LLVM functions
25  "log_assembly": False, # Print assembly executed
26  "cache_ir": None # SaveDir for cached .ll
27  })
28 
29  self.exec_wrapper = Jitllvm.llvm_exec_bloc
30  self.exec_engines = []
31  self.ir_arch = ir_arch
32 
33  def load(self):
34 
35  # Library to load within Jit context
36  libs_to_load = []
37 
38  # Get architecture dependant Jitcore library (if any)
39  lib_dir = os.path.dirname(os.path.realpath(__file__))
40  lib_dir = os.path.join(lib_dir, 'arch')
41  try:
42  jit_lib = os.path.join(
43  lib_dir, self.arch_dependent_libs[self.ir_arch.arch.name])
44  libs_to_load.append(jit_lib)
45  except KeyError:
46  pass
47 
48  # Create a context
49  self.context = LLVMContext_JIT(libs_to_load)
50 
51  # Set the optimisation level
52  self.context.optimise_level()
53 
54  # Save the current architecture parameters
55  self.arch = self.ir_arch.arch
56 
57  # Get the correspondance between registers and vmcpu struct
58  mod_name = "miasm2.jitter.arch.JitCore_%s" % (self.ir_arch.arch.name)
59  mod = importlib.import_module(mod_name)
60  self.context.set_vmcpu(mod.get_gpreg_offset_all())
61 
62  # Save module base
63  self.mod_base_str = str(self.context.mod)
64 
65  # Set IRs transformation to apply
66  self.context.set_IR_transformation(self.ir_arch.expr_fix_regs_for_mode)
67 
68  def add_bloc(self, bloc):
69 
70  # Search in IR cache
71  if self.options["cache_ir"] is not None:
72 
73  # /!\ This part is under development
74  # Use it at your own risk
75 
76  # Compute Hash : label + bloc binary
77  func_name = bloc.label.name
78  to_hash = func_name
79 
80  # Get binary from bloc
81  for line in bloc.lines:
82  b = line.b
83  to_hash += b
84 
85  # Compute Hash
86  md5 = hashlib.md5(to_hash).hexdigest()
87 
88  # Try to load the function from cache
89  filename = self.options["cache_ir"] + md5 + ".ll"
90 
91  try:
92  fcontent = open(filename)
93  content = fcontent.read()
94  fcontent.close()
95 
96  except IOError:
97  content = None
98 
99  if content is None:
100  # Compute the IR
101  super(JitCore_LLVM, self).add_bloc(bloc)
102 
103  # Save it
104  fdest = open(filename, "w")
105  dump = str(self.context.mod.get_function_named(func_name))
106  my = "declare i16 @llvm.bswap.i16(i16) nounwind readnone\n"
107 
108  fdest.write(self.mod_base_str + my + dump)
109  fdest.close()
110 
111  else:
112  import llvm.core as llvm_c
113  import llvm.ee as llvm_e
114  my_mod = llvm_c.Module.from_assembly(content)
115  func = my_mod.get_function_named(func_name)
116  exec_en = llvm_e.ExecutionEngine.new(my_mod)
117  self.exec_engines.append(exec_en)
118 
119  # We can use the same exec_engine
120  ptr = self.exec_engines[0].get_pointer_to_function(func)
121 
122  # Store a pointer on the function jitted code
123  self.lbl2jitbloc[bloc.label.offset] = ptr
124 
125  else:
126  super(JitCore_LLVM, self).add_bloc(bloc)
127 
128  def jitirblocs(self, label, irblocs):
129 
130  # Build a function in the context
131  func = LLVMFunction(self.context, label.name)
132 
133  # Set log level
134  func.log_regs = self.log_regs
135  func.log_mn = self.log_mn
136 
137  # Import irblocs
138  func.from_blocs(irblocs)
139 
140  # Verify
141  if self.options["safe_mode"] is True:
142  func.verify()
143 
144  # Optimise
145  if self.options["optimise"] is True:
146  func.optimise()
147 
148  # Log
149  if self.options["log_func"] is True:
150  print func
151  if self.options["log_assembly"] is True:
152  print func.get_assembly()
153 
154  # Store a pointer on the function jitted code
155  self.lbl2jitbloc[label.offset] = func.get_function_pointer()