DataMuseum.dk

Presents historical artifacts from the history of:

Commodore CBM-900

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about Commodore CBM-900

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - download

⟦f965c4915⟧ TextFile

    Length: 12200 (0x2fa8)
    Types: TextFile
    Notes: UNIX file
    Names: »slgen.c«

Derivation

└─⟦f27320a65⟧ Bits:30001972 Commodore 900 hard disk image with partial source code
    └─⟦f4b8d8c84⟧ UNIX V7 Filesystem
        └─ ⟦this⟧ »cmd/ld/slgen.c« 

TextFile

/*
 * A generator for shared libraries.
 * It is run as two passes.
 * Pass1:
 * 	A list of objects is scanned for entry
 *	points and a jump table object is produced.
 * The jump table and all these objects are loaded
 * into one object.
 * Pass2:
 *	Fixup is done on this one shared library
 *	object (on the jump table).
 */

#include <stdio.h>
#include <n.out.h>
#include <canon.h>

#define	NENTRY	640			/* Adjustable number of entry points */

static	char	dflag;			/* Tell about data entry points */
static	char	pflag;			/* Print objects with private */
static	char	vflag;			/* Verbose */
static	char	*jmpf;			/* Jump table file */
static	FILE	*jmpfp;			/* Jump table file pointer */
static	FILE	*symfp;			/* Symbol table file pointer */
static	struct	ldheader oldh;		/* Jump table l.out header */
static	struct	ldheader ildh;		/* Object file l.out header */
static	int	ncentry;		/* Number of code entries */
static	int	ndentry;		/* Number of data entries */
static	int	ncommon;		/* Number of common entries */
static	int	nsymref;		/* Symbol reference */
static	int	nabs;			/* Number of absolute entries */
static	int	npobj;			/* Number of private objects */
static	int	machtype;		/* Machine type */

static	int	(*pass)();		/* Pass-specific code pointer */
int	pass1();
int	pass2();

typedef	struct	ENTRY {
	char	e_name[NCPLN];
	long	e_addr;
}	ENTRY;

ENTRY	entries[NENTRY];		/* pure entry point table */
ENTRY	*wep;				/* Working pointer */

/*
 * The jump instruction is created into this
 * union by a machine-dependent routine.
 */
union	ins {
	char	c[32];
	short	s[16];
	long	l[8];
}	ins;

static	char	werr[] = "write error on jump table file `%s'";
static	char	jmperr[] = "write error on jump table file `%s', symbol %.*s";
static	char	lfmt[] = "bad l.out format in `%s'";
static	char	badmch[] = "module `%s' of machine type `%s` discarded";
static	char	maxent[] = "too many entries at module `%s' (increase NENTRY)";
static	char	badseg[] = "unexpected segment type %d in object `%s'";
static	char	notset[] = "machine type not yet set";
static	char	support[] = "machine type %d, not supported";
static	char	noreloc[] = "no relocation bits in `%s'";
static	char	symread[] = "read error on symbol table in `%s'";

char	*mtype();
long	symoff();
long	jumpbase();

main(argc, argv)
int argc;
char *argv[];
{
	register char *ap;
	register int es = 0;
	register int i;

	while (argc>1 && *argv[1]=='-') {
		for (ap = &argv[1][1]; *ap!='\0'; ap++)
			switch (*ap) {
			case '1':
				pass = pass1;
				break;

			case '2':
				pass = pass2;
				break;

			case 'd':
				dflag++;
				break;

			case 'p':
				pflag++;
				break;
	
			case 'v':
				vflag++;
				break;
	
			default:
				usage();
			}
		argv++;
		argc--;
	}
	if (pass == NULL) {
		slmsg("must specify `-1' or `-2' pass option");
		usage();
	}
	if (argc < 2)
		usage();
	argc--;
	argv++;
	es = (*pass)(argc, argv);
	exit(es);
}

/*
 * Build the library jump table object in
 * this pass.
 */
pass1(ac, av)
register int ac;
register char *av[];
{
	register int i;
	register int es;

	if (s1init(av[0]))
		return (1);
	if (ac < 2)
		usage();
	es = 0;
	for (i=1; i<ac; i++)
		es |= s1add(av[i]);
	es |= s1term();
	report();
	return (es);
}

