File:  [MW Coherent from dump] / coherent / d / bin / load / main.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Wed May 29 04:56:39 2019 UTC (7 years, 2 months ago) by root
Branches: MarkWilliams, MAIN
CVS tags: relic, HEAD
coherent

/* ld/main.c */

#include "data.h"

extern	char	*mktemp();

main( argc, argv )
int	argc;
char	*argv[];
{
	flag_t	dcomm = 0,		/* define commons even if reloc out */
		nosym = 0,		/* do not output symbol table */
		memld = 0,		/* do in-memory load */
		reloc = 0;		/* output relocation info */
	char	*ofname = "l.out",
		*entrys = NULL,
		*mfn,
		*lp;
	seg_t	*sgp;
	sym_t	*sp;
	mod_t	*mp;
	FILE	*ofp;
	struct	stat	statbuf;
	int	i, segn;
	unsigned int	symno;
	fsize_t	daddr;
	uaddr_t	addr;
#if BREADBOX
	int	abort();
#endif

	setbuf( stdout, NULL );
	setbuf( stderr, NULL );

	/*
	 * set separate code/data flag (required for 286 protected mode)
	 */
	oldh.l_flag |= LF_SEP;

	nmod = mxmsym = mdisk = 0;

	if ( argc <= 1 )
		usage( "no args" );

	/*
	 * Pass 1: Scan argument list.
	 */
	for ( i = 1; i < argc; i++ ) {

		/*
		 * Not -option; attempt to read file
		 */
		if ( *argv[i] != '-' ) {
			if ( !rdfile(argv[i]) )
				fatal( "can't open %s", argv[i] );
		}

		/*
		 * Decode options
		 */
		else switch ( argv[i][1] ) {

		default:
			usage( "unknown option %s", argv[i] );
			continue;

		case 'b':
			/*
			 * -b: undocumented option
			 * 	big link stores module structs on disk
			 */
			mdisk++;

			if ( (mfp = fopen(mfn=mktemp("/tmp/ldXXXXXX"),"wr") )
			   ==NULL) {
			   	unlink( mfn );
				fatal( "can't open temp file" );
			}

			mtemp = malloc( sizeof(mod_t) );
			continue;

		case 'd':
			/*
			 * -d: Define commons (even if undefined symbols).
			 */
			dcomm++;
			continue;

		case 'e':
			/*
			 * -e ent: Set entry point to given symbol/octal number.
			 */
			if ( ++i >= argc )
				usage( "Bad -e option" );

			else {
				undef( argv[i] );
				entrys = argv[i];
			}
			continue;

		case 'i':
			continue;

		case 'k':
			/*
			 * -k[sys]: Kernel process - use system symbol table.
			 */
			oldh.l_flag |= LF_KER;

			if ( argv[i][2] != '\0' )
				rdsystem( &argv[i][2] );
			else
				rdsystem( "/coherent" );
			continue;

		case 'l':
			/*
			 * -l<lib>: Use standard library <lib>.
			 */
			lp = malloc( strlen(argv[i])+16 );
			sprintf( lp, "/lib/lib%s.a", &argv[i][2] );

			if ( rdfile(lp) )
				;

			else {
				sprintf( lp, "/usr/lib/lib%s.a", &argv[i][2] );
				if ( rdfile(lp) )
					;
				else
					fatal(	"can't open lib%s.a",
						&argv[i][2]);
			}
			continue;

		case 'm':
			/*
			 * -m: Perform in-memory load if possible.
			 */
			memld++;
			continue;

		case 'n':
			/*
			 * -n: Bind output shared.
			 */
			oldh.l_flag |= LF_SHR;
#ifdef IAPX86
			/*
			 * Special case, no -n without -i on IBM PC
			 */
			oldh.l_flag |= LF_SEP;
#endif
			continue;

		case 'o':
			/*
			 * -o file: Place output in named file (default l.out).
			 */
			if ( ++i >= argc )
				usage( "bad -o option" );
			else
				ofname = argv[i];
			continue;

		case 'r':
			/*
			 * -r: Retain relocation information.
			 */
			reloc++;
#ifdef IAPX86
			/*
			 * Special case, -r disables -i.
			 */
			oldh.l_flag &= ~LF_SEP;
#endif
			continue;

		case 's':
			/*
			 * -s: Discard symbol table.
			 */
			nosym++;
			continue;

		case 'u':
			/*
			 * -u sym: Undefine 'sym' (forcing library search).
			 */
			if ( ++i >= argc )
				usage( "bad -u option" );
			else
				undef( argv[i] );
			continue;

		case 'w':
			/*
			 * -w: Watch everything happen.
			 */
			watch++;
			message( "watch!" );
			continue;

		case 'X':
			/*
			 * -X: Discard C internal local symbols.
			 */
			noilcl++;
			continue;

		case 'x':
			/*
			 * -x: Discard all local symbols.
			 */
			nolcl++;
			continue;

		case 'C':
			/*
		         * -C: Bind output combined code/data.
			 * (otherwise it will be separate code/data as
			 * required in 286 protected mode)
			 */
			oldh.l_flag &= ~LF_SEP;
			continue;
		}
	}

	if ( oldh.l_machine == 0 )
		fatal( "no input found" );

	/*
	 * all modules have been read
	 * resolve meanings of various flags
	 */

	/*
	 * Relocation or undefined symbols...
	 */
	if ( reloc || nundef ) {

		/*
		 * Requires symbol table be retained
		 */
		nosym = 0;

		if ( oldh.l_flag & LF_SEP ) {

			message("link failed, the following symbols are undefined:");

			for ( i = 0; i < NHASH; i++ ) {
				for ( sp=symtable[i]; sp!=NULL; sp=sp->next ) {
					if(sp->s.ls_type==(L_GLOBAL|L_REF)
					   && sp->s.ls_addr==0)
					   	spmsg(sp,"");
				}
			}

			if ( nundef )
				exit( 1 );
		}
	}

	/*
	 * No relocation, no undefined symbols
	 */
	else {
		/*
		 * Must define commons
		 */
		dcomm++;

		/*
		 * Discarding reloc info
		 */
		if ( oseg[L_REL].size != 0 ) {
			oldh.l_flag |= LF_NRB;		/* make note */
			oseg[L_REL].size = 0;
		}
	}

	/*
	 * To define common symbols...
	 */
	if ( dcomm )
		oseg[L_BSSD].size += commons;	/* we need this much room */

	/*
	 * Discard symbol table.
	 */
	if ( nosym )
		oseg[L_SYM].size = 0;

	if ( watch )
		message( "# undefined=%d", nundef );

	/*
	 * Set segment bases
	 */
	baseall( oseg, &oldh );

#ifdef IAPX86
	if ( oldh.l_machine == M_8086 ) {
		if ( (oseg[L_SHRI].size +
		      oseg[L_PRVI].size +
		      oseg[L_BSSI].size) >= MAXSEG86 )
			fatal("FATAL: code segment too large");

		if ( (oseg[L_SHRD].size +
		      oseg[L_PRVD].size +
		      oseg[L_BSSD].size) >= (MAXSEG86 - DEFSTACK) )
			fatal("FATAL: data segment too large");

		if ( (oseg[L_SHRD].size +
		      oseg[L_PRVD].size +
		      oseg[L_BSSD].size) >= (MAXSEG86 - DEFSTACK - WARNSIZE) )
			message(
			   "Warning: data segment may be too large to execute");
	}
#endif

	/*
	 * Open output file
	 */
	if ( ((ofp = fopen(ofname, "w")) == NULL)
	 &&  ((unlink(ofname) != 0) || ((ofp = fopen(ofname, "w")) == NULL)) )
		fatal( "cannot create %s", ofname );

	stat( ofname, &statbuf );
	chmod( ofname, statbuf.st_mode & ~(S_IEXEC|(S_IEXEC>>3)|(S_IEXEC>>6)));
	setbuf( ofp, NULL );

	/*
	 * set disk offsets of segments
	 * if not bigger than a breadbox, build output file in memory;
	 * otherwise, open the file for each segment,
	 * to get independent buffering
	 */
	daddr = segoffs( oseg, 0L );

	if ( watch )
		message( "size: %ld", daddr );

#if BREADBOX
	if ( memld || (daddr < BREADBOX) )
		outbuf = malloc( (int) daddr );
#endif
	for ( i = 0; i < NLSEG; i++ ) {

		if ( (i == L_BSSI) || (i == L_BSSD) )
			continue;

		sgp = &oseg[i];

		if ( sgp->size == 0 )
			continue;

#if BREADBOX
		if ( outbuf != NULL ) {
			if ( (outputf[i] = malloc(sizeof(FILE))) == NULL )
				fatal("out of space");

			outputf[i]->_cc = sgp->size;
			outputf[i]->_cp = &outbuf[sgp->daddr];
			outputf[i]->_pt = &abort;
		}
		else
#endif
		{
			if ( (outputf[i] = fopen(ofname, "r+w")) == NULL )
				fatal( "cannot open %s (seg %d)", ofname, i );

			fseek( outputf[i], sgp->daddr, 0 );

			if ( i == L_SHRI )
				setbuf( outputf[i], pbuf1 );

			if ( i == L_PRVD )
				setbuf( outputf[i], pbuf2 );
		}
	}

	/*
	 * Define internal symbols which have been referenced
	 */
	if ( dcomm ) {
		i = oldh.l_flag & LF_KER;
		endbind( etext_s, L_PRVI, i );
		endbind( edata_s, L_PRVD, i );
		endbind( end_s,   L_BSSD, i );
	}

	/*
	 * Run through symbol table fixing everything up
	 */
	symno = 0;
	for ( i=0; i < NHASH; i++ ) {

		for ( sp = symtable[i]; sp != NULL; sp = sp->next ) {

			/*
			 * Make defined symbol relative to virtual 0
			 */
			if ( (segn = sp->s.ls_type & ~L_GLOBAL) < L_SYM ) {
				sp->s.ls_addr += oseg[segn].vbase;
			}

			else if ( segn == L_SYM ) {
				spmsg( sp, "references symbol segment" );
			}

			/*
			 * Leave absolutes alone
			 */
			else if ( sp->s.ls_type != (L_GLOBAL|L_REF) ) {
				;
			}

			/*
			 * Undefined global
			 */
			else if ( sp->s.ls_addr == 0 ) {
				if ( ! reloc )
					spmsg( sp, "undefined" );
			}

			/*
			 * Define commons
			 */
			else if ( dcomm ) {
				addr = sp->s.ls_addr;
				sp->s.ls_addr = oseg[L_BSSD].vbase
						+oseg[L_BSSD].size
						-commons;
				commons -= addr;
				sp->s.ls_type = L_GLOBAL | L_BSSD;
			}

			/*
			 * Assign symbol number
			 */
			sp->symno = symno++;

			/*
			 * Output to symbol segment
			 */
			if ( ! nosym ) {
				canint( sp->s.ls_type );
				canvaddr( sp->s.ls_addr );
				putstruc( &sp->s, sizeof(sp->s),
					outputf[L_SYM], &oseg[L_SYM] );
				canint( sp->s.ls_type );
				canvaddr( sp->s.ls_addr );
			}
		}
	}

	/*
	 * get entry point (cannot precede symbol table fixup)
	 */
	oldh.l_entry = (entrys != NULL)
			? lentry(entrys)
			: (oldh.l_flag & LF_KER) ? drvbase[oldh.l_machine] : 0;
	/*
	 * Pass 2
	 */
	if ( mdisk ) {

		free( mtemp );

		if ((mp=malloc(sizeof(mod_t)+ mxmsym*sizeof(sym_t *))) == NULL)
			fatal("out of space - M");

		rewind( mfp );

		for ( i = 0; i < nmod; i++ ) {

			if ( fread( mp, sizeof(mod_t), 1 ,mfp ) != 1 )
baddisk:			fatal( "disk error" );

			if ( fread( mp->sym, sizeof(sym_t *), mp->nsym, mfp )
			   != mp->nsym)
			   	goto baddisk;

			loadmod( mp );
		}

		unlink( mfn );
	}
	
	else {
		for ( mp = modhead; mp != NULL; mp = mp->next )
			loadmod( mp );
	}

	/*
	 * All over but the flushing
	 */
	canint( oldh.l_magic );
	canint( oldh.l_flag );
	canint( oldh.l_machine );
	canvaddr( oldh.l_entry );

	for ( i = 0; i < NLSEG; i++ ) {
		oldh.l_ssize[i] = oseg[i].size;
		cansize(oldh.l_ssize[i]);
	}

	if ( outbuf == NULL )
		fwrite(&oldh, sizeof(oldh), 1, ofp);

	else {
		for ( i = 0; i < sizeof(oldh); i++ )
			outbuf[i] = *((char *)&oldh + i);
		fwrite( outbuf, 1, (int)daddr, ofp );
	}

	/*
	 * Make executable if no undefined symbols, and common storage defined.
	 */
	if ( (nundef == 0) || (dcomm != 0) ) {
		chmod(ofname, statbuf.st_mode|S_IEXEC|(S_IEXEC>>3)|(S_IEXEC>>6));
		return( 0 );
	}

	/*
	 * Supposed to be left relocatable.
	 */
	else if ( reloc )
		return( 0 );

	/*
	 * Undefined symbols left.
	 */
	else
		return( nundef );
}

