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