umakerom.c 7.95 KB
#include <elf.h>
#include <stdio.h>
#include <malloc.h>

#include "rom.h"

typedef struct file {
	char * name;
	struct file * next;
} FILENAME, *FILENAMEPTR;

FILENAMEPTR fileList, fileLast;

typedef struct {
	int fileNum, sectionSize;
	long inFileOffset, outFileOffset;
} SECTION, * SECTIONPTR;

SECTION sectionTable[64];	/* try statically for now */
int loadableSections;

void usage( void )
{
	fprintf( stderr,
		"usage: umakerom -b base [-o romname] -s init_sp absfile*\n" );
	exit( 1 );
}

void nospace( void )
{
	fprintf( stderr, "malloc failed, out of memory\n" );
	exit( 1 );
}

Elf32_Ehdr header;
Elf32_Shdr sectHeaders[16];	/* up to 16 sections for now */
long sstabStart;
long loadableBytes = 0;
long loadAddress = 0;
long bootAddress = 0;
int verbose, outputFileOpen;
FILE * in, * out;
int inputFileNumber = -1;

void AddFileName( const char * name )
{
	FILENAMEPTR newFile;

	newFile = malloc( sizeof( FILENAME ) );
	if ( !newFile )
		nospace();
	newFile->name = malloc( strlen( name ) + 1 );
	if ( !newFile->name )
		nospace();
	strcpy( newFile->name, name );
	newFile->next = 0;
	if ( !fileLast )
		fileList = newFile;
	else
		fileLast->next = newFile;
	fileLast = newFile;
}

char * GetFileName( int index )
{
	FILENAMEPTR fp = fileList;

	while ( index-- )
	{
		if ( !fp )
			return NULL;
		fp = fp->next;
	}
	if ( !fp )
		return NULL;
	return fp->name;
}

void DumpFileHeader()
{
	register int i;

	if ( 	(header.e_ident[0] != 0x7f) ||
		(header.e_ident[1] != 'E') ||
		(header.e_ident[2] != 'L') ||
		(header.e_ident[3] != 'F') )
		{
			fprintf( stderr, "Not an ELF file...\n" );
			exit( 1 );
		}
	if ( verbose )
	{
		if ( header.e_ident[4] == 1 )
			printf( "32 bit " );
		if ( header.e_ident[5] == 1 )
			printf( "LSB " );
		else if ( header.e_ident[5] == 2 )
			printf( "MSB " );
		printf( "ELF file\n" );
		printf( "Type %x\n", header.e_type );
		printf( "Entry %x\n", header.e_entry );
		printf( "Progheader Offset %x\n", header.e_phoff );
		printf( "Sectheader Offset %x\n", header.e_shoff );
		printf( "Num progentries %x\n", header.e_phnum );
		printf( "Num segentries %d\n", header.e_shnum );
		printf( "Sectheader Index %x\n", header.e_shstrndx );
	}
}

void ShowSectionName( int index, FILE * f )
{
	char sectnamebuf[32], *s;

	if ( fseek( f, sstabStart + sectHeaders[index].sh_name, SEEK_SET ) )
		fprintf( stderr, "Seek error to address %lx\n", 
			sstabStart + sectHeaders[index].sh_name );
	else
	{
		int c;
		SECTIONPTR sp;

		s = sectnamebuf;
		while ( c = getc( f ) )
			*s++ = c;
		*s = 0;
		printf( "Section %d name is %s\n", index, sectnamebuf );
		if ( sectHeaders[index].sh_type == SHT_PROGBITS &&
		    (sectHeaders[index].sh_flags & SHF_ALLOC) )
		{
			printf( "\tLoadable@ %08x\n",
				sectHeaders[index].sh_addr );
			printf( "\tSize %x\n",
				sectHeaders[index].sh_size );
			loadableBytes += sectHeaders[index].sh_size;
			if ( !strcmp( sectnamebuf, ".text" ) )
				loadAddress = sectHeaders[index].sh_addr;
			sp = &sectionTable[loadableSections];
			sp->fileNum = inputFileNumber;
			sp->sectionSize = sectHeaders[index].sh_size;
			sp->inFileOffset = sectHeaders[index].sh_offset;
			sp->outFileOffset = sectHeaders[index].sh_addr -
				bootAddress + 32;
			++loadableSections;
			if ( loadableSections >= 64 )
			{
				fprintf( stderr,
					"Too many output sections\n" );
				exit( 1 );
			}
		}
		else if ( verbose )	/* just print addr & size */
			printf( "Non-loadable section @ %08x (%x)\n",
				sectHeaders[index].sh_addr,
				sectHeaders[index].sh_size );

	}
}

void ReadSection( int index, FILE * f )
{
	if ( fread( &sectHeaders[index], sizeof( Elf32_Shdr ), 1, f ) != 1 )
	{
		fprintf( stderr, "Can't read section header\n" );
		fclose( f );
		exit( 1 );
	}
}

void WriteROMHeader( FILE *f, unsigned long sp )
{
	RomHeader	rom;

	rom.magic = ROM_MAGIC;
	rom.version = ROM_VERSION;
	rom.bootOffset = 32;
	rom.bootStack = (void *) sp;
	rom.bootArgument = 0;
	if ( fwrite( &rom, sizeof( RomHeader ), 1, f ) != 1 )
	{
		fprintf( stderr, "Failed to write header\n" );
		exit( 1 );
	}
}

