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-2007 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_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: 52UWord VG_(run_innerloop) ( void* guest_state, UWord do_profiling ); 53*/ 54 55.text 56.globl VG_(run_innerloop) 57VG_(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_unprofiled) 110 jmp VG_(run_innerloop__dispatch_profiled) 111 /*NOTREACHED*/ 112 113/*----------------------------------------------------*/ 114/*--- NO-PROFILING (standard) dispatcher ---*/ 115/*----------------------------------------------------*/ 116 117.align 4 118.globl VG_(run_innerloop__dispatch_unprofiled) 119VG_(run_innerloop__dispatch_unprofiled): 120 /* AT ENTRY: %rax is next guest addr, %rbp is possibly 121 modified guest state ptr */ 122 123 /* Has the guest state pointer been messed with? If yes, exit. */ 124 cmpq 8(%rsp), %rbp 125 movq VG_(tt_fast)@GOTPCREL(%rip), %rcx 126 jnz gsp_changed 127 128 /* save the jump address in the guest state */ 129 movq %rax, OFFSET_amd64_RIP(%rbp) 130 131 /* Are we out of timeslice? If yes, defer to scheduler. */ 132 subl $1, 0(%rsp) 133 jz counter_is_zero 134 135 /* try a fast lookup in the translation cache */ 136 movq %rax, %rbx 137 andq $VG_TT_FAST_MASK, %rbx /* entry# */ 138 shlq $4, %rbx /* entry# * sizeof(FastCacheEntry) */ 139 movq 0(%rcx,%rbx,1), %r10 /* .guest */ 140 movq 8(%rcx,%rbx,1), %r11 /* .host */ 141 cmpq %rax, %r10 142 jnz fast_lookup_failed 143 144 /* Found a match. Jump to .host. */ 145 jmp *%r11 146 ud2 /* persuade insn decoders not to speculate past here */ 147 /* generated code should run, then jump back to 148 VG_(run_innerloop__dispatch_unprofiled). */ 149 /*NOTREACHED*/ 150 151/*----------------------------------------------------*/ 152/*--- PROFILING dispatcher (can be much slower) ---*/ 153/*----------------------------------------------------*/ 154 155.align 4 156.globl VG_(run_innerloop__dispatch_profiled) 157VG_(run_innerloop__dispatch_profiled): 158 /* AT ENTRY: %rax is next guest addr, %rbp is possibly 159 modified guest state ptr */ 160 161 /* Has the guest state pointer been messed with? If yes, exit. */ 162 cmpq 8(%rsp), %rbp 163 movq VG_(tt_fast)@GOTPCREL(%rip), %rcx 164 jnz gsp_changed 165 166 /* save the jump address in the guest state */ 167 movq %rax, OFFSET_amd64_RIP(%rbp) 168 169 /* Are we out of timeslice? If yes, defer to scheduler. */ 170 subl $1, 0(%rsp) 171 jz counter_is_zero 172 173 /* try a fast lookup in the translation cache */ 174 movq %rax, %rbx 175 andq $VG_TT_FAST_MASK, %rbx /* entry# */ 176 shlq $4, %rbx /* entry# * sizeof(FastCacheEntry) */ 177 movq 0(%rcx,%rbx,1), %r10 /* .guest */ 178 movq 8(%rcx,%rbx,1), %r11 /* .host */ 179 cmpq %rax, %r10 180 jnz fast_lookup_failed 181 182 /* increment bb profile counter */ 183 movq VG_(tt_fastN)@GOTPCREL(%rip), %rdx 184 shrq $1, %rbx /* entry# * sizeof(UInt*) */ 185 movq (%rdx,%rbx,1), %rdx 186 addl $1, (%rdx) 187 188 /* Found a match. Jump to .host. */ 189 jmp *%r11 190 ud2 /* persuade insn decoders not to speculate past here */ 191 /* generated code should run, then jump back to 192 VG_(run_innerloop__dispatch_profiled). */ 193 /*NOTREACHED*/ 194 195/*----------------------------------------------------*/ 196/*--- exit points ---*/ 197/*----------------------------------------------------*/ 198 199gsp_changed: 200 /* Someone messed with the gsp. Have to 201 defer to scheduler to resolve this. dispatch ctr 202 is not yet decremented, so no need to increment. */ 203 /* %RIP is NOT up to date here. First, need to write 204 %rax back to %RIP, but without trashing %rbp since 205 that holds the value we want to return to the scheduler. 206 Hence use %r15 transiently for the guest state pointer. */ 207 movq 8(%rsp), %r15 208 movq %rax, OFFSET_amd64_RIP(%r15) 209 movq %rbp, %rax 210 jmp run_innerloop_exit 211 /*NOTREACHED*/ 212 213counter_is_zero: 214 /* %RIP is up to date here */ 215 /* back out decrement of the dispatch counter */ 216 addl $1, 0(%rsp) 217 movq $VG_TRC_INNER_COUNTERZERO, %rax 218 jmp run_innerloop_exit 219 220fast_lookup_failed: 221 /* %RIP is up to date here */ 222 /* back out decrement of the dispatch counter */ 223 addl $1, 0(%rsp) 224 movq $VG_TRC_INNER_FASTMISS, %rax 225 jmp run_innerloop_exit 226 227 228 229/* All exits from the dispatcher go through here. %rax holds 230 the return value. 231*/ 232run_innerloop_exit: 233 /* We're leaving. Check that nobody messed with 234 %mxcsr or %fpucw. We can't mess with %rax here as it 235 holds the tentative return value, but any other is OK. */ 236#if !defined(ENABLE_INNER) 237 /* This check fails for self-hosting, so skip in that case */ 238 pushq $0 239 fstcw (%rsp) 240 cmpl $0x027F, (%rsp) 241 popq %r15 /* get rid of the word without trashing %eflags */ 242 jnz invariant_violation 243#endif 244 pushq $0 245 stmxcsr (%rsp) 246 andl $0xFFFFFFC0, (%rsp) /* mask out status flags */ 247 cmpl $0x1F80, (%rsp) 248 popq %r15 249 jnz invariant_violation 250 /* otherwise we're OK */ 251 jmp run_innerloop_exit_REALLY 252 253invariant_violation: 254 movq $VG_TRC_INVARIANT_FAILED, %rax 255 jmp run_innerloop_exit_REALLY 256 257run_innerloop_exit_REALLY: 258 259 /* restore VG_(dispatch_ctr) */ 260 popq %r14 261 movq VG_(dispatch_ctr)@GOTPCREL(%rip), %r15 262 movl %r14d, (%r15) 263 264 popq %rdi 265 popq %r15 266 popq %r14 267 popq %r13 268 popq %r12 269 popq %r11 270 popq %r10 271 popq %r9 272 popq %r8 273 popq %rbp 274 popq %rsi 275 popq %rdx 276 popq %rcx 277 popq %rbx 278 ret 279 280 281/*------------------------------------------------------------*/ 282/*--- ---*/ 283/*--- A special dispatcher, for running no-redir ---*/ 284/*--- translations. Just runs the given translation once. ---*/ 285/*--- ---*/ 286/*------------------------------------------------------------*/ 287 288/* signature: 289void VG_(run_a_noredir_translation) ( UWord* argblock ); 290*/ 291 292/* Run a no-redir translation. argblock points to 4 UWords, 2 to carry args 293 and 2 to carry results: 294 0: input: ptr to translation 295 1: input: ptr to guest state 296 2: output: next guest PC 297 3: output: guest state pointer afterwards (== thread return code) 298*/ 299.align 4 300.globl VG_(run_a_noredir_translation) 301VG_(run_a_noredir_translation): 302 /* Save callee-saves regs */ 303 pushq %rbx 304 pushq %rbp 305 pushq %r12 306 pushq %r13 307 pushq %r14 308 pushq %r15 309 310 pushq %rdi /* we will need it after running the translation */ 311 movq 8(%rdi), %rbp 312 jmp *0(%rdi) 313 /*NOTREACHED*/ 314 ud2 315 /* If the translation has been correctly constructed, we 316 should resume at the the following label. */ 317.globl VG_(run_a_noredir_translation__return_point) 318VG_(run_a_noredir_translation__return_point): 319 popq %rdi 320 movq %rax, 16(%rdi) 321 movq %rbp, 24(%rdi) 322 323 popq %r15 324 popq %r14 325 popq %r13 326 popq %r12 327 popq %rbp 328 popq %rbx 329 ret 330 331#endif // defined(VGP_amd64_darwin) 332 333/*--------------------------------------------------------------------*/ 334/*--- end ---*/ 335/*--------------------------------------------------------------------*/ 336