mud++0.35/etc/
mud++0.35/etc/guilds/
mud++0.35/help/propert/
mud++0.35/mudC/
mud++0.35/player/
mud++0.35/src/interface/
mud++0.35/src/os/cygwin32/
mud++0.35/src/os/win32/
mud++0.35/src/os/win32/bcppbuilder/
mud++0.35/src/osaddon/
mud++0.35/src/util/
/*
....[@@@..[@@@..............[@.................. 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;
}