Beispiel #1
0
    def allocate_object_with_size(self, instructions, nb_words, register=asm.r10):
        # Save the next free address
        instructions.append(asm.MOV(register, self.register_allocation))

        # Increment the dynamic allocator
        size = nb_words * 8

        instructions.append(asm.MOV(asm.operand.MemoryOperand(self.register_allocation), size-8))

        instructions.append(asm.ADD(self.register_allocation, size))

        return register
Beispiel #2
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
Beispiel #3
0
    def compile_error_stub(self, error_code):
        if not self.stub_error:
            self.stub_error = StubError()

        address = jitcompiler_instance.global_allocator.encode_stub(
            asm.MOV(asm.rdi, error_code))

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

        jitcompiler_instance.global_allocator.encode_stub(
            asm.MOV(asm.r10, function_address))
        jitcompiler_instance.global_allocator.encode_stub(asm.CALL(asm.r10))

        return address
Beispiel #4
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
Beispiel #5
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())
Beispiel #6
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
Beispiel #7
0
    def is_float_asm(self, register):

        instructions = list()
        instructions.append(asm.MOV(asm.r12, register))

        instructions.append(asm.AND(asm.r12, Tags.Float))

        instructions.append(asm.CMP(asm.r12, Tags.Float))

        return instructions
Beispiel #8
0
    def clean(self, return_address):
        instructions = []
        instructions.append(asm.POP(asm.registers.rsp).encode())

        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)
Beispiel #9
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)
Beispiel #10
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)
Beispiel #11
0
    def compile_absolute_jump(self, mfunction, block):

        stub_label = "Stub_label_jump" + str(id(block))

        old_code_offset = jitcompiler_instance.global_allocator.code_offset

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

        jump_instruction = asm.MOV(asm.r10, address)
        mfunction.allocator.encode(jump_instruction)
        mfunction.allocator.encode(asm.JMP(asm.r10))

        # Now create the stub
        stub = StubBB(block, jump_instruction, old_code_offset)
        self.compile_stub(mfunction, stub)
Beispiel #12
0
    def compile_bb_stub(self,
                        mfunction,
                        true_block,
                        false_block,
                        test_instruction,
                        true_instructions=None):

        # Save both offsets
        old_stub_offset = jitcompiler_instance.global_allocator.stub_offset
        old_code_offset = jitcompiler_instance.global_allocator.code_offset

        # And update the dictionary of ids and blocks
        # Compute the offset to the stub, by adding the size of the JL instruction
        offset = old_stub_offset - old_code_offset
        peachpy_instruction = test_instruction(
            asm.operand.RIPRelativeOffset(offset - 6))

        mfunction.allocator.encode(peachpy_instruction)

        # Compile a stub for each branch
        jump_stub = StubBB(true_block, peachpy_instruction, old_code_offset)

        # If any, add some custom instructions for the true branch of the test
        jump_stub.instructions_before = true_instructions
        self.compile_stub(mfunction, jump_stub)

        # For now, jump to the newly compiled stub,
        # This code will be patched later
        old_code_offset = jitcompiler_instance.global_allocator.code_offset

        # Compute the address of the false block stub
        c_buffer = ffi.from_buffer(
            jitcompiler_instance.global_allocator.code_section)
        address_false = lib.get_address(
            c_buffer, jitcompiler_instance.global_allocator.stub_offset)

        peachpy_instruction = asm.MOV(asm.r10, address_false)
        mfunction.allocator.encode(peachpy_instruction)
        mfunction.allocator.encode(asm.JMP(asm.r10))

        # We store the MOV into the register as the jumping instruction, we just need to patch this
        notjump_stub = StubBB(false_block, peachpy_instruction,
                              old_code_offset)
        self.compile_stub(mfunction, notjump_stub)
