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)
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)
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)
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)
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)
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