Tom Hughes 414846a941 Removed all uses of nested functions as they only work with gcc and
cause the stack to be marked as executable in order for them to work.

All assembler files have also had a declaration added so that the
object they generate will be marked as not needing an executable stack.


git-svn-id: svn://svn.valgrind.org/valgrind/trunk@2446
2004-06-27 17:37:21 +00:00

232 lines
6.8 KiB
ArmAsm

##--------------------------------------------------------------------##
##--- The core dispatch loop, for jumping to a code address. ---##
##--- vg_dispatch.S ---##
##--------------------------------------------------------------------##
/*
This file is part of Valgrind, an extensible x86 protected-mode
emulator for monitoring program execution on x86-Unixes.
Copyright (C) 2000-2004 Julian Seward
jseward@acm.org
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307, USA.
The GNU General Public License is contained in the file COPYING.
*/
#include "vg_constants.h"
/*------------------------------------------------------------*/
/*--- The normal-case dispatch machinery. ---*/
/*------------------------------------------------------------*/
/* To transfer to an (original) code address, load it into %eax and
jump to vg_dispatch. This fragment of code tries to find the
address of the corresponding translation by searching the translation
table. If it fails, a new translation is made, added to the
translation table, and then jumped to. Almost all the hard
work is done by C routines; this code simply handles the
common case fast -- when the translation address is found in
the translation cache.
At entry, %eax is the only live (real-machine) register; the
entire simulated state is tidily saved in vg_m_state.
*/
#define TT_LOOKUP(reg, fail) \
movl %eax, reg; \
andl $VG_TT_FAST_MASK, reg; \
movl VG_(tt_fast)(,reg,4), reg; \
cmpl %eax, (reg); \
jnz fail
/* The C world needs a way to get started simulating. So we provide
a function void vg_run_innerloop ( void ), which starts running
from vg_m_eip, and exits when the counter reaches zero. This loop
can also exit if vg_oursignalhandler() catches a non-resumable
signal, for example SIGSEGV. It then longjmp()s back past here.
*/
.globl VG_(run_innerloop)
VG_(run_innerloop):
/* OYNK(1000) */
/* ----- entry point to VG_(run_innerloop) ----- */
pushl %ebx
pushl %ecx
pushl %edx
pushl %esi
pushl %edi
pushl %ebp
/* check to see if we're doing pointer checking */
movb VG_(clo_pointercheck), %al
testb %al,%al
jz 1f
pushl %fs /* save %fs */
mov $(VG_POINTERCHECK_SEGIDX << 3) + 7, %eax /* load new %fs */
movw %ax,%fs
1:
/* Set up the baseBlock pointer */
movl $VG_(baseBlock), %ebp
/* fetch m_eip into %eax */
movl VGOFF_(m_eip), %esi
movl (%ebp, %esi, 4), %eax
dispatch_main:
/* Jump here to do a new dispatch.
%eax holds destination (original) address.
%ebp indicates further details of the control transfer
requested to the address in %eax.
If ebp == & VG_(baseBlock), just jump next to %eax.
If ebp == VG_EBP_JMP_SYSCALL, do a system call before
continuing at eax.
If ebp == VG_EBP_JMP_CLIENTREQ, do a client request before
continuing at eax.
If %ebp has any other value, we panic.
*/
/*cmpl $VG_(baseBlock), %ebp*/
/*jnz dispatch_exceptional*/
/* fall into main loop */
dispatch_boring:
/* save the jump address at VG_(baseBlock)[VGOFF_(m_eip)] */
movl VGOFF_(m_eip), %esi
movl %eax, (%ebp, %esi, 4)
/* Are we out of timeslice? If yes, defer to scheduler. */
cmpl $0, VG_(dispatch_ctr)
jz counter_is_zero
/* try a fast lookup in the translation cache */
TT_LOOKUP(%ebx, fast_lookup_failed)
/* Found a match. Call the tce.payload field (+VG_CODE_OFFSET) */
addl $VG_CODE_OFFSET, %ebx
incl VG_(unchained_jumps_done) /* update stats */
call *%ebx
cmpl $VG_(baseBlock), %ebp
jz dispatch_boring
jmp dispatch_exceptional
fast_lookup_failed:
/* %EIP is up to date here since dispatch_boring dominates */
movl $VG_TRC_INNER_FASTMISS, %eax
jmp run_innerloop_exit
counter_is_zero:
/* %EIP is up to date here since dispatch_boring dominates */
movl $VG_TRC_INNER_COUNTERZERO, %eax
jmp run_innerloop_exit
run_innerloop_exit:
movb VG_(clo_pointercheck), %bl
testb %bl,%bl
jz 1f
/* restore %fs */
popl %fs
1: popl %ebp
popl %edi
popl %esi
popl %edx
popl %ecx
popl %ebx
ret
/* Other ways of getting out of the inner loop. Placed out-of-line to
make it look cleaner.
*/
dispatch_exceptional:
/* this is jumped to only, not fallen-through from above */
cmpl $VG_TRC_INNER_COUNTERZERO, %ebp
jz counter_is_zero
/* save %eax in %EIP and defer to sched */
movl VGOFF_(m_eip), %esi
movl %eax, VG_(baseBlock)(,%esi, 4)
movl %ebp, %eax
jmp run_innerloop_exit
/*
This is the translation chainer, our run-time linker, if you like.
VG_(patch_me) patches the call instruction in the jump site
with a jump to the generated code for the branch target. %eax
contains the original program's EIP - if we get a hit in
tt_fast, then the call is patched into a jump; otherwise it
simply drops back into the dispatch loop for normal
processing.
The callsite is expected to look like:
call VG_(patch_me)
it will be transformed into
jmp $TARGETADDR
The environment we're expecting on entry is:
%eax = branch target address (original code EIP)
*(%esp) = just after call
*/
.globl VG_(patch_me)
VG_(patch_me):
/* try a fast lookup in the translation cache */
TT_LOOKUP(%ebx, 1f)
/* Patch call instruction at callsite into a chained jmp */
popl %eax /* eax = just after (VG_PATCHME_CALLSZ byte) call */
addl $VG_CODE_OFFSET, %ebx /* ebx = target eip */
subl %eax, %ebx /* ebx = delta */
movb $0xE9, -(VG_PATCHME_CALLSZ-0)(%eax) /* 0xe9 = jmp */
movl %ebx, -(VG_PATCHME_CALLSZ-1)(%eax) /* store delta */
addl %eax, %ebx
incl VG_(bb_enchain_count) /* update stats */
jmp *%ebx /* jmp to dest */
/* tt_fast miss: return into main dispatch loop */
1: addl $4, %esp /* remove our call address */
ret /* return into main dispatch loop above */
.data
panic_msg_ebp:
.ascii "vg_dispatch: %ebp has invalid value!"
.byte 0
.text
/* Let the linker know we don't need an executable stack */
.section .note.GNU-stack,"",@progbits
##--------------------------------------------------------------------##
##--- end vg_dispatch.S ---##
##--------------------------------------------------------------------##