Subject: linker (ld) size checks, -z option, cleanup, more (#141)
Index:	bin/ld.c 2.11BSD

Description:
	'ld' could create and mark as executable a file which the
	kernel would refuse to run.

	There were unused functions ('eq', 'savestr') present.

	The '-v' option was evidently left over from an earlier
	incarnation of the linker and was unused in the present
	system.  Removing this option also meant that a couple more
	functions ('record' and 'restore') and variables/structures
	could be removed (the 'overlay' structure was several hundred
	bytes).

	Old syscall sequences were being used:  'link'+'unlink'
	rather than 'rename', 'creat'+'close'+'open' rather than
	'open (..., O_CREAT, ...)'.

Repeat-By:
	This started out as a simple "add size sanity checks" change
	but gradually grew.  The size problem is best seen by creating
	an overlaid program with either the base segment or one of
	the overlays being too big.  Note that 'ld' will not complain
	but the kernel will give a "ENOMEM" error.

Fix:
	There are two new "features" this patch adds to 'ld':

		1) it is no longer a fatal error to include libraries
		   which do not exist

		2) the '-z' option has been added and is the same as '-i'

	Both of these came about because I have to share a great many
	'Makefile's between different systems and some systems require
	'-lcompat' and others do not.  In a similar manner, some compilers
	(notably 'gcc') use the '-i' option for something other than
	"split I/D"; those systems use '-z' to mean 'demand paged loading,
	so it seemed natural to make -z a synonym for -i on 2.11BSD and
	change the Makefiles to all use '-z' instead of '-i'.  As a side
	note 4.3BSD's 'cc'/'ld' would cheerfully ignore the '-i' with
	a warning.

	The man page for 'ld' is updated to reflect the new '-z' option.

	Unshar the following file in /tmp and do:

	patch -p0 < /tmp/19
	patch -p0 < /tmp/23

	Apply the following patch to ld.c and rebuild+install the
	linker.

=============================cut here============================
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
#	19
#	23
# This archive created: Fri Jul  2 21:43:24 1993
export PATH; PATH=/bin:/usr/bin:$PATH
if test -f '19'
then
	echo shar: "will not over-write existing file '19'"
