|
DataMuseum.dkPresents historical artifacts from the history of: Commodore CBM-900 |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about Commodore CBM-900 Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - download
Length: 12200 (0x2fa8) Types: TextFile Notes: UNIX file Names: »slgen.c«
└─⟦f27320a65⟧ Bits:30001972 Commodore 900 hard disk image with partial source code └─⟦f4b8d8c84⟧ UNIX Filesystem └─⟦this⟧ »cmd/ld/slgen.c«
/* * 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); }