/*
 * Set virtual bases in array of segments
 * according to flags in header.
 */
void
baseall( sega, ldhp )
register seg_t	sega[];
register ldh_t	*ldhp;
{
	register uaddr_t addr;

	addr = (ldhp->l_flag & LF_KER) ? drvbase[ldhp->l_machine] : 0;

	/*
	 * Shared code segment first.
	 */
	addr = setbase( &sega[L_SHRI], ldhp, addr );

	/*
	 * Shared data segment next if shared but not separate.
	 */
	if ( (ldhp->l_flag & (LF_SHR|LF_SEP)) == LF_SHR )
		addr = setbase( &sega[L_SHRD], ldhp, addr );

	/*
	 * Round up to page boundary if shared.
	 */
	if ( ldhp->l_flag & LF_SHR )
		addr = newpage(ldhp, addr);

	/*
	 * Private code segment next.
	 */
	addr = setbase( &sega[L_PRVI], ldhp, addr );

	/*
	 * Private data segment next if shared but not separate.
	 */
	if ( (ldhp->l_flag & (LF_SHR|LF_SEP)) == LF_SHR )
		addr = setbase( &sega[L_PRVD], ldhp, addr );

	/*
	 * Uninitialized code segment next.
	 */
	addr = setbase( &sega[L_BSSI], ldhp, addr );

	/*
	 * Set data offset if separate code/data.
	 */
	if ( ldhp->l_flag & LF_SEP )
		addr = (ldhp->l_flag & LF_KER) ? drvbase[ldhp->l_machine] : 0;

	/*
	 * Shared data segment next if not shared.
	 */
	if ( (ldhp->l_flag & (LF_SHR|LF_SEP)) != LF_SHR )
		addr = setbase( &sega[L_SHRD], ldhp, addr );

	/*
	 * Round up to page boundary if shared and separate.
	 */
	if ( (ldhp->l_flag & (LF_SHR|LF_SEP)) == (LF_SHR|LF_SEP) )
		addr = newpage( ldhp, addr );

	/*
	 * Private data segment next unless shared and not separate.
	 */
	if ( (ldhp->l_flag & (LF_SHR|LF_SEP)) != LF_SHR )
		addr = setbase( &sega[L_PRVD], ldhp, addr );

	/*
	 * Uninitialized data segment next.
	 */
	setbase( &sega[L_BSSD], ldhp, addr );
}