else
sed 's/^X//' << \SHAR_EOF > '19'
X*** /usr/src/bin/ld.c.old	Sat Nov 24 22:14:02 1990
X--- /usr/src/bin/ld.c	Sun Jun  6 21:01:55 1993
X***************
X*** 1,6 ****
X! /*
X!  * link editor
X!  */
X  
X  #include <sys/param.h>
X  #include <stdio.h>
X--- 1,6 ----
X! #if	defined(DOSCCS) && !defined(lint)
X! static char *sccsid = "@(#)ld.c	2.1 6/6/93";
X! #endif
X  
X  #include <sys/param.h>
X  #include <stdio.h>
X***************
X*** 88,104 ****
X  	long	cloc;
X  } tab[TABSZ];
X  
X- int	vindex;			/* overlay management */
X- struct overlay {
X- 	int	argsav;
X- 	int	symsav;
X- 	LIBLIST	*libsav;
X- 	char	*vname;
X- 	u_int	ctsav, cdsav, cbsav;
X- 	u_int	offt, offd, offb;
X- 	long offs;
X- } vnodes[NOVL + 1];
X- 
X  typedef struct {		/* input management */
X  	int	nuser;
X  	int	bno;
X--- 88,93 ----
X***************
X*** 177,183 ****
X  int	Oflag;		/* set magic # to 0405 (overlay) */
X  int	dflag;		/* define common even with rflag */
X  int	iflag;		/* I/D space separated */
X- int	vflag;		/* overlays used */
X  
X  /*
X   * These are the cumulative sizes, set in pass1, which
X--- 166,171 ----
X***************
X*** 232,238 ****
X  int	numov;			/* Total number of overlays */
X  int	curov;			/* Overlay being worked on just now */
X  int	inov;			/* 1 if working on an overlay */
X! int	ovsize[NOVL+1];		/* The sizes of the overlays */
X  
X  				/* Kernel overlays have a special
X  				   subroutine to do the switch */
X--- 220,226 ----
X  int	numov;			/* Total number of overlays */
X  int	curov;			/* Overlay being worked on just now */
X  int	inov;			/* 1 if working on an overlay */
X! u_int	ovsize[NOVL+1];		/* The sizes of the overlays */
X  
X  				/* Kernel overlays have a special
X  				   subroutine to do the switch */
X***************
X*** 255,261 ****
X  int	delexit();
X  long	lseek();
X  long	atol();
X- char	*savestr();
X  char	*malloc();
X  char	*mktemp();
X  
X--- 243,248 ----
X***************
X*** 266,273 ****
X  	int num;
X  	register char *ap, **p;
X  	char save;
X- 	int found;
X- 	int vscan;
X  
X  	if (signal(SIGINT, SIG_IGN) != SIG_IGN) {
X  		signal(SIGINT, delexit);
X--- 253,258 ----
X***************
X*** 304,310 ****
X  		filname = 0;
X  		ap = *p++;
X  		if (*ap != '-') {
X! 			load1arg(ap);
X  			continue;
X  		}
X  		for (i=1; ap[i]; i++) switch (ap[i]) {
X--- 289,295 ----
X  		filname = 0;
X  		ap = *p++;
X  		if (*ap != '-') {
X! 			load1arg(ap, 1);
X  			continue;
X  		}
X  		for (i=1; ap[i]; i++) switch (ap[i]) {
X***************
X*** 334,340 ****
X  		case 'l':
X  			save = ap[--i];
X  			ap[i]='-';
X! 			load1arg(&ap[i]);
X  			ap[i]=save;
X  			goto next;
X  		case 'M':
X--- 319,325 ----
X  		case 'l':
X  			save = ap[--i];
X  			ap[i]='-';
X! 			load1arg(&ap[i], -1);
X  			ap[i]=save;
X  			goto next;
X  		case 'M':
X***************
X*** 364,369 ****
X--- 349,355 ----
X  			dflag++;
X  			continue;
X  		case 'i':
X+ 		case 'z':
X  			iflag++;
X  			continue;
X  		case 't':
X***************
X*** 371,391 ****
X  			continue;
X  		case 'L':
X  			goto next;
X- 		case 'v':
X- 			if (++c >= argc)
X- 				error(1, "-v: arg missing");
X- 			vflag=TRUE;
X- 			vscan = vindex;
X- 			found=FALSE;
X- 			while (--vscan>=0 && found==FALSE)
X- 				found = eq(vnodes[vscan].vname, *p);
X- 			if (found) {
X- 				endload(c, argv);
X- 				restore(vscan);
X- 			} else
X- 				record(c, *p);
X- 			p++;
X- 			continue;
X  		case 'O':
X  			Oflag++;
X  			continue;
X--- 357,362 ----
X***************
X*** 420,427 ****
X  			}
X  			curov++;
X  			continue;
X  		case 'y':
X- 		case 'z':
X  		case 'A':
X  		case 'H':
X  		case 'N':
X--- 391,398 ----
X  			}
X  			curov++;
X  			continue;
X+ 		case 'v':
X  		case 'y':
X  		case 'A':
X  		case 'H':
X  		case 'N':
X***************
X*** 465,471 ****
X  		if (trace)
X  			printf("%s:\n", ap);
X  		if (*ap != '-') {
X! 			load2arg(ap);
X  			continue;
X  		}
X  		for (i=1; ap[i]; i++) switch (ap[i]) {
X--- 436,442 ----
X  		if (trace)
X  			printf("%s:\n", ap);
X  		if (*ap != '-') {
X! 			load2arg(ap, 1);
X  			continue;
X  		}
X  		for (i=1; ap[i]; i++) switch (ap[i]) {
X***************
X*** 480,486 ****
X  		case 'u':
X  		case 'e':
X  		case 'o':
X- 		case 'v':
X  			++c;
X  			++p;
X  			/* fall into ... */
X--- 451,456 ----
X***************
X*** 490,496 ****
X  			goto next;
X  		case 'l':
X  			ap[--i]='-';
X! 			load2arg(&ap[i]);
X  			goto next;
X  		case 'Y':
X  			roundov();
X--- 460,466 ----
X  			goto next;
X  		case 'l':
X  			ap[--i]='-';
X! 			load2arg(&ap[i], -1);
X  			goto next;
X  		case 'Y':
X  			roundov();
X***************
X*** 518,530 ****
X  /*
X   * Scan file to find defined symbols.
X   */
X! load1arg(cp)
X  	register char *cp;
X  {
X  	off_t nloc;
X  	int kind;
X  
X! 	kind = getfile(cp);
X  	if (Mflag)
X  		printf("%s\n", filname);
X  	switch (kind) {
X--- 488,501 ----
X  /*
X   * Scan file to find defined symbols.
X   */
X! load1arg(cp, flag)
X  	register char *cp;
X+ 	int flag;
X  {
X  	off_t nloc;
X  	int kind;
X  
X! 	kind = getfile(cp, flag, 1);
X  	if (Mflag)
X  		printf("%s\n", filname);
X  	switch (kind) {
X***************
X*** 579,584 ****
X--- 550,557 ----
X  			nloc += (sizeof(archdr) + atol(archdr.ar_size)) >> 1;
X  		while (step(nloc));
X  		break;
X+ 	case -1:
X+ 		return;
X  	}
X  	close(infil);
X  }
X***************
X*** 898,926 ****
X  	}
X  }
X  
X! load2arg(acp)
X! char *acp;
X  {
X  	register char *cp;
X  	register LIBLIST *lp;
X  
X  	cp = acp;
X! 	if (getfile(cp) == 0) {
X! 		while (*cp)
X! 			cp++;
X! 		while (cp >= acp && *--cp != '/')
X! 			;
X! 		mkfsym(++cp);
X! 		load2(0L);
X! 	} else {	/* scan archive members referenced */
X! 		for (lp = libp; lp->loc != -1; lp++) {
X! 			dseek(&text, lp->loc, sizeof archdr);
X! 			getarhdr();
X! 			mkfsym(archdr.ar_name);
X! 			load2(lp->loc + (sizeof archdr) / 2);
X  		}
X- 		libp = ++lp;
X- 	}
X  	close(infil);
X  }
X  
X--- 871,906 ----
X  	}
X  }
X  
X! load2arg(acp, flag)
X! 	char *acp;
X! 	int flag;
X  {
X  	register char *cp;
X  	register LIBLIST *lp;
X  
X  	cp = acp;
X! 	switch	(getfile(cp, flag, 2))
X! 		{
X! 		case 0:
X! 			while (*cp)
X! 				cp++;
X! 			while (cp >= acp && *--cp != '/')
X! 				;
X! 			mkfsym(++cp);
X! 			load2(0L);
X! 			break;
X! 		case -1:
X! 			return;
X! 		default:	/* scan archive members referenced */
X! 			for (lp = libp; lp->loc != -1; lp++) {
X! 				dseek(&text, lp->loc, sizeof archdr);
X! 				getarhdr();
X! 				mkfsym(archdr.ar_name);
X! 				load2(lp->loc + (sizeof archdr) / 2);
X! 			}
X! 			libp = ++lp;
X! 			break;
X  		}
X  	close(infil);
X  }
X  
X***************
X*** 1093,1099 ****
X  {
X  	register u_int n, *p;
X  	register SYMBOL *sp, *symp;
X! 	long before, after;
X   
X  	if (numov) {
X  		/* int aovno = adrof("__ovno");		XXX KB */
X--- 1073,1080 ----
X  {
X  	register u_int n, *p;
X  	register SYMBOL *sp, *symp;
X! 	int type;
X! 	long before, after, dtotal, rnd8k(), ovrnd;
X   
X  	if (numov) {
X  		/* int aovno = adrof("__ovno");		XXX KB */
X***************
X*** 1175,1189 ****
X  	write(toutb.fildes, &filhdr, sizeof (filhdr));
X  	close(toutb.fildes);
X  	if (!ofilfnd) {
X! 		unlink("a.out");
X! 		if (link("l.out", "a.out") < 0)
X  			error(1, "cannot move l.out to a.out");
X  		ofilename = "a.out";
X  	}
X  	delarg = errlev;
X  	delexit();
X  }
X  
X  mkfsym(s)
X  char *s;
X  {
X--- 1156,1217 ----
X  	write(toutb.fildes, &filhdr, sizeof (filhdr));
X  	close(toutb.fildes);
X  	if (!ofilfnd) {
X! 		if (rename("l.out", "a.out") < 0)
X  			error(1, "cannot move l.out to a.out");
X  		ofilename = "a.out";
X  	}
X+ /*
X+  * we now do a sanity check on the total sizes of things.  Previously the
X+  * linker could produce a program marked as executable but which had bogus
X+  * overlay+root sizes, etc.
X+ */
X+ #define	K56	(56L * 1024L)
X+ #define	K64	(64L * 1024L)
X+ 
X+ 	dtotal = (long)dsize + (long)bsize;
X+ 	ovrnd = rnd8k(ovsize[0]);	/* 0 if not overlaid */
X+ 	type = 0;
X+ 	if (nflag) {
X+ 		if (rnd8k(tsize) + ovrnd + dtotal > K56)
X+ 			type = filhdr.a_magic;
X+ 	}
X+ 	else if (iflag) {
X+ 		if ((rnd8k(tsize) + ovrnd > K64) || (dtotal > K56))
X+ 			type = filhdr.a_magic;
X+ 	}
X+ 	else {
X+ 		if ((long)tsize + dtotal > K56)
X+ 			type = filhdr.a_magic;
X+ 	}
X+ 	if (type && !rflag) {
X+ 		fprintf(stderr, "ld: too big for type %o\n", type);
X+ 		errlev = 2;
X+ 	}
X+ 	if (ovsize[0]) {
X+ 		for (n = numov; n; n--) {
X+ 			if (ovsize[n])	/* look for non zero size */
X+ 				break;
X+ 		}
X+ 		while (--n) {
X+ 			if	(ovsize[n] == 0) {
X+ 				fprintf(stderr, "ld: overlay %d size is 0\n",n);
X+ 				errlev = 2;
X+ 			}
X+ 		}
X+ 	}
X  	delarg = errlev;
X  	delexit();
X  }
X  
X+ long
X+ rnd8k(siz)
X+ 	u_int siz;
X+ 	{
X+ 	long l = siz;
X+ 
X+ 	return((l + 017777) & ~017777L);
X+ 	}
X+ 
X  mkfsym(s)
X  char *s;
X  {
X***************
X*** 1278,1284 ****
X  	}
X  	if (--sp->size <= 0) {
X  		if (sp->size < 0)
X! 			error(1, "premature EOF");
X  		++fpage.nuser;
X  		--sp->pno->nuser;
X  		sp->pno = (PAGE *)&fpage;
X--- 1306,1312 ----
X  	}
X  	if (--sp->size <= 0) {
X  		if (sp->size < 0)
X! 			error(1, "premature EOF#1");
X  		++fpage.nuser;
X  		--sp->pno->nuser;
X  		sp->pno = (PAGE *)&fpage;
X***************
X*** 1286,1293 ****
X  	return(*sp->ptr++);
X  }
X  
X! getfile(acp)
X  char *acp;
X  {
X  	char arcmag[SARMAG+1];
X  	struct stat stb;
X--- 1314,1322 ----
X  	return(*sp->ptr++);
X  }
X  
X! getfile(acp, flag, phase)
X  char *acp;
X+ 	int flag;	/* 1 = fatal if file not found, -1 = not fatal */
X  {
X  	char arcmag[SARMAG+1];
X  	struct stat stb;
X***************
X*** 1298,1305 ****
X  		infil = libopen(filname + 2, O_RDONLY);
X  	else
X  		infil = open(filname, O_RDONLY);
X! 	if (infil < 0)
X! 		error(1, "cannot open");
X  	fstat(infil, &stb);
X  	page[0].bno = page[1].bno = -1;
X  	page[0].nuser = page[1].nuser = 0;
X--- 1327,1337 ----
X  		infil = libopen(filname + 2, O_RDONLY);
X  	else
X  		infil = open(filname, O_RDONLY);
X! 	if (infil < 0) {
X! 		if (phase == 1)		/* only complain once on phase 1 */
X! 			error(flag, "cannot open");
X! 		return(-1);
X! 	}
X  	fstat(infil, &stb);
X  	page[0].bno = page[1].bno = -1;
X  	page[0].nuser = page[1].nuser = 0;
X***************
X*** 1307,1313 ****
X  	fpage.nuser = 2;
X  	dseek(&text, 0L, SARMAG);
X  	if (text.size <= 0)
X! 		error(1, "premature EOF");
X  	mget((char *)arcmag, SARMAG);
X  	arcmag[SARMAG] = 0;
X  	if (strcmp(arcmag, ARMAG))
X--- 1339,1345 ----
X  	fpage.nuser = 2;
X  	dseek(&text, 0L, SARMAG);
X  	if (text.size <= 0)
X! 		error(1, "premature EOF#2");
X  	mget((char *)arcmag, SARMAG);
X  	arcmag[SARMAG] = 0;
X  	if (strcmp(arcmag, ARMAG))
X***************
X*** 1332,1358 ****
X  	register char *p, *cp;
X  	register int i;
X  	static char buf[100];
X! 	int fd = -1;
X  
X! 	if (*name == '\0')			/* backwards compat */
X! 		name = "a";
X! 	for (i = 0; i < ndir && fd == -1; i++) {
X  		p = buf;
X  		for (cp = dirs[i]; *cp; *p++ = *cp++)
X  			;
X  		*p++ = '/';
X! 		for (cp = "lib"; *cp; *p++ = *cp++)
X! 			;
X  		for (cp = name; *cp; *p++ = *cp++)
X  			;
X! 		cp = ".a";
X! 		while (*p++ = *cp++)
X! 			;
X  		fd = open(buf, oflags);
X  	}
X! 	if (fd != -1)
X! 		filname = buf;
X! 	return (fd);
X  }
X  
X  SYMBOL **
X--- 1364,1391 ----
X  	register char *p, *cp;
X  	register int i;
X  	static char buf[100];
X! 	int fd;
X  
X! 	for (i = 0; i < ndir ; i++) {
X  		p = buf;
X  		for (cp = dirs[i]; *cp; *p++ = *cp++)
X  			;
X  		*p++ = '/';
X! 		*p++ = 'l';
X! 		*p++ = 'i';
X! 		*p++ = 'b';
X  		for (cp = name; *cp; *p++ = *cp++)
X  			;
X! 		*p++ = '.';
X! 		*p++ = 'a';
X! 		*p++ = '\0';
X  		fd = open(buf, oflags);
X+ 		if (fd != -1) {
X+ 			filname = buf;
X+ 			return(fd);
X+ 		}
X  	}
X! 	return(-1);
X  }
X  
X  SYMBOL **
X***************
X*** 1493,1502 ****
X  	char *nam;
X  
X  	nam = (tempflg ? tfname : ofilename);
X! 	if ((ufd = creat(nam, 0666)) < 0)
X  		error(2, tempflg?"cannot create temp":"cannot create output");
X! 	close(ufd);
X! 	buf->fildes = open(nam, 2);
X  	if (tempflg)
X  		unlink(tfname);
X  	buf->nleft = sizeof(buf->iobuf)/sizeof(int);
X--- 1526,1534 ----
X  	char *nam;
X  
X  	nam = (tempflg ? tfname : ofilename);
X! 	if ((ufd = open(nam, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
X  		error(2, tempflg?"cannot create temp":"cannot create output");
X! 	buf->fildes = ufd;
X  	if (tempflg)
X  		unlink(tfname);
X  	buf->nleft = sizeof(buf->iobuf)/sizeof(int);
X***************
X*** 1582,1597 ****
X  		*to++ = 0;
X  }
X  
X- eq(s1, s2)
X- register char *s1;
X- register char *s2;
X- {
X- 	while (*s1==*s2++)
X- 		if ((*s1++)==0)
X- 			return(TRUE);
X- 	return(FALSE);
X- }
X- 
X  putw(w, b)
X  register BUF *b;
X  {
X--- 1614,1619 ----
X***************
X*** 1618,1664 ****
X  		putw(0, &voutb);
X  		torigin += sizeof (int);
X  	}
X- }
X- 
X- record(c, nam)
X- int c;
X- char *nam;
X- {
X- 	register struct overlay *v;
X- 
X- 	v = &vnodes[vindex++];
X- 	v->argsav = c;
X- 	v->symsav = symindex;
X- 	v->libsav = libp;
X- 	v->vname = nam;
X- 	v->offt = tsize;
X- 	v->offd = dsize;
X- 	v->offb = bsize;
X- 	v->offs = ssize;
X- 	v->ctsav = ctrel;
X- 	v->cdsav = cdrel;
X- 	v->cbsav = cbrel;
X- }
X- 
X- restore(vscan)
X- int vscan;
X- {
X- 	register struct overlay *v;
X- 	register int saved;
X- 
X- 	v = &vnodes[vscan];
X- 	vindex = vscan+1;
X- 	libp = v->libsav;
X- 	ctrel = v->ctsav;
X- 	cdrel = v->cdsav;
X- 	cbrel = v->cbsav;
X- 	tsize = v->offt;
X- 	dsize = v->offd;
X- 	bsize = v->offb;
X- 	ssize = v->offs;
X- 	saved = v->symsav;
X- 	while (symindex>saved)
X- 		*symhash[--symindex]=0;
X  }
X  
X  long
X--- 1640,1645 ----
SHAR_EOF
fi
if test -f '23'
then
	echo shar: "will not over-write existing file '23'"
else
sed 's/^X//' << \SHAR_EOF > '23'
X*** /usr/src/man/man1/ld.1.old	Mon Feb 23 07:17:02 1987
X--- /usr/src/man/man1/ld.1	Mon May 10 20:45:51 1993
X***************
X*** 2,8 ****
X  .\" All rights reserved.  The Berkeley software License Agreement
X  .\" specifies the terms and conditions for redistribution.
X  .\"
X! .\"	@(#)ld.1	6.2 (Berkeley) 2/23/87
X  .\"
X  .TH LD 1 "February 23, 1987"
X  .UC 2
X--- 2,8 ----
X  .\" All rights reserved.  The Berkeley software License Agreement
X  .\" specifies the terms and conditions for redistribution.
X  .\"
X! .\"	@(#)ld.1	6.3 (2.11BSD GTE) 5/10/93
X  .\"
X  .TH LD 1 "February 23, 1987"
X  .UC 2
X***************
X*** 139,144 ****
X--- 139,158 ----
X  and both start at location 0.
X  This option creates
X  a `separate executable' format.
X+ .TP
X+ .B  \-z
X+ This option is a synonym for the
X+ .B \-i
X+ option.  On other systems (4.3BSD for example) the
X+ .B \-z
X+ option causes a demand paged executable to be built.  This option
X+ was added to 2.11BSD because some systems (those which use gcc)
X+ do not safely ignore (with a warning) the
X+ .B \-i
X+ option.  Adding the
X+ .B \-z
X+ option to 2.11BSD allows makefiles to be copied freely between multiple 
X+ platforms once again.
X  .TP
X  .B "\-O (PDP-11 only)"
X  This is a text replacement overlay file; only the text segment
SHAR_EOF
fi
exit 0
#	End of shell archive
