mirror of
https://github.com/Zenithsiz/ftmemsim-valgrind.git
synced 2026-02-09 05:10:23 +00:00
add a simple compromise, in which the client can notify valgrind that certain code address ranges are invalid and should be retranslated. This is done using the VALGRIND_DISCARD_TRANSLATIONS macro in valgrind.h. At the same time take the opportunity to close the potentially fatal loophole that translations for executable segments were not being discarded when those segments were munmapped. They are now. Documentation updated. git-svn-id: svn://svn.valgrind.org/valgrind/trunk@274
593 lines
11 KiB
ArmAsm
593 lines
11 KiB
ArmAsm
|
|
##--------------------------------------------------------------------##
|
|
##--- 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 couple of stubs for returns which we want to catch: signal
|
|
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
|
|
|
|
|
|
|
|
.global VG_(pthreadreturn_bogusRA)
|
|
VG_(pthreadreturn_bogusRA):
|
|
subl $20, %esp # allocate arg block
|
|
movl %esp, %edx # %edx == &_zzq_args[0]
|
|
movl $VG_USERREQ__PTHREAD_RETURNS, 0(%edx) # request
|
|
movl %eax, 4(%edx) # arg1 == thread return value
|
|
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 $pthreadreturn_bogusRA_panic_msg
|
|
call VG_(panic)
|
|
|
|
.data
|
|
pthreadreturn_bogusRA_panic_msg:
|
|
.ascii "vg_pthreadreturn_bogusRA: VG_USERREQ__PTHREAD_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 <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
|
|
|
|
|
|
/* 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
|
|
|
|
|
|
|
|
/* 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 ---##
|
|
##--------------------------------------------------------------------##
|