/*
 * Pass 2 -- write the actual addresses into
 * the jump table of the linked object. This
 * assumption is that the jump table is
 * first in L_SHRI segment.
 */
pass2(ac, av)
register int ac;
register char *av[];
{
	if (ac != 1)
		usage();
	if (s2init(av[0]))
		return (1);
	if (s2fudge() || s2term())
		return (1);
	report();
	return (0);
}

/*
 * Initialise the jump table file.
 * This is an l.out containing
 * the header for the shared library.
 */
s1init(fn)
char *fn;
{
	wep = &entries[0];
	jmpf = fn;
	if ((jmpfp = fopen(jmpf, "w")) == NULL) {
		slmsg("cannot open jump table file `%s'", jmpf);
		return (1);
	}
	oldh.l_magic = L_MAGIC;
	oldh.l_flag = LF_32;
	oldh.l_tbase = sizeof(oldh);
	return (0);
}

/*
 * Add an object to the list in
 * the jump table.
 */
s1add(fn)
char *fn;
{
	register FILE *lfp;
	register long ss;
	static struct ldsym lds;

	if ((lfp = fopen(fn, "r")) == NULL) {
		slmsg("cannot open object file `%s'", fn);
		return (1);
	}
	if (fread((char*)&ildh, sizeof ildh, 1, lfp) != 1) {
		slmsg(lfmt, fn);
		fclose(lfp);
		return (1);
	}
	canldh(&ildh);
	if (ildh.l_magic!=L_MAGIC || (ildh.l_flag&LF_32)==0) {
		slmsg(lfmt, fn);
		fclose(lfp);
		return (1);
	}
	if (oldh.l_machine == 0) {
		oldh.l_machine = ildh.l_machine;
		machtype = ildh.l_machine;
	}
	if (ildh.l_machine != oldh.l_machine) {
		slmsg(badmch, fn, mtype(ildh.l_machine));
		fclose(lfp);
		return (0);
	}
	if ((ildh.l_flag&LF_NRB) != 0) {
		slmsg(noreloc, fn);
		fclose(lfp);
		return (1);
	}
	if (ildh.l_ssize[L_PRVD] != 0
	 || ildh.l_ssize[L_BSSD] != 0
	 || ildh.l_ssize[L_PRVI] != 0) {
		if (pflag) {
			if (npobj == 0)
				printf("Objects with private text:\n");
			printf("%s\n", fn);
		}
		npobj++;
	}
	fseek(lfp, symoff(&ildh), 0);
	for (ss = ildh.l_ssize[L_SYM]; ss > 0; ss -= sizeof lds) {
		if (fread((char*)&lds, sizeof lds, 1, lfp) != 1) {
			slmsg(symread, fn);
			fclose(lfp);
			return (1);
		}
		cansym(&lds);
		if ((lds.ls_type & L_GLOBAL) == 0)
			continue;
		switch (lds.ls_type & ~L_GLOBAL) {
		case L_REF:
			if (lds.ls_addr != 0)
				ncommon++; else
				nsymref++;
			break;

		case L_ABS:
			nabs++;
			break;

		case L_SHRI:
		case L_PRVI:
		case L_BSSI:
			ncentry++;
			if (wep >= &entries[NENTRY]) {
				slmsg(maxent, fn);
				fclose(lfp);
				return (0);
			}
			strncpy(wep->e_name, lds.ls_id, NCPLN);
			wep->e_addr = lds.ls_addr;
			break;

		case L_SHRD:
		case L_PRVD:
		case L_BSSD:
			if (dflag) {
				if (ndentry == 0)
					printf("Data entry points:\n");
				printf("%14s  %.*s", fn, NCPLN, lds.ls_id);
				if ((lds.ls_type & ~L_GLOBAL) == L_SHRD)
					printf(" (shared)\n"); else
					printf("\n");
			}
			ndentry++;
			break;

		default:
			slmsg(badseg, lds.ls_type, fn);
		}
	}
	fclose(lfp);
	return (0);
}

/*
 * Write the jump table
 */
