Added hitasm

This commit is contained in:
Fatbag 2013-01-23 15:58:58 -06:00
parent 5488883991
commit 0ec39fd968
15 changed files with 12469 additions and 368 deletions

View file

@ -16,17 +16,605 @@
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <errno.h>
#include "hitutils.h"
static uint8_t ObjectHeader[] = {
0x7F, 0x45, 0x4C, 0x46, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x40, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00,
0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
0x19, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00
};
enum {
txt, out, filecount
};
typedef struct {
uint8_t * Data;
size_t Position;
size_t Size;
char * Name;
} ByteWriterContext;
static void bw_expand(ByteWriterContext *bwc){
bwc->Data = realloc(bwc->Data, (bwc->Size <<= 1));
if(!bwc->Data)
Shutdown_M("%sCould not allocate memory for %s section.\n", "hitasm: Error: ", bwc->Name);
}
static void bw_write32(ByteWriterContext *bwc, uint32_t value){
if(bwc->Size-bwc->Position < 4)
bw_expand(bwc);
write_uint32(bwc->Data+bwc->Position, value);
bwc->Position += 4;
}
static void bw_write8(ByteWriterContext *bwc, uint8_t value){
if(bwc->Size-bwc->Position < 1)
bw_expand(bwc);
bwc->Data[bwc->Position] = value;
bwc->Position += 1;
}
static void bw_write_memory(ByteWriterContext *bwc, const uint8_t *ptr, size_t size){
while(bwc->Size-bwc->Position < size)
bw_expand(bwc);
do bwc->Data[bwc->Position++] = *ptr++;
while(--size);
}
static void bw_write_string(ByteWriterContext *bwc, const char *string){
do bw_write8(bwc, *string);
while(*string++);
}
typedef struct {
char * Token;
size_t Line, NextLine;
size_t Col, NextCol;
int GaveLastToken;
ByteReaderContext brc;
} ParserContext;
enum {
TK_CROSSLINES = 1,
CN_LABELONLY = 1
};
static FILE *hFile = NULL;
static char *path[filecount] = {NULL};
static uint8_t *data[filecount] = {NULL};
static ByteWriterContext TextSection = {0,0,1024,"text"};
static ByteWriterContext SymbolTable = {0,0,1024,"symtab"};
static ByteWriterContext StringTable = {0,0,1024,"strtab"};
static ByteWriterContext RelocationTable = {0,0,1024,".rel.text"};
static uint8_t * add_symbol(const char * Name){
bw_write32(&SymbolTable, StringTable.Position);
bw_write32(&SymbolTable, 0);
bw_write32(&SymbolTable, 0);
bw_write32(&SymbolTable, 18);
bw_write_string(&StringTable, Name);
return SymbolTable.Data + SymbolTable.Position - 16;
}
static uint8_t * find_symbol_by_name(const char * Name, uint32_t * SymbolIndex){
uint32_t p;
for(p=48; p<SymbolTable.Position; p+=16){
if(!strcmp((char*) StringTable.Data + read_uint32(SymbolTable.Data + p), Name)){
if(SymbolIndex) *SymbolIndex = p>>4;
return SymbolTable.Data + p;
}
}
if(SymbolIndex) *SymbolIndex = p>>4;
return NULL;
}
static __inline int whitespace(const uint8_t *Data){
return (Data[0] == ' ' || Data[0] == '\t' || Data[0] == '\r' || Data[0] == '\n' || Data[0] == '\0');
}
static __inline int comment(const uint8_t *Data){
return (Data[0] == ';' || (Data[0] == '#' && whitespace(Data+1)));
}
static int parser_next_token(ParserContext *pc, int CrossLines){
if(!pc->brc.Size) return 0;
if(pc->GaveLastToken){
pc->GaveLastToken = 0;
/* find the start of the next token */
while(1){
if(whitespace(pc->brc.Data)){
if(pc->brc.Data[0] == '\n'){
pc->NextLine++; pc->NextCol = 1;
}else if(pc->brc.Data[0] == '\t'){
pc->NextCol += 4 - ((pc->NextCol-1)%4);
}else{
pc->NextCol++;
}
}else if(comment(pc->brc.Data)){
/* skip to the end of the line */
pc->NextLine++; pc->NextCol = 1;
do {
if(!--pc->brc.Size) return 0;
pc->brc.Data++;
} while(pc->brc.Data[0] != '\n');
}else break;
if(!--pc->brc.Size) return 0;
pc->brc.Data++;
}
}
if(!CrossLines && pc->Line != pc->NextLine) return 0;
pc->Token = (char*)pc->brc.Data;
pc->Line = pc->NextLine;
pc->Col = pc->NextCol++;
pc->GaveLastToken = 1;
/* mark the end of this token with a null character */
while(1){
if(!--pc->brc.Size) return 1;
pc->brc.Data++;
if(whitespace(pc->brc.Data)){
if(pc->brc.Data[0] == '\n'){
pc->NextLine++; pc->NextCol = 1;
}else if(pc->brc.Data[0] == '\t'){
pc->NextCol += 4 - ((pc->NextCol-1)%4);
}else{
pc->NextCol++;
}
break;
}else if(comment(pc->brc.Data)){
/* skip to the end of the line */
pc->NextLine++; pc->NextCol = 1;
do {
if(!--pc->brc.Size) return 1;
pc->brc.Data++;
} while(pc->brc.Data[0] != '\n');
break;
}else pc->NextCol++;
}
pc->brc.Size--;
pc->brc.Data[0] = '\0';
pc->brc.Data++;
return 1;
}
static __inline void verify_eol(ParserContext *pc){
if(parser_next_token(pc, 0))
Shutdown_M("%s:%u:%u: error: expected newline before '%s'\n",
path[txt], pc->Line, pc->Col, pc->Token);
}
static void verify_name(const ParserContext *pc, const char *thistoken, const char *nexttoken){
const char *Name;
for(Name = pc->Token; *Name; Name++)
if((Name == pc->Token || *Name < '0' || *Name > '9')
&& (*Name < 'A' || *Name > 'Z') && (*Name < '_' || *Name > '_') && (*Name < 'a' || *Name > 'z'))
Shutdown_M("%s:%u:%u: error: expected %s before '%c'\n",
path[txt], pc->Line, pc->Col, (Name == pc->Token) ? thistoken : nexttoken, *Name);
}
static __inline void parser_add_symbol(const ParserContext *pc){
uint8_t * Symbol;
verify_name(pc, "label or integer constant", "newline");
/* we're using the ELF st_size field (offset 8) to hold the line number temporarily */
Symbol = find_symbol_by_name(pc->Token, NULL);
if(Symbol){
if(read_uint32(Symbol+4))
Shutdown_M("%s:%u:%u: error: label '%s' redefined (previous definition at %s:%u:1)\n",
path[txt], pc->Line, pc->Col, pc->Token, path[txt], read_uint32(Symbol+8));
}else Symbol = add_symbol(pc->Token);
write_uint32(Symbol+4, TextSection.Position);
write_uint32(Symbol+8, pc->Line);
}
static __inline void parser_add_reference(const ParserContext *pc){
uint32_t SymbolIndex;
verify_name(pc, "label", "operand or newline");
if(!find_symbol_by_name(pc->Token, &SymbolIndex))
add_symbol(pc->Token);
bw_write32(&RelocationTable, TextSection.Position);
bw_write32(&RelocationTable, (SymbolIndex<<8)|0x02);
}
static uint32_t read_integer(const ParserContext *pc, uint32_t maxval){
unsigned long value;
char * endptr;
if(pc->Token[0] == '-')
Shutdown_M("%s:%u:%u: error: integer constant '%s' may not be negative\n",
path[txt], pc->Line, pc->Col, pc->Token);
if(pc->Token[0] < '0' || pc->Token[0] > '9')
Shutdown_M("%s:%u:%u: error: expected integer constant before '%s'\n",
path[txt], pc->Line, pc->Col, pc->Token);
if(pc->Token[0] == '0' && (pc->Token[1] == 'x' || pc->Token[1] == '0' || pc->Token[1] == 'o'))
Shutdown_M("%s:%u:%u: error: illegal %s prefix '%s%c' on integer constant '%s'\n",
path[txt], pc->Line, pc->Col, pc->Token[1] == 'x' ? "hexadecimal" : "octal",
pc->Token[1] != '0' ? "0" : "", pc->Token[1], pc->Token);
value = strtoul(pc->Token, &endptr, 10);
if(*endptr == '.')
Shutdown_M("%s:%u:%u: error: illegal floating point constant '%s'\n",
path[txt], pc->Line, pc->Col, endptr, pc->Token);
if(*endptr != '\0')
Shutdown_M("%s:%u:%u: error: illegal suffix '%s' on integer constant '%s'\n",
path[txt], pc->Line, pc->Col, endptr, pc->Token);
if(value > (unsigned long) maxval || errno == ERANGE)
Shutdown_M("%s:%u:%u: error: integer constant '%s' is out of range\n",
path[txt], pc->Line, pc->Col, pc->Token);
return (uint32_t)value;
}
static uint32_t read_constant(ParserContext *pc, int Type, uint32_t maxval){
unsigned i;
if(pc->Token[0] == '#') /* note that the tokens "#" and "" will never be returned by the parser */
pc->Token++;
if((pc->Token[0] >= '0' && pc->Token[0] <= '9') || pc->Token[0] == '-' || pc->Token[0] == '.'){
if(Type == CN_LABELONLY)
Shutdown_M("%s:%u:%u: error: explicit address '%s' is forbidden\n",
path[txt], pc->Line, pc->Col, pc->Token);
return read_integer(pc, maxval);
}
verify_name(pc, "constant or label", "operand or newline");
for(i=0; i<ConstantCount; i++){
if(!strcmp(Constants[i].Name, pc->Token)){
if(Constants[i].Value > maxval)
Shutdown_M("%s:%u:%u: error: integer constant '%s' (%u) is out of range\n",
path[txt], pc->Line, pc->Col, pc->Token, Constants[i].Value);
return Constants[i].Value;
}
}
if(maxval != 0xFFFFFFFF)
Shutdown_M("%s:%u:%u: error: address referenced by label '%s' is out of range\n",
path[txt], pc->Line, pc->Col, pc->Token);
parser_add_reference(pc);
return 0;
}
static __inline uint8_t read_instruction(const ParserContext *pc, uint32_t *operands){
uint8_t i;
verify_name(pc, "instruction", "operand or newline");
for(i=0; i<InstructionCount; i++){
if(!strcmp(pc->Token, Instructions[i].Name)){
*operands = Instructions[i].Operands;
return i+1;
}
}
return 0;
}
static __inline uint8_t read_variable(const ParserContext *pc, const variable_t *Variables, size_t VariableCount){
unsigned i;
verify_name(pc, "variable", "operand or newline");
for(i=0; i<VariableCount; i++)
if(!strcmp(Variables[i].Name, pc->Token))
return Variables[i].Value;
Shutdown_M("%s:%u:%u: error: unrecognized variable '%s'\n",
path[txt], pc->Line, pc->Col, pc->Token);
return 0;
}
static void Shutdown(){
unsigned i;
for(i=0; i<filecount; i++){
free(path[i]);
free(data[i]);
}
free(TextSection.Data);
free(SymbolTable.Data);
free(StringTable.Data);
free(RelocationTable.Data);
if(hFile)
fclose(hFile);
}
int main(int argc, char *argv[]){
unsigned i;
int SimsVersion = 0;
int overwrite = 0;
size_t filesize[filecount-1] = {0};
unsigned slash;
const variable_t * Variables;
size_t VariableCount;
ParserContext pc;
int InBinary = 0;
if(argc == 1 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")){
printf("Usage: hitasm [-ts1|-tso] [-f] [-o outfile.o] infile.txt\n"
"Assemble a HIT source file to an intermediary object file\n"
"which can be linked using hitld.\n"
"\n"
"Use -f to force overwriting without confirmation.\n"
"\n"
"Report bugs to <X-Fi6@phppoll.org>.\n"
"hitutils is maintained by the Niotso project.\n"
"Home page: <http://www.niotso.org/>\n");
return 0;
}
for(i=1; i<(unsigned)argc-1; i++){
if(!strcmp(argv[i], "-ts1")) SimsVersion = VERSION_TS1;
else if(!strcmp(argv[i], "-tso")) SimsVersion = VERSION_TSO;
else if(!strcmp(argv[i], "-f")) overwrite = 1;
else if(i != (unsigned)argc-2){
if(!strcmp(argv[i], "-o")) path[out] = argv[++i];
else break;
}
else break;
}
path[txt] = argv[i];
for(i=0; i<filecount; i++)
if(path[i])
path[i] = strdup(path[i]); /* necessary for free(path[i]) in Shutdown_M */
if(!SimsVersion)
Shutdown_M("%sSims version not specified. (Use -ts1 or -tso.)\n", "hitasm: Error: ");
if(SimsVersion == VERSION_TS1){
Variables = TS1Variables;
VariableCount = TS1VariableCount;
}else{
Variables = TSOVariables;
VariableCount = TSOVariableCount;
}
if(path[out] == NULL){
int length = strlen(path[txt]);
path[out] = malloc(max(length+1, 5));
strcpy(path[out], path[txt]);
strcpy(path[out] + max(length-4, 0), ".o");
}
/****
** Read all of the requested files
*/
for(i=0; i<filecount-1; i++){
size_t bytestransferred;
if(!path[i]) continue;
hFile = fopen(path[i], "rb");
if(hFile == NULL){
if(i != txt){
fprintf(stderr, "%sCould not open file: %s.\n", "hitasm: Warning: ", path[i]);
continue;
}else
Shutdown_M("%sCould not open file: %s.\n", "hitasm: Error: ", path[i]);
}
fseek(hFile, 0, SEEK_END);
filesize[i] = ftell(hFile);
if(filesize[i] == 0 || filesize[i] == SIZE_MAX){
fclose(hFile); hFile = NULL;
if(i != txt){
fprintf(stderr, "%sFile is invalid: %s.\n", "hitasm: Warning: ", path[i]);
continue;
}else
Shutdown_M("%sFile is invalid: %s.\n", "hitasm: Error: ", path[i]);
}
data[i] = malloc(filesize[i]+1);
if(data[i] == NULL){
fclose(hFile); hFile = NULL;
if(i != txt){
fprintf(stderr, "%sCould not allocate memory for file: %s.\n", "hitasm: Warning: ", path[i]);
continue;
}else
Shutdown_M("%sCould not allocate memory for file: %s.\n", "hitasm: Error: ", path[i]);
}
fseek(hFile, 0, SEEK_SET);
bytestransferred = fread(data[i], 1, filesize[i], hFile);
fclose(hFile); hFile = NULL;
if(bytestransferred != filesize[i]){
free(data[i]); data[i] = NULL;
if(i != txt){
fprintf(stderr, "%sCould not read file: %s.\n", "hitasm: Warning: ", path[i]);
continue;
}else
Shutdown_M("%sCould not read file: %s.\n", "hitasm: Error: ", path[i]);
}
data[i][filesize[i]++] = '\0'; /* add a null character to the end of the file */
}
/****
** Open the output file for writing
*/
if(!overwrite){
hFile = fopen(path[out], "rb");
if(hFile != NULL){
/* File exists */
char c;
fclose(hFile); hFile = NULL;
fprintf(stderr, "%sFile \"%s\" exists.\nContinue anyway? (y/n) ", "hitasm: ", path[out]);
c = getchar();
if(c != 'y' && c != 'Y')
Shutdown_M("\nAborted.\n");
}
}
hFile = fopen(path[out], "wb");
if(hFile == NULL)
Shutdown_M("%sCould not open file: %s.\n", "hitasm: Error: ", path[out]);
/****
** Perform the assembly
*/
TextSection.Data = malloc(TextSection.Size);
SymbolTable.Data = malloc(SymbolTable.Size);
StringTable.Data = malloc(StringTable.Size);
RelocationTable.Data = malloc(RelocationTable.Size);
pc.NextLine = 1;
pc.NextCol = 1;
pc.GaveLastToken = 1;
pc.brc.Data = data[txt];
pc.brc.Size = filesize[txt];
bw_write_memory(&SymbolTable, SymbolTableHeader, sizeof(SymbolTableHeader));
for(i=slash=0; path[txt][i]; i++)
if(path[txt][i] == '/' || path[txt][i] == '\\') slash = i+1;
bw_write8(&StringTable, '\0');
bw_write_string(&StringTable, path[txt] + slash);
while(parser_next_token(&pc, TK_CROSSLINES)){
printf("Token: %s\n", pc.Token);
/* Unimplemented commands */
if(!strcmp(pc.Token, "BASEID_TRACKDATA") || !strcmp(pc.Token, "INCLUDE")
|| !strcmp(pc.Token, "include") || !strcmp(pc.Token, "INIFILE")
|| !strcmp(pc.Token, "LIST") || !strcmp(pc.Token, "SYMBOLFILE")){
if(InBinary)
Shutdown_M("%s:%u:%u: error: invalid use of '%s' inside BINARY section\n",
path[txt], pc.Line, pc.Col, pc.Token);
while(parser_next_token(&pc, 0)); /* skip to the end of the line */
continue;
}
if(!strcmp(pc.Token, "BINARY") && !InBinary){
InBinary++;
if(!parser_next_token(&pc, TK_CROSSLINES) || strcmp(pc.Token, "["))
Shutdown_M("%s:%u:%u: error: expected '[' for beginning of BINARY section before %s%s%s\n",
path[txt], pc.Line, pc.Col,
pc.Token ? "'" : "", pc.Token ? pc.Token : "end of file", pc.Token ? "'" : "");
}
else if(!strcmp(pc.Token, "]") && InBinary)
InBinary--;
else if(!InBinary)
Shutdown_M("%s:%u:%u: error: '%s' is not a valid command\n",
path[txt], pc.Line, pc.Col, pc.Token);
/****
** Inside a BINARY section
*/
else if(pc.Col == 1) /* no indent */
parser_add_symbol(&pc);
else{ /* indent */
uint8_t opcode;
uint32_t operands;
if((pc.Token[0] >= '0' && pc.Token[0] <= '9') || pc.Token[0] == '-' || pc.Token[0] == '.'
|| pc.Token[0] == '#' || !(opcode = read_instruction(&pc, &operands))){
/* declare bytes (db and dd pseudo-instructions) */
do {
if(pc.Token[0] != '#')
bw_write8(&TextSection, read_integer(&pc, 0x000000FF));
else
bw_write32(&TextSection, read_constant(&pc, 0, 0xFFFFFFFF));
} while(parser_next_token(&pc, 0));
continue;
}else{
const char * InstructionName = pc.Token;
printf("Instruction: %s\n", pc.Token);
bw_write8(&TextSection, opcode);
for(i=0; (operands >>= 4) != 0; i++){
int type = operands & 15;
const char *position[] = {"one","two","three","four"};
if(!parser_next_token(&pc, 0)){
int j;
for(j=i+1; (operands >>= 4) != 0; j++);
Shutdown_M("%s:%u:%u: error: instruction '%s' wants %s operands but only %s supplied\n",
path[txt], pc.Line, pc.Col, pc.Token, InstructionName, position[j], position[i]);
}
printf("Operand: %s\n", pc.Token);
if(type == o_byte)
bw_write8(&TextSection, read_constant(&pc, 0, 0x000000FF));
else if(type == o_dword)
bw_write32(&TextSection, read_constant(&pc, 0, 0xFFFFFFFF));
else if(type == o_address)
bw_write32(&TextSection, read_constant(&pc, CN_LABELONLY, 0xFFFFFFFF));
else if(type == o_variable)
bw_write8(&TextSection, read_variable(&pc, Variables, VariableCount));
else if(type == o_jump){
/* TODO: Change this */
bw_write32(&TextSection, read_constant(&pc, CN_LABELONLY, 0xFFFFFFFF));
}
}
}
}
verify_eol(&pc);
}
if(InBinary)
Shutdown_M("%s:%u:%u: error: expected ']' for end of BINARY section before end of file\n",
path[txt], pc.Line, pc.Col);
for(i=48+8; i<SymbolTable.Position; i+=16)
write_uint32(SymbolTable.Data + i, 0);
i = 304;
write_uint32(ObjectHeader + 120, i);
write_uint32(ObjectHeader + 124, TextSection.Position);
i += TextSection.Position;
write_uint32(ObjectHeader + 160, i);
write_uint32(ObjectHeader + 164, sizeof(SHStringTable));
i += sizeof(SHStringTable);
write_uint32(ObjectHeader + 200, i);
write_uint32(ObjectHeader + 204, SymbolTable.Position);
i += SymbolTable.Position;
write_uint32(ObjectHeader + 240, i);
write_uint32(ObjectHeader + 244, StringTable.Position);
i += StringTable.Position;
write_uint32(ObjectHeader + 280, i);
write_uint32(ObjectHeader + 284, RelocationTable.Position);
fwrite(ObjectHeader, 1, sizeof(ObjectHeader), hFile);
fwrite(TextSection.Data, 1, TextSection.Position, hFile);
fwrite(SHStringTable, 1, sizeof(SHStringTable), hFile);
fwrite(SymbolTable.Data, 1, SymbolTable.Position, hFile);
fwrite(StringTable.Data, 1, StringTable.Position, hFile);
fwrite(RelocationTable.Data, 1, RelocationTable.Position, hFile);
Shutdown();
int main(){
printf("Usage: hitasm [-f] [-o outfile.o] infile.txt\n"
"Compile a HIT source file to an intermediary object file\n"
"which can be linked using hitld.\n"
"\n"
"Use -f to force overwriting without confirmation.\n"
"\n"
"Report bugs to <X-Fi6@phppoll.org>.\n"
"hitutils is maintained by the Niotso project.\n"
"Home page: <http://www.niotso.org/>\n");
return 0;
}