Initial revision


git-svn-id: svn://svn.valgrind.org/valgrind/trunk@2 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/coregrind/vg_startup.S b/coregrind/vg_startup.S
new file mode 100644
index 0000000..3fa965c
--- /dev/null
+++ b/coregrind/vg_startup.S
@@ -0,0 +1,221 @@
+
+##--------------------------------------------------------------------##
+##--- Startup and shutdown code for Valgrind.                      ---##
+##---                                                 vg_startup.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
+     Julian_Seward@muraroa.demon.co.uk
+
+  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"
+
+
+#---------------------------------------------------------------------
+#
+# 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 .text
+	
+
+
+VG_(startup):
+        # 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.
+	movl	%eax, VG_(m_state_static)+0
+	movl	%ecx, VG_(m_state_static)+4
+	movl	%edx, VG_(m_state_static)+8
+	movl	%ebx, VG_(m_state_static)+12
+	movl	%esp, VG_(m_state_static)+16
+	movl	%ebp, VG_(m_state_static)+20
+	movl	%esi, VG_(m_state_static)+24
+	movl	%edi, VG_(m_state_static)+28
+	pushfl
+	popl	%eax
+	movl	%eax, VG_(m_state_static)+32
+	fwait
+	fnsave	VG_(m_state_static)+40
+	frstor	VG_(m_state_static)+40
+
+	# 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)+36
+	jmp	VG_(main)
+first_insn_to_simulate:
+	# Nothing else to do -- just return in the "normal" way.
+	ret
+
+
+
+.global VG_(shutdown)	
+VG_(shutdown):
+	# ld.so will call here after execution of the program proper
+	# is complete, to allow libraries to close down cleanly.
+	# Note that we will enter here on the synthetic CPU, not
+	# the real one!  So the interpreter must notice when this
+	# procedure is called, and use that as its cue to switch
+	# back to the real CPU.  That means the code placed here is
+	# utterly irrelevant, since it will never get run, but I
+	# place a RET here anyway, since it is the traditional way
+	# to return from a subroutine :-)
+	ret
+
+
+
+.global	VG_(switch_to_real_CPU)
+VG_(switch_to_real_CPU):
+	# Once Valgrind has decided it needs to exit, either
+	# because it has detected a call to vg_shutdown, or
+	# 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.
+	frstor	VG_(m_state_static)+40
+	movl	VG_(m_state_static)+32, %eax
+	pushl	%eax
+	popfl
+	movl	VG_(m_state_static)+0, %eax
+	movl	VG_(m_state_static)+4, %ecx
+	movl	VG_(m_state_static)+8, %edx
+	movl	VG_(m_state_static)+12, %ebx
+	movl	VG_(m_state_static)+16, %esp
+	movl	VG_(m_state_static)+20, %ebp
+	movl	VG_(m_state_static)+24, %esi
+	movl	VG_(m_state_static)+28, %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 ...
+	frstor	VG_(m_state_static)+40	
+	jmp	*VG_(m_state_static)+36
+
+
+
+/*------------------------------------------------------------*/
+/*--- A function to temporarily copy %ESP/%EBP into        ---*/
+/*--- %esp/%ebp and then start up GDB.                     ---*/
+/*------------------------------------------------------------*/
+
+/*--- This is clearly not re-entrant! ---*/
+.data
+vg_ebp_saved_over_GDB_start:
+	.word	0
+vg_esp_saved_over_GDB_start:
+	.word	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
+	
+	movl	$VG_(baseBlock), %ebx
+
+	# fetch %ESP into %esp
+	movl	VGOFF_(m_esp), %esi
+	movl	(%ebx, %esi, 4), %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, via %eax.  This is a faked-up return address.
+	movl	VGOFF_(m_eip), %esi
+	movl	(%ebx, %esi, 4), %eax
+	pushl	%eax
+
+	# push %EBP, via %eax.  This is a faked %ebp-chain pointer.
+	movl	VGOFF_(m_ebp), %esi
+	movl	(%ebx, %esi, 4), %eax
+	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 ---##
+##--------------------------------------------------------------------##