/*
 * Set virtual base in given segment and return next address
 * Check for wraparound and driver space overflow
 */
uaddr_t
setbase( segp, ldhp, addr )
register seg_t	*segp;
register ldh_t	*ldhp;
register uaddr_t addr;
{
	segp->vbase = addr;
	addr += segp->size;

	/*
	 * Address wrap-around.
	 */
	if ( addr < segp->vbase ) {
		fatal("address wraparound");
	}
	
	/*
	 * User process.
	 */
	else if ( ! (ldhp->l_flag & LF_KER) ) {
		;
	}
	
	/*
	 * Invalid kernel process.
	 */
	else if (addr > drvtop[ldhp->l_machine]) {
		fatal("driver larger than %dKb",
			(drvtop[ldhp->l_machine]
			-drvbase[ldhp->l_machine])/1024);
	}

	return (addr);
}

/*
 * Set segment disk offsets, given sizes
 * return size of module
 */
fsize_t
segoffs(sega, offs)
seg_t	sega[];
register fsize_t	offs;
{
	register seg_t	*sgp;

	offs += sizeof(ldh_t);

	for ( sgp = &sega[0]; sgp < &sega[NLSEG]; sgp++ ) {

		/*
		 * Uninitialized code/data do not affect module size.
		 */
		if ( (sgp == &sega[L_BSSI]) || (sgp == &sega[L_BSSD]) )
			continue;

		/*
		 * Record segment address.
		 * Calculate module size.
		 */
		else {
			sgp->daddr = offs;
			offs += sgp->size;
		}
	}

	/*
	 * Return module size.
	 */
	return (offs);
}

