mirror of
https://github.com/Zenithsiz/ftmemsim-valgrind.git
synced 2026-02-06 11:41:34 +00:00
to include the SSE/SSE2 architectural state. Automagically detect at startup, in vg_startup.S, whether or not this is a SSE-enabled CPU and act accordingly. All subsequent FPU/SSE state transfers between the simulated and real machine are then done either with fsave/frstor (as before) or fxsave/fxrstor (the SSE equivalents). Fragile and fiddly; (1) the SSE state needs to be stored on a 16-byte boundary, and (2) certain bits in the saved MXCSR reg in a state written by fxsave need to be anded out before we can safely restore using fxrstor. It does appear to work. I'd appreciate people trying it out on various CPUs to establish whether the SSE / not-SSE check works right, and/or anything else is broken. Unfortunately makes some programs run significantly slower. I don't know why. Perhaps due to copying around more processor state than there was before (SSE state is 512 bytes, FPU state was only 108). I will look into this. git-svn-id: svn://svn.valgrind.org/valgrind/trunk@1574
301 lines
8.9 KiB
ArmAsm
301 lines
8.9 KiB
ArmAsm
|
|
##--------------------------------------------------------------------##
|
|
##--- Startup and shutdown code for Valgrind. ---##
|
|
##--- vg_startup.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"
|
|
|
|
|
|
#---------------------------------------------------------------------
|
|
#
|
|
# Startup and shutdown code for Valgrind. Particularly hairy.
|
|
#
|
|
# The dynamic linker, ld.so, will run the contents of the .init
|
|
# section, once it has located, mmap-d and and linked the shared
|
|
# libraries needed by the program. Valgrind is itself a shared
|
|
# library. ld.so then runs code in the .init sections of each
|
|
# library in turn, in order to give them a chance to initialise
|
|
# themselves. We hijack this mechanism. Our startup routine
|
|
# does return -- and execution continues -- except on the
|
|
# synthetic CPU, not the real one. But ld.so, and the program
|
|
# it is starting, cant tell the difference.
|
|
#
|
|
# The management apologise for the lack of apostrophes in these
|
|
# comments. GNU as seems to object to them, for some reason.
|
|
|
|
|
|
.section .init
|
|
call VG_(startup)
|
|
.section .fini
|
|
call VG_(shutdown)
|
|
|
|
.section .data
|
|
valgrind_already_initted:
|
|
.word 0
|
|
|
|
.section .text
|
|
|
|
|
|
.global VG_(startup)
|
|
VG_(startup):
|
|
pushfl
|
|
cmpl $0, valgrind_already_initted
|
|
je really_start_up
|
|
popfl
|
|
ret
|
|
|
|
really_start_up:
|
|
popfl
|
|
movl $1, valgrind_already_initted
|
|
|
|
# Record %esp as it was when we got here. This is because argv/c
|
|
# and envp[] are passed as args to this function, and we need to see
|
|
# envp so we can get at the env var VG_ARGS without help from libc.
|
|
# The stack layout at this point depends on the version of glibc in
|
|
# use. See process_cmd_line_options() in vg_main.c for details.
|
|
movl %esp, VG_(esp_at_startup)
|
|
|
|
# We have control! Save the state of the machine in
|
|
# the simulators state, and switch stacks.
|
|
# Except ... we cant copy the machines registers into their
|
|
# final places in vg_baseBlock, because the offsets to them
|
|
# have not yet been set up. Instead, they are copied to a
|
|
# temporary place (m_state_static). In vg_main.c, once the
|
|
# baseBlock offsets are set up, values are copied into baseBlock.
|
|
movw %cs, VG_(m_state_static)+0
|
|
movw %ss, VG_(m_state_static)+4
|
|
movw %ds, VG_(m_state_static)+8
|
|
movw %es, VG_(m_state_static)+12
|
|
movw %fs, VG_(m_state_static)+16
|
|
movw %gs, VG_(m_state_static)+20
|
|
movl %eax, VG_(m_state_static)+24
|
|
movl %ecx, VG_(m_state_static)+28
|
|
movl %edx, VG_(m_state_static)+32
|
|
movl %ebx, VG_(m_state_static)+36
|
|
movl %esp, VG_(m_state_static)+40
|
|
movl %ebp, VG_(m_state_static)+44
|
|
movl %esi, VG_(m_state_static)+48
|
|
movl %edi, VG_(m_state_static)+52
|
|
pushfl
|
|
popl %eax
|
|
movl %eax, VG_(m_state_static)+56
|
|
|
|
# now weve captured all the integer registers and
|
|
# flags, figure out whether this is an sse-enabled
|
|
# cpu or not.
|
|
movb $0, VG_(have_ssestate) # assume sse-disabled
|
|
movl $0, %eax
|
|
cpuid
|
|
cmpl $1, %eax
|
|
jl get_fpu # we cant do cpuid(1) ?!
|
|
movl $1, %eax
|
|
cpuid
|
|
testl $(1<<25), %edx
|
|
jz get_fpu # edx bit 25 is set iff sse
|
|
# well, it looks like were sse-enabled
|
|
movb $1, VG_(have_ssestate)
|
|
|
|
# next, capture the FPU/SSE state
|
|
get_fpu:
|
|
fwait
|
|
|
|
pushfl
|
|
cmpb $0, VG_(have_ssestate)
|
|
jz qq3nosse
|
|
fxsave VG_(m_state_static)+64
|
|
andl $0x0000FFBF, VG_(m_state_static)+64+24
|
|
fxrstor VG_(m_state_static)+64
|
|
jmp qq3merge
|
|
qq3nosse:
|
|
fnsave VG_(m_state_static)+64
|
|
frstor VG_(m_state_static)+64
|
|
qq3merge:
|
|
popfl
|
|
|
|
# keep the first and last 10 words free to check for overruns
|
|
movl $VG_(stack)+39996 -40, %esp
|
|
|
|
# Now some real magic. We need this procedure to return,
|
|
# since thats what ld.so expects, but running on the
|
|
# simulator. So vg_main starts the simulator running at
|
|
# the insn labelled first_insn_to_simulate.
|
|
|
|
movl $first_insn_to_simulate, VG_(m_state_static)+60
|
|
jmp VG_(main)
|
|
first_insn_to_simulate:
|
|
# Nothing else to do -- just return in the "normal" way.
|
|
ret
|
|
|
|
|
|
|
|
VG_(shutdown):
|
|
# Just return, and ignore any attempt by ld.so to call
|
|
# valgrind.sos exit function. We just run the client all
|
|
# the way to the final exit() syscall. This sidesteps
|
|
# problems caused by ld.so calling the finalisation code
|
|
# of other .sos *after* it shuts down valgrind, which
|
|
# was causing big problems with threads.
|
|
ret
|
|
|
|
|
|
|
|
.global VG_(switch_to_real_CPU)
|
|
VG_(switch_to_real_CPU):
|
|
# Once Valgrind has decided it needs to exit,
|
|
# because the specified number of insns have been completed
|
|
# during a debugging run, it jumps here, which copies the
|
|
# simulators state into the real machine state. Execution
|
|
# of the rest of the program continues on the real CPU,
|
|
# and there is no way for the simulator to regain control
|
|
# after this point.
|
|
|
|
pushfl
|
|
cmpb $0, VG_(have_ssestate)
|
|
jz qq4nosse
|
|
andl $0x0000FFBF, VG_(m_state_static)+64+24
|
|
fxrstor VG_(m_state_static)+64
|
|
jmp qq4merge
|
|
qq4nosse:
|
|
frstor VG_(m_state_static)+64
|
|
qq4merge:
|
|
popfl
|
|
|
|
movl VG_(m_state_static)+56, %eax
|
|
pushl %eax
|
|
popfl
|
|
/* some of these are apparently illegal */
|
|
/* movw VG_(m_state_static)+0, %cs */
|
|
movw VG_(m_state_static)+4, %ss
|
|
movw VG_(m_state_static)+8, %ds
|
|
movw VG_(m_state_static)+12, %es
|
|
movw VG_(m_state_static)+16, %fs
|
|
movw VG_(m_state_static)+20, %gs
|
|
movl VG_(m_state_static)+24, %eax
|
|
movl VG_(m_state_static)+28, %ecx
|
|
movl VG_(m_state_static)+32, %edx
|
|
movl VG_(m_state_static)+36, %ebx
|
|
movl VG_(m_state_static)+40, %esp
|
|
movl VG_(m_state_static)+44, %ebp
|
|
movl VG_(m_state_static)+48, %esi
|
|
movl VG_(m_state_static)+52, %edi
|
|
|
|
pushal
|
|
pushfl
|
|
# We hope that vg_sigshutdown_actions does not alter
|
|
# the FPU state.
|
|
call VG_(sigshutdown_actions)
|
|
popfl
|
|
popal
|
|
|
|
# re-restore the FPU state anyway ...
|
|
pushfl
|
|
cmpb $0, VG_(have_ssestate)
|
|
jz qq5nosse
|
|
andl $0x0000FFBF, VG_(m_state_static)+64+24
|
|
fxrstor VG_(m_state_static)+64
|
|
jmp qq5merge
|
|
qq5nosse:
|
|
frstor VG_(m_state_static)+64
|
|
qq5merge:
|
|
popfl
|
|
|
|
jmp *VG_(m_state_static)+60
|
|
|
|
|
|
|
|
/*------------------------------------------------------------*/
|
|
/*--- A function to temporarily copy %ESP/%EBP into ---*/
|
|
/*--- %esp/%ebp and then start up GDB. ---*/
|
|
/*------------------------------------------------------------*/
|
|
|
|
/*
|
|
extern void VG_(swizzle_esp_then_start_GDB) ( Addr m_eip_at_error,
|
|
Addr m_esp_at_error,
|
|
Addr m_ebp_at_error );
|
|
*/
|
|
|
|
/*--- This is clearly not re-entrant! ---*/
|
|
.data
|
|
vg_ebp_saved_over_GDB_start:
|
|
.long 0
|
|
vg_esp_saved_over_GDB_start:
|
|
.long 0
|
|
.text
|
|
|
|
.global VG_(swizzle_esp_then_start_GDB)
|
|
VG_(swizzle_esp_then_start_GDB):
|
|
pushal
|
|
|
|
# remember the simulators current stack/frame pointers
|
|
movl %ebp, vg_ebp_saved_over_GDB_start
|
|
movl %esp, vg_esp_saved_over_GDB_start
|
|
|
|
# get args into regs
|
|
movl 44(%esp), %eax # client %EBP
|
|
movl 40(%esp), %ebx # client %ESP
|
|
movl 36(%esp), %ecx # client %EIP
|
|
|
|
# Now that we dont need to refer to simulators stack any more,
|
|
# put %ESP into %esp
|
|
movl %ebx, %esp
|
|
|
|
### %esp now refers to clients stack
|
|
### mess with the clients stack to make it look as if it
|
|
### called this procedure, since otherwise it will look to gdb
|
|
### as if the top (currently executing) stack frame of the
|
|
### client is missing.
|
|
|
|
# push %EIP. This is a faked-up return address.
|
|
pushl %ecx
|
|
|
|
# push %EBP. This is a faked %ebp-chain pointer.
|
|
pushl %eax
|
|
|
|
movl %esp, %ebp
|
|
|
|
call VG_(start_GDB_whilst_on_client_stack)
|
|
|
|
# restore the simulators stack/frame pointer
|
|
movl vg_ebp_saved_over_GDB_start, %ebp
|
|
movl vg_esp_saved_over_GDB_start, %esp
|
|
|
|
popal
|
|
ret
|
|
|
|
# gcc puts this construction at the end of every function. I think it
|
|
# allows the linker to figure out the size of the function. So we do
|
|
# the same, in the vague hope that it might help GDBs navigation.
|
|
.Lend_of_swizzle:
|
|
.size VG_(swizzle_esp_then_start_GDB), .Lend_of_swizzle-VG_(swizzle_esp_then_start_GDB)
|
|
|
|
|
|
##--------------------------------------------------------------------##
|
|
##--- end vg_startup.S ---##
|
|
##--------------------------------------------------------------------##
|