2 /*--------------------------------------------------------------------*/
3 /*--- The core dispatch loop, for jumping to a code address. ---*/
4 /*--- dispatch-amd64-darwin.S ---*/
5 /*--------------------------------------------------------------------*/
8 This file is part of Valgrind, a dynamic binary instrumentation
11 Copyright (C) 2000-2017 Julian Seward
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.
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.
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, see <http://www.gnu.org/licenses/>.
27 The GNU General Public License is contained in the file COPYING.
30 #include "pub_core_basics_asm.h"
32 #if defined(VGP_amd64_darwin)
34 #include "pub_core_dispatch_asm.h"
35 #include "pub_core_transtab_asm.h"
36 #include "libvex_guest_offsets.h" /* for OFFSET_amd64_RIP */
39 /*------------------------------------------------------------*/
41 /*--- The dispatch loop. VG_(disp_run_translations) is ---*/
42 /*--- used to run all translations, ---*/
43 /*--- including no-redir ones. ---*/
45 /*------------------------------------------------------------*/
47 /*----------------------------------------------------*/
48 /*--- Entry and preamble (set everything up) ---*/
49 /*----------------------------------------------------*/
52 void VG_(disp_run_translations)( UWord* two_words,
57 .globl VG_(disp_run_translations)
58 VG_(disp_run_translations):
59 /* %rdi holds two_words */
60 /* %rsi holds guest_state */
61 /* %rdx holds host_addr */
65 /* Save integer registers, since this is a pseudo-function. */
80 /* %rdi must be saved last */
83 /* Get the host CPU in the state expected by generated code. */
85 /* set host FPU control word to the default mode expected
86 by VEX-generated code. See comments in libvex.h for
93 /* set host SSE control word to the default mode expected
94 by VEX-generated code. */
99 /* set dir flag to known value */
102 /* Set up the guest state pointer */
105 /* and jump into the code cache. Chained translations in
106 the code cache run, until for whatever reason, they can't
107 continue. When that happens, the translation in question
108 will jump (or call) to one of the continuation points
109 VG_(cp_...) below. */
113 /*----------------------------------------------------*/
114 /*--- Postamble and exit. ---*/
115 /*----------------------------------------------------*/
118 /* At this point, %rax and %rdx contain two
119 words to be returned to the caller. %rax
120 holds a TRC value, and %rdx optionally may
121 hold another word (for CHAIN_ME exits, the
122 address of the place to patch.) */
124 /* We're leaving. Check that nobody messed with %mxcsr
125 or %fpucw. We can't mess with %rax or %rdx here as they
126 hold the tentative return values, but any others are OK. */
127 #if !defined(ENABLE_INNER)
128 /* This check fails for self-hosting, so skip in that case */
132 popq %r15 /* get rid of the word without trashing %rflags */
133 jnz invariant_violation
137 andl $0xFFFFFFC0, (%rsp) /* mask out status flags */
140 jnz invariant_violation
141 /* otherwise we're OK */
144 movq $VG_TRC_INVARIANT_FAILED, %rax
148 /* Pop %rdi, stash return values */
152 /* Now pop everything else */
169 /*----------------------------------------------------*/
170 /*--- Continuation points ---*/
171 /*----------------------------------------------------*/
173 /* ------ Chain me to slow entry point ------ */
174 .globl VG_(disp_cp_chain_me_to_slowEP)
175 VG_(disp_cp_chain_me_to_slowEP):
176 /* We got called. The return address indicates
177 where the patching needs to happen. Collect
178 the return address and, exit back to C land,
179 handing the caller the pair (Chain_me_S, RA) */
180 movq $VG_TRC_CHAIN_ME_TO_SLOW_EP, %rax
182 /* 10 = movabsq $VG_(disp_chain_me_to_slowEP), %r11;
187 /* ------ Chain me to fast entry point ------ */
188 .globl VG_(disp_cp_chain_me_to_fastEP)
189 VG_(disp_cp_chain_me_to_fastEP):
190 /* We got called. The return address indicates
191 where the patching needs to happen. Collect
192 the return address and, exit back to C land,
193 handing the caller the pair (Chain_me_F, RA) */
194 movq $VG_TRC_CHAIN_ME_TO_FAST_EP, %rax
196 /* 10 = movabsq $VG_(disp_chain_me_to_fastEP), %r11;
201 /* ------ Indirect but boring jump ------ */
202 .global VG_(disp_cp_xindir)
204 /* Where are we going? */
205 movq OFFSET_amd64_RIP(%rbp), %rax // "guest"
208 movabsq $VG_(stats__n_xIndirs_32), %r8
211 // LIVE: %rbp (guest state ptr), %rax (guest address to go to).
212 // We use 5 temporaries:
213 // %r9 (to point at the relevant FastCacheSet),
214 // %r10, %r11 and %r12 (scratch).
215 // %r8 (scratch address)
217 /* Try a fast lookup in the translation cache. This is pretty much
218 a handcoded version of VG_(lookupInFastCache). */
220 // Compute %r9 = VG_TT_FAST_HASH(guest)
221 movq %rax, %r9 // guest
222 shrq $VG_TT_FAST_BITS, %r9 // (guest >> VG_TT_FAST_BITS)
223 xorq %rax, %r9 // (guest >> VG_TT_FAST_BITS) ^ guest
224 andq $VG_TT_FAST_MASK, %r9 // setNo
226 // Compute %r9 = &VG_(tt_fast)[%r9]
227 shlq $VG_FAST_CACHE_SET_BITS, %r9 // setNo * sizeof(FastCacheSet)
228 movabsq $VG_(tt_fast), %r10 // &VG_(tt_fast)[0]
229 leaq (%r10, %r9), %r9 // &VG_(tt_fast)[setNo]
231 // LIVE: %rbp (guest state ptr), %rax (guest addr), %r9 (cache set)
233 cmpq %rax, FCS_g0(%r9) // cmp against .guest0
236 jmp *FCS_h0(%r9) // goto .host0
240 cmpq %rax, FCS_g1(%r9) // cmp against .guest1
242 // hit at way 1; swap upwards
244 movabsq $VG_(stats__n_xIndir_hits1_32), %r8
246 movq FCS_g0(%r9), %r10 // r10 = old .guest0
247 movq FCS_h0(%r9), %r11 // r11 = old .host0
248 movq FCS_h1(%r9), %r12 // r12 = old .host1
249 movq %rax, FCS_g0(%r9) // new .guest0 = guest
250 movq %r12, FCS_h0(%r9) // new .host0 = old .host1
251 movq %r10, FCS_g1(%r9) // new .guest1 = old .guest0
252 movq %r11, FCS_h1(%r9) // new .host1 = old .host0
253 jmp *%r12 // goto old .host1 a.k.a. new .host0
257 cmpq %rax, FCS_g2(%r9) // cmp against .guest2
259 // hit at way 2; swap upwards
261 movabsq $VG_(stats__n_xIndir_hits2_32), %r8
263 movq FCS_g1(%r9), %r10
264 movq FCS_h1(%r9), %r11
265 movq FCS_h2(%r9), %r12
266 movq %rax, FCS_g1(%r9)
267 movq %r12, FCS_h1(%r9)
268 movq %r10, FCS_g2(%r9)
269 movq %r11, FCS_h2(%r9)
274 cmpq %rax, FCS_g3(%r9) // cmp against .guest3
276 // hit at way 3; swap upwards
278 movabsq $VG_(stats__n_xIndir_hits3_32), %r8
280 movq FCS_g2(%r9), %r10
281 movq FCS_h2(%r9), %r11
282 movq FCS_h3(%r9), %r12
283 movq %rax, FCS_g2(%r9)
284 movq %r12, FCS_h2(%r9)
285 movq %r10, FCS_g3(%r9)
286 movq %r11, FCS_h3(%r9)
290 4: // fast lookup failed
292 movabsq $VG_(stats__n_xIndir_misses_32), %r8
295 movq $VG_TRC_INNER_FASTMISS, %rax
299 /* ------ Assisted jump ------ */
300 .globl VG_(disp_cp_xassisted)
301 VG_(disp_cp_xassisted):
302 /* %rbp contains the TRC */
307 /* ------ Event check failed ------ */
308 .globl VG_(disp_cp_evcheck_fail)
309 VG_(disp_cp_evcheck_fail):
310 movq $VG_TRC_INNER_COUNTERZERO, %rax
315 #endif // defined(VGP_amd64_darwin)
317 /* Let the linker know we don't need an executable stack */
320 /*--------------------------------------------------------------------*/
322 /*--------------------------------------------------------------------*/