Beispiel #13
0
    def is_int_asm(self, register):
        # 7FFF FFFF FFFF FFFF max value for a 64 bits signed integer
        instructions = []

        # Collect stats if needed
        if self.jit.interpreter.args.stats:
            # +1 for each type-check executed
            instructions.append(asm.ADD(self.jit.register_stats, 1))

        # Copy the value inside a new register
        instructions.append(asm.MOV(asm.r12, register))

        test_value = 0b111

        # Now compare
        instructions.append(asm.AND(asm.r12, test_value))

        # The result should be 0 if we have an int
        instructions.append(asm.CMP(asm.r12, 0))

        # Make the jumps according to the result
        return instructions
Beispiel #14
0
    def init_allocation_pointer(self):
        # We need to put a value inside the designated register
        address_beginning = self.global_allocator.data_address + self.global_allocator.runtime_offset

        encoded = asm.MOV(self.register_allocation, address_beginning).encode()
        self.global_allocator.code_offset = self.global_allocator.write_instruction(encoded, self.global_allocator.code_offset)
Beispiel #15
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
Beispiel #16
0
    def binary_type_check(self, mfunction, block, context):
        # Try to retrieve information on the context stack
        x_register = asm.r13
        y_register = asm.r14

        if self.jit.interpreter.args.maxvers == 0:
            # BBV is deactivated, replace type values with unknow in the virtual stack
            context.variable_types[0] = Types.Unknown
            context.variable_types[1] = Types.Unknown

            new_tuple0 = (context.stack[-1][0], context.variable_types[0])
            new_tuple1 = (context.stack[-2][0], context.variable_types[1])

            context.stack[-1] = new_tuple0
            context.stack[-2] = new_tuple1
        else:
            # Try to retrieve information on types in the context
            context.variable_types[0] = context.stack[-1][1]
            if context.variable_types[0] == Types.Unknown:
                # Try to see in context.variables_dict
                if context.stack[-1][0] in context.variable_dict:
                    context.variable_types[0] = context.variable_dict[
                        context.stack[-1][0]]

            context.variable_types[1] = context.stack[-2][1]
            if context.variable_types[1] == Types.Unknown:
                if context.stack[-2][0] in context.variable_dict:
                    context.variable_types[1] = context.variable_dict[
                        context.stack[-2][0]]

        context.variables_allocation[0] = x_register
        context.variables_allocation[1] = y_register

        # If we have static information on these types, we will compile a stub to the next block
        if context.variable_types[
                0] != Types.Unknown and context.variable_types[
                    1] != Types.Unknown:
            # Update the stack and directly compile the next block

            # Construct two new tuples to fill the context with up to date information
            new_tuple0 = (context.stack[-1][0], context.variable_types[0])
            new_tuple1 = (context.stack[-2][0], context.variable_types[1])

            context.stack[-1] = new_tuple0
            context.stack[-2] = new_tuple1

            # We should have only one block after
            assert len(block.next) == 1

            for el in block.next:
                self.jit.compile_instructions(mfunction, el)
        else:
            # Move values into registers and keep them on the stack until the end of the test
            instructions = []
            instructions.append(
                asm.MOV(x_register,
                        asm.operand.MemoryOperand(asm.registers.rsp)))
            instructions.append(
                asm.MOV(y_register,
                        asm.operand.MemoryOperand(asm.registers.rsp + 8)))

            # Generate a test for the first variable
            test_instructions = self.is_int_asm(x_register)
            instructions.extend(test_instructions)

            # Code for true and false branches
            true_branch = self.is_int_asm(y_register)
            false_branch = self.is_float_asm(x_register)

            # Indicate which operand has to be tested
            id_var = 0
            if context.variable_types[0] != Types.Unknown:
                id_var = 1

            stub = stub_handler.StubType(mfunction, instructions, true_branch,
                                         false_branch, id_var, context)

            next_block = None
            for el in block.next:
                next_block = el

            # Indicate to the stub, which block must be compiled after the resolution of the test
            stub.following_block(next_block)
