about summary refs log tree commit diff stats
path: root/miasm2/jitter/jitcore_llvm.py
blob: 03bfb90b58ced0efd71c5f48fe40760076bb7432 (plain) (blame)
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()