blob: bc095e4be18dec4ace9ffba85ffbce17c96089d5 [file] [log] [blame]
njnf76d27a2009-05-28 01:53:07 +00001
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-2007 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_amd64_RIP */
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
53.text
54.globl VG_(run_innerloop)
55VG_(run_innerloop):
56 /* %rdi holds guest_state */
57 /* %rsi holds do_profiling */
58
59 /* ----- entry point to VG_(run_innerloop) ----- */
60 pushq %rbx
61 pushq %rcx
62 pushq %rdx
63 pushq %rsi
64 pushq %rbp
65 pushq %r8
66 pushq %r9
67 pushq %r10
68 pushq %r11
69 pushq %r12
70 pushq %r13
71 pushq %r14
72 pushq %r15
73 pushq %rdi /* guest_state */
74
75 movq VG_(dispatch_ctr)@GOTPCREL(%rip), %r15
76 movl (%r15), %r15d
77 pushq %r15
78
79 /* 8(%rsp) holds cached copy of guest_state ptr */
80 /* 0(%rsp) holds cached copy of VG_(dispatch_ctr) */
81
82 /* Set up the guest state pointer */
83 movq %rdi, %rbp
84
85 /* fetch %RIP into %rax */
86 movq OFFSET_amd64_RIP(%rbp), %rax
87
88 /* set host FPU control word to the default mode expected
89 by VEX-generated code. See comments in libvex.h for
90 more info. */
91 finit
92 pushq $0x027F
93 fldcw (%rsp)
94 addq $8, %rsp
95
96 /* set host SSE control word to the default mode expected
97 by VEX-generated code. */
98 pushq $0x1F80
99 ldmxcsr (%rsp)
100 addq $8, %rsp
101
102 /* set dir flag to known value */
103 cld
104
105 /* fall into main loop (the right one) */
106 cmpq $0, %rsi
107 je VG_(run_innerloop__dispatch_unprofiled)
108 jmp VG_(run_innerloop__dispatch_profiled)
109 /*NOTREACHED*/
110
111/*----------------------------------------------------*/
112/*--- NO-PROFILING (standard) dispatcher ---*/
113/*----------------------------------------------------*/
114
115.align 4
116.globl VG_(run_innerloop__dispatch_unprofiled)
117VG_(run_innerloop__dispatch_unprofiled):
118 /* AT ENTRY: %rax is next guest addr, %rbp is possibly
119 modified guest state ptr */
120
121 /* Has the guest state pointer been messed with? If yes, exit. */
122 cmpq 8(%rsp), %rbp
123 movq VG_(tt_fast)@GOTPCREL(%rip), %rcx
124 jnz gsp_changed
125
126 /* save the jump address in the guest state */
127 movq %rax, OFFSET_amd64_RIP(%rbp)
128
129 /* Are we out of timeslice? If yes, defer to scheduler. */
130 subl $1, 0(%rsp)
131 jz counter_is_zero
132
133 /* try a fast lookup in the translation cache */
134 movq %rax, %rbx
135 andq $VG_TT_FAST_MASK, %rbx /* entry# */
136 shlq $4, %rbx /* entry# * sizeof(FastCacheEntry) */
137 movq 0(%rcx,%rbx,1), %r10 /* .guest */
138 movq 8(%rcx,%rbx,1), %r11 /* .host */
139 cmpq %rax, %r10
140 jnz fast_lookup_failed
141
142 /* Found a match. Jump to .host. */
143 jmp *%r11
144 ud2 /* persuade insn decoders not to speculate past here */
145 /* generated code should run, then jump back to
146 VG_(run_innerloop__dispatch_unprofiled). */
147 /*NOTREACHED*/
148
149/*----------------------------------------------------*/
150/*--- PROFILING dispatcher (can be much slower) ---*/
151/*----------------------------------------------------*/
152
153.align 4
154.globl VG_(run_innerloop__dispatch_profiled)
155VG_(run_innerloop__dispatch_profiled):
156 /* AT ENTRY: %rax is next guest addr, %rbp is possibly
157 modified guest state ptr */
158
159 /* Has the guest state pointer been messed with? If yes, exit. */
160 cmpq 8(%rsp), %rbp
161 movq VG_(tt_fast)@GOTPCREL(%rip), %rcx
162 jnz gsp_changed
163
164 /* save the jump address in the guest state */
165 movq %rax, OFFSET_amd64_RIP(%rbp)
166
167 /* Are we out of timeslice? If yes, defer to scheduler. */
168 subl $1, 0(%rsp)
169 jz counter_is_zero
170
171 /* try a fast lookup in the translation cache */
172 movq %rax, %rbx
173 andq $VG_TT_FAST_MASK, %rbx /* entry# */
174 shlq $4, %rbx /* entry# * sizeof(FastCacheEntry) */
175 movq 0(%rcx,%rbx,1), %r10 /* .guest */
176 movq 8(%rcx,%rbx,1), %r11 /* .host */
177 cmpq %rax, %r10
178 jnz fast_lookup_failed
179
180 /* increment bb profile counter */
181 movq VG_(tt_fastN)@GOTPCREL(%rip), %rdx
182 shrq $1, %rbx /* entry# * sizeof(UInt*) */
183 movq (%rdx,%rbx,1), %rdx
184 addl $1, (%rdx)
185
186 /* Found a match. Jump to .host. */
187 jmp *%r11
188 ud2 /* persuade insn decoders not to speculate past here */
189 /* generated code should run, then jump back to
190 VG_(run_innerloop__dispatch_profiled). */
191 /*NOTREACHED*/
192
193/*----------------------------------------------------*/
194/*--- exit points ---*/
195/*----------------------------------------------------*/
196
197gsp_changed:
198 /* Someone messed with the gsp. Have to
199 defer to scheduler to resolve this. dispatch ctr
200 is not yet decremented, so no need to increment. */
201 /* %RIP is NOT up to date here. First, need to write
202 %rax back to %RIP, but without trashing %rbp since
203 that holds the value we want to return to the scheduler.
204 Hence use %r15 transiently for the guest state pointer. */
205 movq 8(%rsp), %r15
206 movq %rax, OFFSET_amd64_RIP(%r15)
207 movq %rbp, %rax
208 jmp run_innerloop_exit
209 /*NOTREACHED*/
210
211counter_is_zero:
212 /* %RIP is up to date here */
213 /* back out decrement of the dispatch counter */
214 addl $1, 0(%rsp)
215 movq $VG_TRC_INNER_COUNTERZERO, %rax
216 jmp run_innerloop_exit
217
218fast_lookup_failed:
219 /* %RIP is up to date here */
220 /* back out decrement of the dispatch counter */
221 addl $1, 0(%rsp)
222 movq $VG_TRC_INNER_FASTMISS, %rax
223 jmp run_innerloop_exit
224
225
226
227/* All exits from the dispatcher go through here. %rax holds
228 the return value.
229*/
230run_innerloop_exit:
231 /* We're leaving. Check that nobody messed with
232 %mxcsr or %fpucw. We can't mess with %rax here as it
233 holds the tentative return value, but any other is OK. */
234#if !defined(ENABLE_INNER)
235 /* This check fails for self-hosting, so skip in that case */
236 pushq $0
237 fstcw (%rsp)
238 cmpl $0x027F, (%rsp)
239 popq %r15 /* get rid of the word without trashing %eflags */
240 jnz invariant_violation
241#endif
242 pushq $0
243 stmxcsr (%rsp)
244 andl $0xFFFFFFC0, (%rsp) /* mask out status flags */
245 cmpl $0x1F80, (%rsp)
246 popq %r15
247 jnz invariant_violation
248 /* otherwise we're OK */
249 jmp run_innerloop_exit_REALLY
250
251invariant_violation:
252 movq $VG_TRC_INVARIANT_FAILED, %rax
253 jmp run_innerloop_exit_REALLY
254
255run_innerloop_exit_REALLY:
256
257 /* restore VG_(dispatch_ctr) */
258 popq %r14
259 movq VG_(dispatch_ctr)@GOTPCREL(%rip), %r15
260 movl %r14d, (%r15)
261
262 popq %rdi
263 popq %r15
264 popq %r14
265 popq %r13
266 popq %r12
267 popq %r11
268 popq %r10
269 popq %r9
270 popq %r8
271 popq %rbp
272 popq %rsi
273 popq %rdx
274 popq %rcx
275 popq %rbx
276 ret
277
278
279/*------------------------------------------------------------*/
280/*--- ---*/
281/*--- A special dispatcher, for running no-redir ---*/
282/*--- translations. Just runs the given translation once. ---*/
283/*--- ---*/
284/*------------------------------------------------------------*/
285
286/* signature:
287void VG_(run_a_noredir_translation) ( UWord* argblock );
288*/
289
290/* Run a no-redir translation. argblock points to 4 UWords, 2 to carry args
291 and 2 to carry results:
292 0: input: ptr to translation
293 1: input: ptr to guest state
294 2: output: next guest PC
295 3: output: guest state pointer afterwards (== thread return code)
296*/
297.align 4
298.globl VG_(run_a_noredir_translation)
299VG_(run_a_noredir_translation):
300 /* Save callee-saves regs */
301 pushq %rbx
302 pushq %rbp
303 pushq %r12
304 pushq %r13
305 pushq %r14
306 pushq %r15
307
308 pushq %rdi /* we will need it after running the translation */
309 movq 8(%rdi), %rbp
310 jmp *0(%rdi)
311 /*NOTREACHED*/
312 ud2
313 /* If the translation has been correctly constructed, we
314 should resume at the the following label. */
315.globl VG_(run_a_noredir_translation__return_point)
316VG_(run_a_noredir_translation__return_point):
317 popq %rdi
318 movq %rax, 16(%rdi)
319 movq %rbp, 24(%rdi)
320
321 popq %r15
322 popq %r14
323 popq %r13
324 popq %r12
325 popq %rbp
326 popq %rbx
327 ret
328
329/*--------------------------------------------------------------------*/
330/*--- end ---*/
331/*--------------------------------------------------------------------*/