Beispiel #17
0
    def patch_instruction(self, first_offset):

        if isinstance(self.instruction, asm.MOV):
            # Moving an address inside a register, we need to change the address here

            # If the MOVE + JUMP is supposed to go just after, put NOP instead
            diff = first_offset - self.position
            if diff > 0 and diff <= 13:
                nop = asm.NOP().encode()
                for i in range(diff):
                    jitcompiler_instance.global_allocator.write_instruction(
                        nop, self.position)
                    self.position += 1
            else:
                # It's a real jump, just compile it and patch the code
                new_address = lib.get_address(
                    ffi.from_buffer(
                        jitcompiler_instance.global_allocator.code_section),
                    first_offset)
                new_instruction = asm.MOV(self.instruction.operands[0],
                                          new_address)

                # Create the new encoded instruction and replace the old one in the code section
                encoded = new_instruction.encode()
                jitcompiler_instance.global_allocator.write_instruction(
                    encoded, self.position)
        elif isinstance(self.instruction, asm.JG):

            new_operand = first_offset - self.position - len(
                self.instruction.encode())

            # Update to the new position
            new_instruction = asm.JG(
                asm.operand.RIPRelativeOffset(new_operand))
            encoded = new_instruction.encode()

            # If the previous instruction was a 32 bits offset, force it to the new one
            if len(self.instruction.encode()) > 2:
                encoded = bytearray(len(self.instruction.encode()))

                # Force the 32 encoding of the JG instruction
                encoded[0] = 0x0F
                encoded[1] = 0x8F
                encoded[2] = 0
                encoded[3] = 0
                encoded[4] = 0
                encoded[5] = 0

                size = custom_ceil(new_operand / 255)
                bytes = new_operand.to_bytes(size, 'little')

                for i in range(0, len(bytes)):
                    encoded[i + 2] = bytes[i]

            jitcompiler_instance.global_allocator.write_instruction(
                encoded, self.position)
        elif isinstance(self.instruction, asm.JGE):
            new_operand = first_offset - self.position - len(
                self.instruction.encode())

            # Update to the new position
            new_instruction = asm.JGE(
                asm.operand.RIPRelativeOffset(new_operand))
            encoded = new_instruction.encode()

            # If the previous instruction was a 32 bits offset, force it to the new one
            if len(encoded) != 6 and len(self.instruction.encode()) > 2:
                encoded = bytearray(6)

                # Force the 32 encoding of the JGE
                encoded[0] = 0x0F
                encoded[1] = 0x8D
                encoded[2] = 0
                encoded[3] = 0
                encoded[4] = 0
                encoded[5] = 0

                # Keep the same value for the jump
                size = custom_ceil(new_operand / 255)
                bytes = new_operand.to_bytes(size, 'little')

                for i in range(0, len(bytes)):
                    encoded[i + 2] = bytes[i]

            jitcompiler_instance.global_allocator.write_instruction(
                encoded, self.position)
        elif isinstance(self.instruction, asm.JE):

            new_operand = first_offset - self.position - len(
                self.instruction.encode())

            # Update to the new position
            new_instruction = asm.JE(
                asm.operand.RIPRelativeOffset(new_operand))
            encoded = new_instruction.encode()

            # If the previous instruction was a 32 bits offset, force it to the new one
            if len(self.instruction.encode()) > 2:
                encoded = bytearray(len(self.instruction.encode()))

                # Force the 32 encoding of the JE instruction
                encoded[0] = 0x0F
                encoded[1] = 0x84
                encoded[2] = 0
                encoded[3] = 0
                encoded[4] = 0
                encoded[5] = 0

                size = custom_ceil(new_operand / 255)
                bytes = new_operand.to_bytes(size, 'little')

                for i in range(0, len(bytes)):
                    encoded[i + 2] = bytes[i]

            jitcompiler_instance.global_allocator.write_instruction(
                encoded, self.position)
        elif isinstance(self.instruction, asm.JL):
            new_operand = first_offset - self.position - len(
                self.instruction.encode())

            new_instruction = asm.JL(
                asm.operand.RIPRelativeOffset(new_operand))
            encoded = new_instruction.encode()

            # If the previous instruction was a 32 bits offset, force the same length for the new one
            if len(self.instruction.encode()) > 2 and len(encoded) != 6:
                encoded = bytearray(len(self.instruction.encode()))

                # Force the 32 encoding of the JL instruction
                encoded[0] = 0x0F
                encoded[1] = 0x8C
                encoded[2] = 0
                encoded[3] = 0
                encoded[4] = 0
                encoded[5] = 0

                size = custom_ceil(new_operand / 255)
                bytes = None
                if size < 0 or new_operand < 0:
                    size = 4
                    bytes = new_operand.to_bytes(size, 'little', signed=True)
                else:
                    bytes = new_operand.to_bytes(size, 'little')

                for i in range(0, len(bytes)):
                    encoded[i + 2] = bytes[i]

            jitcompiler_instance.global_allocator.write_instruction(
                encoded, self.position)
        elif isinstance(self.instruction, asm.JLE):
            new_operand = first_offset - self.position - len(
                self.instruction.encode())

            # Update to the new position
            new_instruction = asm.JLE(
                asm.operand.RIPRelativeOffset(new_operand))
            encoded = new_instruction.encode()

            # If the previous instruction was a 32 bits offset, force it to the new one
            if len(encoded) != 6 and len(self.instruction.encode()) > 2:
                encoded = bytearray(6)

                # Force the 32 encoding of the JGE
                encoded[0] = 0x0F
                encoded[1] = 0x8E
                encoded[2] = 0
                encoded[3] = 0
                encoded[4] = 0
                encoded[5] = 0

                # Keep the same value for the jump
                size = custom_ceil(new_operand / 255)
                bytes = new_operand.to_bytes(size, 'little')

                for i in range(0, len(bytes)):
                    encoded[i + 2] = bytes[i]

            jitcompiler_instance.global_allocator.write_instruction(
                encoded, self.position)
        elif isinstance(self.instruction, asm.JNE):
            new_operand = first_offset - self.position - len(
                self.instruction.encode())
            if new_operand < 255:
                # We will encode the instruction
                new_operand = first_offset - self.position - 2

            new_instruction = asm.JNE(
                asm.operand.RIPRelativeOffset(new_operand))
            encoded = new_instruction.encode()

            # Need to add some NOP instruction to fill the space left from the previous longer instruction
            if len(encoded) < len(self.instruction.encode()):

                diff = len(self.instruction.encode()) - len(encoded)

                for i in range(diff):
                    encoded += asm.NOP().encode()
            else:
                # If the previous instruction was a 32 bits offset, force the same length for the new one
                encoded = bytearray(len(self.instruction.encode()))

                # Force the 32 encoding of the JNE instruction
                encoded[0] = 0x0F
                encoded[1] = 0x85
                encoded[2] = 0
                encoded[3] = 0
                encoded[4] = 0
                encoded[5] = 0

                size = custom_ceil(new_operand / 255)
                bytes = new_operand.to_bytes(size, 'little')

                for i in range(0, len(bytes)):
                    encoded[i + 2] = bytes[i]

            jitcompiler_instance.global_allocator.write_instruction(
                encoded, self.position)
        elif isinstance(self.instruction, asm.JB):
            old_instruction_encoded = self.instruction.encode()
            new_operand = first_offset - self.position - len(
                old_instruction_encoded)

            if new_operand < 255:
                # We will encode the instruction
                new_operand = first_offset - self.position - len(
                    old_instruction_encoded)

            new_instruction = asm.JB(
                asm.operand.RIPRelativeOffset(new_operand))
            encoded = new_instruction.encode()

            # Need to add some NOP instruction to fill the space left from the previous longer instruction
            if len(old_instruction_encoded) != len(new_instruction.encode()):
                # If the previous instruction was a 32 bits offset, force the same length for the new one
                encoded = bytearray(len(old_instruction_encoded))

                # Force the 32 encoding of the JNE instruction
                encoded[0] = 0x0F
                encoded[1] = 0x82
                encoded[2] = 0
                encoded[3] = 0
                encoded[4] = 0
                encoded[5] = 0

                size = custom_ceil(new_operand / 255)
                bytes = new_operand.to_bytes(size, 'little')

                for i in range(0, len(bytes)):
                    encoded[i + 2] = bytes[i]

            jitcompiler_instance.global_allocator.write_instruction(
                encoded, self.position)
        else:
            print("Not yet implemented patch " + str(self.instruction))