mirror of
https://github.com/DrBeef/ioq3quest.git
synced 2024-11-23 04:12:39 +00:00
- move code for standalone compilation out of vm_x86_64.c
- reset vm->compiled if something goes wrong in VM_Compile
This commit is contained in:
parent
8a18ecb961
commit
48ee88ad77
1 changed files with 37 additions and 273 deletions
|
@ -32,120 +32,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#ifdef VM_X86_64_STANDALONE
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <time.h>
|
|
||||||
|
|
||||||
static vmInterpret_t interpret = VMI_COMPILED;
|
|
||||||
|
|
||||||
#define DEBUG_VM
|
|
||||||
|
|
||||||
static FILE* _asout;
|
|
||||||
vm_t* currentVM;
|
|
||||||
|
|
||||||
static cvar_t _com_developer;
|
|
||||||
cvar_t *com_developer = &_com_developer;
|
|
||||||
|
|
||||||
char* mmapfile(const char* fn, size_t* size);
|
|
||||||
|
|
||||||
long printsyscall(long* args)
|
|
||||||
{
|
|
||||||
printf("callnr %ld, args: %ld %ld %ld %ld\n",
|
|
||||||
args[0],
|
|
||||||
args[1],
|
|
||||||
args[2],
|
|
||||||
args[3],
|
|
||||||
args[4]);
|
|
||||||
|
|
||||||
switch( args[0] ) {
|
|
||||||
case 0:
|
|
||||||
case 1:
|
|
||||||
{
|
|
||||||
char * s = VMA(1)?VMA(1):"(NULL)\n";
|
|
||||||
fputs(s, stderr);
|
|
||||||
if(s[strlen(s)-1] != '\n')
|
|
||||||
putc('\n', stderr);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
case 999:
|
|
||||||
{
|
|
||||||
int a[5];
|
|
||||||
a[0] = 3;
|
|
||||||
a[1] = args[1];
|
|
||||||
a[2] = args[2];
|
|
||||||
a[3] = args[3];
|
|
||||||
a[4] = args[4];
|
|
||||||
if(!currentVM->compiled)
|
|
||||||
return VM_CallInterpreted(currentVM, a);
|
|
||||||
else
|
|
||||||
return VM_CallCompiled(currentVM, a);
|
|
||||||
}
|
|
||||||
case 1000:
|
|
||||||
{
|
|
||||||
int a[5];
|
|
||||||
a[0] = 4;
|
|
||||||
a[1] = args[1];
|
|
||||||
a[2] = args[2];
|
|
||||||
a[3] = args[3];
|
|
||||||
a[4] = args[4];
|
|
||||||
if(!currentVM->compiled)
|
|
||||||
return VM_CallInterpreted(currentVM, a);
|
|
||||||
else
|
|
||||||
return VM_CallCompiled(currentVM, a);
|
|
||||||
}
|
|
||||||
case 1001:
|
|
||||||
printf("got buffer with content '%s', length %d\n", (char*)VMA(1), (int)args[2]);
|
|
||||||
strncpy(VMA(1), "blah\n", args[2]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0x66;
|
|
||||||
}
|
|
||||||
|
|
||||||
fileHandle_t FS_FOpenFileWrite( const char *filename )
|
|
||||||
{
|
|
||||||
_asout = fopen(filename, "w");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int FS_Write( const void *buffer, int len, fileHandle_t h )
|
|
||||||
{
|
|
||||||
return fwrite(buffer, 1, len, _asout);
|
|
||||||
}
|
|
||||||
|
|
||||||
void FS_Printf( fileHandle_t h, const char *fmt, ... )
|
|
||||||
{
|
|
||||||
va_list ap;
|
|
||||||
va_start(ap, fmt);
|
|
||||||
vfprintf(_asout, fmt, ap);
|
|
||||||
va_end(ap);
|
|
||||||
}
|
|
||||||
|
|
||||||
void FS_Flush( fileHandle_t f )
|
|
||||||
{
|
|
||||||
fflush(_asout);
|
|
||||||
}
|
|
||||||
|
|
||||||
void FS_FCloseFile( fileHandle_t f )
|
|
||||||
{
|
|
||||||
fclose(_asout);
|
|
||||||
}
|
|
||||||
|
|
||||||
char *FS_BuildOSPath( const char *base, const char *game, const char *qpath )
|
|
||||||
{
|
|
||||||
static char buf[4096];
|
|
||||||
strcpy(buf, "./");
|
|
||||||
strcat(buf, qpath);
|
|
||||||
return buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
cvar_t *Cvar_Get( const char *var_name, const char *var_value, int flags ) {
|
|
||||||
static cvar_t c = { .string = "" };
|
|
||||||
return &c;
|
|
||||||
}
|
|
||||||
#endif // VM_X86_64_STANDALONE
|
|
||||||
|
|
||||||
#ifdef DEBUG_VM
|
#ifdef DEBUG_VM
|
||||||
#define Dfprintf(fd, args...) fprintf(fd, ##args)
|
#define Dfprintf(fd, args...) fprintf(fd, ##args)
|
||||||
static FILE* qdasmout;
|
static FILE* qdasmout;
|
||||||
|
@ -386,7 +272,7 @@ static unsigned char op_argsize[256] =
|
||||||
do { Com_Error(ERR_DROP, "instruction not implemented: %s\n", opnames[x]); } while(0)
|
do { Com_Error(ERR_DROP, "instruction not implemented: %s\n", opnames[x]); } while(0)
|
||||||
#else
|
#else
|
||||||
#define NOTIMPL(x) \
|
#define NOTIMPL(x) \
|
||||||
do { Com_Error(ERR_DROP, "instruction not implemented: %x\n", x); } while(0)
|
do { Com_Printf(S_COLOR_RED "instruction not implemented: %x\n", x); vm->compiled = qfalse; return; } while(0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void* getentrypoint(vm_t* vm)
|
static void* getentrypoint(vm_t* vm)
|
||||||
|
@ -442,7 +328,10 @@ static int doas(const char* in, const char* out, unsigned char** compiledcode)
|
||||||
Com_Printf("running assembler < %s > %s\n", rin, rout);
|
Com_Printf("running assembler < %s > %s\n", rin, rout);
|
||||||
pid = fork();
|
pid = fork();
|
||||||
if(pid == -1)
|
if(pid == -1)
|
||||||
Com_Error(ERR_FATAL, "can't fork\n");
|
{
|
||||||
|
Com_Printf(S_COLOR_RED "can't fork\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if(!pid)
|
if(!pid)
|
||||||
{
|
{
|
||||||
|
@ -461,23 +350,38 @@ static int doas(const char* in, const char* out, unsigned char** compiledcode)
|
||||||
{
|
{
|
||||||
int status;
|
int status;
|
||||||
if(waitpid(pid, &status, 0) == -1)
|
if(waitpid(pid, &status, 0) == -1)
|
||||||
Com_Error(ERR_FATAL, "can't wait for as: %s\n", strerror(errno));
|
{
|
||||||
|
Com_Printf(S_COLOR_RED "can't wait for as: %s\n", strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if(!WIFEXITED(status))
|
if(!WIFEXITED(status))
|
||||||
Com_Error(ERR_FATAL, "as died\n");
|
{
|
||||||
|
Com_Printf(S_COLOR_RED "as died\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
if(WEXITSTATUS(status))
|
if(WEXITSTATUS(status))
|
||||||
Com_Error(ERR_FATAL, "as failed with status %d\n", WEXITSTATUS(status));
|
{
|
||||||
|
Com_Printf(S_COLOR_RED "as failed with status %d\n", WEXITSTATUS(status));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Com_Printf("done\n");
|
Com_Printf("done\n");
|
||||||
|
|
||||||
mem = mmapfile(rout, &size);
|
mem = mmapfile(rout, &size);
|
||||||
if(!mem)
|
if(!mem)
|
||||||
Com_Error(ERR_FATAL, "can't mmap object file %s: %s\n", rout, strerror(errno));
|
{
|
||||||
|
Com_Printf(S_COLOR_RED "can't mmap object file %s: %s\n", rout, strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
ps = sysconf(_SC_PAGE_SIZE);
|
ps = sysconf(_SC_PAGE_SIZE);
|
||||||
if(ps == -1)
|
if(ps == -1)
|
||||||
Com_Error(ERR_FATAL, "can't determine page size: %s\n", strerror(errno));
|
{
|
||||||
|
Com_Printf(S_COLOR_RED "can't determine page size: %s\n", strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
--ps;
|
--ps;
|
||||||
|
|
||||||
|
@ -494,7 +398,9 @@ static int doas(const char* in, const char* out, unsigned char** compiledcode)
|
||||||
{
|
{
|
||||||
#ifdef VM_X86_64_STANDALONE // no idea why
|
#ifdef VM_X86_64_STANDALONE // no idea why
|
||||||
if(mprotect(buf, allocsize, PROT_READ|PROT_EXEC) == -1)
|
if(mprotect(buf, allocsize, PROT_READ|PROT_EXEC) == -1)
|
||||||
|
{
|
||||||
Com_Error(ERR_FATAL, "mprotect failed on %p+%x: %s\n", buf, allocsize, strerror(errno));
|
Com_Error(ERR_FATAL, "mprotect failed on %p+%x: %s\n", buf, allocsize, strerror(errno));
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
@ -514,9 +420,6 @@ static void block_copy_vm(unsigned dest, unsigned src, unsigned count)
|
||||||
Com_Error(ERR_DROP, "OP_BLOCK_COPY out of range!\n");
|
Com_Error(ERR_DROP, "OP_BLOCK_COPY out of range!\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Com_Printf("OP_BLOCK_COPY %s %x %x %d\n", currentVM->name, dest, src, count);
|
|
||||||
// __asm__ __volatile__ ("int3");
|
|
||||||
|
|
||||||
memcpy(currentVM->dataBase+dest, currentVM->dataBase+src, count);
|
memcpy(currentVM->dataBase+dest, currentVM->dataBase+src, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -558,7 +461,11 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) {
|
||||||
|
|
||||||
fh_s = FS_FOpenFileWrite(fn_s);
|
fh_s = FS_FOpenFileWrite(fn_s);
|
||||||
if(fh_s == -1)
|
if(fh_s == -1)
|
||||||
Com_Error(ERR_DROP, "can't write %s\n", fn_s);
|
{
|
||||||
|
Com_Printf(S_COLOR_RED "can't write %s\n", fn_s);
|
||||||
|
vm->compiled = qfalse;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// translate all instructions
|
// translate all instructions
|
||||||
pc = 0;
|
pc = 0;
|
||||||
|
@ -979,6 +886,11 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) {
|
||||||
FS_FCloseFile(fh_s);
|
FS_FCloseFile(fh_s);
|
||||||
|
|
||||||
compiledsize = doas(fn_s, fn_o, &compiledcode);
|
compiledsize = doas(fn_s, fn_o, &compiledcode);
|
||||||
|
if(compiledsize == -1)
|
||||||
|
{
|
||||||
|
vm->compiled = qfalse;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
vm->codeBase = compiledcode; // remember to skip ELF header!
|
vm->codeBase = compiledcode; // remember to skip ELF header!
|
||||||
vm->codeLength = compiledsize;
|
vm->codeLength = compiledsize;
|
||||||
|
@ -1105,151 +1017,3 @@ int VM_CallCompiled( vm_t *vm, int *args ) {
|
||||||
|
|
||||||
return *(int *)opStack;
|
return *(int *)opStack;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef VM_X86_64_STANDALONE
|
|
||||||
|
|
||||||
#include <tests.c>
|
|
||||||
|
|
||||||
int testops(vm_t* vm)
|
|
||||||
{
|
|
||||||
int i1, i2, vmres;
|
|
||||||
int i;
|
|
||||||
float f1, f2, fres, fvmres;
|
|
||||||
int numitests = 32;
|
|
||||||
int numftests = 11;
|
|
||||||
int ret = 0;
|
|
||||||
int testno;
|
|
||||||
int res = 0xC0DEDBAD;
|
|
||||||
|
|
||||||
srand(time(NULL));
|
|
||||||
|
|
||||||
i1 = 1 + (int) (1000.0 * (rand() / (RAND_MAX + 1.0)));
|
|
||||||
i2 = 1 + (int) (1000.0 * (rand() / (RAND_MAX + 1.0)));
|
|
||||||
|
|
||||||
if(i1 < i2)
|
|
||||||
{
|
|
||||||
i = i1;
|
|
||||||
i1 = i2;
|
|
||||||
i2 = i;
|
|
||||||
}
|
|
||||||
|
|
||||||
f1 = i1/1.5;
|
|
||||||
f2 = i2/1.5;
|
|
||||||
|
|
||||||
if(!i2) i2=i1;
|
|
||||||
if(!f2) f2=f1;
|
|
||||||
|
|
||||||
printf("i1: %d i2: %d\n", i1, i2);
|
|
||||||
printf("f1: %f f2: %f\n", f1, f2);
|
|
||||||
|
|
||||||
testintops:
|
|
||||||
for (testno = 1; testno < numitests; ++testno)
|
|
||||||
{
|
|
||||||
printf("int test %d ... ", testno);
|
|
||||||
fflush(stdout);
|
|
||||||
|
|
||||||
res = test(testno, i1, i2);
|
|
||||||
vmres = VM_Call(vm, testno, i1, i2);
|
|
||||||
|
|
||||||
if(vmres == res)
|
|
||||||
{
|
|
||||||
printf("ok: %d == %d\n", res, vmres);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
printf("failed: %d != %d\n", res, vmres);
|
|
||||||
ret = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(i1 != i2)
|
|
||||||
{
|
|
||||||
i2 = i1;
|
|
||||||
goto testintops;
|
|
||||||
}
|
|
||||||
|
|
||||||
testfops:
|
|
||||||
i1 = *(int*)&f1;
|
|
||||||
i2 = *(int*)&f2;
|
|
||||||
|
|
||||||
for (testno = 100; testno < 100+numftests; ++testno)
|
|
||||||
{
|
|
||||||
printf("float test %d ... ", testno);
|
|
||||||
fflush(stdout);
|
|
||||||
|
|
||||||
res = test(testno, i1, i2);
|
|
||||||
vmres = VM_Call(vm, testno, i1, i2);
|
|
||||||
|
|
||||||
fres = *(float*)&res;
|
|
||||||
fvmres = *(float*)&vmres;
|
|
||||||
|
|
||||||
if(fvmres == fres)
|
|
||||||
{
|
|
||||||
printf("ok: %f == %f\n", fres, fvmres);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
printf("failed: %f != %f\n", fres, fvmres);
|
|
||||||
ret = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(f1 > f2)
|
|
||||||
{
|
|
||||||
float t = f1;
|
|
||||||
f1 = f2;
|
|
||||||
f2 = t;
|
|
||||||
goto testfops;
|
|
||||||
}
|
|
||||||
else if(f1 < f2)
|
|
||||||
{
|
|
||||||
f2 = f1;
|
|
||||||
goto testfops;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void VM_VmInfo_f( void );
|
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
|
||||||
{
|
|
||||||
vm_t* vm[3];
|
|
||||||
int i;
|
|
||||||
long args[11] = {0};
|
|
||||||
int ret = 0xDEADBEEF;
|
|
||||||
|
|
||||||
char* file = argv[1];
|
|
||||||
|
|
||||||
char module[128];
|
|
||||||
|
|
||||||
if(argc < 2)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
strcpy(module, file);
|
|
||||||
*strchr(module, '.') = '\0';
|
|
||||||
|
|
||||||
vm[0] = VM_Create( module, printsyscall, interpret );
|
|
||||||
|
|
||||||
VM_VmInfo_f();
|
|
||||||
|
|
||||||
if(argc > 2)
|
|
||||||
{
|
|
||||||
for(i = 2; i < argc; ++i)
|
|
||||||
{
|
|
||||||
args[i-2] = strtol(argv[i],NULL,0);
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = VM_Call(vm[0], args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ret = testops(vm[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef DEBUG_VM
|
|
||||||
printf("ret: %d [%X]\n", ret, ret);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
Loading…
Reference in a new issue