Home | History | Annotate | Download | only in m_dispatch
      1 
      2 /*--------------------------------------------------------------------*/
      3 /*--- The core dispatch loop, for jumping to a code address.       ---*/
      4 /*---                                      dispatch-amd64-darwin.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_amd64_darwin)
     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_amd64_RIP */
     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 
     55 .text
     56 .globl VG_(run_innerloop)
     57 VG_(run_innerloop):
     58 	/* %rdi holds guest_state */
     59 	/* %rsi holds do_profiling */
     60 
     61 	/* ----- entry point to VG_(run_innerloop) ----- */
     62 	pushq	%rbx
     63 	pushq	%rcx
     64 	pushq	%rdx
     65 	pushq	%rsi
     66 	pushq	%rbp
     67 	pushq	%r8
     68 	pushq	%r9
     69 	pushq	%r10
     70 	pushq	%r11
     71 	pushq	%r12
     72 	pushq	%r13
     73 	pushq	%r14
     74 	pushq	%r15
     75 	pushq	%rdi  /* guest_state */
     76 
     77 	movq	VG_(dispatch_ctr)@GOTPCREL(%rip), %r15
     78 	movl	(%r15), %r15d
     79 	pushq	%r15
     80 
     81 	/* 8(%rsp) holds cached copy of guest_state ptr */
     82 	/* 0(%rsp) holds cached copy of VG_(dispatch_ctr) */
     83 
     84 	/* Set up the guest state pointer */
     85 	movq	%rdi, %rbp
     86 
     87 	/* fetch %RIP into %rax */
     88 	movq	OFFSET_amd64_RIP(%rbp), %rax
     89 
     90 	/* set host FPU control word to the default mode expected
     91            by VEX-generated code.  See comments in libvex.h for
     92            more info. */
     93 	finit
     94 	pushq	$0x027F
     95 	fldcw	(%rsp)
     96 	addq	$8, %rsp
     97 
     98 	/* set host SSE control word to the default mode expected
     99 	   by VEX-generated code. */
    100 	pushq	$0x1F80
    101 	ldmxcsr	(%rsp)
    102 	addq	$8, %rsp
    103 
    104 	/* set dir flag to known value */
    105 	cld
    106 
    107 	/* fall into main loop  (the right one) */
    108 	cmpq	$0, %rsi
    109 	je	VG_(run_innerloop__dispatch_unassisted_unprofiled)
    110 	jmp	VG_(run_innerloop__dispatch_unassisted_profiled)
    111 	/*NOTREACHED*/
    112 
    113 /*----------------------------------------------------*/
    114 /*--- NO-PROFILING (standard) dispatcher           ---*/
    115 /*----------------------------------------------------*/
    116 
    117 .align	4
    118 .globl	VG_(run_innerloop__dispatch_unassisted_unprofiled)
    119 VG_(run_innerloop__dispatch_unassisted_unprofiled):
    120 	/* AT ENTRY: %rax is next guest addr, %rbp is the
    121            unmodified guest state ptr */
    122 
    123 	/* save the jump address in the guest state */
    124 	movq	%rax, OFFSET_amd64_RIP(%rbp)
    125 
    126 	/* Are we out of timeslice?  If yes, defer to scheduler. */
    127 	subl	$1, 0(%rsp)
    128 	jz	counter_is_zero
    129 
    130 	/* try a fast lookup in the translation cache */
    131 	movabsq	$VG_(tt_fast), %rcx
    132 	movq	%rax, %rbx
    133 	andq	$VG_TT_FAST_MASK, %rbx	/* entry# */
    134 	shlq	$4, %rbx		/* entry# * sizeof(FastCacheEntry) */
    135 	movq	0(%rcx,%rbx,1), %r10	/* .guest */
    136 	movq	8(%rcx,%rbx,1), %r11	/* .host */
    137 	cmpq	%rax, %r10
    138 	jnz	fast_lookup_failed
    139 
    140         /* Found a match.  Jump to .host. */
    141 	jmp 	*%r11
    142 	ud2	/* persuade insn decoders not to speculate past here */
    143 	/* generated code should run, then jump back to
    144 	   VG_(run_innerloop__dispatch_{un,}assisted_unprofiled). */
    145 	/*NOTREACHED*/
    146 
    147 .align	4
    148 .globl	VG_(run_innerloop__dispatch_assisted_unprofiled)
    149 VG_(run_innerloop__dispatch_assisted_unprofiled):
    150 	/* AT ENTRY: %rax is next guest addr, %rbp is the
    151            modified guest state ptr.  Since the GSP has changed,
    152            jump directly to gsp_changed. */
    153         jmp     gsp_changed
    154         ud2
    155         /*NOTREACHED*/
    156 
    157 /*----------------------------------------------------*/
    158 /*--- PROFILING dispatcher (can be much slower)    ---*/
    159 /*----------------------------------------------------*/
    160 
    161 .align	4
    162 .globl	VG_(run_innerloop__dispatch_unassisted_profiled)
    163 VG_(run_innerloop__dispatch_unassisted_profiled):
    164 	/* AT ENTRY: %rax is next guest addr, %rbp is the
    165            unmodified guest state ptr */
    166 
    167 	/* save the jump address in the guest state */
    168 	movq	%rax, OFFSET_amd64_RIP(%rbp)
    169 
    170 	/* Are we out of timeslice?  If yes, defer to scheduler. */
    171 	subl	$1, 0(%rsp)
    172 	jz	counter_is_zero
    173 
    174 	/* try a fast lookup in the translation cache */
    175         movabsq $VG_(tt_fast), %rcx
    176 	movq	%rax, %rbx
    177 	andq	$VG_TT_FAST_MASK, %rbx	/* entry# */
    178 	shlq	$4, %rbx		/* entry# * sizeof(FastCacheEntry) */
    179 	movq	0(%rcx,%rbx,1), %r10	/* .guest */
    180 	movq	8(%rcx,%rbx,1), %r11	/* .host */
    181 	cmpq	%rax, %r10
    182 	jnz	fast_lookup_failed
    183 
    184 	/* increment bb profile counter */
    185 	movabsq	$VG_(tt_fastN), %rdx
    186 	shrq	$1, %rbx		/* entry# * sizeof(UInt*) */
    187 	movq	(%rdx,%rbx,1), %rdx
    188 	addl	$1, (%rdx)
    189 
    190         /* Found a match.  Jump to .host. */
    191 	jmp 	*%r11
    192 	ud2	/* persuade insn decoders not to speculate past here */
    193 	/* generated code should run, then jump back to
    194 	   VG_(run_innerloop__dispatch_{un,}assisted_profiled). */
    195 	/*NOTREACHED*/
    196 
    197 .align	4
    198 .globl	VG_(run_innerloop__dispatch_assisted_profiled)
    199 VG_(run_innerloop__dispatch_assisted_profiled):
    200 	/* AT ENTRY: %rax is next guest addr, %rbp is the
    201            modified guest state ptr.  Since the GSP has changed,
    202            jump directly to gsp_changed. */
    203         jmp     gsp_changed
    204         ud2
    205         /*NOTREACHED*/
    206 
    207 /*----------------------------------------------------*/
    208 /*--- exit points                                  ---*/
    209 /*----------------------------------------------------*/
    210 
    211 gsp_changed:
    212 	/* Someone messed with the gsp.  Have to
    213            defer to scheduler to resolve this.  dispatch ctr
    214 	   is not yet decremented, so no need to increment. */
    215 	/* %RIP is NOT up to date here.  First, need to write
    216 	   %rax back to %RIP, but without trashing %rbp since
    217 	   that holds the value we want to return to the scheduler.
    218 	   Hence use %r15 transiently for the guest state pointer. */
    219 	movq	8(%rsp), %r15
    220 	movq	%rax, OFFSET_amd64_RIP(%r15)
    221 	movq	%rbp, %rax
    222 	jmp	run_innerloop_exit
    223 	/*NOTREACHED*/
    224 
    225 counter_is_zero:
    226 	/* %RIP is up to date here */
    227 	/* back out decrement of the dispatch counter */
    228 	addl	$1, 0(%rsp)
    229 	movq	$VG_TRC_INNER_COUNTERZERO, %rax
    230 	jmp	run_innerloop_exit
    231 
    232 fast_lookup_failed:
    233 	/* %RIP is up to date here */
    234 	/* back out decrement of the dispatch counter */
    235 	addl	$1, 0(%rsp)
    236 	movq	$VG_TRC_INNER_FASTMISS, %rax
    237 	jmp	run_innerloop_exit
    238 
    239 
    240 
    241 /* All exits from the dispatcher go through here.  %rax holds
    242    the return value.
    243 */
    244 run_innerloop_exit:
    245 	/* We're leaving.  Check that nobody messed with
    246            %mxcsr or %fpucw.  We can't mess with %rax here as it
    247 	   holds the tentative return value, but any other is OK. */
    248 #if !defined(ENABLE_INNER)
    249         /* This check fails for self-hosting, so skip in that case */
    250 	pushq	$0
    251 	fstcw	(%rsp)
    252 	cmpl	$0x027F, (%rsp)
    253 	popq	%r15 /* get rid of the word without trashing %eflags */
    254 	jnz	invariant_violation
    255 #endif
    256 	pushq	$0
    257 	stmxcsr	(%rsp)
    258 	andl	$0xFFFFFFC0, (%rsp)  /* mask out status flags */
    259 	cmpl	$0x1F80, (%rsp)
    260 	popq	%r15
    261 	jnz	invariant_violation
    262 	/* otherwise we're OK */
    263 	jmp	run_innerloop_exit_REALLY
    264 
    265 invariant_violation:
    266 	movq	$VG_TRC_INVARIANT_FAILED, %rax
    267 	jmp	run_innerloop_exit_REALLY
    268 
    269 run_innerloop_exit_REALLY:
    270 
    271 	/* restore VG_(dispatch_ctr) */
    272 	popq	%r14
    273 	movq	VG_(dispatch_ctr)@GOTPCREL(%rip), %r15
    274 	movl	%r14d, (%r15)
    275 
    276 	popq	%rdi
    277 	popq	%r15
    278 	popq	%r14
    279 	popq	%r13
    280 	popq	%r12
    281 	popq	%r11
    282 	popq	%r10
    283 	popq	%r9
    284 	popq	%r8
    285 	popq	%rbp
    286 	popq	%rsi
    287 	popq	%rdx
    288 	popq	%rcx
    289 	popq	%rbx
    290 	ret
    291 
    292 
    293 /*------------------------------------------------------------*/
    294 /*---                                                      ---*/
    295 /*--- A special dispatcher, for running no-redir           ---*/
    296 /*--- translations.  Just runs the given translation once. ---*/
    297 /*---                                                      ---*/
    298 /*------------------------------------------------------------*/
    299 
    300 /* signature:
    301 void VG_(run_a_noredir_translation) ( UWord* argblock );
    302 */
    303 
    304 /* Run a no-redir translation.  argblock points to 4 UWords, 2 to carry args
    305    and 2 to carry results:
    306       0: input:  ptr to translation
    307       1: input:  ptr to guest state
    308       2: output: next guest PC
    309       3: output: guest state pointer afterwards (== thread return code)
    310 */
    311 .align 4
    312 .globl VG_(run_a_noredir_translation)
    313 VG_(run_a_noredir_translation):
    314 	/* Save callee-saves regs */
    315 	pushq %rbx
    316 	pushq %rbp
    317 	pushq %r12
    318 	pushq %r13
    319 	pushq %r14
    320 	pushq %r15
    321 
    322 	pushq %rdi  /* we will need it after running the translation */
    323 	movq 8(%rdi), %rbp
    324 	jmp *0(%rdi)
    325 	/*NOTREACHED*/
    326 	ud2
    327 	/* If the translation has been correctly constructed, we
    328 	should resume at the the following label. */
    329 .globl VG_(run_a_noredir_translation__return_point)
    330 VG_(run_a_noredir_translation__return_point):
    331 	popq %rdi
    332 	movq %rax, 16(%rdi)
    333 	movq %rbp, 24(%rdi)
    334 
    335 	popq  %r15
    336 	popq  %r14
    337 	popq  %r13
    338 	popq  %r12
    339 	popq  %rbp
    340 	popq  %rbx
    341 	ret
    342 
    343 #endif // defined(VGP_amd64_darwin)
    344 
    345 /*--------------------------------------------------------------------*/
    346 /*--- end                                                          ---*/
    347 /*--------------------------------------------------------------------*/
    348