Translate a list of operations into its assembler source.

        Arguments:
            ops(list): A list of shellcode operations.

        Returns:
            str: The assembler source code that implements the shellcode.

def compile(self, ops):
        """
        Translate a list of operations into its assembler source.

        Arguments:
            ops(list): A list of shellcode operations.

        Returns:
            str: The assembler source code that implements the shellcode.
        """

        def _compile():
            code = []

            for op in ops:
                if isinstance(op, SyscallInvoke):
                    code.extend(self.syscall(op))
                elif isinstance(op, LoadRegister):
                    code.extend(self.reg_load(op.register, op.value))
                elif isinstance(op, str):
                    code.extend(op.split('\n'))
                else:
                    raise ValueError('No idea how to assemble "%s"' % repr(op))
            return ['\t%s' % line for line in code]

        # We do 2 passes to make sure all data is allocated so buffers point at the right offset.
        _compile()
        return '\n'.join(self.finalize(self.data_finalizer(_compile(), self.data))) + '\n'