blob: 091f8e8674133432c61af8ec2dc859140e546ab8 [file] [log] [blame]
##--------------------------------------------------------------------##
##--- Support routines for the JITter output. ---##
##--- vg_helpers.S ---##
##--------------------------------------------------------------------##
/*
This file is part of Valgrind, an extensible x86 protected-mode
emulator for monitoring program execution on x86-Unixes.
Copyright (C) 2000-2003 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 COPYING.
*/
#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.
This isn't used in-place. It is copied into the client address space
at an arbitary address. Therefore, this code must be completely
position-independent.
*/
.global VG_(signalreturn_bogusRA)
.global VG_(signalreturn_bogusRA_length)
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
ud2
VG_(signalreturn_bogusRA_length):
.long . - VG_(signalreturn_bogusRA)
/* ------------------ 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.
*/
/* 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
/*
Fetch a byte/word/dword from given port
On entry:
size 1, 2 or 4
port, replaced by result
RA
*/
.global VG_(helper_IN)
VG_(helper_IN):
pushl %eax
pushl %edx
movl 16(%esp), %eax
movl 12(%esp), %edx
cmpl $4, %eax
je in_dword
cmpl $2, %eax
je in_word
in_byte:
inb (%dx), %al
jmp in_done
in_word:
in (%dx), %ax
jmp in_done
in_dword:
inl (%dx),%eax
in_done:
movl %eax,12(%esp)
popl %edx
popl %eax
ret
/*
Write a byte/word/dword to given port
On entry:
size 1, 2 or 4
port
value
RA
*/
.global VG_(helper_OUT)
VG_(helper_OUT):
pushl %eax
pushl %edx
movl 16(%esp), %edx
movl 12(%esp), %eax
cmpl $4, 20(%esp)
je out_dword
cmpl $2, 20(%esp)
je out_word
out_byte:
outb %al,(%dx)
jmp out_done
out_word:
out %ax,(%dx)
jmp out_done
out_dword:
outl %eax,(%dx)
out_done:
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
For simulating the cpuid instruction, we will
issue a "real" cpuid instruction and then mask out
the bits of the features we do not support currently (3dnow mostly).
Dirk Mueller <mueller@kde.org>
http://www.sandpile.org/ia32/cpuid.htm
references:
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
cmpl $0x80000001, %eax
je cpuid_no3dnow
cpuid
jmp cpuid__99
cpuid_no3dnow:
cpuid
andl $0x3fffffff, %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_ssestate), %esi
pushfl
cmpb $0, VG_(have_ssestate)
jz aa1nosse
fxrstor (%ebp, %esi, 4)
jmp aa1merge
aa1nosse:
frstor (%ebp, %esi, 4)
aa1merge:
popfl
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
/* Copy %eflags into %ah.
On entry:
value of %eax
RA <- %esp
*/
.global VG_(helper_LAHF)
VG_(helper_LAHF):
pushl %eax
movl 8(%esp), %eax
lahf
movl %eax, 8(%esp)
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):
pushl %eax
movl VGOFF_(m_dflag), %eax
movl (%ebp, %eax, 4), %eax
movl %eax, 8(%esp)
popl %eax
ret
/* Clear/set the direction flag. */
.global VG_(helper_CLD)
VG_(helper_CLD):
pushl %eax
movl VGOFF_(m_dflag), %eax
movl $1, (%ebp, %eax, 4)
popl %eax
ret
.global VG_(helper_STD)
VG_(helper_STD):
pushl %eax
movl VGOFF_(m_dflag), %eax
movl $-1, (%ebp, %eax, 4)
popl %eax
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
/* Undefined instruction (generates SIGILL) */
.globl VG_(helper_undefined_instruction)
VG_(helper_undefined_instruction):
1: ud2
jmp 1b
##--------------------------------------------------------------------##
##--- end vg_helpers.S ---##
##--------------------------------------------------------------------##