s1term()
{
	register unsigned short i;
	register short l;

	if ((l = jumpsize()) == 0)
		return (1);
	l *= ncentry;
	i = l + sizeof(short);
	oldh.l_ssize[L_SHRI] = i;
	canldh(&oldh);
	if (fwrite((char*)&oldh, sizeof oldh, 1, jmpfp) != 1) {
		slmsg(werr, jmpf);
		fclose(jmpfp);
		return (1);
	}
	fputc(i>>8, jmpfp);
	fputc(i, jmpfp);
	for (i=0; i<l; i++)
		fputc(0, jmpfp);
	fflush(jmpfp);
	if (ferror(jmpfp)) {
		slmsg(werr, jmpf);
		fclose(jmpfp);
		return (1);
	}
	fclose(jmpfp);
	return (0);
}

/*
 * Size of an entry in the jump table.
 * This routine is dependent upon the
 * possible machine types.
 * The value returned is the number of bytes
 * (maximum) in a jump instruction.
 * Also, writes the jump instruction into the
 * `union ins' which can be written out by the
 * caller.
 * This data must be stored to be in the
 * correct byte order for the target machine.
 */
jumpsize(addr)
long addr;
{
	register int t;

	switch (machtype) {
	case 0:
		slmsg(notset);
		return (0);

	case M_Z8001:
		ins.c[0] = 0x5E;		/* jp un, DA */
		ins.c[1] = 0x08;
		if ((addr & 0xFF00) == 0) {	/* Short mode ? */
			t = (addr>>16) & 0x7F00;
			t += addr & 0xFF;
			ins.c[2] = (addr>>24) & 0x7F;
			ins.c[3] = addr & 0xFF;
		} else {
			ins.c[2] = 0x80 | (addr>>24);
			ins.c[3] = 0x00;
			ins.c[4] = addr>>8;
			ins.c[5] = addr;
		}
		return (6);

	case M_Z8002:
		ins.s[0] = 0x5E08;		/* jp un, DA */
		ins.s[1] = addr;
		return (4);

	case M_8086:		/* Large model */
		/* To do */
		return (6);

	case M_PDP11:
		ins.s[0] = 0167;		/* jmp *$DA */
		ins.s[1] = addr;
		return (4);

	default:
		slmsg(support, machtype);
		return (0);
	}
	/* NOTREACHED */
}

/*
 * Return the base of the jump table.
 * The value is machine-dependent.
 */
long
jumpbase()
{
	switch (machtype) {
	case 0:
		slmsg(notset);
		return (0L);

	case M_Z8001:
		return (0x01000000L);		/* Base of SHRI */

	case M_PDP11:
		return (0L);

	default:
		slmsg(support, machtype);
		return (0L);
	}
	/* NOTREACHED */
}

/*
 * Open the shared library (file name is in `jmpf')
 * one for reading, one for writing.
 */
s2init(fn)
char *fn;
{
	jmpf = fn;
	if ((jmpfp = fopen(jmpf, "r+w")) == NULL
	 || (symfp = fopen(jmpf, "r+w")) == NULL) {
		slmsg("cannot open shared library file  `%s'", jmpf);
		return (1);
	}
	return (0);
}

/*
 * Fixup the jump entries into
 * the output file.
 */
