Exemple #1
0
    def compile_function_stub(self, mfunction, nbargs, address_after):
        # Now encode the stub
        stub_label = asm.Label("Stub_label_" + str(mfunction.name))

        # The call to that will be compiled after the stub compilation is over
        address = mfunction.allocator.encode_stub(asm.LABEL(stub_label))

        # Save the association
        mfunction.allocator.jump_labels[address] = asm.LABEL(stub_label)

        # Save the rsp for the stub
        mfunction.allocator.encode_stub(asm.MOV(asm.rdi, asm.registers.rsp))

        # Call the stub function in C
        function_address = int(
            ffi.cast("intptr_t", ffi.addressof(lib, "function_stub")))

        # Align the stack on 16 bits
        mfunction.allocator.encode_stub(asm.MOV(asm.rax, asm.registers.rsp))
        mfunction.allocator.encode_stub(asm.AND(asm.registers.rsp, -16))
        mfunction.allocator.encode_stub(asm.PUSH(asm.registers.rsp))

        mfunction.allocator.encode_stub(asm.MOV(asm.r10, function_address))
        mfunction.allocator.encode_stub(asm.CALL(asm.r10))

        # Now put additional informations for the stub
        # Force min 8 bits encoding for this value
        nbargs_bytes = encode_bytes(nbargs)

        stub_function = StubFunction()
        self.stub_dictionary[address_after] = stub_function

        self.data_addresses[
            address_after] = jitcompiler_instance.global_allocator.stub_offset

        address_after_bytes = address_after.to_bytes(
            address_after.bit_length(), "little")

        # Write after the stub
        jitcompiler_instance.global_allocator.stub_offset = jitcompiler_instance.global_allocator.write_instruction(
            nbargs_bytes, jitcompiler_instance.global_allocator.stub_offset)
        jitcompiler_instance.global_allocator.stub_offset = jitcompiler_instance.global_allocator.write_instruction(
            address_after_bytes,
            jitcompiler_instance.global_allocator.stub_offset)

        for i in range(5):
            mfunction.allocator.encode_stub(asm.NOP())

        return address
Exemple #2
0
    def encode_stub_test(self, branch, label, type_value):
        # Giving rsp to C function
        address = self.mfunction.allocator.encode_stub(
            asm.MOV(asm.rdi, asm.registers.rsp))

        # Save the association
        self.mfunction.allocator.jump_labels[address] = label

        # Call to C to compile the block
        reg_id = asm.r10
        function_address = int(
            ffi.cast("intptr_t", ffi.addressof(lib, "type_test_stub")))

        # Align the stack on 16 bits
        self.mfunction.allocator.encode_stub(
            asm.MOV(asm.rax, asm.registers.rsp))
        self.mfunction.allocator.encode_stub(asm.PUSH(asm.registers.rsp))

        self.mfunction.allocator.encode_stub(asm.MOV(reg_id, function_address))
        self.mfunction.allocator.encode_stub(asm.CALL(reg_id))

        # Compute the return address to link this stub to self
        return_address = lib.get_address(
            ffi.from_buffer(
                jitcompiler_instance.global_allocator.code_section),
            jitcompiler_instance.global_allocator.stub_offset)

        return_address = return_address & -16
        # Associate this return address to self in the stub_handler
        stubhandler_instance.stub_dictionary[return_address] = self

        variable_id = encode_bytes(self.variable)
        type_bytes = encode_bytes(type_value)

        offset = jitcompiler_instance.global_allocator.stub_offset

        stubhandler_instance.data_addresses[return_address] = offset

        jitcompiler_instance.global_allocator.stub_offset = jitcompiler_instance.global_allocator.write_instruction(
            variable_id, offset)
        jitcompiler_instance.global_allocator.stub_offset = jitcompiler_instance.global_allocator.write_instruction(
            type_bytes, jitcompiler_instance.global_allocator.stub_offset)

        # Saving some space for the cleaning
        for i in range(5):
            self.mfunction.allocator.encode_stub(asm.NOP())

        return return_address
Exemple #3
0
    def compile_class_stub(self, mfunction):
        # Push on the stack the address of the class' stub
        c_buffer = ffi.from_buffer(
            jitcompiler_instance.global_allocator.code_section)
        address_stub = lib.get_address(
            c_buffer, jitcompiler_instance.global_allocator.stub_offset)

        mfunction.allocator.encode(asm.MOV(asm.r10, address_stub))
        mfunction.allocator.encode(asm.PUSH(asm.r10))

        # Save the address after the PUSH to be able to jump there later
        c_buffer = ffi.from_buffer(
            jitcompiler_instance.global_allocator.code_section)
        address_code = lib.get_address(
            c_buffer, jitcompiler_instance.global_allocator.code_offset)

        # Be able to find them in the collection during the later callback
        self.class_stub_addresses.append(address_stub)

        # Call the stub function
        mfunction.allocator.encode_stub(asm.MOV(asm.rdi, asm.registers.rsp))

        function_address = int(
            ffi.cast("intptr_t", ffi.addressof(lib, "class_stub")))
        mfunction.allocator.encode_stub(asm.MOV(asm.r10, function_address))
        mfunction.allocator.encode_stub(asm.CALL(asm.r10))

        offset = jitcompiler_instance.global_allocator.stub_offset

        return_address = lib.get_address(
            ffi.from_buffer(
                jitcompiler_instance.global_allocator.code_section),
            jitcompiler_instance.global_allocator.stub_offset)

        stub = StubClass()
        stub.data_address = offset
        stub.return_address = address_code

        # Indicate this offset correspond to the "return address" on the stub after the call to C returned
        self.data_addresses[return_address] = offset
        self.stub_dictionary[return_address] = stub

        # Reserve some space for the cleanup
        for i in range(5):
            mfunction.allocator.encode_stub(asm.NOP())
