blob: 6d20d4c36c3eab1985ae3add6f9e46b834867f03 [file] [log] [blame]
##--------------------------------------------------------------------##
##--- The core dispatch loop, for jumping to a code address. ---##
##--- dispatch-x86.S ---##
##--------------------------------------------------------------------##
/*
This file is part of Valgrind, a dynamic binary instrumentation
framework.
Copyright (C) 2000-2005 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 "pub_tool_basics_asm.h"
#include "pub_core_dispatch_asm.h"
#include "pub_core_transtab_asm.h"
#include "libvex_guest_offsets.h" /* for OFFSET_x86_EIP */
/*------------------------------------------------------------*/
/*--- The dispatch loop. ---*/
/*------------------------------------------------------------*/
/* signature: UWord VG_(run_innerloop) ( void* guest_state ) */
.globl VG_(run_innerloop)
VG_(run_innerloop):
/* 4(%esp) holds guest_state */
/* ----- entry point to VG_(run_innerloop) ----- */
pushl %ebx
pushl %ecx
pushl %edx
pushl %esi
pushl %edi
pushl %ebp
/* 28(%esp) holds guest_state */
/* Set up the guest state pointer */
movl 28(%esp), %ebp
/* fetch %EIP into %eax */
movl OFFSET_x86_EIP(%ebp), %eax
/* set host FPU control word to the default mode expected
by VEX-generated code. See comments in libvex.h for
more info. */
finit
pushl $0x027F
fldcw (%esp)
addl $4, %esp
/* set host SSE control word to the default mode expected
by VEX-generated code. */
pushl $0x1F80
ldmxcsr (%esp)
addl $4, %esp
/* set dir flag to known value */
cld
/* fall into main loop */
/* Here, %eax is the only live (real) register. The entire
simulated state is saved in the ThreadState. */
dispatch_boring:
/* save the jump address in the guest state */
movl %eax, OFFSET_x86_EIP(%ebp)
/* Are we out of timeslice? If yes, defer to scheduler. */
subl $1, VG_(dispatch_ctr)
jz counter_is_zero
/* try a fast lookup in the translation cache */
movl %eax, %ebx
andl $VG_TT_FAST_MASK, %ebx
movl VG_(tt_fast)(,%ebx,4), %ecx
cmpl %eax, (%ecx)
jnz fast_lookup_failed
/* increment bb profile counter */
movl VG_(tt_fastN)(,%ebx,4), %edx
incl (%edx)
/* Found a match. Call tce[1], which is 8 bytes along, since
each tce element is a 64-bit int. */
addl $8, %ecx
call *%ecx
/*
%eax holds destination (original) address.
%ebp indicates further details of the control transfer
requested to the address in %eax.
If ebp is unchanged (== * 28(%esp)), just jump next to %eax.
Otherwise fall out, back to the scheduler, and let it
figure out what to do next.
*/
cmpl 28(%esp), %ebp
jz dispatch_boring
jmp dispatch_exceptional
/* All exits from the dispatcher go through here. %eax holds
the return value.
*/
run_innerloop_exit:
/* We're leaving. Check that nobody messed with
%mxcsr or %fpucw. We can't mess with %eax here as it
holds the tentative return value, but any other is OK. */
pushl $0
fstcw (%esp)
cmpl $0x027F, (%esp)
popl %esi /* get rid of the word without trashing %eflags */
jnz invariant_violation
pushl $0
stmxcsr (%esp)
andl $0xFFFFFFC0, (%esp) /* mask out status flags */
cmpl $0x1F80, (%esp)
popl %esi
jnz invariant_violation
/* otherwise we're OK */
jmp run_innerloop_exit_REALLY
invariant_violation:
movl $VG_TRC_INVARIANT_FAILED, %eax
jmp run_innerloop_exit_REALLY
run_innerloop_exit_REALLY:
popl %ebp
popl %edi
popl %esi
popl %edx
popl %ecx
popl %ebx
ret
/* Other ways of getting out of the inner loop. Placed out-of-line to
make it look cleaner.
*/
dispatch_exceptional:
/* this is jumped to only, not fallen-through from above */
/* save %eax in %EIP and defer to sched */
movl 28(%esp), %edi
movl %eax, OFFSET_x86_EIP(%edi)
movl %ebp, %eax
jmp run_innerloop_exit
fast_lookup_failed:
/* %EIP is up to date here since dispatch_boring dominates */
addl $1, VG_(dispatch_ctr)
movl $VG_TRC_INNER_FASTMISS, %eax
jmp run_innerloop_exit
counter_is_zero:
/* %EIP is up to date here since dispatch_boring dominates */
addl $1, VG_(dispatch_ctr)
movl $VG_TRC_INNER_COUNTERZERO, %eax
jmp run_innerloop_exit
/* Let the linker know we don't need an executable stack */
.section .note.GNU-stack,"",@progbits
##--------------------------------------------------------------------##
##--- end ---##
##--------------------------------------------------------------------##