q3asm.c
来自「quake3工具源码。包括生成bsp文件」· C语言 代码 · 共 1,017 行 · 第 1/2 页
C
1,017 行
#include "cmdlib.h"
#include "mathlib.h"
#include "qfiles.h"
char outputFilename[MAX_OS_PATH];
// the zero page size is just used for detecting run time faults
#define ZERO_PAGE_SIZE 0 // 256
typedef enum {
OP_UNDEF,
OP_IGNORE,
OP_BREAK,
OP_ENTER,
OP_LEAVE,
OP_CALL,
OP_PUSH,
OP_POP,
OP_CONST,
OP_LOCAL,
OP_JUMP,
//-------------------
OP_EQ,
OP_NE,
OP_LTI,
OP_LEI,
OP_GTI,
OP_GEI,
OP_LTU,
OP_LEU,
OP_GTU,
OP_GEU,
OP_EQF,
OP_NEF,
OP_LTF,
OP_LEF,
OP_GTF,
OP_GEF,
//-------------------
OP_LOAD1,
OP_LOAD2,
OP_LOAD4,
OP_STORE1,
OP_STORE2,
OP_STORE4, // *(stack[top-1]) = stack[yop
OP_ARG,
OP_BLOCK_COPY,
//-------------------
OP_SEX8,
OP_SEX16,
OP_NEGI,
OP_ADD,
OP_SUB,
OP_DIVI,
OP_DIVU,
OP_MODI,
OP_MODU,
OP_MULI,
OP_MULU,
OP_BAND,
OP_BOR,
OP_BXOR,
OP_BCOM,
OP_LSH,
OP_RSHI,
OP_RSHU,
OP_NEGF,
OP_ADDF,
OP_SUBF,
OP_DIVF,
OP_MULF,
OP_CVIF,
OP_CVFI
} opcode_t;
typedef struct {
int imageBytes; // after decompression
int entryPoint;
int stackBase;
int stackSize;
} executableHeader_t;
typedef enum {
CODESEG,
DATASEG, // initialized 32 bit data, will be byte swapped
LITSEG, // strings
BSSSEG, // 0 filled
NUM_SEGMENTS
} segmentName_t;
#define MAX_IMAGE 0x400000
typedef struct {
byte image[MAX_IMAGE];
int imageUsed;
int segmentBase; // only valid on second pass
} segment_t;
typedef struct symbol_s {
struct symbol_s *next;
int hash;
segment_t *segment;
char *name;
int value;
} symbol_t;
segment_t segment[NUM_SEGMENTS];
segment_t *currentSegment;
int passNumber;
int numSymbols;
int errorCount;
symbol_t *symbols;
symbol_t *lastSymbol;
#define MAX_ASM_FILES 256
int numAsmFiles;
char *asmFiles[MAX_ASM_FILES];
char *asmFileNames[MAX_ASM_FILES];
int currentFileIndex;
char *currentFileName;
int currentFileLine;
//int stackSize = 16384;
int stackSize = 0x10000;
// we need to convert arg and ret instructions to
// stores to the local stack frame, so we need to track the
// characteristics of the current functions stack frame
int currentLocals; // bytes of locals needed by this function
int currentArgs; // bytes of largest argument list called from this function
int currentArgOffset; // byte offset in currentArgs to store next arg, reset each call
#define MAX_LINE_LENGTH 1024
char lineBuffer[MAX_LINE_LENGTH];
int lineParseOffset;
char token[MAX_LINE_LENGTH];
int instructionCount;
typedef struct {
char *name;
int opcode;
} sourceOps_t;
sourceOps_t sourceOps[] = {
#include "opstrings.h"
};
#define NUM_SOURCE_OPS ( sizeof( sourceOps ) / sizeof( sourceOps[0] ) )
int opcodesHash[ NUM_SOURCE_OPS ];
/*
=============
HashString
=============
*/
int HashString( char *s ) {
int v;
while ( *s ) {
v += *s;
s++;
}
return v;
}
/*
============
CodeError
============
*/
void CodeError( char *fmt, ... ) {
va_list argptr;
errorCount++;
printf( "%s:%i ", currentFileName, currentFileLine );
va_start( argptr,fmt );
vprintf( fmt,argptr );
va_end( argptr );
}
/*
============
EmitByte
============
*/
void EmitByte( segment_t *seg, int v ) {
if ( seg->imageUsed >= MAX_IMAGE ) {
Error( "MAX_IMAGE" );
}
seg->image[ seg->imageUsed ] = v;
seg->imageUsed++;
}
/*
============
EmitInt
============
*/
void EmitInt( segment_t *seg, int v ) {
if ( seg->imageUsed >= MAX_IMAGE - 4) {
Error( "MAX_IMAGE" );
}
seg->image[ seg->imageUsed ] = v & 255;
seg->image[ seg->imageUsed + 1 ] = ( v >> 8 ) & 255;
seg->image[ seg->imageUsed + 2 ] = ( v >> 16 ) & 255;
seg->image[ seg->imageUsed + 3 ] = ( v >> 24 ) & 255;
seg->imageUsed += 4;
}
/*
============
DefineSymbol
Symbols can only be defined on pass 0
============
*/
void DefineSymbol( char *sym, int value ) {
symbol_t *s, *after;
char expanded[MAX_LINE_LENGTH];
int hash;
if ( passNumber == 1 ) {
return;
}
// add the file prefix to local symbols to guarantee unique
if ( sym[0] == '$' ) {
sprintf( expanded, "%s_%i", sym, currentFileIndex );
sym = expanded;
}
hash = HashString( sym );
for ( s = symbols ; s ; s = s->next ) {
if ( hash == s->hash && !strcmp( sym, s->name ) ) {
CodeError( "Multiple definitions for %s\n", sym );
return;
}
}
s = malloc( sizeof( *s ) );
s->name = copystring( sym );
s->hash = hash;
s->value = value;
s->segment = currentSegment;
lastSymbol = s; /* for the move-to-lit-segment byteswap hack */
// insert it in order
if ( !symbols || s->value < symbols->value ) {
s->next = symbols;
symbols = s;
return;
}
for ( after = symbols ; after->next && after->next->value < value ; after = after->next ) {
}
s->next = after->next;
after->next = s;
}
/*
============
LookupSymbol
Symbols can only be evaluated on pass 1
============
*/
int LookupSymbol( char *sym ) {
symbol_t *s;
char expanded[MAX_LINE_LENGTH];
int hash;
if ( passNumber == 0 ) {
return 0;
}
// add the file prefix to local symbols to guarantee unique
if ( sym[0] == '$' ) {
sprintf( expanded, "%s_%i", sym, currentFileIndex );
sym = expanded;
}
hash = HashString( sym );
for ( s = symbols ; s ; s = s->next ) {
if ( hash == s->hash && !strcmp( sym, s->name ) ) {
return s->segment->segmentBase + s->value;
}
}
CodeError( "ERROR: symbol %s undefined\n", sym );
passNumber = 0;
DefineSymbol( sym, 0 ); // so more errors aren't printed
passNumber = 1;
return 0;
}
/*
==============
ExtractLine
Extracts the next line from the given text block.
If a full line isn't parsed, returns NULL
Otherwise returns the updated parse pointer
===============
*/
char *ExtractLine( char *data ) {
int i;
currentFileLine++;
lineParseOffset = 0;
token[0] = 0;
if ( data[0] == 0 ) {
lineBuffer[0] = 0;
return NULL;
}
for ( i = 0 ; i < MAX_LINE_LENGTH ; i++ ) {
if ( data[i] == 0 || data[i] == '\n' ) {
break;
}
}
if ( i == MAX_LINE_LENGTH ) {
CodeError( "MAX_LINE_LENGTH" );
return data;
}
memcpy( lineBuffer, data, i );
lineBuffer[i] = 0;
data += i;
if ( data[0] == '\n' ) {
data++;
}
return data;
}
/*
==============
Parse
Parse a token out of linebuffer
==============
*/
qboolean Parse( void ) {
int c;
int len;
len = 0;
token[0] = 0;
// skip whitespace
while ( lineBuffer[ lineParseOffset ] <= ' ' ) {
if ( lineBuffer[ lineParseOffset ] == 0 ) {
return qfalse;
}
lineParseOffset++;
}
// skip ; comments
c = lineBuffer[ lineParseOffset ];
if ( c == ';' ) {
return qfalse;
}
// parse a regular word
do {
token[len] = c;
len++;
lineParseOffset++;
c = lineBuffer[ lineParseOffset ];
} while (c>32);
token[len] = 0;
return qtrue;
}
/*
==============
ParseValue
==============
*/
int ParseValue( void ) {
Parse();
return atoi( token );
}
/*
==============
ParseExpression
==============
*/
int ParseExpression(void) {
int i, j;
char sym[MAX_LINE_LENGTH];
int v;
if ( token[0] == '-' ) {
i = 1;
} else {
i = 0;
}
for ( ; i < MAX_LINE_LENGTH ; i++ ) {
if ( token[i] == '+' || token[i] == '-' || token[i] == 0 ) {
break;
}
}
memcpy( sym, token, i );
sym[i] = 0;
if ( ( sym[0] >= '0' && sym[0] <= '9' ) || sym[0] == '-' ) {
v = atoi( sym );
} else {
v = LookupSymbol( sym );
}
// parse add / subtract offsets
while ( token[i] != 0 ) {
for ( j = i + 1 ; j < MAX_LINE_LENGTH ; j++ ) {
if ( token[j] == '+' || token[j] == '-' || token[j] == 0 ) {
break;
}
}
memcpy( sym, token+i+1, j-i-1 );
sym[j-i-1] = 0;
if ( token[i] == '+' ) {
v += atoi( sym );
}
if ( token[i] == '-' ) {
v -= atoi( sym );
}
i = j;
}
return v;
}
/*
==============
HackToSegment
BIG HACK: I want to put all 32 bit values in the data
segment so they can be byte swapped, and all char data in the lit
segment, but switch jump tables are emited in the lit segment and
initialized strng variables are put in the data segment.
I can change segments here, but I also need to fixup the
label that was just defined
Note that the lit segment is read-write in the VM, so strings
aren't read only as in some architectures.
==============
*/
void HackToSegment( segmentName_t seg ) {
if ( currentSegment == &segment[seg] ) {
return;
}
currentSegment = &segment[seg];
if ( passNumber == 0 ) {
lastSymbol->segment = currentSegment;
lastSymbol->value = currentSegment->imageUsed;
}
}
/*
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?