diff --git a/code/cgame/cg_syscalls.c b/code/cgame/cg_syscalls.c index c7ad938..77449a6 100644 --- a/code/cgame/cg_syscalls.c +++ b/code/cgame/cg_syscalls.c @@ -28,10 +28,10 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "cg_local.h" -static int (QDECL *syscall)( int arg, ... ) = (int (QDECL *)( int, ...))-1; +static intptr_t (QDECL *syscall)( intptr_t arg, ... ) = (intptr_t (QDECL *)( intptr_t, ...))-1; -void dllEntry( int (QDECL *syscallptr)( int arg,... ) ) { +void dllEntry( intptr_t (QDECL *syscallptr)( intptr_t arg,... ) ) { syscall = syscallptr; } diff --git a/code/client/cl_cgame.c b/code/client/cl_cgame.c index b6531fb..69bdc25 100644 --- a/code/client/cl_cgame.c +++ b/code/client/cl_cgame.c @@ -413,8 +413,9 @@ The cgame module is making a system call ==================== */ #define VMA(x) VM_ArgPtr(args[x]) -#define VMF(x) ((float *)args)[x] -int CL_CgameSystemCalls( int *args ) { +#define VMF(x) (*(float*)&args[x]) + +intptr_t CL_CgameSystemCalls( intptr_t *args ) { switch( args[0] ) { case CG_PRINT: Com_Printf( "%s", VMA(1) ); diff --git a/code/client/cl_ui.c b/code/client/cl_ui.c index b6a6fc6..1d765d4 100644 --- a/code/client/cl_ui.c +++ b/code/client/cl_ui.c @@ -757,9 +757,9 @@ static int FloatAsInt( float f ) { return temp; } -void *VM_ArgPtr( int intValue ); +void *VM_ArgPtr( intptr_t intValue ); #define VMA(x) VM_ArgPtr(args[x]) -#define VMF(x) ((float *)args)[x] +#define VMF(x) (*(float*)&args[x]) /* ==================== @@ -768,7 +768,7 @@ CL_UISystemCalls The ui module is making a system call ==================== */ -int CL_UISystemCalls( int *args ) { +intptr_t CL_UISystemCalls( intptr_t *args ) { switch( args[0] ) { case UI_ERROR: Com_Error( ERR_DROP, "%s", VMA(1) ); diff --git a/code/game/g_syscalls.c b/code/game/g_syscalls.c index 0e7c8cd..3ef3f5c 100644 --- a/code/game/g_syscalls.c +++ b/code/game/g_syscalls.c @@ -28,10 +28,10 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #error "Do not use in VM build" #endif -static int (QDECL *syscall)( int arg, ... ) = (int (QDECL *)( int, ...))-1; +static intptr_t (QDECL *syscall)( intptr_t arg, ... ) = (intptr_t (QDECL *)( intptr_t, ...))-1; -void dllEntry( int (QDECL *syscallptr)( int arg,... ) ) { +void dllEntry( intptr_t (QDECL *syscallptr)( intptr_t arg,... ) ) { syscall = syscallptr; } diff --git a/code/q3_ui/ui_syscalls.c b/code/q3_ui/ui_syscalls.c index 7240c2b..890bd0c 100644 --- a/code/q3_ui/ui_syscalls.c +++ b/code/q3_ui/ui_syscalls.c @@ -28,9 +28,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #error "Do not use in VM build" #endif -static int (QDECL *syscall)( int arg, ... ) = (int (QDECL *)( int, ...))-1; +static intptr_t (QDECL *syscall)( intptr_t arg, ... ) = (intptr_t (QDECL *)( intptr_t, ...))-1; -void dllEntry( int (QDECL *syscallptr)( int arg,... ) ) { +void dllEntry( intptr_t (QDECL *syscallptr)( intptr_t arg,... ) ) { syscall = syscallptr; } diff --git a/code/qcommon/qcommon.h b/code/qcommon/qcommon.h index 7e38c0b..b7485f4 100644 --- a/code/qcommon/qcommon.h +++ b/code/qcommon/qcommon.h @@ -310,7 +310,7 @@ typedef enum { } sharedTraps_t; void VM_Init( void ); -vm_t *VM_Create( const char *module, int (*systemCalls)(int *), +vm_t *VM_Create( const char *module, intptr_t (*systemCalls)(intptr_t *), vmInterpret_t interpret ); // module should be bare: "cgame", not "cgame.dll" or "vm/cgame.qvm" @@ -322,8 +322,9 @@ intptr_t QDECL VM_Call( vm_t *vm, int callNum, ... ); void VM_Debug( int level ); -void *VM_ArgPtr( int intValue ); -void *VM_ExplicitArgPtr( vm_t *vm, int intValue ); +void *VM_ArgPtr( intptr_t intValue ); +void *VM_ExplicitArgPtr( vm_t *vm, intptr_t intValue ); + /* ============================================================== @@ -928,7 +929,7 @@ void Sys_Init (void); // general development dll loading for virtual machine testing // fqpath param added 7/20/02 by T.Ray - Sys_LoadDll is only called in vm.c at this time void * QDECL Sys_LoadDll( const char *name, char *fqpath , intptr_t (QDECL **entryPoint)(int, ...), - int (QDECL *systemcalls)(int, ...) ); + intptr_t (QDECL *systemcalls)(intptr_t, ...) ); void Sys_UnloadDll( void *dllHandle ); void Sys_UnloadGame( void ); diff --git a/code/qcommon/vm.c b/code/qcommon/vm.c index 63aa283..d87f667 100644 --- a/code/qcommon/vm.c +++ b/code/qcommon/vm.c @@ -249,62 +249,19 @@ void VM_LoadSymbols( vm_t *vm ) { FS_FreeFile( mapfile ); } -/* -============ -VM_DllSyscall - -Dlls will call this directly - - rcg010206 The horror; the horror. - - The syscall mechanism relies on stack manipulation to get it's args. - This is likely due to C's inability to pass "..." parameters to - a function in one clean chunk. On PowerPC Linux, these parameters - are not necessarily passed on the stack, so while (&arg[0] == arg) - is true, (&arg[1] == 2nd function parameter) is not necessarily - accurate, as arg's value might have been stored to the stack or - other piece of scratch memory to give it a valid address, but the - next parameter might still be sitting in a register. - - Quake's syscall system also assumes that the stack grows downward, - and that any needed types can be squeezed, safely, into a signed int. - - This hack below copies all needed values for an argument to a - array in memory, so that Quake can get the correct values. This can - also be used on systems where the stack grows upwards, as the - presumably standard and safe stdargs.h macros are used. - - As for having enough space in a signed int for your datatypes, well, - it might be better to wait for DOOM 3 before you start porting. :) - - The original code, while probably still inherently dangerous, seems - to work well enough for the platforms it already works on. Rather - than add the performance hit for those platforms, the original code - is still in use there. - - For speed, we just grab 15 arguments, and don't worry about exactly - how many the syscall actually needs; the extra is thrown away. - -============ -*/ -int QDECL VM_DllSyscall( int arg, ... ) { -#ifdef _WIN64 - // rcg010206 - see commentary above - int args[16]; +intptr_t QDECL VM_DllSyscall( intptr_t arg, ... ) { + intptr_t args[MAX_VMSYSCALL_ARGS]; int i; va_list ap; - + args[0] = arg; va_start(ap, arg); - for (i = 1; i < sizeof (args) / sizeof (args[i]); i++) - args[i] = va_arg(ap, int); + for (i = 1; i < ARRAY_LEN(args); i++) + args[i] = va_arg(ap, intptr_t); va_end(ap); return currentVM->systemCall( args ); -#else // original id code - return currentVM->systemCall( &arg ); -#endif } /* @@ -325,7 +282,7 @@ vm_t *VM_Restart( vm_t *vm ) { // DLL's can't be restarted in place if ( vm->dllHandle ) { char name[MAX_QPATH]; - int (*systemCall)( int *parms ); + intptr_t (*systemCall)( intptr_t *parms ); systemCall = vm->systemCall; Q_strncpyz( name, vm->name, sizeof( name ) ); @@ -395,7 +352,7 @@ it will attempt to load as a system dll #define STACK_SIZE 0x20000 -vm_t *VM_Create( const char *module, int (*systemCalls)(int *), +vm_t *VM_Create( const char *module, intptr_t (*systemCalls)(intptr_t *), vmInterpret_t interpret ) { vm_t *vm; vmHeader_t *header; @@ -572,7 +529,7 @@ void VM_Clear(void) { lastVM = NULL; } -void *VM_ArgPtr( int intValue ) { +void *VM_ArgPtr( intptr_t intValue ) { if ( !intValue ) { return NULL; } @@ -588,7 +545,7 @@ void *VM_ArgPtr( int intValue ) { } } -void *VM_ExplicitArgPtr( vm_t *vm, int intValue ) { +void *VM_ExplicitArgPtr( vm_t *vm, intptr_t intValue ) { if ( !intValue ) { return NULL; } @@ -805,7 +762,7 @@ void VM_LogSyscalls( int *args ) { f = fopen("syscalls.log", "w" ); } callnum++; - fprintf(f, "%i: %i (%i) = %i %i %i %i\n", callnum, args - (int *)currentVM->dataBase, + fprintf(f, "%i: %i (%i) = %i %i %i %i\n", callnum, (int)(intptr_t)( args - (int *)currentVM->dataBase ), args[0], args[1], args[2], args[3], args[4] ); } diff --git a/code/qcommon/vm_interpreted.c b/code/qcommon/vm_interpreted.c index 2c0087f..a9182c4 100644 --- a/code/qcommon/vm_interpreted.c +++ b/code/qcommon/vm_interpreted.c @@ -479,7 +479,7 @@ nextInstruction2: src = (int *)&image[ r0&dataMask ]; dest = (int *)&image[ r1&dataMask ]; - if ( ( (int)src | (int)dest | count ) & 3 ) { + if ( ( (intptr_t)src | (intptr_t)dest | count ) & 3 ) { Com_Error( ERR_DROP, "OP_BLOCK_COPY not dword aligned" ); } count >>= 2; @@ -518,7 +518,16 @@ nextInstruction2: *(int *)&image[ programStack + 4 ] = -1 - programCounter; //VM_LogSyscalls( (int *)&image[ programStack + 4 ] ); - r = vm->systemCall( (int *)&image[ programStack + 4 ] ); + { + intptr_t argarr[MAX_VMSYSCALL_ARGS]; + int *imagePtr = (int *)&image[ programStack + 4 ]; + int i; + for (i = 0; i < ARRAY_LEN(argarr); i++) { + argarr[i] = *imagePtr; + imagePtr++; + } + r = vm->systemCall( argarr ); + } #ifdef DEBUG_VM // this is just our stack frame pointer, only needed diff --git a/code/qcommon/vm_local.h b/code/qcommon/vm_local.h index c982f6a..8e8c462 100644 --- a/code/qcommon/vm_local.h +++ b/code/qcommon/vm_local.h @@ -22,6 +22,10 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "../game/q_shared.h" #include "qcommon.h" +// Max number of arguments to pass from a vm to engine's syscall handler function for the vm. +// syscall number + 15 arguments +#define MAX_VMSYSCALL_ARGS 16 + typedef enum { OP_UNDEF, @@ -127,7 +131,7 @@ struct vm_s { // DO NOT MOVE OR CHANGE THESE WITHOUT CHANGING THE VM_OFFSET_* DEFINES // USED BY THE ASM CODE int programStack; // the vm may be recursively entered - int (*systemCall)( int *parms ); + intptr_t (*systemCall)( intptr_t *parms ); //------------------------------------ diff --git a/code/server/sv_game.c b/code/server/sv_game.c index 2ab78cc..e7d6ee5 100644 --- a/code/server/sv_game.c +++ b/code/server/sv_game.c @@ -305,16 +305,10 @@ SV_GameSystemCalls The module is making a system call ==================== */ -//rcg010207 - see my comments in VM_DllSyscall(), in qcommon/vm.c ... -#if ((defined __linux__) && (defined __powerpc__)) -#define VMA(x) ((void *) args[x]) -#else #define VMA(x) VM_ArgPtr(args[x]) -#endif +#define VMF(x) (*(float*)&args[x]) -#define VMF(x) ((float *)args)[x] - -int SV_GameSystemCalls( int *args ) { +intptr_t SV_GameSystemCalls( intptr_t *args ) { switch( args[0] ) { case G_PRINT: Com_Printf( "%s", VMA(1) ); diff --git a/code/win32/win_main.c b/code/win32/win_main.c index 603b233..b2bab6f 100644 --- a/code/win32/win_main.c +++ b/code/win32/win_main.c @@ -527,10 +527,10 @@ extern char *FS_BuildOSPath( const char *base, const char *game, const char *qp // fqpath will be empty if dll not loaded, otherwise will hold fully qualified path of dll module loaded // fqpath buffersize must be at least MAX_QPATH+1 bytes long void * QDECL Sys_LoadDll( const char *name, char *fqpath , intptr_t (QDECL **entryPoint)(int, ...), - int (QDECL *systemcalls)(int, ...) ) { + intptr_t (QDECL *systemcalls)(intptr_t, ...) ) { static int lastWarning = 0; HINSTANCE libHandle; - void (QDECL *dllEntry)( int (QDECL *syscallptr)(int, ...) ); + void (QDECL *dllEntry)( intptr_t (QDECL *syscallptr)(intptr_t, ...) ); char *basepath; char *cdpath; char *gamedir; @@ -606,7 +606,7 @@ void * QDECL Sys_LoadDll( const char *name, char *fqpath , intptr_t (QDECL **ent } #endif - dllEntry = ( void (QDECL *)( int (QDECL *)( int, ... ) ) )GetProcAddress( libHandle, "dllEntry" ); + dllEntry = ( void (QDECL *)( intptr_t (QDECL *)( intptr_t, ... ) ) )GetProcAddress( libHandle, "dllEntry" ); *entryPoint = (intptr_t (QDECL *)(int,...))GetProcAddress( libHandle, "vmMain" ); if ( !*entryPoint || !dllEntry ) { FreeLibrary( libHandle );