15 import llvm.core
as llvm_c
16 import llvm.ee
as llvm_e
17 import llvm.passes
as llvm_p
30 def int(cls, size=32):
32 return cls.int_cache[size]
34 cls.int_cache[size] = llvm_c.Type.int(size)
35 return cls.int_cache[size]
39 "Generic pointer for execution"
40 return llvm_e.GenericValue.pointer(addr)
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):
55 "Context for llvm binding. Stand for a LLVM Module"
60 "Initialize a context with a module named 'name'"
61 self.
mod = llvm_c.Module.new(name)
67 """Set the optimisation level :
71 - global value numbering
82 if classic_passes
is True:
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)
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)
93 self.pass_manager.initialize()
96 "Return the Execution Engine associated with this context"
100 "Return the Pass Manager associated with this context"
104 "Return the module associated with this context"
108 "Load the shared library 'filename'"
109 return llvm_c.load_library_permanently(filename)
112 "Add function into known_fc"
114 for name, detail
in fc.items():
115 self.mod.add_function(LLVMType.function(detail[
"ret"],
122 "Extend LLVMContext_JIT in order to handle memory management"
125 "Init a LLVMContext object, and load the mem management shared library"
126 LLVMContext.__init__(self, name)
127 for lib_fname
in library_filenames:
136 "Add MEM_LOOKUP functions"
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),
145 fc[
"MEM_WRITE_%02d" % i] = {
"ret": LLVMType.void(),
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),
159 "Add operations functions"
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(),
168 self.
add_fc({
"rot_right": {
"ret": LLVMType.int(),
169 "args": [LLVMType.int(),
173 self.
add_fc({
"segm2addr": {
"ret": LLVMType.int(64),
179 self.
add_fc({
"bcdadd_%s" % k: {
"ret": LLVMType.int(k),
180 "args": [LLVMType.int(k),
182 self.
add_fc({
"bcdadd_cf_%s" % k: {
"ret": LLVMType.int(k),
183 "args": [LLVMType.int(k),
186 for k
in [16, 32, 64]:
187 self.
add_fc({
"imod%s" % k: {
"ret": LLVMType.int(k),
191 self.
add_fc({
"idiv%s" % k: {
"ret": LLVMType.int(k),
197 "Add functions for state logging"
199 p8 = llvm_c.PointerType.pointer(LLVMType.int(8))
200 self.
add_fc({
"dump_gpregs": {
"ret": LLVMType.void(),
204 "Set the correspondance between register name and vmcpu offset"
206 self.
vmcpu = lookup_table
209 """Set a list of transformation to apply on expression before their
211 args: function Expr(Expr)"""
217 "Represent a llvm function"
224 "Create a new function with name fc"
226 self.
mod = self.llvm_context.get_module()
237 "Return a new branch name"
243 "Show the CFG of the current function"
247 """Add a new basic block to the current function.
248 @label: str or asmlabel
249 Return the corresponding LLVM Basic Block"""
251 bbl = self.fc.append_basic_block(name)
260 fc_type = LLVMType.function(
265 fc = self.mod.add_function(fc_type, self.
name)
266 except llvm.LLVMException:
268 previous_fc = self.mod.get_function_named(self.
name)
270 fc = self.mod.add_function(fc_type, self.
name)
273 for i, a
in enumerate(self.
my_args):
274 fc.args[i].name = a[2]
279 for i, a
in enumerate(self.
my_args):
298 "Create an alloca instruction at the beginning of the current fc"
300 current_bbl = builder.basic_block
303 ret = builder.alloca(var_type)
304 builder.position_at_end(current_bbl)
308 """"Return a pointer casted corresponding to ExprId expr. If it is not
309 already computed, compute it at the end of entry_bloc"""
320 current_bbl = builder.basic_block
324 builder.position_at_end(entry_bloc_bbl)
327 offset = self.llvm_context.vmcpu[name]
331 [llvm_c.Constant.int(LLVMType.int(),
333 int_size = LLVMType.int(expr.size)
334 ptr_casted = builder.bitcast(ptr,
335 llvm_c.PointerType.pointer(int_size))
340 builder.position_at_end(current_bbl)
345 "Remove from the cache values which depends on regs_updated"
347 regs_updated_set = set(regs_updated)
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)
354 "Add 'name' = 'value' to the cache iff main_stream = True"
360 "Add a Miasm2 IR to the last bbl. Return the var created"
367 if isinstance(expr, m2_expr.ExprInt):
368 ret = llvm_c.Constant.int(LLVMType.int(expr.size), int(expr.arg))
372 if isinstance(expr, m2_expr.ExprId):
374 if not isinstance(name, str):
377 ret = llvm_c.Constant.int(LLVMType.int(expr.size), offset)
389 var = builder.load(ptr_casted, name)
393 if isinstance(expr, m2_expr.ExprOp):
397 fc_ptr = self.mod.get_function_named(
"parity")
398 arg = builder.zext(self.
add_ir(expr.args[0]),
400 ret = builder.call(fc_ptr, [arg])
401 ret = builder.trunc(ret, LLVMType.int(expr.size))
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
412 args = [builder.zext(arg, LLVMType.int(32))
414 arg_size_cst = llvm_c.Constant.int(LLVMType.int(),
416 ret = builder.call(fc_ptr, [arg_size_cst] + args)
419 ret = builder.trunc(ret, LLVMType.int(arg_size))
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)
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))
441 zero = llvm_c.Constant.int(LLVMType.int(expr.size),
443 ret = builder.sub(zero, self.
add_ir(expr.args[0]))
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))
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)
466 if len(expr.args) > 1:
469 callback = builder.mul
471 callback = builder.add
473 callback = builder.and_
475 callback = builder.xor
477 callback = builder.or_
479 callback = builder.lshr
481 callback = builder.shl
483 callback = builder.ashr
485 callback = builder.udiv
487 callback = builder.urem
489 raise NotImplementedError(
'Unknown op: %s' % op)
491 last = self.
add_ir(expr.args[0])
493 for i
in range(1, len(expr.args)):
494 last = callback(last,
495 self.
add_ir(expr.args[i]))
501 raise NotImplementedError()
503 if isinstance(expr, m2_expr.ExprMem):
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),
510 ret = builder.call(fc_ptr, [self.
local_vars[
"vmmngr"],
516 if isinstance(expr, m2_expr.ExprCond):
518 cond = self.
add_ir(expr.cond)
519 zero_casted = llvm_c.Constant.int(LLVMType.int(expr.cond.size),
521 condition_bool = builder.icmp(llvm_c.ICMP_NE, cond,
533 builder.cbranch(condition_bool, then_block, else_block)
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)
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)
552 builder.position_at_end(merge_block)
553 ret = builder.load(alloca)
561 if isinstance(expr, m2_expr.ExprSlice):
563 src = self.
add_ir(expr.arg)
567 to_shr = llvm_c.Constant.int(LLVMType.int(expr.arg.size),
569 shred = builder.lshr(src,
575 to_and = llvm_c.Constant.int(LLVMType.int(expr.arg.size),
576 (1 << (expr.stop - expr.start)) - 1)
577 anded = builder.and_(shred,
581 ret = builder.trunc(anded,
582 LLVMType.int(expr.size))
587 if isinstance(expr, m2_expr.ExprCompose):
592 for arg
in expr.args:
593 src, start, stop = arg
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,
606 to_shl = llvm_c.Constant.int(LLVMType.int(expr.size),
608 shled = builder.shl(anded, to_shl)
618 for i
in xrange(1, len(expr.args)):
619 last = builder.or_(last, args[i])
624 raise Exception(
"UnkownExpression", expr.__class__.__name__)
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))
632 self.builder.ret(var_casted)
635 "Build the function from an expression"
638 args = expr.get_r(
True)
640 if not isinstance(a, m2_expr.ExprMem):
641 self.my_args.append((a, LLVMType.int(a.size), a.name))
643 self.
ret_type = LLVMType.int(expr.size)
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"
660 self.
add_ir(m2_expr.ExprId(
"vmcpu"))
662 if isinstance(dst, m2_expr.ExprId):
663 dst_name = dst.name +
"_new" if add_new
else dst.name
666 m2_expr.ExprId(dst_name, dst.size))
667 builder.store(src, ptr_casted)
669 elif isinstance(dst, m2_expr.ExprMem):
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"],
682 raise Exception(
"UnknownAffectationType")
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"""
692 t_size = LLVMType.int(size)
695 pc_to_return = line.offset
699 fc_ptr = self.mod.get_function_named(
"get_exception_flag")
700 exceptionflag = builder.call(fc_ptr, [self.
local_vars[
"vmmngr"]])
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)
708 zero_casted = llvm_c.Constant.int(t_size, 0)
709 condition_bool = builder.icmp(llvm_c.ICMP_NE,
718 builder.cbranch(condition_bool, then_block, merge_block)
725 builder.position_at_end(then_block)
728 builder.position_at_end(merge_block)
734 "Print current instruction and registers if options are set"
744 fc_ptr = self.mod.get_function_named(
"dump_gpregs")
745 builder.call(fc_ptr, [self.
local_vars[
"vmcpu"]])
748 "Add a bloc of instruction in the current function"
750 for instruction, line
in zip(bloc, lines):
755 self.offsets_jitted.add(line.offset)
763 if len(instruction) == 0:
766 for expression
in instruction:
768 for func
in self.llvm_context.IR_transformation_functions:
769 expression = func(expression)
772 self.
affect(expression.src, expression.dst)
775 new_reg.update(expression.dst.get_w())
778 self.
check_error(line, except_do_not_update_pc=
True)
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)
793 """Build the function from a bloc, with the dst equation.
794 Prototype : f(i8* vmcpu, i8* vmmngr)"""
797 self.my_args.append((m2_expr.ExprId(
"vmcpu"),
798 llvm_c.PointerType.pointer(LLVMType.int(8)),
800 self.my_args.append((m2_expr.ExprId(
"vmmngr"),
801 llvm_c.PointerType.pointer(LLVMType.int(8)),
803 self.
ret_type = LLVMType.int(final_expr.size)
814 raise NotImplementedError(
"Not tested")
817 """Canonize @label names to a common form.
818 @label: str or asmlabel instance"""
819 if isinstance(label, str):
821 elif isinstance(label, m2_asmbloc.asm_label):
822 return "label_%s" % label.name
824 raise ValueError(
"label must either be str or asmlabel")
827 "Return the bbl corresponding to label, None otherwise"
831 """Manage the dest ExprId. If label, branch on it if it is known.
832 Otherwise, return the ExprId or the offset value"""
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):
841 dest_name = dest.arg.name
845 if not isinstance(dest_name, str):
848 if target_bbl
is None:
851 builder.branch(target_bbl)
856 "Add the content of irbloc at the corresponding labeled block"
866 builder.position_at_end(label_block)
878 for func
in self.llvm_context.IR_transformation_functions:
881 if isinstance(dest, m2_expr.ExprCond):
883 cond = self.
add_ir(dest.cond)
884 zero_casted = llvm_c.Constant.int(LLVMType.int(dest.cond.size),
886 condition_bool = builder.icmp(llvm_c.ICMP_NE, cond,
894 builder.cbranch(condition_bool, then_block, else_block)
897 builder.position_at_end(then_block)
901 builder.position_at_end(else_block)
904 elif isinstance(dest, m2_expr.ExprId):
907 elif isinstance(dest, m2_expr.ExprSlice):
911 raise Exception(
"Bloc dst has to be an ExprId or an ExprCond")
914 """Build the function from a list of bloc (irbloc instances).
915 Prototype : f(i8* vmcpu, i8* vmmngr)"""
918 self.my_args.append((m2_expr.ExprId(
"vmcpu"),
919 llvm_c.PointerType.pointer(LLVMType.int(8)),
921 self.my_args.append((m2_expr.ExprId(
"vmmngr"),
922 llvm_c.PointerType.pointer(LLVMType.int(8)),
926 self.
ret_type = LLVMType.int(ret_size)
939 builder.position_at_end(entry_bbl)
945 builder.position_at_end(entry_bbl)
947 builder.branch(first_label_bbl)
950 "Print the llvm IR corresponding to the current module"
955 "Verify the module syntax"
957 return self.mod.verify()
960 "Return native assembly corresponding to the current module"
962 return self.mod.to_native_assembly()
965 "Optimise the function in place"
966 while self.llvm_context.pass_manager.run(self.
fc):
970 "Eval the function with arguments args"
972 e = self.llvm_context.get_execengine()
974 genargs = [LLVMType.generic(a)
for a
in args]
975 ret = e.run_function(self.
fc, genargs)
980 "Return a pointer on the Jitted function"
981 e = self.llvm_context.get_execengine()
983 return e.get_pointer_to_function(self.
fc)
def set_IR_transformation
def get_basic_bloc_by_label
IR_transformation_functions
def CreateEntryBlockAlloca
def add_get_exceptionflag