andy@cit-vax.Caltech.Edu (Andy Fyfe) (03/17/89)
Here are the sources to my front end to /bin/ld, as described in unix-pc.general. Andy Fyfe andy@csvax.caltech.edu wjafyfe@caltech.bitnet andy@cit-vax.UUCP (...!ames!elroy!cit-vax!andy) Of all the things I've lost I miss my mind the most. #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of shell archive." # Contents: README Makefile ld.c ld.h load.c munge.c # Wrapped by andy@marmot on Thu Mar 16 12:45:59 1989 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'README' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'README'\" else echo shar: Extracting \"'README'\" \(2921 characters\) sed "s/^X//" >'README' <<'END_OF_FILE' XThis is a front end to the loader, /bin/ld, to make "better" use of Xthe shared library. X XIf the string "/lib/shlib.ifile" does not appear as one of the arguments Xto ld, then it will simply exec /bin/ld with the same arguments. X XIf the string does appear, then ld will make two calls to /bin/ld. The Xfirst will be with all the specified object files and libraries, but Xnot the shared library. The object file will then be scanned for Xunresolved symbols and an "ifile" will be built from those symbols. Then X/bin/ld will be run again to complete the load. X XIf this program is installed with GNU C (as /usr/local/lib/gcc-ld, or Xwhatever), then the "-shlib" option to gcc will cause the two pass load Xas described above. Without "-shlib", it will just exec /bin/ld with Xthe same arguments. This means that, for example, you can build gnu Xcpp with "-lmalloc" and still use "-shlib" (and the malloc library makes Xfor a quicker cpp). X XIf this program is installed as "ld" (in the search path before /bin/ld, Xor my renaming /bin/ld (and updating the Makefile to use the new name)) Xthen explicit "ld" commands in Makefiles to use the shared library will Xalso get the two pass behaviour. To prevent this, it's only necessary Xto refer to the system ifile as "//lib/shlib.ifile". X XINSTALLATION X XFirst you need to make a library. The shared library contains most of Xlibc but not all of it. The missing parts of libc are listed in the XMakefile for both Unix 3.5 and 3.51. Select the right one for you and Xexecute "make lib". This will make "libminic.a". You don't need to Xcall this library "minic" if you don't want to, and you can install it Xwherever you like. The Makefile assumes it will be installed as X"/usr/local/lib/libminic.a". If you install it in "/lib" or "/usr/lib" Xyou can change that string to be simply "-lminic". In any case, you'll Xhave to copy it wherever you want it yourself. X XMake sure that the ifile file, library file and location of the system ld Xare all correct in the Makefile, and run "make". Part of the process will Xbe running the program "munge" on the system "ifile" and compiling a Xsorted list of symbols contained in it into "ld". (The file "ifile.c" Xshould be 5 lines longer than "/lib/shlib.ifile".) If you upgrade your Xsystem you will have to remake "ld" if the ifile changed. (Ld will Xcheck to see if it is older than the system ifile, and if it is it will Xrefuse to do the load.) Ld will be made as "ld.temp" and then that will Xbe used to relink "ld". "Ld" can then be installed wherever you like. X X"Ld" can be compiled with either gcc or cc, though gcc will get you a Xsomewhat smaller binary (and will put all the "ifile" stuff that is Xcompiled in into the .text section). X XACKNOWLEDGEMENTS X XThis is based on John MacMillan's shcc. Since it only deals with the Xloader, it's much simpler. This seemed like the easiest way to bring Xshcc's functionality to the GNU C compiler. END_OF_FILE if test 2921 -ne `wc -c <'README'`; then echo shar: \"'README'\" unpacked with wrong size! fi # end of 'README' fi if test -f 'Makefile' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'Makefile'\" else echo shar: Extracting \"'Makefile'\" \(2689 characters\) sed "s/^X//" >'Makefile' <<'END_OF_FILE' X# X# This makefile is based largely on the one John MacMillan provided X# with shcc X# X X# What you want it called, and where to put it: X XNAME = ld XREAL_LD = /bin/ld XTARGET = /usr/local/lib/gcc-ld X X# LIBMISSING can is the name of the archive created here. LIBMINIC X# is where it will be installed. If you install it in /lib or /usr/lib, X# then LIBMINIC can be of the form "-lminic". The name "minic" isn't X# important, and can be whatever you want. X XLIBMISSING = libminic.a XLIBMINIC = /usr/local/lib/libminic.a X X# SHLIB is where the system ifile is X XSHLIB = /lib/shlib.ifile X X# Things missing from the shared version of libc. I used the same list X# as is in Jeffery Small's ccc, who did the hard part and figured out X# what was missing (and he credits Jim Apedaile for the 3.5 stuff). X# Thanks Jeffery and Jim! X XMISSING35 = acct.o assert.o aulrem.o biglitpow.o bsearch.o clrerr.o \ X doprnt.o doscan.o dtop.o fakcu.o findiop.o hsearch.o \ X lfind.o lockf.o lsearch.o ltostr.o mcount.o mon.o ptod.o \ X setvbuf.o sigrte.o strtod.o sigtrap.o tell.o tfind.o \ X tsearch.o vfprintf.o vprintf.o vsprintf.o XMISSING351 = acct.o aulrem.o biglitpow.o clrerr.o doprnt.o doscan.o \ X dtop.o fakcu.o findiop.o lfind.o lockf.o lsearch.o ltostr.o \ X mcount.o ptod.o setvbuf.o sigrte.o strtod.o tell.o tfind.o \ X vfprintf.o vprintf.o vsprintf.o X X# Now pick MISSING35 if you're using Version 3.5 of the OS, MISSING351 if X# you're using version 3.51: X XMISSING = $(MISSING35) X#MISSING = $(MISSING351) X X# Compile time options X# X# ld will compile with both gcc and cc X XCC = gcc XDEFINES = -DTARGET=\"$(TARGET)\" -DREAL_LD=\"$(REAL_LD)\" \ X -DSHLIB=\"$(SHLIB)\" -DLIBMINIC=\"$(LIBMINIC)\" XCFLAGS = -O $(DEFINES) XLDFLAGS = -s X X# You shouldn't have to touch these X XSRCS = ld.c load.c XMISC = README Makefile munge.c XINCS = ld.h XOBJS = ld.o load.o XLIBS = -lld XLIBC = /lib/libc.a X Xall: $(NAME) X Xlib: $(LIBMISSING) X X$(NAME): $(OBJS) X $(CC) $(LDFLAGS) -o ld.temp $(OBJS) $(LIBS) X ./ld.temp -s -o $@ /lib/crt0s.o $(SHLIB) $(OBJS) $(LIBS) X rm ld.temp X Xinstall: $(NAME) X cp $(NAME) $(TARGET) X Xload.o: ifile.c ld.h Xld.o: ld.h X Xifile.c: munge $(SHLIB) X sed -e '/"/s/"/\\"/g' $(SHLIB) | ./munge > $@ X X$(LIBMISSING): $(LIBC) Makefile X -rm -f $(LIBMISSING) X ar x $(LIBC) $(MISSING) X ar cr $@ `lorder $(MISSING) | tsort` X grep daylight $(SHLIB) > /dev/null || ( \ X echo 'int daylight = 1;' > daylight.c ; \ X $(CC) -c daylight.c ; \ X ar cr $@ daylight.o \ X ) X rm -f $(MISSING) daylight.[co] X Xlint: $(SRCS) X lint $(SRCS) X Xshar $(NAME).shar: X shar $(MISC) $(SRCS) $(INCS) > $(NAME).shar X Xclean: X rm -f $(NAME) ld.temp munge munge.o ifile.c $(OBJS) $(MISSING) \ X $(LIBMISSING) daylight.[co] *.out core END_OF_FILE if test 2689 -ne `wc -c <'Makefile'`; then echo shar: \"'Makefile'\" unpacked with wrong size! fi # end of 'Makefile' fi if test -f 'ld.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'ld.c'\" else echo shar: Extracting \"'ld.c'\" \(4516 characters\) sed "s/^X//" >'ld.c' <<'END_OF_FILE' X/* X * ld -- the main program X * X * front in to /bin/ld to do a two-pass load when the shared library X * is used. this is designed to be used with the gnu c compiler. X * X */ X X#include <stdio.h> X#include <signal.h> X#include <sys/types.h> X#include <sys/wait.h> X#include <sys/stat.h> X X#include "ld.h" X Xchar *cmd_name; X X#ifdef __STDC__ Xextern void *malloc(unsigned); Xstatic void parse_args(int argc, char *argv[], int skip); Xstatic int execute(char **argv); Xstatic void catch(void); Xstatic void check_dates(const char *); X#else Xextern void *malloc(); Xstatic void parse_args(); Xstatic int execute(); Xstatic void catch(); Xstatic void check_dates(); X#endif X Xstatic char a_out[30], ifile[30]; Xstatic char **ld1, **ld2; Xstatic int ac1, ac2; X X#ifdef __STDC__ Xmain(int argc, char *argv[]) X#else Xmain(argc, argv) Xint argc; Xchar *argv[]; X#endif X{ X int shlib = 0, i, ret; X X cmd_name = argv[0]; X X for (i=1; i<argc; ++i) X if (strcmp(argv[i], SHLIB) == 0) { X shlib = i; X break; X } X X if (shlib == 0) { X argv[0] = "ld"; X exit(execute(argv)); X } X X check_dates(argv[0]); X X strcpy(a_out, "/tmp/lda.out-XXXXXX"); X strcpy(ifile, "/tmp/ldifile-XXXXXX"); X mktemp(a_out); X mktemp(ifile); X X parse_args(argc, argv, shlib); X X if (signal(SIGINT, SIG_IGN) != SIG_IGN) X signal(SIGINT, catch); X if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) X signal(SIGQUIT, catch); X X ret = execute(ld1); X if (ret != 0) { X unlink(a_out); X exit(ret); X } X X if (make_ifile(a_out, ifile) < 0) { X unlink(a_out); X unlink(ifile); X exit(1); X } X X ret = execute(ld2); X unlink(a_out); X unlink(ifile); X exit(ret); X} X X#ifdef __STDC__ Xstatic void Xparse_args(int argc, char *argv[], int skip) X#else Xstatic void Xparse_args(argc, argv, skip) Xint argc; Xchar *argv[]; Xint skip; X#endif X{ X int i; X X ld1 = (char **)malloc((argc + 5) * sizeof(char *)); X ld2 = (char **)malloc((argc + 3) * sizeof(char *)); X if (ld1 == 0 || ld2 == 0) { X fprintf(stderr, "%s: can't malloc: ", cmd_name); X perror(""); X exit(1); X } X ac1 = 0; X ac2 = 0; X ld1[ac1++] = "ld"; X ld1[ac1++] = "-r"; X ld1[ac1++] = "-o"; X ld1[ac1++] = a_out; X ld2[ac2++] = "ld"; X for (i=1; i<argc; ++i) { X if (i == skip) X continue; X if (argv[i][0] == '-') { X switch(argv[i][1]) { X case 't': X ld1[ac1++] = argv[i]; X break; X case 'F': X case 'm': X case 'n': X case 'N': X case 'r': X case 's': X case 'x': X case 'z': X ld2[ac2++] = argv[i]; X break; X case 'l': X case 'L': X case 'u': X ld1[ac1++] = argv[i]; X if (argv[i][2] == '\0') X ld1[ac1++] = argv[++i]; X break; X case 'e': X case 'f': X case 'o': X ld2[ac2++] = argv[i]; X if (argv[i][2] == '\0') X ld2[ac2++] = argv[++i]; X break; X case 'V': X if (argv[i][2] != 'S') X ld1[ac1++] = argv[i]; X else { X ld2[ac2++] = argv[i]; X if (argv[i][3] == '\0') X ld2[ac2++] = argv[++i]; X } X break; X } X } X else X ld1[ac1++] = argv[i]; X } X ld1[ac1++] = LIBMINIC; X ld2[ac2++] = a_out; X ld2[ac2++] = ifile; X X ld1[ac1] = 0; X ld2[ac2] = 0; X X return; X} X X#ifdef __STDC__ Xstatic int Xexecute(char *argv[]) X#else Xstatic int Xexecute(argv) Xchar *argv[]; X#endif X{ X int pid; X union wait status; X X pid = fork(); X if (pid < 0) { X fprintf(stderr, "%s: can't fork: ", cmd_name); X perror(""); X return 1; X } X X if (pid == 0) { X execv(REAL_LD, argv); X fprintf(stderr, "%s: can't exec %s: ", cmd_name, REAL_LD); X perror(""); X exit(1); X } X else { X while (pid != wait(&status)) X ; X if (status.w_termsig == 0) X return status.w_retcode; X else { X fprintf(stderr, "%s: caught signal %d%s\n", X cmd_name, status.w_termsig, X (status.w_coredump ? " (core dumped)" : "")); X return 1; X } X } X} X X#ifdef __STDC__ Xstatic void Xcatch(void) X#else Xstatic void Xcatch() X#endif X{ X unlink(a_out); X unlink(ifile); X exit(1); X} X X#ifdef __STDC__ Xstatic void Xcheck_dates(const char *name) X#else Xstatic void Xcheck_dates(name) Xchar *name; X#endif X{ X struct stat buf1, buf2; X char *p, *strrchr(); X X p = strrchr(TARGET, '/'); X p = (p == NULL || strrchr(name, '/') != NULL) ? TARGET : p+1; X X if (strcmp(p, name) != 0) X return; X X if (stat(TARGET, &buf1) < 0) X return; X if (stat(SHLIB, &buf2) < 0) { X fprintf(stderr, "%s: can't stat %s: ", cmd_name, SHLIB); X perror(""); X exit(1); X } X if (buf1.st_mtime < buf2.st_mtime) { X fprintf(stderr, "%s: %s has changed -- %s must be remade\n", X cmd_name, SHLIB, TARGET); X exit(1); X } X} END_OF_FILE if test 4516 -ne `wc -c <'ld.c'`; then echo shar: \"'ld.c'\" unpacked with wrong size! fi # end of 'ld.c' fi if test -f 'ld.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'ld.h'\" else echo shar: Extracting \"'ld.h'\" \(548 characters\) sed "s/^X//" >'ld.h' <<'END_OF_FILE' X/* X * ld.h -- configuration stuff X * X * most of which is handled by the makefile X */ X X#ifndef SHLIB X#define SHLIB "/lib/shlib.ifile" X#endif X X#ifndef LIBMINIC X#define LIBMINIC "/usr/local/lib/libminic.a" X#endif X X#ifndef TARGET X#define TARGET "/usr/local/lib/gcc-ld" X#endif X X#ifndef REAL_LD X#define REAL_LD "/bin/ld" X#endif X X#ifdef __STDC__ Xextern int make_ifile(const char *a_out, const char *ifile); X#else Xextern int make_ifile(); X#endif X Xextern char *cmd_name; X X#ifdef __STDC__ X#ifndef __GNUC__ X#define inline X#endif X#else X#define const X#endif END_OF_FILE if test 548 -ne `wc -c <'ld.h'`; then echo shar: \"'ld.h'\" unpacked with wrong size! fi # end of 'ld.h' fi if test -f 'load.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'load.c'\" else echo shar: Extracting \"'load.c'\" \(2889 characters\) sed "s/^X//" >'load.c' <<'END_OF_FILE' X/* X * load.c -- find the unresolved symbols and build an ifile X * X * after the first load pass, the object is scanned for unsresolved X * symbols. each one is looked up in the compiled-in copy of the X * system ifile, and if found is added to a temporary ifile used in X * the second load pass. X * X */ X X#include <stdio.h> X#include <filehdr.h> X#include <syms.h> X#include <ldfcn.h> X X#include "ld.h" X Xstruct symbolentry { X char *name; X long addr; X}; X X#include "ifile.c" X Xextern void *malloc(); X X#ifdef __STDC__ Xstatic inline void Xlookup(const char *name, FILE *f) X#else Xstatic void Xlookup(name, f) Xchar *name; XFILE *f; X#endif X{ X int l, m, h, d; X X l = 0; X h = sizeof(symtable) / sizeof(struct symbolentry); X while (h >= l) { X m = (l + h) / 2; X d = strcmp(name, symtable[m].name); X if (d == 0) { X fprintf(f, "%s = %#.8x;\n", name, symtable[m].addr); X return; X } X if (d > 0) X l = m + 1; X else X h = m - 1; X } X} X X#ifdef __STDC__ Xint Xmake_ifile(const char *a_out, const char *ifile) X#else Xint Xmake_ifile(a_out, ifile) Xchar *a_out, *ifile; X#endif X{ X int i; X FILE *f; X LDFILE *ld; X SYMENT sym; X char *strtab = 0, *name; X static char sname[SYMNMLEN + 1]; X X ld = ldopen(a_out, (LDFILE *)0); X if (ld == NULL) { X fprintf(stderr, "%s: can't ldopen %s: ", cmd_name, a_out); X perror(""); X return -1; X } X f = fopen(ifile, "w"); X if (f == NULL) { X fprintf(stderr, "%s: can't fopen %s: ", cmd_name, ifile); X perror(""); X return -1; X } X X for (i=0; i<sizeof(header)/sizeof(char *); ++i) X fprintf(f, "%s\n", header[i]); X X for (i=0; i<HEADER(ld).f_nsyms; ++i) { X if (ldtbread(ld, i, &sym) != SUCCESS) { X fprintf(stderr, "%s: ldtbread failed: ", cmd_name); X perror(""); X return -1; X } X i += sym.n_numaux; X if (sym.n_value != 0 || sym.n_scnum != 0) X continue; X if (sym._n._n_n._n_zeroes == 0) { X if (strtab == 0) { X long size, count; X FSEEK(ld, HEADER(ld).f_symptr + HEADER(ld).f_nsyms * SYMESZ, 0); X if (FREAD(&size, sizeof(long), 1, ld) != 1) { X fprintf(stderr, "%s: read string table size: ", cmd_name); X perror(""); X return -1; X } X size -= sizeof(long); X strtab = (char *)malloc(size); X if (strtab == 0) { X fprintf(stderr, "%s: can't malloc: ", cmd_name); X perror(""); X return -1; X } X if ((count = FREAD(strtab, sizeof(char), size, ld)) != size) { X fprintf(stderr, X "%s: read string table: wanted %d, got %d: ", X cmd_name, size, count); X perror(""); X return -1; X } X } X name = &strtab[sym._n._n_n._n_offset - sizeof(long)]; X } X else { X strncpy(sname, sym._n._n_name, SYMNMLEN); X sname[SYMNMLEN] = '\0'; X name = sname; X } X lookup(name, f); X } X X ldclose(ld); X if (fclose(f) == EOF) { X fprintf(stderr, "%s: error closing %s: ", cmd_name, ifile); X perror(""); X return -1; X } X X if (strtab != 0) X free(strtab); X X return 0; X} END_OF_FILE if test 2889 -ne `wc -c <'load.c'`; then echo shar: \"'load.c'\" unpacked with wrong size! fi # end of 'load.c' fi if test -f 'munge.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'munge.c'\" else echo shar: Extracting \"'munge.c'\" \(1871 characters\) sed "s/^X//" >'munge.c' <<'END_OF_FILE' X/* X * Munge the /lib/shlib.ifile to produce ifile.c. X * X * This is basically taken from John MacMillan's shcc. X */ X X#include <stdio.h> X X#define INIT_SIZE 500 X Xstruct sym { X char *name; X long addr; X}; X Xmain() X{ X struct sym *symp; X char line[256], *p, *base; X int inheader = 1; X int size, count, i, cmp(); X long baseval; X long value(); X extern char *strchr(); X extern void *malloc(), *realloc(); X X printf("const char * const header[] = {\n"); X while (inheader && gets(line)) { X if (line[0] != ' ' && line[0] != '\t' && strchr(line, '=')) X inheader = 0; X else X printf(" \"%s\",\n", line); X } X printf("};\n\nconst struct symbolentry symtable[] = {\n"); X X size = INIT_SIZE; X count = 0; X symp = (struct sym *)malloc(size * sizeof(struct sym)); X do { X if (count == size) { X size *= 2; X free(symp); X symp = (struct sym *)realloc(size * sizeof(struct sym)); X } X p = strchr(line, ' '); X *p = '\0'; X symp[count].name = (char *)malloc(p - line + 1); X (void) strcpy(symp[count].name, line); X p = strchr(++p, '='); X p += 2; X if (*p == '0') { X p += 2; X sscanf(p, "%lx", &symp[count].addr); X } X else { X base = p; X p = strchr(p, ' '); X *p = '\0'; X baseval = value(symp, base, count); X p = strchr(++p, '+'); X p += 4; X sscanf(p, "%lx", &symp[count].addr); X symp[count].addr += baseval; X } X ++count; X } while (gets(line)); X X qsort(symp, count, sizeof(struct sym), cmp); X for (i=0; i<count; ++i) X printf(" {\"%s\", %#lx},\n", symp[i].name, symp[i].addr); X printf("};\n"); X exit(0); X} X Xlong Xvalue(symp, sym, count) Xstruct sym *symp; Xchar *sym; Xint count; X{ X int i; X X for (i=0; i<count; ++i) { X if (strcmp(symp[i].name, sym) == 0) X return(symp[i].addr); X } X return 0L; X} X Xint cmp(a, b) Xstruct sym *a, *b; X{ X return strcmp(a->name, b->name); X} END_OF_FILE if test 1871 -ne `wc -c <'munge.c'`; then echo shar: \"'munge.c'\" unpacked with wrong size! fi # end of 'munge.c' fi echo shar: End of shell archive. exit 0