Miasm2
 All Classes Namespaces Files Functions Variables Typedefs Properties Macros
llvmconvert.py
Go to the documentation of this file.
1 #
2 #
3 # Miasm2 Extension: #
4 # - Miasm2 IR to LLVM IR #
5 # - JiT #
6 #
7 # Requires: #
8 # - llvmpy (tested on v0.11.2) #
9 #
10 # Authors : Fabrice DESCLAUX (CEA/DAM), Camille MOUGEY (CEA/DAM) #
11 #
12 #
13 
14 import llvm
15 import llvm.core as llvm_c
16 import llvm.ee as llvm_e
17 import llvm.passes as llvm_p
18 import miasm2.expression.expression as m2_expr
19 import miasm2.jitter.csts as m2_csts
20 import miasm2.core.asmbloc as m2_asmbloc
21 
22 
23 class LLVMType(llvm_c.Type):
24 
25  "Handle LLVM Type"
26 
27  int_cache = {}
28 
29  @classmethod
30  def int(cls, size=32):
31  try:
32  return cls.int_cache[size]
33  except KeyError:
34  cls.int_cache[size] = llvm_c.Type.int(size)
35  return cls.int_cache[size]
36 
37  @classmethod
38  def pointer(cls, addr):
39  "Generic pointer for execution"
40  return llvm_e.GenericValue.pointer(addr)
41 
42  @classmethod
43  def generic(cls, e):
44  "Generic value for execution"
45  if isinstance(e, m2_expr.ExprInt):
46  return llvm_e.GenericValue.int(LLVMType.int(e.size), int(e.arg))
47  elif isinstance(e, llvm_e.GenericValue):
48  return e
49  else:
50  raise ValueError()
51 
52 
53 class LLVMContext():
54 
55  "Context for llvm binding. Stand for a LLVM Module"
56 
57  known_fc = {}
58 
59  def __init__(self, name="mod"):
60  "Initialize a context with a module named 'name'"
61  self.mod = llvm_c.Module.new(name)
62  self.pass_manager = llvm_p.FunctionPassManager.new(self.mod)
63  self.exec_engine = llvm_e.ExecutionEngine.new(self.mod)
64  self.add_fc(self.known_fc)
65 
66  def optimise_level(self, classic_passes=True, dead_passes=True):
67  """Set the optimisation level :
68  classic_passes :
69  - combine instruction
70  - reassociate
71  - global value numbering
72  - simplify cfg
73 
74  dead_passes :
75  - dead code
76  - dead store
77  - dead instructions
78  """
79 
80  # Set up the optimiser pipeline
81 
82  if classic_passes is True:
83  # self.pass_manager.add(llvm_p.PASS_INSTCOMBINE)
84  self.pass_manager.add(llvm_p.PASS_REASSOCIATE)
85  self.pass_manager.add(llvm_p.PASS_GVN)
86  self.pass_manager.add(llvm_p.PASS_SIMPLIFYCFG)
87 
88  if dead_passes is True:
89  self.pass_manager.add(llvm_p.PASS_DCE)
90  self.pass_manager.add(llvm_p.PASS_DSE)
91  self.pass_manager.add(llvm_p.PASS_DIE)
92 
93  self.pass_manager.initialize()
94 
95  def get_execengine(self):
96  "Return the Execution Engine associated with this context"
97  return self.exec_engine
98 
99  def get_passmanager(self):
100  "Return the Pass Manager associated with this context"
101  return self.exec_engine
102 
103  def get_module(self):
104  "Return the module associated with this context"
105  return self.mod
106 
107  def add_shared_library(self, filename):
108  "Load the shared library 'filename'"
109  return llvm_c.load_library_permanently(filename)
110 
111  def add_fc(self, fc):
112  "Add function into known_fc"
113 
114  for name, detail in fc.items():
115  self.mod.add_function(LLVMType.function(detail["ret"],
116  detail["args"]),
117  name)
118 
119 
121 
122  "Extend LLVMContext_JIT in order to handle memory management"
123 
124  def __init__(self, library_filenames, name="mod"):
125  "Init a LLVMContext object, and load the mem management shared library"
126  LLVMContext.__init__(self, name)
127  for lib_fname in library_filenames:
128  self.add_shared_library(lib_fname)
129  self.add_memlookups()
130  self.add_get_exceptionflag()
131  self.add_op()
132  self.add_log_functions()
133  self.vmcpu = {}
134 
135  def add_memlookups(self):
136  "Add MEM_LOOKUP functions"
137 
138  fc = {}
139  p8 = llvm_c.PointerType.pointer(LLVMType.int(8))
140  for i in [8, 16, 32, 64]:
141  fc["MEM_LOOKUP_%02d" % i] = {"ret": LLVMType.int(i),
142  "args": [p8,
143  LLVMType.int(64)]}
144 
145  fc["MEM_WRITE_%02d" % i] = {"ret": LLVMType.void(),
146  "args": [p8,
147  LLVMType.int(64),
148  LLVMType.int(i)]}
149 
150  self.add_fc(fc)
151 
153  "Add 'get_exception_flag' function"
154  p8 = llvm_c.PointerType.pointer(LLVMType.int(8))
155  self.add_fc({"get_exception_flag": {"ret": LLVMType.int(64),
156  "args": [p8]}})
157 
158  def add_op(self):
159  "Add operations functions"
160 
161  p8 = llvm_c.PointerType.pointer(LLVMType.int(8))
162  self.add_fc({"parity": {"ret": LLVMType.int(),
163  "args": [LLVMType.int()]}})
164  self.add_fc({"rot_left": {"ret": LLVMType.int(),
165  "args": [LLVMType.int(),
166  LLVMType.int(),
167  LLVMType.int()]}})
168  self.add_fc({"rot_right": {"ret": LLVMType.int(),
169  "args": [LLVMType.int(),
170  LLVMType.int(),
171  LLVMType.int()]}})
172 
173  self.add_fc({"segm2addr": {"ret": LLVMType.int(64),
174  "args": [p8,
175  LLVMType.int(64),
176  LLVMType.int(64)]}})
177 
178  for k in [8, 16]:
179  self.add_fc({"bcdadd_%s" % k: {"ret": LLVMType.int(k),
180  "args": [LLVMType.int(k),
181  LLVMType.int(k)]}})
182  self.add_fc({"bcdadd_cf_%s" % k: {"ret": LLVMType.int(k),
183  "args": [LLVMType.int(k),
184  LLVMType.int(k)]}})
185 
186  for k in [16, 32, 64]:
187  self.add_fc({"imod%s" % k: {"ret": LLVMType.int(k),
188  "args": [p8,
189  LLVMType.int(k),
190  LLVMType.int(k)]}})
191  self.add_fc({"idiv%s" % k: {"ret": LLVMType.int(k),
192  "args": [p8,
193  LLVMType.int(k),
194  LLVMType.int(k)]}})
195 
196  def add_log_functions(self):
197  "Add functions for state logging"
198 
199  p8 = llvm_c.PointerType.pointer(LLVMType.int(8))
200  self.add_fc({"dump_gpregs": {"ret": LLVMType.void(),
201  "args": [p8]}})
202 
203  def set_vmcpu(self, lookup_table):
204  "Set the correspondance between register name and vmcpu offset"
205 
206  self.vmcpu = lookup_table
207 
208  def set_IR_transformation(self, *args):
209  """Set a list of transformation to apply on expression before their
210  treatments.
211  args: function Expr(Expr)"""
213 
214 
215 class LLVMFunction():
216 
217  "Represent a llvm function"
218 
219  # Default logging values
220  log_mn = False
221  log_regs = False
222 
223  def __init__(self, llvm_context, name="fc"):
224  "Create a new function with name fc"
225  self.llvm_context = llvm_context
226  self.mod = self.llvm_context.get_module()
227 
228  self.my_args = [] # (Expr, LLVMType, Name)
229  self.ret_type = None
230  self.builder = None
231  self.entry_bbl = None
232 
233  self.branch_counter = 0
234  self.name = name
235 
236  def new_branch_name(self):
237  "Return a new branch name"
238 
239  self.branch_counter += 1
240  return "%s" % self.branch_counter
241 
242  def viewCFG(self):
243  "Show the CFG of the current function"
244  self.fc.viewCFG()
245 
246  def append_basic_block(self, label):
247  """Add a new basic block to the current function.
248  @label: str or asmlabel
249  Return the corresponding LLVM Basic Block"""
250  name = self.canonize_label_name(label)
251  bbl = self.fc.append_basic_block(name)
252  self.name2bbl[label] = bbl
253 
254  return bbl
255 
256  def init_fc(self):
257  "Init the function"
258 
259  # Build type for fc signature
260  fc_type = LLVMType.function(
261  self.ret_type, [k[1] for k in self.my_args])
262 
263  # Add fc in module
264  try:
265  fc = self.mod.add_function(fc_type, self.name)
266  except llvm.LLVMException:
267  # Overwrite the previous function
268  previous_fc = self.mod.get_function_named(self.name)
269  previous_fc.delete()
270  fc = self.mod.add_function(fc_type, self.name)
271 
272  # Name args
273  for i, a in enumerate(self.my_args):
274  fc.args[i].name = a[2]
275 
276  # Initialize local variable pool
277  self.local_vars = {}
279  for i, a in enumerate(self.my_args):
280  self.local_vars[a[2]] = fc.args[i]
281 
282  # Init cache
283  self.expr_cache = {}
284  self.main_stream = True
285  self.name2bbl = {}
286  self.offsets_jitted = set()
287 
288  # Function link
289  self.fc = fc
290 
291  # Add a first BasicBlock
292  self.entry_bbl = self.append_basic_block("entry")
293 
294  # Instruction builder
295  self.builder = llvm_c.Builder.new(self.entry_bbl)
296 
297  def CreateEntryBlockAlloca(self, var_type):
298  "Create an alloca instruction at the beginning of the current fc"
299  builder = self.builder
300  current_bbl = builder.basic_block
301  builder.position_at_end(self.entry_bbl)
302 
303  ret = builder.alloca(var_type)
304  builder.position_at_end(current_bbl)
305  return ret
306 
307  def get_ptr_by_expr(self, expr):
308  """"Return a pointer casted corresponding to ExprId expr. If it is not
309  already computed, compute it at the end of entry_bloc"""
310 
311  name = expr.name
312 
313  try:
314  # If the pointer has already been computed
315  ptr_casted = self.local_vars_pointers[name]
316 
317  except KeyError:
318  # Get current objects
319  builder = self.builder
320  current_bbl = builder.basic_block
321 
322  # Go at the right position
323  entry_bloc_bbl = self.entry_bbl
324  builder.position_at_end(entry_bloc_bbl)
325 
326  # Compute the pointer address
327  offset = self.llvm_context.vmcpu[name]
328 
329  # Pointer cast
330  ptr = builder.gep(self.local_vars["vmcpu"],
331  [llvm_c.Constant.int(LLVMType.int(),
332  offset)])
333  int_size = LLVMType.int(expr.size)
334  ptr_casted = builder.bitcast(ptr,
335  llvm_c.PointerType.pointer(int_size))
336  # Store in cache
337  self.local_vars_pointers[name] = ptr_casted
338 
339  # Reset builder
340  builder.position_at_end(current_bbl)
341 
342  return ptr_casted
343 
344  def clear_cache(self, regs_updated):
345  "Remove from the cache values which depends on regs_updated"
346 
347  regs_updated_set = set(regs_updated)
348 
349  for expr in self.expr_cache.keys():
350  if expr.get_r(True).isdisjoint(regs_updated_set) is not True:
351  self.expr_cache.pop(expr)
352 
353  def update_cache(self, name, value):
354  "Add 'name' = 'value' to the cache iff main_stream = True"
355 
356  if self.main_stream is True:
357  self.expr_cache[name] = value
358 
359  def add_ir(self, expr):
360  "Add a Miasm2 IR to the last bbl. Return the var created"
361 
362  if self.main_stream is True and expr in self.expr_cache:
363  return self.expr_cache[expr]
364 
365  builder = self.builder
366 
367  if isinstance(expr, m2_expr.ExprInt):
368  ret = llvm_c.Constant.int(LLVMType.int(expr.size), int(expr.arg))
369  self.update_cache(expr, ret)
370  return ret
371 
372  if isinstance(expr, m2_expr.ExprId):
373  name = expr.name
374  if not isinstance(name, str):
375  # Resolve label
376  offset = name.offset
377  ret = llvm_c.Constant.int(LLVMType.int(expr.size), offset)
378  self.update_cache(expr, ret)
379  return ret
380 
381  try:
382  # If expr.name is already known (args)
383  return self.local_vars[name]
384  except KeyError:
385  pass
386 
387  ptr_casted = self.get_ptr_by_expr(expr)
388 
389  var = builder.load(ptr_casted, name)
390  self.update_cache(expr, var)
391  return var
392 
393  if isinstance(expr, m2_expr.ExprOp):
394  op = expr.op
395 
396  if op == "parity":
397  fc_ptr = self.mod.get_function_named("parity")
398  arg = builder.zext(self.add_ir(expr.args[0]),
399  LLVMType.int())
400  ret = builder.call(fc_ptr, [arg])
401  ret = builder.trunc(ret, LLVMType.int(expr.size))
402  self.update_cache(expr, ret)
403  return ret
404 
405  if op in ["<<<", ">>>"]:
406  fc_name = "rot_left" if op == "<<<" else "rot_right"
407  fc_ptr = self.mod.get_function_named(fc_name)
408  args = [self.add_ir(arg) for arg in expr.args]
409  arg_size = expr.args[0].size
410  if arg_size < 32:
411  # Cast args
412  args = [builder.zext(arg, LLVMType.int(32))
413  for arg in args]
414  arg_size_cst = llvm_c.Constant.int(LLVMType.int(),
415  arg_size)
416  ret = builder.call(fc_ptr, [arg_size_cst] + args)
417  if arg_size < 32:
418  # Cast ret
419  ret = builder.trunc(ret, LLVMType.int(arg_size))
420  self.update_cache(expr, ret)
421  return ret
422 
423  if op == "bcdadd":
424  size = expr.args[0].size
425  fc_ptr = self.mod.get_function_named("bcdadd_%s" % size)
426  args = [self.add_ir(arg) for arg in expr.args]
427  ret = builder.call(fc_ptr, args)
428  self.update_cache(expr, ret)
429  return ret
430 
431  if op == "bcdadd_cf":
432  size = expr.args[0].size
433  fc_ptr = self.mod.get_function_named("bcdadd_cf_%s" % size)
434  args = [self.add_ir(arg) for arg in expr.args]
435  ret = builder.call(fc_ptr, args)
436  ret = builder.trunc(ret, LLVMType.int(expr.size))
437  self.update_cache(expr, ret)
438  return ret
439 
440  if op == "-":
441  zero = llvm_c.Constant.int(LLVMType.int(expr.size),
442  0)
443  ret = builder.sub(zero, self.add_ir(expr.args[0]))
444  self.update_cache(expr, ret)
445  return ret
446 
447  if op == "segm":
448  fc_ptr = self.mod.get_function_named("segm2addr")
449  args_casted = [builder.zext(self.add_ir(arg), LLVMType.int(64))
450  for arg in expr.args]
451  args = [self.local_vars["vmcpu"]] + args_casted
452  ret = builder.call(fc_ptr, args)
453  ret = builder.trunc(ret, LLVMType.int(expr.size))
454  self.update_cache(expr, ret)
455  return ret
456 
457  if op in ["imod", "idiv"]:
458  fc_ptr = self.mod.get_function_named(
459  "%s%s" % (op, expr.args[0].size))
460  args_casted = [self.add_ir(arg) for arg in expr.args]
461  args = [self.local_vars["vmcpu"]] + args_casted
462  ret = builder.call(fc_ptr, args)
463  self.update_cache(expr, ret)
464  return ret
465 
466  if len(expr.args) > 1:
467 
468  if op == "*":
469  callback = builder.mul
470  elif op == "+":
471  callback = builder.add
472  elif op == "&":
473  callback = builder.and_
474  elif op == "^":
475  callback = builder.xor
476  elif op == "|":
477  callback = builder.or_
478  elif op == ">>":
479  callback = builder.lshr
480  elif op == "<<":
481  callback = builder.shl
482  elif op == "a>>":
483  callback = builder.ashr
484  elif op == "udiv":
485  callback = builder.udiv
486  elif op == "umod":
487  callback = builder.urem
488  else:
489  raise NotImplementedError('Unknown op: %s' % op)
490 
491  last = self.add_ir(expr.args[0])
492 
493  for i in range(1, len(expr.args)):
494  last = callback(last,
495  self.add_ir(expr.args[i]))
496 
497  self.update_cache(expr, last)
498 
499  return last
500 
501  raise NotImplementedError()
502 
503  if isinstance(expr, m2_expr.ExprMem):
504 
505  fc_name = "MEM_LOOKUP_%02d" % expr.size
506  fc_ptr = self.mod.get_function_named(fc_name)
507  addr_casted = builder.zext(self.add_ir(expr.arg),
508  LLVMType.int(64))
509 
510  ret = builder.call(fc_ptr, [self.local_vars["vmmngr"],
511  addr_casted])
512 
513  # Do not update memory cache to avoid pointer collision
514  return ret
515 
516  if isinstance(expr, m2_expr.ExprCond):
517  # Compute cond
518  cond = self.add_ir(expr.cond)
519  zero_casted = llvm_c.Constant.int(LLVMType.int(expr.cond.size),
520  0)
521  condition_bool = builder.icmp(llvm_c.ICMP_NE, cond,
522  zero_casted)
523 
524  # Alloc return var
525  alloca = self.CreateEntryBlockAlloca(LLVMType.int(expr.size))
526 
527  # Create bbls
528  branch_id = self.new_branch_name()
529  then_block = self.append_basic_block('then%s' % branch_id)
530  else_block = self.append_basic_block('else%s' % branch_id)
531  merge_block = self.append_basic_block('ifcond%s' % branch_id)
532 
533  builder.cbranch(condition_bool, then_block, else_block)
534 
535  # Deactivate object caching
536  current_main_stream = self.main_stream
537  self.main_stream = False
538 
539  # Then Bloc
540  builder.position_at_end(then_block)
541  then_value = self.add_ir(expr.src1)
542  builder.store(then_value, alloca)
543  builder.branch(merge_block)
544 
545  # Else Bloc
546  builder.position_at_end(else_block)
547  else_value = self.add_ir(expr.src2)
548  builder.store(else_value, alloca)
549  builder.branch(merge_block)
550 
551  # Merge bloc
552  builder.position_at_end(merge_block)
553  ret = builder.load(alloca)
554 
555  # Reactivate object caching
556  self.main_stream = current_main_stream
557 
558  self.update_cache(expr, ret)
559  return ret
560 
561  if isinstance(expr, m2_expr.ExprSlice):
562 
563  src = self.add_ir(expr.arg)
564 
565  # Remove trailing bits
566  if expr.start != 0:
567  to_shr = llvm_c.Constant.int(LLVMType.int(expr.arg.size),
568  expr.start)
569  shred = builder.lshr(src,
570  to_shr)
571  else:
572  shred = src
573 
574  # Remove leading bits
575  to_and = llvm_c.Constant.int(LLVMType.int(expr.arg.size),
576  (1 << (expr.stop - expr.start)) - 1)
577  anded = builder.and_(shred,
578  to_and)
579 
580  # Cast into e.size
581  ret = builder.trunc(anded,
582  LLVMType.int(expr.size))
583 
584  self.update_cache(expr, ret)
585  return ret
586 
587  if isinstance(expr, m2_expr.ExprCompose):
588 
589  args = []
590 
591  # Build each part
592  for arg in expr.args:
593  src, start, stop = arg
594 
595  # src & (stop - start)
596  src = self.add_ir(src)
597  src_casted = builder.zext(src,
598  LLVMType.int(expr.size))
599  to_and = llvm_c.Constant.int(LLVMType.int(expr.size),
600  (1 << (stop - start)) - 1)
601  anded = builder.and_(src_casted,
602  to_and)
603 
604  if (start != 0):
605  # result << start
606  to_shl = llvm_c.Constant.int(LLVMType.int(expr.size),
607  start)
608  shled = builder.shl(anded, to_shl)
609  final = shled
610  else:
611  # Optimisation
612  final = anded
613 
614  args.append(final)
615 
616  # result = part1 | part2 | ...
617  last = args[0]
618  for i in xrange(1, len(expr.args)):
619  last = builder.or_(last, args[i])
620 
621  self.update_cache(expr, last)
622  return last
623 
624  raise Exception("UnkownExpression", expr.__class__.__name__)
625 
626  def set_ret(self, var):
627  "Cast @var and return it at the end of current bbl"
628  if var.type.width < 64:
629  var_casted = self.builder.zext(var, LLVMType.int(64))
630  else:
631  var_casted = var
632  self.builder.ret(var_casted)
633 
634  def from_expr(self, expr):
635  "Build the function from an expression"
636 
637  # Build function signature
638  args = expr.get_r(True)
639  for a in args:
640  if not isinstance(a, m2_expr.ExprMem):
641  self.my_args.append((a, LLVMType.int(a.size), a.name))
642 
643  self.ret_type = LLVMType.int(expr.size)
644 
645  # Initialise the function
646  self.init_fc()
647 
648  ret = self.add_ir(expr)
649 
650  self.set_ret(ret)
651 
652  def affect(self, src, dst, add_new=True):
653  "Affect from M2 src to M2 dst. If add_new, add a suffix '_new' to dest"
654 
655  # Source
656  src = self.add_ir(src)
657 
658  # Destination
659  builder = self.builder
660  self.add_ir(m2_expr.ExprId("vmcpu"))
661 
662  if isinstance(dst, m2_expr.ExprId):
663  dst_name = dst.name + "_new" if add_new else dst.name
664 
665  ptr_casted = self.get_ptr_by_expr(
666  m2_expr.ExprId(dst_name, dst.size))
667  builder.store(src, ptr_casted)
668 
669  elif isinstance(dst, m2_expr.ExprMem):
670  self.add_ir(dst.arg)
671 
672  # Function call
673  fc_name = "MEM_WRITE_%02d" % dst.size
674  fc_ptr = self.mod.get_function_named(fc_name)
675  dst = self.add_ir(dst.arg)
676  dst_casted = builder.zext(dst, LLVMType.int(64))
677  builder.call(fc_ptr, [self.local_vars["vmmngr"],
678  dst_casted,
679  src])
680 
681  else:
682  raise Exception("UnknownAffectationType")
683 
684  def check_error(self, line, except_do_not_update_pc=False):
685  """Add a check for memory errors.
686  @line: Irbloc line corresponding to the current instruction
687  If except_do_not_update_pc, check only for exception which do not
688  require a pc update"""
689 
690  # VmMngr "get_exception_flag" return's size
691  size = 64
692  t_size = LLVMType.int(size)
693 
694  # Current address
695  pc_to_return = line.offset
696 
697  # Get exception flag value
698  builder = self.builder
699  fc_ptr = self.mod.get_function_named("get_exception_flag")
700  exceptionflag = builder.call(fc_ptr, [self.local_vars["vmmngr"]])
701 
702  if except_do_not_update_pc is True:
703  auto_mod_flag = m2_csts.EXCEPT_DO_NOT_UPDATE_PC
704  m2_flag = llvm_c.Constant.int(t_size, auto_mod_flag)
705  exceptionflag = builder.and_(exceptionflag, m2_flag)
706 
707  # Compute cond
708  zero_casted = llvm_c.Constant.int(t_size, 0)
709  condition_bool = builder.icmp(llvm_c.ICMP_NE,
710  exceptionflag,
711  zero_casted)
712 
713  # Create bbls
714  branch_id = self.new_branch_name()
715  then_block = self.append_basic_block('then%s' % branch_id)
716  merge_block = self.append_basic_block('ifcond%s' % branch_id)
717 
718  builder.cbranch(condition_bool, then_block, merge_block)
719 
720  # Deactivate object caching
721  current_main_stream = self.main_stream
722  self.main_stream = False
723 
724  # Then Bloc
725  builder.position_at_end(then_block)
726  self.set_ret(llvm_c.Constant.int(self.ret_type, pc_to_return))
727 
728  builder.position_at_end(merge_block)
729 
730  # Reactivate object caching
731  self.main_stream = current_main_stream
732 
733  def log_instruction(self, instruction, line):
734  "Print current instruction and registers if options are set"
735 
736  # Get builder
737  builder = self.builder
738 
739  if self.log_mn is True:
740  print instruction # TODO
741 
742  if self.log_regs is True:
743  # Call dump general purpose registers
744  fc_ptr = self.mod.get_function_named("dump_gpregs")
745  builder.call(fc_ptr, [self.local_vars["vmcpu"]])
746 
747  def add_bloc(self, bloc, lines):
748  "Add a bloc of instruction in the current function"
749 
750  for instruction, line in zip(bloc, lines):
751  new_reg = set()
752 
753  # Check general errors only at the beggining of instruction
754  if line.offset not in self.offsets_jitted:
755  self.offsets_jitted.add(line.offset)
756  self.check_error(line)
757 
758  # Log mn and registers if options is set
759  self.log_instruction(instruction, line)
760 
761 
762  # Pass on empty instruction
763  if len(instruction) == 0:
764  continue
765 
766  for expression in instruction:
767  # Apply preinit transformation
768  for func in self.llvm_context.IR_transformation_functions:
769  expression = func(expression)
770 
771  # Treat current expression
772  self.affect(expression.src, expression.dst)
773 
774  # Save registers updated
775  new_reg.update(expression.dst.get_w())
776 
777  # Check for errors (without updating PC)
778  self.check_error(line, except_do_not_update_pc=True)
779 
780  # new -> normal
781  reg_written = []
782  for r in new_reg:
783  if isinstance(r, m2_expr.ExprId):
784  r_new = m2_expr.ExprId(r.name + "_new", r.size)
785  reg_written += [r, r_new]
786  self.affect(r_new, r, add_new=False)
787 
788  # Clear cache
789  self.clear_cache(reg_written)
790  self.main_stream = True
791 
792  def from_bloc(self, bloc, final_expr):
793  """Build the function from a bloc, with the dst equation.
794  Prototype : f(i8* vmcpu, i8* vmmngr)"""
795 
796  # Build function signature
797  self.my_args.append((m2_expr.ExprId("vmcpu"),
798  llvm_c.PointerType.pointer(LLVMType.int(8)),
799  "vmcpu"))
800  self.my_args.append((m2_expr.ExprId("vmmngr"),
801  llvm_c.PointerType.pointer(LLVMType.int(8)),
802  "vmmngr"))
803  self.ret_type = LLVMType.int(final_expr.size)
804 
805  # Initialise the function
806  self.init_fc()
807 
808  # Add content
809  self.add_bloc(bloc, [])
810 
811  # Finalise the function
812  self.set_ret(self.add_ir(final_expr))
813 
814  raise NotImplementedError("Not tested")
815 
816  def canonize_label_name(self, label):
817  """Canonize @label names to a common form.
818  @label: str or asmlabel instance"""
819  if isinstance(label, str):
820  return label
821  elif isinstance(label, m2_asmbloc.asm_label):
822  return "label_%s" % label.name
823  else:
824  raise ValueError("label must either be str or asmlabel")
825 
826  def get_basic_bloc_by_label(self, label):
827  "Return the bbl corresponding to label, None otherwise"
828  return self.name2bbl.get(self.canonize_label_name(label), None)
829 
830  def gen_ret_or_branch(self, dest):
831  """Manage the dest ExprId. If label, branch on it if it is known.
832  Otherwise, return the ExprId or the offset value"""
833 
834  builder = self.builder
835 
836  if isinstance(dest, m2_expr.ExprId):
837  dest_name = dest.name
838  elif isinstance(dest, m2_expr.ExprSlice) and \
839  isinstance(dest.arg, m2_expr.ExprId):
840  # Manage ExprId mask case
841  dest_name = dest.arg.name
842  else:
843  raise ValueError()
844 
845  if not isinstance(dest_name, str):
846  label = dest_name
847  target_bbl = self.get_basic_bloc_by_label(label)
848  if target_bbl is None:
849  self.set_ret(self.add_ir(dest))
850  else:
851  builder.branch(target_bbl)
852  else:
853  self.set_ret(self.add_ir(dest))
854 
855  def add_irbloc(self, irbloc):
856  "Add the content of irbloc at the corresponding labeled block"
857  builder = self.builder
858 
859  bloc = irbloc.irs
860  dest = irbloc.dst
861  label = irbloc.label
862  lines = irbloc.lines
863 
864  # Get labeled basic bloc
865  label_block = self.get_basic_bloc_by_label(label)
866  builder.position_at_end(label_block)
867 
868  # Erase cache
869  self.expr_cache = {}
870 
871  # Add the content of the bloc with corresponding lines
872  self.add_bloc(bloc, lines)
873 
874  # Erase cache
875  self.expr_cache = {}
876 
877  # Manage ret
878  for func in self.llvm_context.IR_transformation_functions:
879  dest = func(dest)
880 
881  if isinstance(dest, m2_expr.ExprCond):
882  # Compute cond
883  cond = self.add_ir(dest.cond)
884  zero_casted = llvm_c.Constant.int(LLVMType.int(dest.cond.size),
885  0)
886  condition_bool = builder.icmp(llvm_c.ICMP_NE, cond,
887  zero_casted)
888 
889  # Create bbls
890  branch_id = self.new_branch_name()
891  then_block = self.append_basic_block('then%s' % branch_id)
892  else_block = self.append_basic_block('else%s' % branch_id)
893 
894  builder.cbranch(condition_bool, then_block, else_block)
895 
896  # Then Bloc
897  builder.position_at_end(then_block)
898  self.gen_ret_or_branch(dest.src1)
899 
900  # Else Bloc
901  builder.position_at_end(else_block)
902  self.gen_ret_or_branch(dest.src2)
903 
904  elif isinstance(dest, m2_expr.ExprId):
905  self.gen_ret_or_branch(dest)
906 
907  elif isinstance(dest, m2_expr.ExprSlice):
908  self.gen_ret_or_branch(dest)
909 
910  else:
911  raise Exception("Bloc dst has to be an ExprId or an ExprCond")
912 
913  def from_blocs(self, blocs):
914  """Build the function from a list of bloc (irbloc instances).
915  Prototype : f(i8* vmcpu, i8* vmmngr)"""
916 
917  # Build function signature
918  self.my_args.append((m2_expr.ExprId("vmcpu"),
919  llvm_c.PointerType.pointer(LLVMType.int(8)),
920  "vmcpu"))
921  self.my_args.append((m2_expr.ExprId("vmmngr"),
922  llvm_c.PointerType.pointer(LLVMType.int(8)),
923  "vmmngr"))
924  ret_size = 64
925 
926  self.ret_type = LLVMType.int(ret_size)
927 
928  # Initialise the function
929  self.init_fc()
930 
931  # Create basic blocks (for label branchs)
932  entry_bbl, builder = self.entry_bbl, self.builder
933 
934  for irbloc in blocs:
935  name = self.canonize_label_name(irbloc.label)
936  self.append_basic_block(name)
937 
938  # Add content
939  builder.position_at_end(entry_bbl)
940 
941  for irbloc in blocs:
942  self.add_irbloc(irbloc)
943 
944  # Branch entry_bbl on first label
945  builder.position_at_end(entry_bbl)
946  first_label_bbl = self.get_basic_bloc_by_label(blocs[0].label)
947  builder.branch(first_label_bbl)
948 
949  def __str__(self):
950  "Print the llvm IR corresponding to the current module"
951 
952  return str(self.fc)
953 
954  def verify(self):
955  "Verify the module syntax"
956 
957  return self.mod.verify()
958 
959  def get_assembly(self):
960  "Return native assembly corresponding to the current module"
961 
962  return self.mod.to_native_assembly()
963 
964  def optimise(self):
965  "Optimise the function in place"
966  while self.llvm_context.pass_manager.run(self.fc):
967  continue
968 
969  def __call__(self, *args):
970  "Eval the function with arguments args"
971 
972  e = self.llvm_context.get_execengine()
973 
974  genargs = [LLVMType.generic(a) for a in args]
975  ret = e.run_function(self.fc, genargs)
976 
977  return ret.as_int()
978 
980  "Return a pointer on the Jitted function"
981  e = self.llvm_context.get_execengine()
982 
983  return e.get_pointer_to_function(self.fc)
984 
985 # TODO:
986 # - Add more expressions