Path: blob/master/libmupen64plus/mupen64plus-core/src/r4300/x86/rjump.c
2 views
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *1* Mupen64plus - rjump.c *2* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *3* Copyright (C) 2002 Hacktarux *4* *5* This program is free software; you can redistribute it and/or modify *6* it under the terms of the GNU General Public License as published by *7* the Free Software Foundation; either version 2 of the License, or *8* (at your option) any later version. *9* *10* This program is distributed in the hope that it will be useful, *11* but WITHOUT ANY WARRANTY; without even the implied warranty of *12* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *13* GNU General Public License for more details. *14* *15* You should have received a copy of the GNU General Public License *16* along with this program; if not, write to the *17* Free Software Foundation, Inc., *18* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *19* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */2021#include <stdlib.h>2223#include "api/m64p_types.h"24#include "api/callbacks.h"25#include "r4300/recomp.h"26#include "r4300/r4300.h"27#include "r4300/macros.h"28#include "r4300/ops.h"29#include "r4300/recomph.h"3031#ifdef __GNUC__32# define ASM_NAME(name) asm(name)33#else34# define ASM_NAME(name)35#endif3637static long save_ebp ASM_NAME("save_ebp") = 0;38static long save_ebx ASM_NAME("save_ebx") = 0;39static long save_esi ASM_NAME("save_esi") = 0;40static long save_edi ASM_NAME("save_edi") = 0;41static long save_esp ASM_NAME("save_esp") = 0;42static long save_eip ASM_NAME("save_eip") = 0;4344// that's where the dynarec will restart when going back from a C function45static unsigned long *return_address ASM_NAME("return_address");4647void dyna_jump()48{49if (stop == 1)50{51dyna_stop();52return;53}5455if (PC->reg_cache_infos.need_map)56*return_address = (unsigned long) (PC->reg_cache_infos.jump_wrapper);57else58*return_address = (unsigned long) (actual->code + PC->local_addr);59}6061#if defined(WIN32) && !defined(__GNUC__) /* this warning disable only works if placed outside of the scope of a function */62#pragma warning(disable:4731) /* frame pointer register 'ebp' modified by inline assembly code */63#endif6465void dyna_start(void *code)66{67/* save the base and stack pointers */68/* make a call and a pop to retrieve the instruction pointer and save it too */69/* then call the code(), which should theoretically never return. */70/* When dyna_stop() sets the *return_address to the saved EIP, the emulator thread will come back here. */71/* It will jump to label 2, restore the base and stack pointers, and exit this function */72#if defined(WIN32) && !defined(__GNUC__)73__asm74{75mov save_ebp, ebp76mov save_esp, esp77mov save_ebx, ebx78mov save_esi, esi79mov save_edi, edi80call point181jmp point282point1:83pop eax84mov save_eip, eax8586sub esp, 0x1087and esp, 0xfffffff088mov return_address, esp89sub return_address, 49091mov eax, code92call eax93point2:94mov ebp, save_ebp95mov esp, save_esp96mov ebx, save_ebx97mov esi, save_esi98mov edi, save_edi99}100#elif defined(__GNUC__) && defined(__i386__)101#if defined(__PIC__)102/* for -fPIC (shared libraries) */103#if __GNUC_PREREQ (4, 7)104# define GET_PC_THUNK_STR(reg) "__x86.get_pc_thunk." #reg105#else106# define GET_PC_THUNK_STR(reg) "__i686.get_pc_thunk." #reg107#endif108#define STORE_EBX109#define LOAD_EBX "call " GET_PC_THUNK_STR(bx) " \n" \110"addl $_GLOBAL_OFFSET_TABLE_, %%ebx \n"111#else112/* for non-PIC binaries */113#define STORE_EBX "movl %%ebx, %[save_ebx] \n"114#define LOAD_EBX "movl %[save_ebx], %%ebx \n"115#endif116117asm volatile118(STORE_EBX119" movl %%ebp, %[save_ebp] \n"120" movl %%esp, %[save_esp] \n"121" movl %%esi, %[save_esi] \n"122" movl %%edi, %[save_edi] \n"123" call 1f \n"124" jmp 2f \n"125"1: \n"126" popl %%eax \n"127" movl %%eax, %[save_eip] \n"128129" subl $16, %%esp \n" /* save 16 bytes of padding just in case */130" andl $-16, %%esp \n" /* align stack on 16-byte boundary for OSX */131" movl %%esp, %[return_address] \n"132" subl $4, %[return_address] \n"133134" call *%[codeptr] \n"135"2: \n"136LOAD_EBX137" movl %[save_ebp], %%ebp \n"138" movl %[save_esp], %%esp \n"139" movl %[save_esi], %%esi \n"140" movl %[save_edi], %%edi \n"141: [save_ebp]"=m"(save_ebp), [save_esp]"=m"(save_esp), [save_ebx]"=m"(save_ebx), [save_esi]"=m"(save_esi), [save_edi]"=m"(save_edi), [save_eip]"=m"(save_eip), [return_address]"=m"(return_address)142: [codeptr]"r"(code)143: "eax", "ecx", "edx", "memory"144);145#endif146147/* clear the registers so we don't return here a second time; that would be a bug */148/* this is also necessary to prevent compiler from optimizing out the static variables */149save_edi=0;150save_esi=0;151save_ebx=0;152save_ebp=0;153save_esp=0;154save_eip=0;155}156157void dyna_stop()158{159if (save_eip == 0)160DebugMessage(M64MSG_WARNING, "instruction pointer is 0 at dyna_stop()");161else162{163*return_address = (unsigned long) save_eip;164}165}166167168169