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