##--------------------------------------------------------------------## ##--- 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 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" /* ------------------ SIMULATED CPU HELPERS ------------------ */ /* A stubs for a return which we want to catch: a signal return. returns and pthread returns. In the latter case, the thread's return value is in %EAX, so we pass this as the first argument to the request. In both cases we use the user request mechanism. You need to to read the definition of VALGRIND_MAGIC_SEQUENCE in valgrind.h to make sense of this. */ .global VG_(signalreturn_bogusRA) VG_(signalreturn_bogusRA): subl $20, %esp # allocate arg block movl %esp, %edx # %edx == &_zzq_args[0] movl $VG_USERREQ__SIGNAL_RETURNS, 0(%edx) # request movl $0, 4(%edx) # arg1 movl $0, 8(%edx) # arg2 movl $0, 12(%edx) # arg3 movl $0, 16(%edx) # arg4 movl %edx, %eax # and now the magic sequence itself: roll $29, %eax roll $3, %eax rorl $27, %eax rorl $5, %eax roll $13, %eax roll $19, %eax # should never get here pushl $signalreturn_bogusRA_panic_msg call VG_(panic) .data signalreturn_bogusRA_panic_msg: .ascii "vg_signalreturn_bogusRA: VG_USERREQ__SIGNAL_RETURNS was missed" .byte 0 .text /* ------------------ REAL CPU HELPERS ------------------ */ /* The rest of this lot run on the real CPU. */ /* 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. */ .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 /* 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 ) 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). cpuid words (0): 0x1 0x756e6547 0x6c65746e 0x49656e69 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 /* Do %al = DAS(%al). Note that the passed param has %AL as the least significant 8 bits, since it was generated with GETB %AL, some-temp. Fortunately %al is the least significant 8 bits of %eax anyway, which is why it's safe to work with %eax as a whole. On entry: value of %eax RA <- %esp */ .global VG_(helper_DAS) VG_(helper_DAS): pushl %eax movl 8(%esp), %eax das movl %eax, 8(%esp) popl %eax ret /* Similarly, do %al = DAA(%al). */ .global VG_(helper_DAA) VG_(helper_DAA): pushl %eax movl 8(%esp), %eax daa movl %eax, 8(%esp) 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 movl 12(%esp), %eax bsrl 8(%esp), %eax movl %eax, 12(%esp) popl %eax ret .global VG_(helper_bsf) VG_(helper_bsf): pushl %eax movl 12(%esp), %eax bsfl 8(%esp), %eax movl %eax, 12(%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 /* Clear/set the carry flag. */ .global VG_(helper_CLC) VG_(helper_CLC): clc ret .global VG_(helper_STC) VG_(helper_STC): stc 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 ---## ##--------------------------------------------------------------------##