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@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_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) 119VG_(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) 149VG_(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) 163VG_(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) 199VG_(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 211gsp_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 225counter_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 232fast_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*/ 244run_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 265invariant_violation: 266 movq $VG_TRC_INVARIANT_FAILED, %rax 267 jmp run_innerloop_exit_REALLY 268 269run_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: 301void 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) 313VG_(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) 330VG_(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