• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1
2/*--------------------------------------------------------------------*/
3/*--- The core dispatch loop, for jumping to a code address.       ---*/
4/*---                                        dispatch-x86-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_x86_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_x86_EIP */
38
39
40/* Global variables */
41/* These are defined here instead of in their respective C files to
42   avoid extra PIC branch code here. */
43.data
44.align 2
45
46/* m_transtab.c */
47.globl VG_(tt_fast)
48.align 4
49VG_(tt_fast):	.space VG_TT_FAST_SIZE*8, 0  /* (2*Addr) [VG_TT_FAST_SIZE] */
50.globl VG_(tt_fastN)
51VG_(tt_fastN):	.space VG_TT_FAST_SIZE*4, 0  /* (UInt *) [VG_TT_FAST_SIZE] */
52
53/* scheduler.c */
54.globl VG_(dispatch_ctr)
55VG_(dispatch_ctr):	.long 0
56
57
58/*------------------------------------------------------------*/
59/*---                                                      ---*/
60/*--- The dispatch loop.  VG_(run_innerloop) is used to    ---*/
61/*--- run all translations except no-redir ones.           ---*/
62/*---                                                      ---*/
63/*------------------------------------------------------------*/
64
65/*----------------------------------------------------*/
66/*--- Preamble (set everything up)                 ---*/
67/*----------------------------------------------------*/
68
69/* signature:
70UWord VG_(run_innerloop) ( void* guest_state, UWord do_profiling );
71*/
72.text
73.globl VG_(run_innerloop)
74VG_(run_innerloop):
75	/* 4(%esp) holds guest_state */
76	/* 8(%esp) holds do_profiling */
77
78	/* ----- entry point to VG_(run_innerloop) ----- */
79	pushl	%ebx
80	pushl	%ecx
81	pushl	%edx
82	pushl	%esi
83	pushl	%edi
84	pushl	%ebp
85
86	/* 28(%esp) holds guest_state */
87	/* 32(%esp) holds do_profiling */
88
89	/* Set up the guest state pointer */
90	movl	28(%esp), %ebp
91
92	/* fetch %EIP into %eax */
93	movl	OFFSET_x86_EIP(%ebp), %eax
94
95	/* set host FPU control word to the default mode expected
96           by VEX-generated code.  See comments in libvex.h for
97           more info. */
98	finit
99	pushl	$0x027F
100	fldcw	(%esp)
101	addl	$4, %esp
102
103	/* set host SSE control word to the default mode expected
104	   by VEX-generated code. */
105	cmpl	$0, VG_(machine_x86_have_mxcsr)
106	jz	L1
107	pushl	$0x1F80
108	ldmxcsr	(%esp)
109	addl	$4, %esp
110L1:
111	/* set dir flag to known value */
112	cld
113
114	/* fall into main loop (the right one) */
115	cmpl	$0, 32(%esp) /* do_profiling */
116	je	VG_(run_innerloop__dispatch_unassisted_unprofiled)
117	jmp	VG_(run_innerloop__dispatch_unassisted_profiled)
118	/*NOTREACHED*/
119
120/*----------------------------------------------------*/
121/*--- NO-PROFILING (standard) dispatcher           ---*/
122/*----------------------------------------------------*/
123
124.globl	VG_(run_innerloop__dispatch_unassisted_unprofiled)
125VG_(run_innerloop__dispatch_unassisted_unprofiled):
126	/* AT ENTRY: %eax is next guest addr, %ebp is the
127           unmodified guest state ptr */
128
129	/* save the jump address in the guest state */
130	movl	%eax, OFFSET_x86_EIP(%ebp)
131
132	/* Are we out of timeslice?  If yes, defer to scheduler. */
133	subl	$1, VG_(dispatch_ctr)
134	jz	counter_is_zero
135
136	/* try a fast lookup in the translation cache */
137	movl	%eax, %ebx
138	andl	$VG_TT_FAST_MASK, %ebx
139	movl	0+VG_(tt_fast)(,%ebx,8), %esi	/* .guest */
140	movl	4+VG_(tt_fast)(,%ebx,8), %edi	/* .host */
141	cmpl	%eax, %esi
142	jnz	fast_lookup_failed
143
144	/* Found a match.  Jump to .host. */
145	jmp 	*%edi
146	ud2	/* persuade insn decoders not to speculate past here */
147	/* generated code should run, then jump back to
148	   VG_(run_innerloop__dispatch_{un,}assisted_unprofiled). */
149	/*NOTREACHED*/
150
151.globl	VG_(run_innerloop__dispatch_assisted_unprofiled)
152VG_(run_innerloop__dispatch_assisted_unprofiled):
153	/* AT ENTRY: %eax is next guest addr, %ebp is the
154           modified guest state ptr */
155        jmp     gsp_changed
156        ud2
157        /*NOTREACHED*/
158
159/*----------------------------------------------------*/
160/*--- PROFILING dispatcher (can be much slower)    ---*/
161/*----------------------------------------------------*/
162
163.globl	VG_(run_innerloop__dispatch_unassisted_profiled)
164VG_(run_innerloop__dispatch_unassisted_profiled):
165	/* AT ENTRY: %eax is next guest addr, %ebp is the
166           unmodified guest state ptr */
167
168	/* save the jump address in the guest state */
169	movl	%eax, OFFSET_x86_EIP(%ebp)
170
171	/* Are we out of timeslice?  If yes, defer to scheduler. */
172	subl	$1, VG_(dispatch_ctr)
173	jz	counter_is_zero
174
175	/* try a fast lookup in the translation cache */
176	movl	%eax, %ebx
177	andl	$VG_TT_FAST_MASK, %ebx
178	movl	0+VG_(tt_fast)(,%ebx,8), %esi	/* .guest */
179	movl	4+VG_(tt_fast)(,%ebx,8), %edi	/* .host */
180	cmpl	%eax, %esi
181	jnz	fast_lookup_failed
182	/* increment bb profile counter */
183	/* note: innocuous as this sounds, it causes a huge amount more
184           stress on D1 and significantly slows everything down. */
185	movl	VG_(tt_fastN)(,%ebx,4), %edx
186	/* Use "addl $1", not "incl", to avoid partial-flags stall on P4 */
187	addl	$1, (%edx)
188
189	/* Found a match.  Jump to .host. */
190	jmp 	*%edi
191	ud2	/* persuade insn decoders not to speculate past here */
192	/* generated code should run, then jump back to
193	   VG_(run_innerloop__dispatch_{un,}assisted_profiled). */
194	/*NOTREACHED*/
195
196.globl	VG_(run_innerloop__dispatch_assisted_profiled)
197VG_(run_innerloop__dispatch_assisted_profiled):
198	/* AT ENTRY: %eax is next guest addr, %ebp is the
199           modified guest state ptr */
200        jmp     gsp_changed
201        ud2
202        /*NOTREACHED*/
203
204/*----------------------------------------------------*/
205/*--- exit points                                  ---*/
206/*----------------------------------------------------*/
207
208gsp_changed:
209	/* Someone messed with the gsp.  Have to
210           defer to scheduler to resolve this.  dispatch ctr
211	   is not yet decremented, so no need to increment. */
212	/* %EIP is NOT up to date here.  First, need to write
213	   %eax back to %EIP, but without trashing %ebp since
214	   that holds the value we want to return to the scheduler.
215	   Hence use %esi transiently for the guest state pointer. */
216	movl	28(%esp), %esi
217	movl	%eax, OFFSET_x86_EIP(%esi)
218	movl	%ebp, %eax
219	jmp	run_innerloop_exit
220	/*NOTREACHED*/
221
222counter_is_zero:
223	/* %EIP is up to date here */
224	/* back out decrement of the dispatch counter */
225	addl	$1, VG_(dispatch_ctr)
226	movl	$VG_TRC_INNER_COUNTERZERO, %eax
227	jmp	run_innerloop_exit
228	/*NOTREACHED*/
229
230fast_lookup_failed:
231	/* %EIP is up to date here */
232	/* back out decrement of the dispatch counter */
233	addl	$1, VG_(dispatch_ctr)
234	movl	$VG_TRC_INNER_FASTMISS, %eax
235	jmp	run_innerloop_exit
236	/*NOTREACHED*/
237
238
239
240/* All exits from the dispatcher go through here.  %eax holds
241   the return value.
242*/
243run_innerloop_exit:
244	/* We're leaving.  Check that nobody messed with
245           %mxcsr or %fpucw.  We can't mess with %eax here as it
246	   holds the tentative return value, but any other is OK. */
247#if !defined(ENABLE_INNER)
248        /* This check fails for self-hosting, so skip in that case */
249	pushl	$0
250	fstcw	(%esp)
251	cmpl	$0x027F, (%esp)
252	popl	%esi /* get rid of the word without trashing %eflags */
253	jnz	invariant_violation
254#endif
255	cmpl	$0, VG_(machine_x86_have_mxcsr)
256	jz	L2
257	pushl	$0
258	stmxcsr	(%esp)
259	andl	$0xFFFFFFC0, (%esp)  /* mask out status flags */
260	cmpl	$0x1F80, (%esp)
261	popl	%esi
262	jnz	invariant_violation
263L2:	/* otherwise we're OK */
264	jmp	run_innerloop_exit_REALLY
265
266invariant_violation:
267	movl	$VG_TRC_INVARIANT_FAILED, %eax
268	jmp	run_innerloop_exit_REALLY
269
270run_innerloop_exit_REALLY:
271	popl	%ebp
272	popl	%edi
273	popl	%esi
274	popl	%edx
275	popl	%ecx
276	popl	%ebx
277	ret
278
279
280/*------------------------------------------------------------*/
281/*---                                                      ---*/
282/*--- A special dispatcher, for running no-redir           ---*/
283/*--- translations.  Just runs the given translation once. ---*/
284/*---                                                      ---*/
285/*------------------------------------------------------------*/
286
287/* signature:
288void VG_(run_a_noredir_translation) ( UWord* argblock );
289*/
290
291/* Run a no-redir translation.  argblock points to 4 UWords, 2 to carry args
292   and 2 to carry results:
293      0: input:  ptr to translation
294      1: input:  ptr to guest state
295      2: output: next guest PC
296      3: output: guest state pointer afterwards (== thread return code)
297*/
298.globl VG_(run_a_noredir_translation)
299VG_(run_a_noredir_translation):
300	/* Save callee-saves regs */
301	pushl %esi
302	pushl %edi
303	pushl %ebp
304	pushl %ebx
305
306	movl 20(%esp), %edi	/* %edi = argblock */
307	movl 4(%edi), %ebp	/* argblock[1] */
308	jmp *0(%edi)		/* argblock[0] */
309	/*NOTREACHED*/
310	ud2
311	/* If the translation has been correctly constructed, we
312	should resume at the the following label. */
313.globl VG_(run_a_noredir_translation__return_point)
314VG_(run_a_noredir_translation__return_point):
315	movl 20(%esp), %edi
316	movl %eax, 8(%edi)	/* argblock[2] */
317	movl %ebp, 12(%edi)	/* argblock[3] */
318
319	popl %ebx
320	popl %ebp
321	popl %edi
322	popl %esi
323	ret
324
325#endif // defined(VGP_x86_darwin)
326
327/*--------------------------------------------------------------------*/
328/*--- end                                                          ---*/
329/*--------------------------------------------------------------------*/
330