/*
....[@@@..[@@@..............[@.................. MUD++ is a written from
....[@..[@..[@..[@..[@..[@@@@@....[@......[@.... scratch multi-user swords and
....[@..[@..[@..[@..[@..[@..[@..[@@@@@..[@@@@@.. sorcery game written in C++.
....[@......[@..[@..[@..[@..[@....[@......[@.... This server is an ongoing
....[@......[@..[@@@@@..[@@@@@.................. development project. All
................................................ contributions are welcome.
....Copyright(C).1995.Melvin.Smith.............. Enjoy.
------------------------------------------------------------------------------
Melvin Smith (aka Fusion) msmith@hom.net
MUD++ development mailing list mudpp@van.ml.org
------------------------------------------------------------------------------
asmloader.cpp
*/
#include "config.h"
#include "array.h"
#include "memoryblock.h"
#include "asmloader.h"
#include "vmachine.h"
#include "vmopcodes.h"
Array <vmstack> vmconstant_table(200,100);
Array <vmfun> vmfun_table(50,20);
Array <vmstack> vmstatvar_table( 50, 20 );
Array <String> vmstatvar_nametable( 50, 20 );
bool vmachine_enabled = false;
bool allow_redefinition_of_funs = false;
int lookup_vmfun_number( const char * name )
{
u16 i, size;
size = vmfun_table.length();
for ( i=1; i < size; i++ )
{
if ( vmfun_table[i].name == name )
return i;
}
return -1;
}
int deflookup_vmfun_number( const char * name )
{
u16 i, size;
size = vmfun_table.length();
for ( i=1; i < size; i++ )
{
if ( vmfun_table[i].name == name )
return i;
}
vmfun vmf;
vmf.low_border = NULL;
vmf.high_border = NULL;
vmf.name = name;
vmfun_table.add(vmf);
return i;
}
void add_vmfun( const char * name, memorycell * low_border, memorycell * high_border )
{
u16 i, size;
size = vmfun_table.length();
for ( i=1; i < size; i++ )
{
if ( vmfun_table[i].name == name )
{
if ( vmfun_table[i].low_border != NULL )
{
if ( !allow_redefinition_of_funs )
{
Cout << "AsmLinker - redefinition of function " << name <<endl;
mudpp_exit(1);
}
delete [] vmfun_table[i].low_border;
}
// Cout << "Resolved function " << name << " at " << (int) vmfun_table[i].low_border <<endl;
vmfun_table[i].low_border = low_border;
vmfun_table[i].high_border = high_border;
return;
}
}
vmfun vmf;
vmf.low_border = low_border;
vmf.high_border = high_border;
vmf.name = name;
vmfun_table.add(vmf);
// Cout << "Added function " << name << " at " << (int) vmfun_table[i].low_border <<endl;
return;
}
u16 lookup_static_number( const char * name )
{
u16 i,size;
vmstack vmsv;
size = vmstatvar_nametable.length();
for ( i=0; i < size; i++ )
{
if ( vmstatvar_nametable[i] == name )
return i;
}
vmsv.type = VMT_NULL;
vmsv.val.i = 0;
vmstatvar_table.add(vmsv);
vmstatvar_nametable.add(String (name));
return i;
}
bool link_vmachine()
{
AsmObjFile * image;
InputFile * inf;
int i;
char name[128];
vmfun vmf;
vmf.name = "FAKE_FUN";
vmf.low_border = 0;
vmf.high_border = 0;
vmf.error = vmf.name;
vmfun_table.add(vmf);
for ( i=0; ; i++ )
{
sprintf( name, "../mudC/image/image.%d.mo", i);
inf = new InputFile(name);
if ( !(*inf) )
{
delete inf;
break;
}
image = new AsmObjFile();
image->readFrom( *inf );
delete inf;
if ( !add_asmobject( *image ) )
{
delete image;
return false;
}
delete image;
}
return true;
}
enum funFound
{
NOT_NEEDED = 0,
MUDASM, INTERFACE
};
bool add_asmobject( AsmObjFile & aof )
{
int i,size;
int j, mapsize;
int itmp,cnumber;
char * buf;
asmobjconst oconst;
vmstack vmconst;
vmfilefun vmff;
memorycell * memptr;
vmfunmap vfm;
Array< vmfunmap > funmap( 10, 10);
// it has size of const_count not reloc_count, as we map in-file
// constants to in memory ones + funs + interfaces
size = aof.constants_def.length();
int * reloc_table = new int[size];
funFound * reloc_funfound_table = new funFound[size];
for ( i=0; i < size; i++)
reloc_funfound_table[i] = NOT_NEEDED;
/* for (i =0; i < size; i++)
{
Cout << "Constant offset " << aof.constants_def[i].offset<<
" starting with " << (int) aof.constants[constants_def[i].offset]; << endl;
}
*/
for ( i=0; i < size; i++ )
{
oconst = aof.constants_def[i];
switch ( oconst.type )
{
case VMT_CONST_STRING:
vmconst.type = VMT_STRING;
vmconst.val.s = new String(&(aof.constants[oconst.offset]));
vmconstant_table.add(vmconst);
reloc_table[i] = vmconstant_table.length()-1;
// Cout << "Added string " << *vmconst.val.s <<" at vmc_table " << reloc_table[i] <<endl;
break;
case VMT_IMPORT_FUN:
reloc_table[i] = deflookup_vmfun_number( &aof.constants[oconst.offset] );
// Cout << "Added import fun at vmf_table " <<reloc_table[i] <<endl;
break;
case VMT_EXPORT_FUN:
vmff = *((vmfilefun*)aof.constants.getStruct(oconst.offset));
// if we don't get name constant first - crash :(
memptr = new memorycell[vmff.end - vmff.start];
memcpy( memptr, &aof[vmff.start], (vmff.end - vmff.start) * sizeof(memorycell) );
// Cout << "Index name of fun " << vmff.name << " and relocated " << reloc_table[vmff.name] <<endl;
add_vmfun( vmconstant_table[reloc_table[vmff.name]].val.s->chars(),
memptr, memptr + (vmff.end - vmff.start));
vfm.low_offset = vmff.start;
vfm.high_offset = vmff.end;
vfm.fun_ptr = memptr;
funmap.add(vfm);
reloc_table[i] = -1;
// Cout << "Added fun." <<endl;
break;
case VMT_IMPORT_INTERFACE:
if ( (reloc_table[i] = lookup_interface_number( &aof.constants[oconst.offset] )) == 0 )
{
Cout << "AsmLoader:: Unknown interface call "<< endl;
mudpp_exit(1);
}
// Cout << "Added interface fun " << " at vmi_table " << reloc_table[i] <<endl;
break;
case VMT_IMPORT_STATIC:
reloc_table[i] = lookup_static_number( &aof.constants[oconst.offset] );
break;
case VMT_FIELD_DATA:
buf = &aof.constants[oconst.offset];
itmp = vmtype_lookup( buf );
if ( itmp < 0 )
{
Cout << "AsmLoader::field data unknown class";
mudpp_exit(1);
}
j = fieldname_lookup( (vmtype) itmp, buf + strlen(buf) +1);
/* Cout << "Fieldname lookup of " << buf+strlen(buf) +1 <<
" at constant nr " << i <<
" resulted in " << j << endl;*/
if ( j < 0 )
{
Cout << "AsmLoader::field data unknown field";
mudpp_exit(1);
}
reloc_table[i] = j;
break;
case VMT_CLASS_TYPE:
buf = &aof.constants[oconst.offset];
itmp = vmtype_lookup( buf );
if ( itmp < 0 )
{
Cout << "AsmLoader::class type - unknown class";
mudpp_exit(1);
}
reloc_table[i] = itmp;
break;
case VMT_IMPORT_FUN_OR_INTERFACE:
if ( (reloc_table[i] = lookup_interface_number( &aof.constants[oconst.offset] )) == 0 )
{
reloc_table[i] = deflookup_vmfun_number( &aof.constants[oconst.offset] );
reloc_funfound_table[i] = MUDASM;
}
else
{
reloc_funfound_table[i] = INTERFACE;
}
break;
default:
reloc_table[i] = -1;
Cout << "AsmLoader::Unknown type of constant"<<endl;
mudpp_exit(1);
break;
}
}
size = aof.relocation_table.length();
mapsize = funmap.length();
for (i = 0; i < size; i++ )
{
memptr =NULL;
itmp = aof.relocation_table[i];
for ( j=0; j < mapsize; j++ )
{
if ( (funmap[j].low_offset <= itmp) &&
(funmap[j].high_offset >= itmp ) )
{
memptr = funmap[j].fun_ptr + (itmp - funmap[j].low_offset);
break;
}
}
if ( memptr == NULL )
{
Cout << "Relocation for cell not belonging to any function" <<endl;
mudpp_exit(1);
}
cnumber = memptr->s.u.number;
memptr->s.u.number = reloc_table[cnumber];
if ( reloc_funfound_table[cnumber] != NOT_NEEDED )
{
switch( reloc_funfound_table[cnumber] )
{
case MUDASM:
memptr->s.opcode = VMOPC_FCALL;
break;
case INTERFACE:
memptr->s.opcode = VMOPC_ICALL;
break;
default:
abort();
}
}
// Cout << "Relocating call " << cnumber<< " to use " << reloc_table[cnumber] <<endl;
}
delete [] reloc_table;
createVMs();
vmachine_enabled = true;
return true;
}