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