Exemple #4
0
    def compile_stub(self, mfunction, stub):

        # The call to that will be compiled after the stub compilation is over
        stub_label = "Stub_label_" + str(id(stub))

        # Now we store the stack pointer to patch it later
        address = mfunction.allocator.encode_stub(
            asm.MOV(asm.rdi, asm.registers.rsp))

        # Save the association
        mfunction.allocator.jump_labels[address] = stub_label

        reg_id = asm.r10

        function_address = int(
            ffi.cast("intptr_t", ffi.addressof(lib, "bb_stub")))

        # Align the stack on 16 bits

        mfunction.allocator.encode_stub(asm.MOV(asm.rax, asm.registers.rsp))
        mfunction.allocator.encode_stub(asm.PUSH(asm.registers.rsp))

        mfunction.allocator.encode_stub(asm.MOV(reg_id, function_address))

        mfunction.allocator.encode_stub(asm.CALL(reg_id))

        # Save the offset
        offset = jitcompiler_instance.global_allocator.stub_offset

        return_address = lib.get_address(
            ffi.from_buffer(
                jitcompiler_instance.global_allocator.code_section),
            jitcompiler_instance.global_allocator.stub_offset)

        # Indicate this offset correspond to the "return address" on the stub after the call to C returned
        self.data_addresses[return_address] = offset
        self.stub_dictionary[return_address] = stub

        # Save some space for cleaning instructions
        for i in range(15):
            mfunction.allocator.encode_stub(asm.NOP())

        return address
Exemple #5
0
    def clean(self, class_address, address_class_function):
        instructions = []

        # Now push the function address
        instructions.append(asm.MOV(asm.rax, class_address))
        instructions.append(asm.PUSH(asm.rax))

        instructions.append(asm.MOV(asm.r10, address_class_function))
        instructions.append(asm.CALL(asm.r10))

        # Clean the stack
        instructions.append(asm.ADD(asm.registers.rsp, 32))

        # Finally, jump to the correct destination
        instructions.append(asm.MOV(asm.rax, class_address))
        instructions.append(asm.MOV(asm.r11, self.return_address))
        instructions.append(asm.JMP(asm.r11))

        offset = self.data_address
        for i in instructions:
            offset = jitcompiler_instance.global_allocator.write_instruction(
                i.encode(), offset)
Exemple #6
0
    def clean(self, return_address, function_address, canary_value=None):
        instructions = []

        # restore rsp
        instructions.append(asm.POP(asm.registers.rsp).encode())

        if canary_value in stubhandler_instance.class_stub_addresses:
            instructions.append(asm.ADD(asm.registers.rsp, 32).encode())
        else:
            # Discard the three top values on the stack
            instructions.append(asm.ADD(asm.registers.rsp, 24).encode())

        # Now push the function address
        instructions.append(asm.MOV(asm.rax, function_address).encode())
        instructions.append(asm.PUSH(asm.rax).encode())

        # Finally, jump to the correct destination
        instructions.append(asm.MOV(asm.rax, return_address).encode())
        instructions.append(asm.JMP(asm.rax).encode())

        offset = self.data_address
        for i in instructions:
            offset = jitcompiler_instance.global_allocator.write_instruction(
                i, offset)
Exemple #7
0
    def allocate_instance(self, class_address, init_function, class_function):
        # Save the address of the initializer definition
        c_buffer = stub_handler.ffi.from_buffer(self.global_allocator.code_section)
        init_code_address = stub_handler.lib.get_address(c_buffer, self.global_allocator.code_offset)

        self.global_allocator.jitcompiler.initializer_addresses[class_function.name] = init_code_address

        instructions = list()

        # Move the next available address into rax to return it
        instructions.append(asm.MOV(asm.rax, self.register_allocation))

        # Construct the header with the size of the object
        size = 2
        instructions.append(asm.MOV(asm.operand.MemoryOperand(asm.r15), size))

        # Put a pointer to the class address in the second field
        instructions.append(asm.MOV(asm.r10, class_address))
        instructions.append(asm.MOV(asm.operand.MemoryOperand(self.register_allocation + 8), asm.r10))

        # Increment the allocation pointer
        instructions.append(asm.ADD(self.register_allocation, 8 * 5))

        # Finally, tag the address inside rax
        tag_instructions = self.global_allocator.jitcompiler.tags.tag_object_asm(asm.rax)

        instructions.extend(tag_instructions)

        # Now call the __init__() method of the class if any
        # TODO: handle __init__ with more than 1 parameters
        if init_function is not None:
            init_offset = 4

            # Save the return address of the current call
            instructions.append(asm.POP(asm.r9))

            # Saving parameter
            instructions.append(asm.POP(asm.r8))

            # Depop the class address
            instructions.append(asm.ADD(asm.registers.rsp, 8))

            # TODO: problem stack size
            instructions.append(asm.PUSH(asm.r9))

            # Push back object and parameters
            instructions.append(asm.PUSH(asm.rax))
            instructions.append(asm.PUSH(asm.r8))

            # Make the call to init
            instructions.append(asm.ADD(asm.r10, 8 * init_offset))
            instructions.append(asm.CALL(asm.operand.MemoryOperand(asm.r10)))

        # Saving return address in a register
        instructions.append(asm.POP(asm.r9))

        instructions.append(asm.JMP(asm.r9))

        offset = self.global_allocator.code_offset
        for i in instructions:
            offset = self.global_allocator.write_instruction(i.encode(), offset)

        self.global_allocator.code_offset = offset