Add 469782 to NEWS
[valgrind.git] / coregrind / m_dispatch / dispatch-x86-linux.S
blob9c0c0455488356c440d4834e921cc845f0733803
2 /*--------------------------------------------------------------------*/
3 /*--- The core dispatch loop, for jumping to a code address.       ---*/
4 /*---                                         dispatch-x86-linux.S ---*/
5 /*--------------------------------------------------------------------*/
7 /*
8   This file is part of Valgrind, a dynamic binary instrumentation
9   framework.
11   Copyright (C) 2000-2017 Julian Seward 
12      jseward@acm.org
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.
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.
24   You should have received a copy of the GNU General Public License
25   along with this program; if not, see <http://www.gnu.org/licenses/>.
27   The GNU General Public License is contained in the file COPYING.
30 #include "pub_core_basics_asm.h"
32 #if defined(VGP_x86_linux)
34 #include "pub_core_dispatch_asm.h"
35 #include "pub_core_transtab_asm.h"
36 #include "libvex_guest_offsets.h"       /* for OFFSET_x86_EIP */
39 /*------------------------------------------------------------*/
40 /*---                                                      ---*/
41 /*--- The dispatch loop.  VG_(disp_run_translations) is    ---*/
42 /*--- used to run all translations,                        ---*/
43 /*--- including no-redir ones.                             ---*/
44 /*---                                                      ---*/
45 /*------------------------------------------------------------*/
47 /*----------------------------------------------------*/
48 /*--- Entry and preamble (set everything up)       ---*/
49 /*----------------------------------------------------*/
51 /* signature:
52 void VG_(disp_run_translations)( UWord* two_words,
53                                  void*  guest_state, 
54                                  Addr   host_addr );
56 .text
57 .globl VG_(disp_run_translations)
58 .type  VG_(disp_run_translations), @function
59 VG_(disp_run_translations):
60         /* 0(%esp) holds our return address. */
61         /* 4(%esp) holds two_words */
62         /* 8(%esp) holds guest_state */
63         /* 12(%esp) holds host_addr */
65         /* The preamble */
67         /* Save integer registers, since this is a pseudo-function. */
68         pushl   %eax
69         pushl   %ebx
70         pushl   %ecx
71         pushl   %edx
72         pushl   %esi
73         pushl   %edi
74         pushl   %ebp
75         
76         /* 28+4(%esp) holds two_words */
77         /* 28+8(%esp) holds guest_state */
78         /* 28+12(%esp) holds host_addr */
80         /* Get the host CPU in the state expected by generated code. */
82         /* set host FPU control word to the default mode expected 
83            by VEX-generated code.  See comments in libvex.h for
84            more info. */
85         finit
86         pushl   $0x027F
87         fldcw   (%esp)
88         addl    $4, %esp
89         
90         /* set host SSE control word to the default mode expected 
91            by VEX-generated code. */
92         cmpl    $0, VG_(machine_x86_have_mxcsr)
93         jz      L1
94         pushl   $0x1F80
95         ldmxcsr (%esp)
96         addl    $4, %esp
97 L1:
98         /* set dir flag to known value */
99         cld
101         /* Set up the guest state pointer */
102         movl    28+8(%esp), %ebp
104         /* and jump into the code cache.  Chained translations in
105            the code cache run, until for whatever reason, they can't
106            continue.  When that happens, the translation in question
107            will jump (or call) to one of the continuation points
108            VG_(cp_...) below. */
109         jmpl    *28+12(%esp)
110         /*NOTREACHED*/
112 /*----------------------------------------------------*/
113 /*--- Postamble and exit.                          ---*/
114 /*----------------------------------------------------*/
116 postamble:
117         /* At this point, %eax and %edx contain two
118            words to be returned to the caller.  %eax
119            holds a TRC value, and %edx optionally may
120            hold another word (for CHAIN_ME exits, the
121            address of the place to patch.) */
123         /* We're leaving.  Check that nobody messed with %mxcsr
124            or %fpucw.  We can't mess with %eax or %edx here as they
125            holds the tentative return value, but any others are OK. */
126 #if !defined(ENABLE_INNER)
127         /* This check fails for self-hosting, so skip in that case */
128         pushl   $0
129         fstcw   (%esp)
130         cmpl    $0x027F, (%esp)
131         popl    %esi /* get rid of the word without trashing %eflags */
132         jnz     invariant_violation
133 #endif
134 #       cmpl    $0, VG_(machine_x86_have_mxcsr)
135         jz      L2
136         pushl   $0
137         stmxcsr (%esp)
138         andl    $0xFFFFFFC0, (%esp)  /* mask out status flags */
139         cmpl    $0x1F80, (%esp)
140         popl    %esi
141         jnz     invariant_violation
142 L2:     /* otherwise we're OK */
143         jmp     remove_frame
144 invariant_violation:
145         movl    $VG_TRC_INVARIANT_FAILED, %eax
146         movl    $0, %edx
148 remove_frame:
149         /* Stash return values */
150         movl    28+4(%esp), %edi        /* two_words */
151         movl    %eax, 0(%edi)
152         movl    %edx, 4(%edi)
153         /* Restore int regs and return. */
154         popl    %ebp
155         popl    %edi
156         popl    %esi
157         popl    %edx
158         popl    %ecx
159         popl    %ebx
160         popl    %eax
161         ret     
162         
163 /*----------------------------------------------------*/
164 /*--- Continuation points                          ---*/
165 /*----------------------------------------------------*/
167 /* ------ Chain me to slow entry point ------ */
168 .global VG_(disp_cp_chain_me_to_slowEP)
169 VG_(disp_cp_chain_me_to_slowEP):
170         /* We got called.  The return address indicates
171            where the patching needs to happen.  Collect
172            the return address and, exit back to C land,
173            handing the caller the pair (Chain_me_S, RA) */
174         movl    $VG_TRC_CHAIN_ME_TO_SLOW_EP, %eax
175         popl    %edx
176         /* 5 = movl $VG_(disp_chain_me_to_slowEP), %edx;
177            2 = call *%edx */
178         subl    $5+2, %edx
179         jmp     postamble
181 /* ------ Chain me to fast entry point ------ */
182 .global VG_(disp_cp_chain_me_to_fastEP)
183 VG_(disp_cp_chain_me_to_fastEP):
184         /* We got called.  The return address indicates
185            where the patching needs to happen.  Collect
186            the return address and, exit back to C land,
187            handing the caller the pair (Chain_me_F, RA) */
188         movl    $VG_TRC_CHAIN_ME_TO_FAST_EP, %eax
189         popl    %edx
190         /* 5 = movl $VG_(disp_chain_me_to_fastEP), %edx;
191            2 = call *%edx */
192         subl    $5+2, %edx
193         jmp     postamble
195 /* ------ Indirect but boring jump ------ */
196 .global VG_(disp_cp_xindir)
197 VG_(disp_cp_xindir):
198         /* Where are we going? */
199         movl    OFFSET_x86_EIP(%ebp), %eax    // "guest"
201         /* stats only */
202         addl    $1, VG_(stats__n_xIndirs_32)
204         // LIVE: %ebp (guest state ptr), %eax (guest address to go to).
205         // We use 4 temporaries:
206         //   %esi (to point at the relevant FastCacheSet),
207         //   %ebx, %ecx and %edx (scratch).
209         /* Try a fast lookup in the translation cache.  This is pretty much
210            a handcoded version of VG_(lookupInFastCache). */
212         // Compute %esi = VG_TT_FAST_HASH(guest)
213         movl    %eax, %esi               // guest
214         shrl    $VG_TT_FAST_BITS, %esi   // (guest >> VG_TT_FAST_BITS)
215         xorl    %eax, %esi               // (guest >> VG_TT_FAST_BITS) ^ guest
216         andl    $VG_TT_FAST_MASK, %esi   // setNo
218         // Compute %esi = &VG_(tt_fast)[%esi]
219         shll    $VG_FAST_CACHE_SET_BITS, %esi  // setNo * sizeof(FastCacheSet)
220         leal    VG_(tt_fast)(%esi), %esi       // &VG_(tt_fast)[setNo]
222         // LIVE: %ebp (guest state ptr), %eax (guest addr), %esi (cache set)
223         // try way 0
224         cmpl    %eax, FCS_g0(%esi)   // cmp against .guest0
225         jnz     1f
226         // hit at way 0
227         jmp    *FCS_h0(%esi)         // goto .host0
228         ud2
230 1:      // try way 1
231         cmpl    %eax, FCS_g1(%esi)   // cmp against .guest1
232         jnz     2f
233         // hit at way 1; swap upwards
234         /* stats only */
235         addl    $1, VG_(stats__n_xIndir_hits1_32)
236         movl    FCS_g0(%esi), %ebx   // ebx = old .guest0
237         movl    FCS_h0(%esi), %ecx   // ecx = old .host0
238         movl    FCS_h1(%esi), %edx   // edx = old .host1
239         movl    %eax, FCS_g0(%esi)   // new .guest0 = guest
240         movl    %edx, FCS_h0(%esi)   // new .host0 = old .host1
241         movl    %ebx, FCS_g1(%esi)   // new .guest1 = old .guest0
242         movl    %ecx, FCS_h1(%esi)   // new .host1 = old .host0
243         jmp     *%edx                // goto old .host1 a.k.a. new .host0
244         ud2
246 2:      // try way 2
247         cmpl    %eax, FCS_g2(%esi)   // cmp against .guest2
248         jnz     3f
249         // hit at way 2; swap upwards
250         /* stats only */
251         addl    $1, VG_(stats__n_xIndir_hits2_32)
252         movl    FCS_g1(%esi), %ebx
253         movl    FCS_h1(%esi), %ecx
254         movl    FCS_h2(%esi), %edx
255         movl    %eax, FCS_g1(%esi)
256         movl    %edx, FCS_h1(%esi)
257         movl    %ebx, FCS_g2(%esi)
258         movl    %ecx, FCS_h2(%esi)
259         jmp     *%edx
260         ud2
262 3:      // try way 3
263         cmpl    %eax, FCS_g3(%esi)   // cmp against .guest3
264         jnz     4f
265         // hit at way 3; swap upwards
266         /* stats only */
267         addl    $1, VG_(stats__n_xIndir_hits3_32)
268         movl    FCS_g2(%esi), %ebx
269         movl    FCS_h2(%esi), %ecx
270         movl    FCS_h3(%esi), %edx
271         movl    %eax, FCS_g2(%esi)
272         movl    %edx, FCS_h2(%esi)
273         movl    %ebx, FCS_g3(%esi)
274         movl    %ecx, FCS_h3(%esi)
275         jmp     *%edx
276         ud2
278 4:      // fast lookup failed
279         /* stats only */
280         addl    $1, VG_(stats__n_xIndir_misses_32)
282         movl    $VG_TRC_INNER_FASTMISS, %eax
283         movl    $0, %edx
284         jmp     postamble
286 /* ------ Assisted jump ------ */
287 .global VG_(disp_cp_xassisted)
288 VG_(disp_cp_xassisted):
289         /* %ebp contains the TRC */
290         movl    %ebp, %eax
291         movl    $0, %edx
292         jmp     postamble
294 /* ------ Event check failed ------ */
295 .global VG_(disp_cp_evcheck_fail)
296 VG_(disp_cp_evcheck_fail):
297         movl    $VG_TRC_INNER_COUNTERZERO, %eax
298         movl    $0, %edx
299         jmp     postamble
302 .size VG_(disp_run_translations), .-VG_(disp_run_translations)
304 #endif // defined(VGP_x86_linux)
306 /* Let the linker know we don't need an executable stack */
307 MARK_STACK_NO_EXEC
309 /*--------------------------------------------------------------------*/
310 /*--- end                                                          ---*/
311 /*--------------------------------------------------------------------*/