/*
 * Bump address to next hardware segment boundary
 */
uaddr_t
newpage( ldhp, addr )
ldh_t	*ldhp;
uaddr_t	addr;
{
	register uaddr_t inc = segsize[ldhp->l_machine]-1;

	return ((addr+inc)&~inc);
}

/*
 * Determine entry point; either octal address or symbol name.
 */
uaddr_t
lentry(str)
char	*str;
{
	char	id[NCPLN], *s = &id[0];
	uaddr_t	oaddr=0;
	int	notoct=0;
	register sym_t	*sp;

	/*
	 * Scan string.
	 */
	for ( ; *str; str++ ) {

		if ( s < &id[NCPLN] )
			*s++ = *str;

		/*
		 * Accumulate octal digits.
		 */
		if ( ('0' <= *str) && (*str <= '7') )
			oaddr = oaddr*8 + *str - '0';

		/*
		 * Not an octal digit.
		 */
		else
			++notoct;
	}

	/*
	 * Octal string: return numeric value.
	 */
	if (!notoct)
		return (oaddr);

	/*
	 * Extend string with nulls.
	 */
	while ( s < &id[NCPLN] )
		*s++ = 0;

	/*
	 * Search for string in symbol table.
	 */
	for ( sp = symtable[hash(id)]; sp != NULL; sp = sp->next ) {
		if ( (sp->s.ls_type & L_GLOBAL)
		 &&  (sp->s.ls_type != (L_GLOBAL|L_REF))
		 &&  eq(sp->s.ls_id, id) )
			return( sp->s.ls_addr );
	}

	/*
	 * Symbol not found.
	 */
	message("entry point %.*s undefined", NCPLN, id);
	return (0);
}

/*
 * Define referenced internal symbol (as end of given segment)
 */
void
endbind( sp, sn, ldrv )
register sym_t	*sp;
int	sn, ldrv;
{
	if ( sp == NULL ) {
		return;
	}

	else if ((sp->s.ls_type == (L_GLOBAL|L_REF)) && (sp->s.ls_addr == 0)) {
		sp->s.ls_type = L_GLOBAL|sn;
		sp->s.ls_addr = oseg[sn].size;
	}

	else if ( ldrv ) {
		return;
	}

	else {
		spmsg(sp, "redefines builtin");
	}
}

/*
 * Add reference to symbol table
 */
void
undef( s )
char * s;
{
	lds_t	lds;
	int	i;

	/*
	 * Copy reference, extending with NULL.
	 */
	for ( i = 0; i < NCPLN; i++ ) {
		lds.ls_id[i] = *s;
		if ( *s != '\0' )
			s++;
	}

	/*
	 * Define symbol as global reference.
	 */
	lds.ls_type = L_GLOBAL|L_REF;
	lds.ls_addr = 0;

	/*
	 * Add [undefined] to symbol table.
	 */
	addsym(&lds, NULL);
}

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.