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