blob: f43bcb1a688fb0778a3ed1e04bc65f144f5fb424 [file] [log] [blame]
/*--------------------------------------------------------------------*/
/*--- The core dispatch loop, for jumping to a code address. ---*/
/*--- dispatch-x86-darwin.S ---*/
/*--------------------------------------------------------------------*/
/*
This file is part of Valgrind, a dynamic binary instrumentation
framework.
Copyright (C) 2000-2006 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.
*/
#if defined(VGP_x86_darwin)
#include "pub_core_basics_asm.h"
#include "pub_core_dispatch_asm.h"
#include "pub_core_transtab_asm.h"
#include "libvex_guest_offsets.h" /* for OFFSET_x86_EIP */
/* Global variables */
/* These are defined here instead of in their respective C files to
avoid extra PIC branch code here. */
.data
.align 2
/* m_transtab.c */
.globl VG_(tt_fast)
.align 4
VG_(tt_fast): .space VG_TT_FAST_SIZE*8, 0 /* (2*Addr) [VG_TT_FAST_SIZE] */
.globl VG_(tt_fastN)
VG_(tt_fastN): .space VG_TT_FAST_SIZE*4, 0 /* (UInt *) [VG_TT_FAST_SIZE] */
/* scheduler.c */
.globl VG_(dispatch_ctr)
VG_(dispatch_ctr): .long 0
/*------------------------------------------------------------*/
/*--- ---*/
/*--- The dispatch loop. VG_(run_innerloop) is used to ---*/
/*--- run all translations except no-redir ones. ---*/
/*--- ---*/
/*------------------------------------------------------------*/
/*----------------------------------------------------*/
/*--- Preamble (set everything up) ---*/
/*----------------------------------------------------*/
/* signature:
UWord VG_(run_innerloop) ( void* guest_state, UWord do_profiling );
*/
.text
.globl VG_(run_innerloop)
VG_(run_innerloop):
/* 4(%esp) holds guest_state */
/* 8(%esp) holds do_profiling */
/* ----- entry point to VG_(run_innerloop) ----- */
pushl %ebx
pushl %ecx
pushl %edx
pushl %esi
pushl %edi
pushl %ebp
/* 28(%esp) holds guest_state */
/* 32(%esp) holds do_profiling */
/* 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. */
cmpl $0, VG_(machine_x86_have_mxcsr)
jz L1
pushl $0x1F80
ldmxcsr (%esp)
addl $4, %esp
L1:
/* set dir flag to known value */
cld
/* fall into main loop (the right one) */
cmpl $0, 32(%esp) /* do_profiling */
je VG_(run_innerloop__dispatch_unassisted_unprofiled)
jmp VG_(run_innerloop__dispatch_unassisted_profiled)
/*NOTREACHED*/
/*----------------------------------------------------*/
/*--- NO-PROFILING (standard) dispatcher ---*/
/*----------------------------------------------------*/
.globl VG_(run_innerloop__dispatch_unassisted_unprofiled)
VG_(run_innerloop__dispatch_unassisted_unprofiled):
/* AT ENTRY: %eax is next guest addr, %ebp is the
unmodified guest state ptr */
/* 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 0+VG_(tt_fast)(,%ebx,8), %esi /* .guest */
movl 4+VG_(tt_fast)(,%ebx,8), %edi /* .host */
cmpl %eax, %esi
jnz fast_lookup_failed
/* Found a match. Jump to .host. */
jmp *%edi
ud2 /* persuade insn decoders not to speculate past here */
/* generated code should run, then jump back to
VG_(run_innerloop__dispatch_{un,}assisted_unprofiled). */
/*NOTREACHED*/
.globl VG_(run_innerloop__dispatch_assisted_unprofiled)
VG_(run_innerloop__dispatch_assisted_unprofiled):
/* AT ENTRY: %eax is next guest addr, %ebp is the
modified guest state ptr */
jmp gsp_changed
ud2
/*NOTREACHED*/
/*----------------------------------------------------*/
/*--- PROFILING dispatcher (can be much slower) ---*/
/*----------------------------------------------------*/
.globl VG_(run_innerloop__dispatch_unassisted_profiled)
VG_(run_innerloop__dispatch_unassisted_profiled):
/* AT ENTRY: %eax is next guest addr, %ebp is the
unmodified guest state ptr */
/* 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 0+VG_(tt_fast)(,%ebx,8), %esi /* .guest */
movl 4+VG_(tt_fast)(,%ebx,8), %edi /* .host */
cmpl %eax, %esi
jnz fast_lookup_failed
/* increment bb profile counter */
/* note: innocuous as this sounds, it causes a huge amount more
stress on D1 and significantly slows everything down. */
movl VG_(tt_fastN)(,%ebx,4), %edx
/* Use "addl $1", not "incl", to avoid partial-flags stall on P4 */
addl $1, (%edx)
/* Found a match. Jump to .host. */
jmp *%edi
ud2 /* persuade insn decoders not to speculate past here */
/* generated code should run, then jump back to
VG_(run_innerloop__dispatch_{un,}assisted_profiled). */
/*NOTREACHED*/
.globl VG_(run_innerloop__dispatch_assisted_profiled)
VG_(run_innerloop__dispatch_assisted_profiled):
/* AT ENTRY: %eax is next guest addr, %ebp is the
modified guest state ptr */
jmp gsp_changed
ud2
/*NOTREACHED*/
/*----------------------------------------------------*/
/*--- exit points ---*/
/*----------------------------------------------------*/
gsp_changed:
/* Someone messed with the gsp. Have to
defer to scheduler to resolve this. dispatch ctr
is not yet decremented, so no need to increment. */
/* %EIP is NOT up to date here. First, need to write
%eax back to %EIP, but without trashing %ebp since
that holds the value we want to return to the scheduler.
Hence use %esi transiently for the guest state pointer. */
movl 28(%esp), %esi
movl %eax, OFFSET_x86_EIP(%esi)
movl %ebp, %eax
jmp run_innerloop_exit
/*NOTREACHED*/
counter_is_zero:
/* %EIP is up to date here */
/* back out decrement of the dispatch counter */
addl $1, VG_(dispatch_ctr)
movl $VG_TRC_INNER_COUNTERZERO, %eax
jmp run_innerloop_exit
/*NOTREACHED*/
fast_lookup_failed:
/* %EIP is up to date here */
/* back out decrement of the dispatch counter */
addl $1, VG_(dispatch_ctr)
movl $VG_TRC_INNER_FASTMISS, %eax
jmp run_innerloop_exit
/*NOTREACHED*/
/* 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. */
#if !defined(ENABLE_INNER)
/* This check fails for self-hosting, so skip in that case */
pushl $0
fstcw (%esp)
cmpl $0x027F, (%esp)
popl %esi /* get rid of the word without trashing %eflags */
jnz invariant_violation
#endif
cmpl $0, VG_(machine_x86_have_mxcsr)
jz L2
pushl $0
stmxcsr (%esp)
andl $0xFFFFFFC0, (%esp) /* mask out status flags */
cmpl $0x1F80, (%esp)
popl %esi
jnz invariant_violation
L2: /* 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
/*------------------------------------------------------------*/
/*--- ---*/
/*--- A special dispatcher, for running no-redir ---*/
/*--- translations. Just runs the given translation once. ---*/
/*--- ---*/
/*------------------------------------------------------------*/
/* signature:
void VG_(run_a_noredir_translation) ( UWord* argblock );
*/
/* Run a no-redir translation. argblock points to 4 UWords, 2 to carry args
and 2 to carry results:
0: input: ptr to translation
1: input: ptr to guest state
2: output: next guest PC
3: output: guest state pointer afterwards (== thread return code)
*/
.globl VG_(run_a_noredir_translation)
VG_(run_a_noredir_translation):
/* Save callee-saves regs */
pushl %esi
pushl %edi
pushl %ebp
pushl %ebx
movl 20(%esp), %edi /* %edi = argblock */
movl 4(%edi), %ebp /* argblock[1] */
jmp *0(%edi) /* argblock[0] */
/*NOTREACHED*/
ud2
/* If the translation has been correctly constructed, we
should resume at the the following label. */
.globl VG_(run_a_noredir_translation__return_point)
VG_(run_a_noredir_translation__return_point):
movl 20(%esp), %edi
movl %eax, 8(%edi) /* argblock[2] */
movl %ebp, 12(%edi) /* argblock[3] */
popl %ebx
popl %ebp
popl %edi
popl %esi
ret
#endif // defined(VGP_x86_darwin)
/*--------------------------------------------------------------------*/
/*--- end ---*/
/*--------------------------------------------------------------------*/