mirror of
https://github.com/UberGames/lilium-voyager.git
synced 2024-12-13 13:40:56 +00:00
* (Non-trivial) fix to the "opStack corrupted in compiled code" bug
This commit is contained in:
parent
8295a83897
commit
35cb35ff61
5 changed files with 93 additions and 20 deletions
|
@ -44,6 +44,7 @@ QVM files
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define VM_MAGIC 0x12721444
|
#define VM_MAGIC 0x12721444
|
||||||
|
#define VM_MAGIC_VER2 0x12721445
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int vmMagic;
|
int vmMagic;
|
||||||
|
|
||||||
|
@ -56,6 +57,9 @@ typedef struct {
|
||||||
int dataLength;
|
int dataLength;
|
||||||
int litLength; // ( dataLength - litLength ) should be byteswapped on load
|
int litLength; // ( dataLength - litLength ) should be byteswapped on load
|
||||||
int bssLength; // zero filled memory appended to datalength
|
int bssLength; // zero filled memory appended to datalength
|
||||||
|
|
||||||
|
//!!! below here is VM_MAGIC_VER2 !!!
|
||||||
|
int jtrgLength; // number of jump table targets
|
||||||
} vmHeader_t;
|
} vmHeader_t;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -381,7 +381,7 @@ vm_t *VM_Restart( vm_t *vm ) {
|
||||||
// load the image
|
// load the image
|
||||||
Com_Printf( "VM_Restart()\n", filename );
|
Com_Printf( "VM_Restart()\n", filename );
|
||||||
Com_sprintf( filename, sizeof(filename), "vm/%s.qvm", vm->name );
|
Com_sprintf( filename, sizeof(filename), "vm/%s.qvm", vm->name );
|
||||||
Com_Printf( "Loading vm file %s.\n", filename );
|
Com_Printf( "Loading vm file %s...\n", filename );
|
||||||
length = FS_ReadFile( filename, (void **)&header );
|
length = FS_ReadFile( filename, (void **)&header );
|
||||||
if ( !header ) {
|
if ( !header ) {
|
||||||
Com_Error( ERR_DROP, "VM_Restart failed.\n" );
|
Com_Error( ERR_DROP, "VM_Restart failed.\n" );
|
||||||
|
@ -392,6 +392,19 @@ vm_t *VM_Restart( vm_t *vm ) {
|
||||||
((int *)header)[i] = LittleLong( ((int *)header)[i] );
|
((int *)header)[i] = LittleLong( ((int *)header)[i] );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( header->vmMagic == VM_MAGIC_VER2 ) {
|
||||||
|
Com_Printf( "...which has vmMagic VM_MAGIC_VER2\n" );
|
||||||
|
// validate
|
||||||
|
if ( header->vmMagic != VM_MAGIC_VER2
|
||||||
|
|| header->jtrgLength < 0
|
||||||
|
|| header->bssLength < 0
|
||||||
|
|| header->dataLength < 0
|
||||||
|
|| header->litLength < 0
|
||||||
|
|| header->codeLength <= 0 ) {
|
||||||
|
VM_Free( vm );
|
||||||
|
Com_Error( ERR_FATAL, "%s has bad header", filename );
|
||||||
|
}
|
||||||
|
} else {
|
||||||
// validate
|
// validate
|
||||||
if ( header->vmMagic != VM_MAGIC
|
if ( header->vmMagic != VM_MAGIC
|
||||||
|| header->bssLength < 0
|
|| header->bssLength < 0
|
||||||
|
@ -401,6 +414,7 @@ vm_t *VM_Restart( vm_t *vm ) {
|
||||||
VM_Free( vm );
|
VM_Free( vm );
|
||||||
Com_Error( ERR_FATAL, "%s has bad header", filename );
|
Com_Error( ERR_FATAL, "%s has bad header", filename );
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// round up to next power of 2 so all data operations can
|
// round up to next power of 2 so all data operations can
|
||||||
// be mask protected
|
// be mask protected
|
||||||
|
@ -420,6 +434,19 @@ vm_t *VM_Restart( vm_t *vm ) {
|
||||||
*(int *)(vm->dataBase + i) = LittleLong( *(int *)(vm->dataBase + i ) );
|
*(int *)(vm->dataBase + i) = LittleLong( *(int *)(vm->dataBase + i ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( header->vmMagic == VM_MAGIC_VER2 ) {
|
||||||
|
vm->numJumpTableTargets = header->jtrgLength >> 2;
|
||||||
|
Com_Printf( "Loading %d jump table targets\n", vm->numJumpTableTargets );
|
||||||
|
Com_Memset( vm->jumpTableTargets, 0, header->jtrgLength );
|
||||||
|
Com_Memcpy( vm->jumpTableTargets, (byte *)header + header->dataOffset +
|
||||||
|
header->dataLength + header->litLength, header->jtrgLength );
|
||||||
|
|
||||||
|
// byte swap the longs
|
||||||
|
for ( i = 0 ; i < header->jtrgLength ; i += 4 ) {
|
||||||
|
*(int *)(vm->jumpTableTargets + i) = LittleLong( *(int *)(vm->jumpTableTargets + i ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// free the original file
|
// free the original file
|
||||||
FS_FreeFile( header );
|
FS_FreeFile( header );
|
||||||
|
|
||||||
|
@ -504,7 +531,7 @@ vm_t *VM_Create( const char *module, long (*systemCalls)(long *),
|
||||||
|
|
||||||
// load the image
|
// load the image
|
||||||
Com_sprintf( filename, sizeof(filename), "vm/%s.qvm", vm->name );
|
Com_sprintf( filename, sizeof(filename), "vm/%s.qvm", vm->name );
|
||||||
Com_Printf( "Loading vm file %s.\n", filename );
|
Com_Printf( "Loading vm file %s...\n", filename );
|
||||||
length = FS_ReadFile( filename, (void **)&header );
|
length = FS_ReadFile( filename, (void **)&header );
|
||||||
if ( !header ) {
|
if ( !header ) {
|
||||||
Com_Printf( "Failed.\n" );
|
Com_Printf( "Failed.\n" );
|
||||||
|
@ -517,6 +544,19 @@ vm_t *VM_Create( const char *module, long (*systemCalls)(long *),
|
||||||
((int *)header)[i] = LittleLong( ((int *)header)[i] );
|
((int *)header)[i] = LittleLong( ((int *)header)[i] );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( header->vmMagic == VM_MAGIC_VER2 ) {
|
||||||
|
Com_Printf( "...which has vmMagic VM_MAGIC_VER2\n" );
|
||||||
|
// validate
|
||||||
|
if ( header->vmMagic != VM_MAGIC_VER2
|
||||||
|
|| header->jtrgLength < 0
|
||||||
|
|| header->bssLength < 0
|
||||||
|
|| header->dataLength < 0
|
||||||
|
|| header->litLength < 0
|
||||||
|
|| header->codeLength <= 0 ) {
|
||||||
|
VM_Free( vm );
|
||||||
|
Com_Error( ERR_FATAL, "%s has bad header", filename );
|
||||||
|
}
|
||||||
|
} else {
|
||||||
// validate
|
// validate
|
||||||
if ( header->vmMagic != VM_MAGIC
|
if ( header->vmMagic != VM_MAGIC
|
||||||
|| header->bssLength < 0
|
|| header->bssLength < 0
|
||||||
|
@ -526,6 +566,7 @@ vm_t *VM_Create( const char *module, long (*systemCalls)(long *),
|
||||||
VM_Free( vm );
|
VM_Free( vm );
|
||||||
Com_Error( ERR_FATAL, "%s has bad header", filename );
|
Com_Error( ERR_FATAL, "%s has bad header", filename );
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// round up to next power of 2 so all data operations can
|
// round up to next power of 2 so all data operations can
|
||||||
// be mask protected
|
// be mask protected
|
||||||
|
@ -546,6 +587,19 @@ vm_t *VM_Create( const char *module, long (*systemCalls)(long *),
|
||||||
*(int *)(vm->dataBase + i) = LittleLong( *(int *)(vm->dataBase + i ) );
|
*(int *)(vm->dataBase + i) = LittleLong( *(int *)(vm->dataBase + i ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( header->vmMagic == VM_MAGIC_VER2 ) {
|
||||||
|
vm->numJumpTableTargets = header->jtrgLength >> 2;
|
||||||
|
Com_Printf( "Loading %d jump table targets\n", vm->numJumpTableTargets );
|
||||||
|
vm->jumpTableTargets = Hunk_Alloc( header->jtrgLength, h_high );
|
||||||
|
Com_Memcpy( vm->jumpTableTargets, (byte *)header + header->dataOffset +
|
||||||
|
header->dataLength + header->litLength, header->jtrgLength );
|
||||||
|
|
||||||
|
// byte swap the longs
|
||||||
|
for ( i = 0 ; i < header->jtrgLength ; i += 4 ) {
|
||||||
|
*(int *)(vm->jumpTableTargets + i) = LittleLong( *(int *)(vm->jumpTableTargets + i ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// allocate space for the jump targets, which will be filled in by the compile/prep functions
|
// allocate space for the jump targets, which will be filled in by the compile/prep functions
|
||||||
vm->instructionPointersLength = header->instructionCount * 4;
|
vm->instructionPointersLength = header->instructionCount * 4;
|
||||||
vm->instructionPointers = Hunk_Alloc( vm->instructionPointersLength, h_high );
|
vm->instructionPointers = Hunk_Alloc( vm->instructionPointersLength, h_high );
|
||||||
|
|
|
@ -161,6 +161,9 @@ struct vm_s {
|
||||||
|
|
||||||
// fqpath member added 7/20/02 by T.Ray
|
// fqpath member added 7/20/02 by T.Ray
|
||||||
char fqpath[MAX_QPATH+1] ;
|
char fqpath[MAX_QPATH+1] ;
|
||||||
|
|
||||||
|
byte *jumpTableTargets;
|
||||||
|
int numJumpTableTargets;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -419,6 +419,12 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) {
|
||||||
|
|
||||||
Com_Memset(jused, 0, header->instructionCount+2);
|
Com_Memset(jused, 0, header->instructionCount+2);
|
||||||
|
|
||||||
|
// ensure that the optimisation pass knows about all the jump
|
||||||
|
// table targets
|
||||||
|
for( i = 0; i < vm->numJumpTableTargets; i++ ) {
|
||||||
|
jused[ *(int *)(vm->jumpTableTargets + ( i * sizeof( int ) ) ) ] = 1;
|
||||||
|
}
|
||||||
|
|
||||||
for(pass=0;pass<2;pass++) {
|
for(pass=0;pass<2;pass++) {
|
||||||
oc0 = -23423;
|
oc0 = -23423;
|
||||||
oc1 = -234354;
|
oc1 = -234354;
|
||||||
|
|
|
@ -135,6 +135,7 @@ typedef enum {
|
||||||
DATASEG, // initialized 32 bit data, will be byte swapped
|
DATASEG, // initialized 32 bit data, will be byte swapped
|
||||||
LITSEG, // strings
|
LITSEG, // strings
|
||||||
BSSSEG, // 0 filled
|
BSSSEG, // 0 filled
|
||||||
|
JTRGSEG, // psuedo-segment that contains only jump table targets
|
||||||
NUM_SEGMENTS
|
NUM_SEGMENTS
|
||||||
} segmentName_t;
|
} segmentName_t;
|
||||||
|
|
||||||
|
@ -989,6 +990,8 @@ STAT("ADDRESS");
|
||||||
/* Addresses are 32 bits wide, and therefore go into data segment. */
|
/* Addresses are 32 bits wide, and therefore go into data segment. */
|
||||||
HackToSegment( DATASEG );
|
HackToSegment( DATASEG );
|
||||||
EmitInt( currentSegment, v );
|
EmitInt( currentSegment, v );
|
||||||
|
if( passNumber == 1 && token[ 0 ] == '$' ) // crude test for labels
|
||||||
|
EmitInt( &segment[ JTRGSEG ], v );
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1375,7 +1378,7 @@ void WriteVmFile( void ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
header.vmMagic = VM_MAGIC;
|
header.vmMagic = VM_MAGIC_VER2;
|
||||||
header.instructionCount = instructionCount;
|
header.instructionCount = instructionCount;
|
||||||
header.codeOffset = sizeof( header );
|
header.codeOffset = sizeof( header );
|
||||||
header.codeLength = segment[CODESEG].imageUsed;
|
header.codeLength = segment[CODESEG].imageUsed;
|
||||||
|
@ -1383,6 +1386,7 @@ void WriteVmFile( void ) {
|
||||||
header.dataLength = segment[DATASEG].imageUsed;
|
header.dataLength = segment[DATASEG].imageUsed;
|
||||||
header.litLength = segment[LITSEG].imageUsed;
|
header.litLength = segment[LITSEG].imageUsed;
|
||||||
header.bssLength = segment[BSSSEG].imageUsed;
|
header.bssLength = segment[BSSSEG].imageUsed;
|
||||||
|
header.jtrgLength = segment[JTRGSEG].imageUsed;
|
||||||
|
|
||||||
report( "Writing to %s\n", imageName );
|
report( "Writing to %s\n", imageName );
|
||||||
|
|
||||||
|
@ -1392,6 +1396,7 @@ void WriteVmFile( void ) {
|
||||||
SafeWrite( f, &segment[CODESEG].image, segment[CODESEG].imageUsed );
|
SafeWrite( f, &segment[CODESEG].image, segment[CODESEG].imageUsed );
|
||||||
SafeWrite( f, &segment[DATASEG].image, segment[DATASEG].imageUsed );
|
SafeWrite( f, &segment[DATASEG].image, segment[DATASEG].imageUsed );
|
||||||
SafeWrite( f, &segment[LITSEG].image, segment[LITSEG].imageUsed );
|
SafeWrite( f, &segment[LITSEG].image, segment[LITSEG].imageUsed );
|
||||||
|
SafeWrite( f, &segment[JTRGSEG].image, segment[JTRGSEG].imageUsed );
|
||||||
fclose( f );
|
fclose( f );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1417,6 +1422,7 @@ void Assemble( void ) {
|
||||||
for ( passNumber = 0 ; passNumber < 2 ; passNumber++ ) {
|
for ( passNumber = 0 ; passNumber < 2 ; passNumber++ ) {
|
||||||
segment[LITSEG].segmentBase = segment[DATASEG].imageUsed;
|
segment[LITSEG].segmentBase = segment[DATASEG].imageUsed;
|
||||||
segment[BSSSEG].segmentBase = segment[LITSEG].segmentBase + segment[LITSEG].imageUsed;
|
segment[BSSSEG].segmentBase = segment[LITSEG].segmentBase + segment[LITSEG].imageUsed;
|
||||||
|
segment[JTRGSEG].segmentBase = segment[BSSSEG].segmentBase + segment[BSSSEG].imageUsed;
|
||||||
for ( i = 0 ; i < NUM_SEGMENTS ; i++ ) {
|
for ( i = 0 ; i < NUM_SEGMENTS ; i++ ) {
|
||||||
segment[i].imageUsed = 0;
|
segment[i].imageUsed = 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue