• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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