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 X #include 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 X #include 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