int lastFileWritten = -1;

void WriteROMSection( int index )
{
	long outSeek;
	int size;
	char * fileName;

	size = sectionTable[index].sectionSize;
	if ( lastFileWritten != sectionTable[index].fileNum )
	{
		fclose( in );
		fileName = GetFileName( sectionTable[index].fileNum );
		if ( verbose )
			printf( "Opening input file %s\n", fileName );
		if ( (in = fopen( fileName, "r" )) == NULL )
		{
			fprintf( stderr, "Can't reopen input file %s\n",
				fileName );
			exit( 1 );
		}
		lastFileWritten = sectionTable[index].fileNum;
	}
	if ( fseek( in, sectionTable[index].inFileOffset, SEEK_SET ) )
	{
		fprintf( stderr, "Seek failed in input file\n" );
		exit( 1 );
	}
	outSeek = sectionTable[index].outFileOffset;
	if ( fseek( out, outSeek, SEEK_SET ) )
	{
		fprintf( stderr, "Seek failed in output file\n" );
		exit( 1 );
	}
	if ( verbose )
		printf( "Copying %d bytes from in file offset %x to out file offset %x\n",
			sectionTable[index].sectionSize,
			sectionTable[index].inFileOffset,
			outSeek );
	while ( size-- )
	{
		int c;

		if ( (c = getc( in )) == EOF )
		{
			fprintf( stderr, "PANIC- premature EOF on input\n" );
			exit( 1 );
		}
		putc( c, out );
	}
}

void DoInputFile( const char * infilename )
{
	register int i;

	if ( (in = fopen( infilename, "r" )) == NULL )
	{
		fprintf( stderr, "Can't open %s\n", infilename );
		exit( 1 );
	}

	++inputFileNumber;
	AddFileName( infilename );

	if ( fread( &header, sizeof( header ), 1, in ) != 1 )
	{
		fprintf( stderr, "Can't read header from %s\n", infilename );
		fclose( in );
		exit( 1 );
	}

	DumpFileHeader();

	if ( fseek( in, header.e_shoff, SEEK_SET ) )
	{
		fprintf( stderr, "Seek failed in %s\n", infilename );
		fclose( in );
		exit( 1 );
	}

	if ( header.e_shnum > 16 )
	{
		fprintf( stderr,
			"Sorry, can't deal with %d sections in this version\n",
			header.e_shnum );
		fclose( in );
		exit( 1 );
	}

	for ( i = 0; i < header.e_shnum; ++i )
		ReadSection( i, in );

	sstabStart = sectHeaders[header.e_shstrndx].sh_offset;
	for ( i = 0; i < header.e_shnum; ++i )
		ShowSectionName( i, in );
	fclose( in );
}

int main( int argc, char **argv )
{
	register int i;
	char * outfilename = 0, * infilename = 0;
	unsigned long initsp;
	FILENAMEPTR fp;

	if ( argc < 3 )
		usage();
	i = 1;
	while ( --argc )
	{
		if ( argv[i][0] == '-' )
		{
			switch ( argv[i][1] )
			{
			case 'b':
				bootAddress = strtoul( argv[i+1], NULL, 16 );
				if ( verbose )
					printf( "Boot addr %08x\n", initsp );
				++i;
				--argc;
				break;

			case 'o':
				outfilename = argv[i+1];
				++i;
				--argc;
				break;

			case 's':
				initsp = strtoul( argv[i+1], NULL, 16 );
				if ( verbose )
					printf( "SP set to %08x\n", initsp );
				++i;
				--argc;
				break;

			case 'v':
				++verbose;
				break;

			default:
				fprintf( stderr,
					"Unknown option %c, ignored\n",
					argv[i][1] );
			}
		}
		else
		{
			infilename = argv[i];
			printf( "Input File %s\n", infilename );

			/* We need to open the output file first */

			if ( !outputFileOpen )
			{
				if ( !outfilename )	/* make one up */
				{
					if ( (outfilename = malloc( strlen( infilename ) + 5 ) ) == NULL )
						nospace();
					strcat( strcpy( outfilename, infilename ), ".rom" );
				}
				if ( verbose )
					printf( "Out file name %s\n",
						outfilename );
				if ( !bootAddress )
					usage();
				if ( !initsp )
					usage();
				if ( (out = fopen( outfilename, "w" )) == NULL )
				{
					fprintf( stderr,
						"Can't create rom file %s\n",
						outfilename );
					exit( 1 );
				}
				WriteROMHeader( out, initsp );
				++outputFileOpen;
			}
			DoInputFile( infilename );
		}
		++i;
	}

	for ( i = 0; i < loadableSections; ++i )
		WriteROMSection( i );

	/* fix up load info */

	if ( fseek( out, 12L, SEEK_SET ) )
		fprintf( stderr, "Seek failed in output file header\n" );
	fwrite( &loadableBytes, sizeof( long ), 1, out );
	printf( "ROM Image size = %x\n", loadableBytes );
	fwrite( &bootAddress, sizeof( long ), 1, out );
	fwrite( &bootAddress, sizeof( long ), 1, out );
	printf( "Load addr = %x\n", bootAddress );
	fclose( out );
}