Initial revision


git-svn-id: svn://svn.valgrind.org/valgrind/trunk@2 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/vg_helpers.S b/vg_helpers.S
new file mode 100644
index 0000000..781175d
--- /dev/null
+++ b/vg_helpers.S
@@ -0,0 +1,625 @@
+
+##--------------------------------------------------------------------##
+##--- Support routines for the JITter output.                      ---##
+##---                                                 vg_helpers.S ---##
+##--------------------------------------------------------------------##
+
+/*
+  This file is part of Valgrind, an x86 protected-mode emulator 
+  designed for debugging and profiling binaries on x86-Unixes.
+
+  Copyright (C) 2000-2002 Julian Seward 
+     jseward@acm.org
+     Julian_Seward@muraroa.demon.co.uk
+
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU General Public License as
+  published by the Free Software Foundation; either version 2 of the
+  License, or (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+  02111-1307, USA.
+
+  The GNU General Public License is contained in the file LICENSE.
+*/
+
+#include "vg_constants.h"
+
+
+/* Various helper routines, for instructions which are just too
+   darn tedious for the JITter to output code in-line:
+	
+	* integer division
+	* integer multiplication
+        * setting and getting obscure eflags
+	* double-length shifts
+	
+   All routines use a standard calling convention designed for
+   calling from translations, in which the incoming args are
+   underneath the return address, the callee saves _all_ registers,
+   and the incoming parameters can be modified, to return results.
+*/
+
+
+/*
+   On entry:
+	%ECX value
+	%EBX value
+	%EAX value -- also the result
+	RA   <- %esp  -- after pushal+pushfl is 36(%esp)
+*/
+.global VG_(helper_do_client_request)
+VG_(helper_do_client_request):
+	pushal
+	pushfl
+	
+	movl	48(%esp), %eax
+	pushl	%eax
+	movl	48(%esp), %eax
+	pushl	%eax
+	movl	48(%esp), %eax
+	pushl	%eax
+
+	call	VG_(handle_client_request)
+	movl	%eax, 52(%esp)
+
+	addl	$12, %esp
+	
+	popfl
+	popal
+	ret
+
+
+.global VG_(helper_do_syscall)
+VG_(helper_do_syscall):
+	pushal
+	call	VG_(wrap_syscall)
+	popal
+#	movl	$VG_(baseBlock), %ebp
+	ret
+
+
+	
+.global VG_(helper_value_check0_fail)
+VG_(helper_value_check0_fail):
+	pushal
+	call	VG_(helperc_value_check0_fail)
+	popal
+	ret
+
+.global VG_(helper_value_check1_fail)
+VG_(helper_value_check1_fail):
+	pushal
+	call	VG_(helperc_value_check1_fail)
+	popal
+	ret
+
+.global VG_(helper_value_check2_fail)
+VG_(helper_value_check2_fail):
+	pushal
+	call	VG_(helperc_value_check2_fail)
+	popal
+	ret
+
+.global VG_(helper_value_check4_fail)
+VG_(helper_value_check4_fail):
+	pushal
+	call	VG_(helperc_value_check4_fail)
+	popal
+	ret
+
+
+/* Set things up so the dispatch loop exits normally.  Used when it is
+   detected that the program wants to finish, ie it has called
+   vg_shutdown. 
+*/
+.global VG_(helper_request_normal_exit)
+VG_(helper_request_normal_exit):
+	pushl	%eax
+	movl	VG_(dispatch_ctr), %eax
+	movl	%eax, VG_(dispatch_ctr_SAVED)
+	movl	$1, VG_(dispatch_ctr)
+	movl	$VG_Y_EXIT, VG_(interrupt_reason)
+	popl	%eax
+	ret
+
+
+/* Do a original-code-write check for the address in %ebp. */
+.global VG_(helper_smc_check4)
+VG_(helper_smc_check4):
+#if VG_SMC_FASTCHECK_IN_C
+
+	# save the live regs
+	pushl	%eax
+	pushl	%ebx
+	pushl	%ecx
+	pushl	%edx
+	pushl	%esi
+	pushl	%edi
+	
+	pushl	%ebp
+	call	VG_(smc_check4)
+	addl	$4, %esp
+
+	popl	%edi
+	popl	%esi
+	popl	%edx
+	popl	%ecx
+	popl	%ebx
+	popl	%eax
+	
+	ret
+#else	
+	incl	VG_(smc_total_check4s)
+	pushl	%ebp
+	shrl	$VG_SMC_CACHE_SHIFT, %ebp
+	andl	$VG_SMC_CACHE_MASK, %ebp
+	cmpb	$0, VG_(smc_cache)(%ebp)
+	jnz	vg_smc_cache_failure
+	addl	$4, %esp
+	ret
+      vg_smc_cache_failure:
+	popl	%ebp
+	pushal
+	pushl	%ebp
+	call	VG_(smc_check4)
+	addl	$4, %esp
+	popal
+	ret
+#endif
+
+	
+/* Fetch the time-stamp-ctr reg.
+   On entry:
+	dummy, replaced by %EAX value
+	dummy, replaced by %EDX value
+	RA   <- %esp
+*/
+.global VG_(helper_RDTSC)
+VG_(helper_RDTSC):
+	pushl	%eax
+	pushl	%edx
+	rdtsc
+	movl	%edx, 12(%esp)
+	movl	%eax, 16(%esp)
+	popl	%edx
+	popl	%eax
+	ret
+
+
+/* Do the CPUID instruction.
+   On entry:
+	dummy, replaced by %EAX value
+	dummy, replaced by %EBX value
+	dummy, replaced by %ECX value
+	dummy, replaced by %EDX value
+	RA   <- %esp
+
+   As emulating a real CPUID is kinda hard, as it
+   has to return different values depending on EAX, 
+   we just pretend to not support CPUID at all until
+   it becomes a problem. This will for sure disable
+   all MMX / 3dnow checks so they don't bother us
+   with code we don't understand. (Dirk <dirk@kde.org>)
+   
+   http://www.sandpile.org/ia32/cpuid.htm
+
+   (Later: we instead pretend to be like Werner's P54C P133, that is
+    an original pre-MMX Pentium).
+   <werner> cpuid words (0): 0x1 0x756e6547 0x6c65746e 0x49656e69
+   <werner> cpuid words (1): 0x52b 0x0 0x0 0x1bf
+*/
+.global VG_(helper_CPUID)
+VG_(helper_CPUID):
+	pushl	%eax
+	pushl	%ebx
+	pushl	%ecx
+	pushl	%edx
+	movl	32(%esp), %eax
+/*
+	cpuid
+*/
+/*
+        xor     %eax,%eax
+        xor     %ebx,%ebx
+        xor     %ecx,%ecx
+        xor     %edx,%edx
+*/
+	cmpl	$0, %eax
+	jz	cpuid__0
+	movl	$0x52b, %eax
+	movl	$0x0,   %ebx
+	movl	$0x0,   %ecx
+	movl	$0x1bf, %edx
+	jmp	cpuid__99
+cpuid__0:
+	movl	$0x1,        %eax
+	movl	$0x756e6547, %ebx
+	movl	$0x6c65746e, %ecx
+	movl	$0x49656e69, %edx
+cpuid__99:
+		
+	movl	%edx, 20(%esp)
+	movl	%ecx, 24(%esp)
+	movl	%ebx, 28(%esp)
+	movl	%eax, 32(%esp)
+	popl	%edx
+	popl	%ecx
+	popl	%ebx
+	popl	%eax
+	ret
+
+
+/* Fetch the FPU status register.
+   On entry:
+	dummy, replaced by result
+	RA   <- %esp
+*/
+.global VG_(helper_fstsw_AX)
+VG_(helper_fstsw_AX):
+	pushl	%eax
+	pushl	%esi
+	movl	VGOFF_(m_fpustate), %esi
+	frstor	(%ebp, %esi, 4)
+	fstsw	%ax
+	popl	%esi
+	movw	%ax, 8(%esp)
+	popl	%eax
+	ret
+
+
+/* Copy %ah into %eflags.
+   On entry:
+	value of %eax
+	RA   <- %esp
+*/
+.global VG_(helper_SAHF)
+VG_(helper_SAHF):
+	pushl	%eax
+	movl	8(%esp), %eax
+	sahf
+	popl	%eax
+	ret
+
+
+/* Bit scan forwards/reverse.  Sets flags (??).
+   On entry:
+	value, replaced by result
+	RA   <- %esp
+*/
+.global VG_(helper_bsr)
+VG_(helper_bsr):
+	pushl	%eax
+	bsrl	8(%esp), %eax
+	movl	%eax, 8(%esp)
+	popl	%eax
+	ret
+
+.global VG_(helper_bsf)
+VG_(helper_bsf):
+	pushl	%eax
+	bsfl	8(%esp), %eax
+	movl	%eax, 8(%esp)
+	popl	%eax
+	ret
+
+
+/* Bit test and set/reset/complement.  Sets flags.
+   On entry:
+	src
+	dst
+	RA   <- %esp
+*/
+.global VG_(helper_bt)
+VG_(helper_bt):
+	pushl	%eax
+	movl	12(%esp), %eax
+	btl	%eax, 8(%esp)
+	popl	%eax
+	ret
+.global VG_(helper_bts)
+VG_(helper_bts):
+	pushl	%eax
+	movl	12(%esp), %eax
+	btsl	%eax, 8(%esp)
+	popl	%eax
+	ret
+.global VG_(helper_btr)
+VG_(helper_btr):
+	pushl	%eax
+	movl	12(%esp), %eax
+	btrl	%eax, 8(%esp)
+	popl	%eax
+	ret
+.global VG_(helper_btc)
+VG_(helper_btc):
+	pushl	%eax
+	movl	12(%esp), %eax
+	btcl	%eax, 8(%esp)
+	popl	%eax
+	ret
+	
+	
+/* 32-bit double-length shift left/right.
+   On entry:
+	amount
+	src
+	dst
+	RA   <- %esp
+*/
+.global VG_(helper_shldl)
+VG_(helper_shldl):
+	pushl	%eax
+	pushl	%ebx
+	pushl	%ecx
+
+	movb	24(%esp), %cl
+	movl	20(%esp), %ebx
+	movl	16(%esp), %eax
+	shldl	%cl, %ebx, %eax
+	movl	%eax, 16(%esp)
+	
+	popl	%ecx
+	popl	%ebx
+	popl	%eax
+	ret
+
+.global VG_(helper_shldw)
+VG_(helper_shldw):
+	pushl	%eax
+	pushl	%ebx
+	pushl	%ecx
+
+	movb	24(%esp), %cl
+	movw	20(%esp), %bx
+	movw	16(%esp), %ax
+	shldw	%cl, %bx, %ax
+	movw	%ax, 16(%esp)
+	
+	popl	%ecx
+	popl	%ebx
+	popl	%eax
+	ret
+
+.global VG_(helper_shrdl)
+VG_(helper_shrdl):
+	pushl	%eax
+	pushl	%ebx
+	pushl	%ecx
+
+	movb	24(%esp), %cl
+	movl	20(%esp), %ebx
+	movl	16(%esp), %eax
+	shrdl	%cl, %ebx, %eax
+	movl	%eax, 16(%esp)
+	
+	popl	%ecx
+	popl	%ebx
+	popl	%eax
+	ret
+
+.global VG_(helper_shrdw)
+VG_(helper_shrdw):
+	pushl	%eax
+	pushl	%ebx
+	pushl	%ecx
+
+	movb	24(%esp), %cl
+	movw	20(%esp), %bx
+	movw	16(%esp), %ax
+	shrdw	%cl, %bx, %ax
+	movw	%ax, 16(%esp)
+	
+	popl	%ecx
+	popl	%ebx
+	popl	%eax
+	ret
+
+	
+/* Get the direction flag, and return either 1 or -1. */
+.global VG_(helper_get_dirflag)
+VG_(helper_get_dirflag):
+	pushfl
+	pushl	%eax
+
+	pushfl
+	popl	%eax
+	shrl	$10, %eax
+	andl	$1, %eax
+	jnz	L1
+	movl	$1, %eax
+	jmp	L2
+L1:	movl	$-1, %eax
+L2:	movl	%eax, 12(%esp)
+
+	popl %eax
+	popfl
+	ret
+
+
+/* Clear/set the direction flag. */
+.global VG_(helper_CLD)
+VG_(helper_CLD):
+	cld
+	ret
+
+.global VG_(helper_STD)
+VG_(helper_STD):
+	std
+	ret
+
+
+
+/* Signed 32-to-64 multiply. */
+.globl VG_(helper_imul_32_64)
+VG_(helper_imul_32_64):
+	pushl	%eax
+	pushl	%edx
+	movl	16(%esp), %eax
+	imull	12(%esp)
+	movl	%eax, 16(%esp)
+	movl	%edx, 12(%esp)
+	popl	%edx
+	popl	%eax
+	ret
+	
+/* Signed 16-to-32 multiply. */
+.globl VG_(helper_imul_16_32)
+VG_(helper_imul_16_32):
+	pushl	%eax
+	pushl	%edx
+	movw	16(%esp), %ax
+	imulw	12(%esp)
+	movw	%ax, 16(%esp)
+	movw	%dx, 12(%esp)
+	popl	%edx
+	popl	%eax
+	ret
+	
+/* Signed 8-to-16 multiply. */
+.globl VG_(helper_imul_8_16)
+VG_(helper_imul_8_16):
+	pushl	%eax
+	pushl	%edx
+	movb	16(%esp), %al
+	imulb	12(%esp)
+	movw	%ax, 16(%esp)
+	popl	%edx
+	popl	%eax
+	ret
+	
+
+	
+	
+	
+	
+/* Unsigned 32-to-64 multiply. */
+.globl VG_(helper_mul_32_64)
+VG_(helper_mul_32_64):
+	pushl	%eax
+	pushl	%edx
+	movl	16(%esp), %eax
+	mull	12(%esp)
+	movl	%eax, 16(%esp)
+	movl	%edx, 12(%esp)
+	popl	%edx
+	popl	%eax
+	ret
+	
+/* Unsigned 16-to-32 multiply. */
+.globl VG_(helper_mul_16_32)
+VG_(helper_mul_16_32):
+	pushl	%eax
+	pushl	%edx
+	movw	16(%esp), %ax
+	mulw	12(%esp)
+	movw	%ax, 16(%esp)
+	movw	%dx, 12(%esp)
+	popl	%edx
+	popl	%eax
+	ret
+	
+/* Unsigned 8-to-16 multiply. */
+.globl VG_(helper_mul_8_16)
+VG_(helper_mul_8_16):
+	pushl	%eax
+	pushl	%edx
+	movb	16(%esp), %al
+	mulb	12(%esp)
+	movw	%ax, 16(%esp)
+	popl	%edx
+	popl	%eax
+	ret
+	
+	
+	
+		
+/* Unsigned 64-into-32 divide. */
+.globl	VG_(helper_div_64_32)
+VG_(helper_div_64_32):
+	pushl	%eax
+	pushl	%edx
+	movl	16(%esp),%eax
+	movl	12(%esp),%edx
+	divl	20(%esp)
+	movl	%eax,16(%esp)
+	movl	%edx,12(%esp)
+	popl	%edx
+	popl	%eax
+	ret
+
+/* Signed 64-into-32 divide. */
+.globl	VG_(helper_idiv_64_32)
+VG_(helper_idiv_64_32):
+	pushl	%eax
+	pushl	%edx
+	movl	16(%esp),%eax
+	movl	12(%esp),%edx
+	idivl	20(%esp)
+	movl	%eax,16(%esp)
+	movl	%edx,12(%esp)
+	popl	%edx
+	popl	%eax
+	ret
+
+/* Unsigned 32-into-16 divide. */
+.globl	VG_(helper_div_32_16)
+VG_(helper_div_32_16):
+	pushl	%eax
+	pushl	%edx
+	movw	16(%esp),%ax
+	movw	12(%esp),%dx
+	divw	20(%esp)
+	movw	%ax,16(%esp)
+	movw	%dx,12(%esp)
+	popl	%edx
+	popl	%eax
+	ret
+
+/* Signed 32-into-16 divide. */
+.globl	VG_(helper_idiv_32_16)
+VG_(helper_idiv_32_16):
+	pushl	%eax
+	pushl	%edx
+	movw	16(%esp),%ax
+	movw	12(%esp),%dx
+	idivw	20(%esp)
+	movw	%ax,16(%esp)
+	movw	%dx,12(%esp)
+	popl	%edx
+	popl	%eax
+	ret
+
+/* Unsigned 16-into-8 divide. */
+.globl	VG_(helper_div_16_8)
+VG_(helper_div_16_8):
+	pushl	%eax
+	movw	12(%esp),%ax
+	divb	16(%esp)
+	movb	%ah,12(%esp)
+	movb	%al,8(%esp)
+	popl	%eax
+	ret
+
+/* Signed 16-into-8 divide. */
+.globl	VG_(helper_idiv_16_8)
+VG_(helper_idiv_16_8):
+	pushl	%eax
+	movw	12(%esp),%ax
+	idivb	16(%esp)
+	movb	%ah,12(%esp)
+	movb	%al,8(%esp)
+	popl	%eax
+	ret
+
+		
+##--------------------------------------------------------------------##
+##--- end                                             vg_helpers.S ---##
+##--------------------------------------------------------------------##