s2fudge()
{
	static struct ldsym lds;
	unsigned char c1, c2;
	register int s;
	register long ss;
	register long jaddr;
	short int jsize;

	if (fread((char*)&ildh, sizeof ildh, 1, jmpfp) != 1) {
		slmsg(lfmt, jmpf);
		return (1);
	}
	canldh(&ildh);
	if (ildh.l_magic!=L_MAGIC || (ildh.l_flag&LF_32)==0) {
		slmsg(lfmt, jmpf);
		return (1);
	}
	if (ildh.l_flag & LF_SLIB) {
		slmsg("don't re-run pass 2 on `%s'", jmpf);
		return (1);
	}
	machtype = ildh.l_machine;
	if (ildh.l_ssize[L_PRVD] != 0
	 || ildh.l_ssize[L_BSSD] != 0
	 || ildh.l_ssize[L_PRVI] != 0) {
		if (pflag)
			printf("Library `%s' has private text\n", jmpf);
		npobj++;
	}
	ildh.l_flag |= LF_SLIB;
	c1 = fgetc(jmpfp);
	c2 = fgetc(jmpfp);
	jsize = (c1<<8) + c2;
	jaddr = jumpbase() + sizeof(jsize);
	jsize -= sizeof(jsize);
	fseek(symfp, symoff(&ildh), 0);
	for (ss = ildh.l_ssize[L_SYM]; ss > 0; ss -= sizeof lds) {
		if (fread((char*)&lds, sizeof lds, 1, symfp) != 1) {
			slmsg(symread, jmpf);
			return (1);
		}
		cansym(&lds);
		if ((lds.ls_type & L_GLOBAL) == 0)
			continue;
		switch (lds.ls_type & ~L_GLOBAL) {
		case L_REF:
			if (lds.ls_addr != 0)
				ncommon++; else
				nsymref++;
			break;

		case L_ABS:
			nabs++;
			break;

		case L_SHRI:
		case L_PRVI:
		case L_BSSI:
			ncentry++;
			s = jumpsize(lds.ls_addr);
			jsize -= s;
			if (fwrite((char *)&ins, s, 1, jmpfp) != 1) {
				slmsg(jmperr, jmpf, NCPLN, lds.ls_id);
				return (1);
			}
			lds.ls_type = L_SHRI|L_GLOBAL;
			lds.ls_addr = jaddr;
			cansym(&lds);
			fseek(symfp, -(long)sizeof lds, 1);
			if (fwrite((char *)&lds, sizeof lds, 1, symfp) != 1) {
				slmsg(jmperr, jmpf, NCPLN, lds.ls_id);
				return (1);
			}
			jaddr += s;
			break;

		case L_SHRD:
		case L_PRVD:
		case L_BSSD:
			if (dflag) {
				if (ndentry == 0)
					printf("Data entry points:\n");
				printf("%14s  %.*s", jmpf, NCPLN, lds.ls_id);
				if ((lds.ls_type & ~L_GLOBAL) == L_SHRD)
					printf(" (shared)\n"); else
					printf("\n");
			}
			ndentry++;
			break;

		default:
			slmsg(badseg, lds.ls_type, jmpf);
			break;
		}
	}
	if (jsize != 0)
		slmsg("warning: jump table sizes disagree between passes");
	canldh(&ildh);
	fseek(jmpfp, 0L, 0);
	if (fwrite((char*)&ildh, sizeof ildh, 1, jmpfp) != 1) {
		slmsg(werr, jmpf);
		return (1);
	}
	return (0);
}

/*
 * Close output file and
 * check for write errors.
 */
s2term()
{
	fflush(jmpfp);
	if (ferror(jmpfp)) {
		slmsg(werr, jmpf);
		fclose(jmpfp);
		return (1);
	}
	fclose(jmpfp);
	fclose(symfp);
	return (0);
}

/*
 * Canonicalise the l.out (n.out)
 * header (can be used on input or output)
 */
canldh(ldhp)
register struct ldheader *ldhp;
{
	register int i;

	canshort(ldhp->l_magic);
	canshort(ldhp->l_flag);
	canshort(ldhp->l_machine);
	canshort(ldhp->l_tbase);
	for (i=0; i<NLSEG; i++)
		canlong(ldhp->l_ssize[i]);
	canlong(ldhp->l_entry);
}

/*
 * Canonicalise a symbol table
 * entry.
 */
cansym(ldsp)
register struct ldsym *ldsp;
{
	canshort(ldsp->ls_type);
	canlong(ldsp->ls_addr);
}

/*
 * Offset into the file for a the symbol
 * table.
 */
long
symoff(ldhp)
register struct ldheader *ldhp;
{
	register long base;
	register int i;

	base = ldhp->l_tbase;
	for (i=0; i<L_SYM; i++)
		if (i!=L_BSSI && i!=L_BSSD)
			base += ldhp->l_ssize[i];
	return (base);
}

/*
 * produce a report of the types of symbols
 * found in the library.
 */
report()
{
	if (!vflag)
		return;
	printf("Number of code entries: %3d\n", ncentry);
	printf("Number of data entries: %3d\n", ndentry);
	printf("Number of absolutes:    %3d\n", nabs);
	printf("Number of common refs:  %3d\n", ncommon);
	printf("Number of symbol refs:  %3d\n", nsymref);
	printf("Number of objects with private text: %3d\n", npobj);
}

/* VARARGS 1 */
slmsg(x)
{
	fprintf(stderr, "slgen: %r\n", &x);
}


usage()
{
	fprintf(stderr, "Usage:	slgen -1 [-dpv] jmpfile obj ... \n");
	fprintf(stderr, "       slgen -2 slibrary\n");
	exit(1);
}