Files
ftmemsim-valgrind/coregrind/vg_helpers.S
Jeremy Fitzhardinge 918c3a7b7e This jumbo-checkin is the Full Virtualization checkin. This eliminates
Valgrind's dependency on the dynamic linker for getting started, and
instead takes things into its own hands.

This checkin doesn't add much in the way of new functionality, but it
is the basis for all future work on Valgrind.  It allows us much more
flexibility in implementation, and well as increasing the reliability
of Valgrind by protecting it more from its clients.

This patch requires some changes to tools to update them to the changes
in the tool API, but they are straightforward.  See the posting "Heads
up: Full Virtualization" on valgrind-developers for a more complete
description of this change and its effects on you.


git-svn-id: svn://svn.valgrind.org/valgrind/trunk@2118
2003-12-16 02:05:15 +00:00

626 lines
11 KiB
ArmAsm

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