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 ---##
+##--------------------------------------------------------------------##