2 /*--------------------------------------------------------------------*/
3 /*--- The core dispatch loop, for jumping to a code address. ---*/
4 /*--- dispatch-amd64-freebsd.S ---*/
5 /*--------------------------------------------------------------------*/
8 This file is part of Valgrind, a dynamic binary instrumentation
11 Copyright (C) 2000-2017 Julian Seward
13 Copyright (C) 2018-2021 Paul Floyd
16 This program is free software; you can redistribute it and/or
17 modify it under the terms of the GNU General Public License as
18 published by the Free Software Foundation; either version 2 of the
19 License, or (at your option) any later version.
21 This program is distributed in the hope that it will be useful, but
22 WITHOUT ANY WARRANTY; without even the implied warranty of
23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24 General Public License for more details.
26 You should have received a copy of the GNU General Public License
27 along with this program; if not, see <http://www.gnu.org/licenses/>.
29 The GNU General Public License is contained in the file COPYING.
32 #include "pub_core_basics_asm.h"
34 #if defined(VGP_amd64_freebsd)
36 #include "pub_core_dispatch_asm.h"
37 #include "pub_core_transtab_asm.h"
38 #include "libvex_guest_offsets.h" /* for OFFSET_amd64_RIP */
41 /*------------------------------------------------------------*/
43 /*--- The dispatch loop. VG_(disp_run_translations) is ---*/
44 /*--- used to run all translations, ---*/
45 /*--- including no-redir ones. ---*/
47 /*------------------------------------------------------------*/
49 /*----------------------------------------------------*/
50 /*--- Entry and preamble (set everything up) ---*/
51 /*----------------------------------------------------*/
54 void VG_(disp_run_translations)( UWord* two_words,
59 .globl VG_(disp_run_translations)
60 .type VG_(disp_run_translations), @function
61 VG_(disp_run_translations):
62 /* %rdi holds two_words */
63 /* %rsi holds guest_state */
64 /* %rdx holds host_addr */
68 /* Save integer registers, since this is a pseudo-function. */
83 /* %rdi must be saved last */
86 /* Get the host CPU in the state expected by generated code. */
88 /* set host FPU control word to the default mode expected
89 by VEX-generated code. See comments in libvex.h for
96 /* set host SSE control word to the default mode expected
97 by VEX-generated code. */
102 /* set dir flag to known value */
105 /* Set up the guest state pointer */
108 /* and jump into the code cache. Chained translations in
109 the code cache run, until for whatever reason, they can't
110 continue. When that happens, the translation in question
111 will jump (or call) to one of the continuation points
112 VG_(cp_...) below. */
116 /*----------------------------------------------------*/
117 /*--- Postamble and exit. ---*/
118 /*----------------------------------------------------*/
121 /* At this point, %rax and %rdx contain two
122 words to be returned to the caller. %rax
123 holds a TRC value, and %rdx optionally may
124 hold another word (for CHAIN_ME exits, the
125 address of the place to patch.) */
127 /* We're leaving. Check that nobody messed with %mxcsr
128 or %fpucw. We can't mess with %rax or %rdx here as they
129 hold the tentative return values, but any others are OK. */
130 #if !defined(ENABLE_INNER)
131 /* This check fails for self-hosting, so skip in that case */
135 popq %r15 /* get rid of the word without trashing %rflags */
136 jnz invariant_violation
140 andl $0xFFFFFFC0, (%rsp) /* mask out status flags */
143 jnz invariant_violation
144 /* otherwise we're OK */
147 movq $VG_TRC_INVARIANT_FAILED, %rax
151 /* Pop %rdi, stash return values */
155 /* Now pop everything else */
172 /*----------------------------------------------------*/
173 /*--- Continuation points ---*/
174 /*----------------------------------------------------*/
176 /* ------ Chain me to slow entry point ------ */
177 .global VG_(disp_cp_chain_me_to_slowEP)
178 VG_(disp_cp_chain_me_to_slowEP):
179 /* We got called. The return address indicates
180 where the patching needs to happen. Collect
181 the return address and, exit back to C land,
182 handing the caller the pair (Chain_me_S, RA) */
183 movq $VG_TRC_CHAIN_ME_TO_SLOW_EP, %rax
185 /* 10 = movabsq $VG_(disp_chain_me_to_slowEP), %r11;
190 /* ------ Chain me to fast entry point ------ */
191 .global VG_(disp_cp_chain_me_to_fastEP)
192 VG_(disp_cp_chain_me_to_fastEP):
193 /* We got called. The return address indicates
194 where the patching needs to happen. Collect
195 the return address and, exit back to C land,
196 handing the caller the pair (Chain_me_F, RA) */
197 movq $VG_TRC_CHAIN_ME_TO_FAST_EP, %rax
199 /* 10 = movabsq $VG_(disp_chain_me_to_fastEP), %r11;
204 /* ------ Indirect but boring jump ------ */
205 .global VG_(disp_cp_xindir)
207 /* Where are we going? */
208 movq OFFSET_amd64_RIP(%rbp), %rax // "guest"
211 addl $1, VG_(stats__n_xIndirs_32)
213 // LIVE: %rbp (guest state ptr), %rax (guest address to go to).
214 // We use 4 temporaries:
215 // %r9 (to point at the relevant FastCacheSet),
216 // %r10, %r11 and %r12 (scratch).
218 /* Try a fast lookup in the translation cache. This is pretty much
219 a handcoded version of VG_(lookupInFastCache). */
221 // Compute %r9 = VG_TT_FAST_HASH(guest)
222 movq %rax, %r9 // guest
223 shrq $VG_TT_FAST_BITS, %r9 // (guest >> VG_TT_FAST_BITS)
224 xorq %rax, %r9 // (guest >> VG_TT_FAST_BITS) ^ guest
225 andq $VG_TT_FAST_MASK, %r9 // setNo
227 // Compute %r9 = &VG_(tt_fast)[%r9]
228 shlq $VG_FAST_CACHE_SET_BITS, %r9 // setNo * sizeof(FastCacheSet)
229 movabsq $VG_(tt_fast), %r10 // &VG_(tt_fast)[0]
230 leaq (%r10, %r9), %r9 // &VG_(tt_fast)[setNo]
232 // LIVE: %rbp (guest state ptr), %rax (guest addr), %r9 (cache set)
234 cmpq %rax, FCS_g0(%r9) // cmp against .guest0
237 jmp *FCS_h0(%r9) // goto .host0
241 cmpq %rax, FCS_g1(%r9) // cmp against .guest1
243 // hit at way 1; swap upwards
245 addl $1, VG_(stats__n_xIndir_hits1_32)
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 addl $1, VG_(stats__n_xIndir_hits2_32)
262 movq FCS_g1(%r9), %r10
263 movq FCS_h1(%r9), %r11
264 movq FCS_h2(%r9), %r12
265 movq %rax, FCS_g1(%r9)
266 movq %r12, FCS_h1(%r9)
267 movq %r10, FCS_g2(%r9)
268 movq %r11, FCS_h2(%r9)
273 cmpq %rax, FCS_g3(%r9) // cmp against .guest3
275 // hit at way 3; swap upwards
277 addl $1, VG_(stats__n_xIndir_hits3_32)
278 movq FCS_g2(%r9), %r10
279 movq FCS_h2(%r9), %r11
280 movq FCS_h3(%r9), %r12
281 movq %rax, FCS_g2(%r9)
282 movq %r12, FCS_h2(%r9)
283 movq %r10, FCS_g3(%r9)
284 movq %r11, FCS_h3(%r9)
288 4: // fast lookup failed
290 addl $1, VG_(stats__n_xIndir_misses_32)
292 movq $VG_TRC_INNER_FASTMISS, %rax
296 /* ------ Assisted jump ------ */
297 .global VG_(disp_cp_xassisted)
298 VG_(disp_cp_xassisted):
299 /* %rbp contains the TRC */
304 /* ------ Event check failed ------ */
305 .global VG_(disp_cp_evcheck_fail)
306 VG_(disp_cp_evcheck_fail):
307 movq $VG_TRC_INNER_COUNTERZERO, %rax
312 .size VG_(disp_run_translations), .-VG_(disp_run_translations)
314 #endif // defined(VGP_amd64_freebsd)
316 /* Let the linker know we don't need an executable stack */
319 /*--------------------------------------------------------------------*/
321 /*--------------------------------------------------------------------*/