Home | History | Annotate | Download | only in m_dispatch
      1 
      2 /*--------------------------------------------------------------------*/
      3 /*--- The core dispatch loop, for jumping to a code address.       ---*/
      4 /*---                                         dispatch-x86-linux.S ---*/
      5 /*--------------------------------------------------------------------*/
      6 
      7 /*
      8   This file is part of Valgrind, a dynamic binary instrumentation
      9   framework.
     10 
     11   Copyright (C) 2000-2011 Julian Seward
     12      jseward (at) acm.org
     13 
     14   This program is free software; you can redistribute it and/or
     15   modify it under the terms of the GNU General Public License as
     16   published by the Free Software Foundation; either version 2 of the
     17   License, or (at your option) any later version.
     18 
     19   This program is distributed in the hope that it will be useful, but
     20   WITHOUT ANY WARRANTY; without even the implied warranty of
     21   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     22   General Public License for more details.
     23 
     24   You should have received a copy of the GNU General Public License
     25   along with this program; if not, write to the Free Software
     26   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
     27   02111-1307, USA.
     28 
     29   The GNU General Public License is contained in the file COPYING.
     30 */
     31 
     32 #if defined(VGP_x86_linux)
     33 
     34 #include "pub_core_basics_asm.h"
     35 #include "pub_core_dispatch_asm.h"
     36 #include "pub_core_transtab_asm.h"
     37 #include "libvex_guest_offsets.h"	/* for OFFSET_x86_EIP */
     38 
     39 
     40 /*------------------------------------------------------------*/
     41 /*---                                                      ---*/
     42 /*--- The dispatch loop.  VG_(run_innerloop) is used to    ---*/
     43 /*--- run all translations except no-redir ones.           ---*/
     44 /*---                                                      ---*/
     45 /*------------------------------------------------------------*/
     46 
     47 /*----------------------------------------------------*/
     48 /*--- Preamble (set everything up)                 ---*/
     49 /*----------------------------------------------------*/
     50 
     51 /* signature:
     52 UWord VG_(run_innerloop) ( void* guest_state, UWord do_profiling );
     53 */
     54 .text
     55 .globl VG_(run_innerloop)
     56 .type  VG_(run_innerloop), @function
     57 VG_(run_innerloop):
     58 	/* 4(%esp) holds guest_state */
     59 	/* 8(%esp) holds do_profiling */
     60 
     61 	/* ----- entry point to VG_(run_innerloop) ----- */
     62 	pushl	%ebx
     63 	pushl	%ecx
     64 	pushl	%edx
     65 	pushl	%esi
     66 	pushl	%edi
     67 	pushl	%ebp
     68 
     69 	/* 28(%esp) holds guest_state */
     70 	/* 32(%esp) holds do_profiling */
     71 
     72 	/* Set up the guest state pointer */
     73 	movl	28(%esp), %ebp
     74 
     75 	/* fetch %EIP into %eax */
     76 	movl	OFFSET_x86_EIP(%ebp), %eax
     77 
     78 	/* set host FPU control word to the default mode expected
     79            by VEX-generated code.  See comments in libvex.h for
     80            more info. */
     81 	finit
     82 	pushl	$0x027F
     83 	fldcw	(%esp)
     84 	addl	$4, %esp
     85 
     86 	/* set host SSE control word to the default mode expected
     87 	   by VEX-generated code. */
     88 	cmpl	$0, VG_(machine_x86_have_mxcsr)
     89 	jz	L1
     90 	pushl	$0x1F80
     91 	ldmxcsr	(%esp)
     92 	addl	$4, %esp
     93 L1:
     94 	/* set dir flag to known value */
     95 	cld
     96 
     97 	/* fall into main loop (the right one) */
     98 	cmpl	$0, 32(%esp) /* do_profiling */
     99 	je	VG_(run_innerloop__dispatch_unassisted_unprofiled)
    100 	jmp	VG_(run_innerloop__dispatch_unassisted_profiled)
    101 	/*NOTREACHED*/
    102 
    103 /*----------------------------------------------------*/
    104 /*--- NO-PROFILING (standard) dispatcher           ---*/
    105 /*----------------------------------------------------*/
    106 
    107 .align	16
    108 .global	VG_(run_innerloop__dispatch_unassisted_unprofiled)
    109 VG_(run_innerloop__dispatch_unassisted_unprofiled):
    110 	/* AT ENTRY: %eax is next guest addr, %ebp is the
    111            unmodified guest state ptr */
    112 
    113 	/* save the jump address in the guest state */
    114 	movl	%eax, OFFSET_x86_EIP(%ebp)
    115 
    116 	/* Are we out of timeslice?  If yes, defer to scheduler. */
    117 	subl	$1, VG_(dispatch_ctr)
    118 	jz	counter_is_zero
    119 
    120 	/* try a fast lookup in the translation cache */
    121 	movl	%eax, %ebx			/* next guest addr */
    122 	andl	$ VG_TT_FAST_MASK, %ebx		/* entry# */
    123 	movl	0+VG_(tt_fast)(,%ebx,8), %esi	/* .guest */
    124 	movl	4+VG_(tt_fast)(,%ebx,8), %edi	/* .host */
    125 	cmpl	%eax, %esi
    126 	jnz	fast_lookup_failed
    127 
    128 	/* Found a match.  Jump to .host. */
    129 	jmp 	*%edi
    130 	ud2	/* persuade insn decoders not to speculate past here */
    131 	/* generated code should run, then jump back to either
    132 	   VG_(run_innerloop__dispatch_unassisted_unprofiled) or
    133 	   VG_(run_innerloop__dispatch_assisted_unprofiled). */
    134 	/*NOTREACHED*/
    135 
    136 .align	16
    137 .global	VG_(run_innerloop__dispatch_assisted_unprofiled)
    138 VG_(run_innerloop__dispatch_assisted_unprofiled):
    139 	/* AT ENTRY: %eax is next guest addr, %ebp is the
    140            modified guest state ptr */
    141 	/* We know the guest state pointer has been modified.
    142 	   So jump directly to gsp_changed. */
    143 	jmp	gsp_changed
    144 	ud2
    145 	/*NOTREACHED*/
    146 
    147 /*----------------------------------------------------*/
    148 /*--- PROFILING dispatcher (can be much slower)    ---*/
    149 /*----------------------------------------------------*/
    150 
    151 .align	16
    152 .global	VG_(run_innerloop__dispatch_unassisted_profiled)
    153 VG_(run_innerloop__dispatch_unassisted_profiled):
    154 	/* AT ENTRY: %eax is next guest addr, %ebp is the
    155            unmodified guest state ptr */
    156 
    157 	/* save the jump address in the guest state */
    158 	movl	%eax, OFFSET_x86_EIP(%ebp)
    159 
    160 	/* Are we out of timeslice?  If yes, defer to scheduler. */
    161 	subl	$1, VG_(dispatch_ctr)
    162 	jz	counter_is_zero
    163 
    164 	/* try a fast lookup in the translation cache */
    165 	movl	%eax, %ebx			/* next guest addr */
    166 	andl	$ VG_TT_FAST_MASK, %ebx		/* entry# */
    167 	movl	0+VG_(tt_fast)(,%ebx,8), %esi	/* .guest */
    168 	movl	4+VG_(tt_fast)(,%ebx,8), %edi	/* .host */
    169 	cmpl	%eax, %esi
    170 	jnz	fast_lookup_failed
    171 
    172 	/* increment bb profile counter */
    173 	/* note: innocuous as this sounds, it causes a huge amount more
    174            stress on D1 and significantly slows everything down. */
    175 	movl	VG_(tt_fastN)(,%ebx,4), %edx
    176 	/* Use "addl $1", not "incl", to avoid partial-flags stall on P4 */
    177 	addl	$1, (%edx)
    178 
    179 	/* Found a match.  Jump to .host. */
    180 	jmp 	*%edi
    181 	ud2	/* persuade insn decoders not to speculate past here */
    182 	/* generated code should run, then jump back to either
    183 	   VG_(run_innerloop__dispatch_unassisted_profiled) or
    184 	   VG_(run_innerloop__dispatch_assisted_profiled). */
    185 	/*NOTREACHED*/
    186 
    187 .align	16
    188 .global	VG_(run_innerloop__dispatch_assisted_profiled)
    189 VG_(run_innerloop__dispatch_assisted_profiled):
    190 	/* AT ENTRY: %eax is next guest addr, %ebp is the
    191            modified guest state ptr */
    192 	/* We know the guest state pointer has been modified.
    193 	   So jump directly to gsp_changed. */
    194 	jmp	gsp_changed
    195 	ud2
    196 	/*NOTREACHED*/
    197 
    198 /*----------------------------------------------------*/
    199 /*--- exit points                                  ---*/
    200 /*----------------------------------------------------*/
    201 
    202 gsp_changed:
    203 	/* Someone messed with the gsp.  Have to
    204            defer to scheduler to resolve this.  dispatch ctr
    205 	   is not yet decremented, so no need to increment. */
    206 	/* %EIP is NOT up to date here.  First, need to write
    207 	   %eax back to %EIP, but without trashing %ebp since
    208 	   that holds the value we want to return to the scheduler.
    209 	   Hence use %esi transiently for the guest state pointer. */
    210 	movl	28(%esp), %esi
    211 	movl	%eax, OFFSET_x86_EIP(%esi)
    212 	movl	%ebp, %eax
    213 	jmp	run_innerloop_exit
    214 	/*NOTREACHED*/
    215 
    216 counter_is_zero:
    217 	/* %EIP is up to date here */
    218 	/* back out decrement of the dispatch counter */
    219 	addl	$1, VG_(dispatch_ctr)
    220 	movl	$ VG_TRC_INNER_COUNTERZERO, %eax
    221 	jmp	run_innerloop_exit
    222 	/*NOTREACHED*/
    223 
    224 fast_lookup_failed:
    225 	/* %EIP is up to date here */
    226 	/* back out decrement of the dispatch counter */
    227 	addl	$1, VG_(dispatch_ctr)
    228 	movl	$ VG_TRC_INNER_FASTMISS, %eax
    229 	jmp	run_innerloop_exit
    230 	/*NOTREACHED*/
    231 
    232 
    233 
    234 /* All exits from the dispatcher go through here.  %eax holds
    235    the return value.
    236 */
    237 run_innerloop_exit:
    238 	/* We're leaving.  Check that nobody messed with
    239            %mxcsr or %fpucw.  We can't mess with %eax here as it
    240 	   holds the tentative return value, but any other is OK. */
    241 #if !defined(ENABLE_INNER)
    242         /* This check fails for self-hosting, so skip in that case */
    243 	pushl	$0
    244 	fstcw	(%esp)
    245 	cmpl	$0x027F, (%esp)
    246 	popl	%esi /* get rid of the word without trashing %eflags */
    247 	jnz	invariant_violation
    248 #endif
    249 	cmpl	$0, VG_(machine_x86_have_mxcsr)
    250 	jz	L2
    251 	pushl	$0
    252 	stmxcsr	(%esp)
    253 	andl	$0xFFFFFFC0, (%esp)  /* mask out status flags */
    254 	cmpl	$0x1F80, (%esp)
    255 	popl	%esi
    256 	jnz	invariant_violation
    257 L2:	/* otherwise we're OK */
    258 	jmp	run_innerloop_exit_REALLY
    259 
    260 invariant_violation:
    261 	movl	$ VG_TRC_INVARIANT_FAILED, %eax
    262 	jmp	run_innerloop_exit_REALLY
    263 
    264 run_innerloop_exit_REALLY:
    265 	popl	%ebp
    266 	popl	%edi
    267 	popl	%esi
    268 	popl	%edx
    269 	popl	%ecx
    270 	popl	%ebx
    271 	ret
    272 .size VG_(run_innerloop), .-VG_(run_innerloop)
    273 
    274 
    275 /*------------------------------------------------------------*/
    276 /*---                                                      ---*/
    277 /*--- A special dispatcher, for running no-redir           ---*/
    278 /*--- translations.  Just runs the given translation once. ---*/
    279 /*---                                                      ---*/
    280 /*------------------------------------------------------------*/
    281 
    282 /* signature:
    283 void VG_(run_a_noredir_translation) ( UWord* argblock );
    284 */
    285 
    286 /* Run a no-redir translation.  argblock points to 4 UWords, 2 to carry args
    287    and 2 to carry results:
    288       0: input:  ptr to translation
    289       1: input:  ptr to guest state
    290       2: output: next guest PC
    291       3: output: guest state pointer afterwards (== thread return code)
    292 */
    293 .align 16
    294 .global VG_(run_a_noredir_translation)
    295 .type VG_(run_a_noredir_translation), @function
    296 VG_(run_a_noredir_translation):
    297 	/* Save callee-saves regs */
    298 	pushl %esi
    299 	pushl %edi
    300 	pushl %ebp
    301 	pushl %ebx
    302 
    303 	movl 20(%esp), %edi	/* %edi = argblock */
    304 	movl 4(%edi), %ebp	/* argblock[1] */
    305 	jmp *0(%edi)		/* argblock[0] */
    306 	/*NOTREACHED*/
    307 	ud2
    308 	/* If the translation has been correctly constructed, we
    309 	should resume at the the following label. */
    310 .global VG_(run_a_noredir_translation__return_point)
    311 VG_(run_a_noredir_translation__return_point):
    312 	movl 20(%esp), %edi
    313 	movl %eax, 8(%edi)	/* argblock[2] */
    314 	movl %ebp, 12(%edi)	/* argblock[3] */
    315 
    316 	popl %ebx
    317 	popl %ebp
    318 	popl %edi
    319 	popl %esi
    320 	ret
    321 .size VG_(run_a_noredir_translation), .-VG_(run_a_noredir_translation)
    322 
    323 
    324 /* Let the linker know we don't need an executable stack */
    325 .section .note.GNU-stack,"",@progbits
    326 
    327 #endif // defined(VGP_x86_linux)
    328 
    329 /*--------------------------------------------------------------------*/
    330 /*--- end                                                          ---*/
    331 /*--------------------------------------------------------------------*/
    332