1: /*
   2:  *	Program Name:   symcompact.c
   3:  *	Date: January 21, 1994
   4:  *	Author: S.M. Schultz
   5:  *
   6:  *	-----------------   Modification History   ---------------
   7:  *      Version Date            Reason For Modification
   8:  *      1.0     21Jan94         1. Initial release into the public domain.
   9:  *	1.1	11Feb94		2. Remove register symbols to save memory.
  10: */
  11: 
  12: /*
  13:  * This program compacts the symbol table of an executable.  This is
  14:  * done by removing '~symbol' references when _both_ the '~symbol' and
  15:  * '_symbol' have an overlay number of 0.  The assembler always generates
  16:  * both forms.  The only time both forms are needed is in an overlaid
  17:  * program and the routine has been relocated by the linker, in that event
  18:  * the '_' form is the overlay "thunk" and the '~' form is the actual
  19:  * routine itself.  Only 'text' symbols have both forms.  Reducing the
  20:  * number of symbols greatly speeds up 'nlist' processing as well as
  21:  * cutting down memory requirements for programs such as 'adb' and 'nm'.
  22:  *
  23:  * NOTE: This program attempts to hold both the string and symbol tables
  24:  * in memory.  For the kernel which has not been 'strcompact'd this
  25:  * amounts to about 49kb.  IF this program runs out of memory you should
  26:  * run 'strcompact' first - that program removes redundant strings,
  27:  * significantly reducing the amount of memory needed.  Alas, this program
  28:  * will undo some of strcompact's work and you may/will need to run
  29:  * strcompact once more after removing excess symbols.
  30:  *
  31:  * Register symbols are removed to save memory.  This program was initially
  32:  * used with a smaller kernel, adding an additional driver caused the symbol
  33:  * table to grow enough that memory couldn't be allocated for strings.  See
  34:  * the comments in 'symorder.c' - they explain why register variables are
  35:  * no big loss.
  36: */
  37: 
  38: #include <stdio.h>
  39: #include <a.out.h>
  40: #include <ctype.h>
  41: #include <signal.h>
  42: #include <string.h>
  43: #include <sysexits.h>
  44: #include <sys/file.h>
  45: 
  46:     char    *Pgm;
  47: static  char    strtmp[20];
  48: 
  49: main(argc, argv)
  50:     int argc;
  51:     char    **argv;
  52:     {
  53:     FILE    *fp, *strfp;
  54:     int cnt, nsyms, len, c, symsremoved = 0, i;
  55:     void    cleanup();
  56:     char    *strtab;
  57:     char    fbuf1[BUFSIZ], fbuf2[BUFSIZ];
  58:     off_t   symoff, stroff, ltmp;
  59:     long    strsiz;
  60:     register struct nlist   *sp, *sp2;
  61:     struct  nlist   *symtab, *symtabend, syment;
  62:     struct  xexec   xhdr;
  63: 
  64:     Pgm = argv[0];
  65:     signal(SIGQUIT, cleanup);
  66:     signal(SIGINT, cleanup);
  67:     signal(SIGHUP, cleanup);
  68: 
  69:     if  (argc != 2)
  70:         {
  71:         fprintf(stderr, "%s: filename argument missing\n", Pgm);
  72:         exit(EX_USAGE);
  73:         }
  74:     fp = fopen(argv[1], "r+");
  75:     if  (!fp)
  76:         {
  77:         fprintf(stderr, "%s: can't open '%s' for update\n", Pgm,
  78:             argv[1]);
  79:         exit(EX_NOINPUT);
  80:         }
  81:     setbuf(fp, fbuf1);
  82:     cnt = fread(&xhdr, 1, sizeof (xhdr), fp);
  83:     if  (cnt < sizeof (xhdr.e))
  84:         {
  85:         fprintf(stderr, "%s: Premature EOF reading header\n", Pgm);
  86:         exit(EX_DATAERR);
  87:         }
  88:     if  (N_BADMAG(xhdr.e))
  89:         {
  90:         fprintf(stderr, "%s: Bad magic number\n", Pgm);
  91:         exit(EX_DATAERR);
  92:         }
  93:     nsyms = xhdr.e.a_syms / sizeof (struct nlist);
  94:     if  (!nsyms)
  95:         {
  96:         fprintf(stderr, "%s: '%s' stripped\n", Pgm);
  97:         exit(EX_OK);
  98:         }
  99:     stroff = N_STROFF(xhdr);
 100:     symoff = N_SYMOFF(xhdr);
 101: /*
 102:  * Seek to the string table size longword and read it.  Then attempt to
 103:  * malloc memory to hold the string table.  First make a sanity check on
 104:  * the size.
 105: */
 106:     fseek(fp, stroff, L_SET);
 107:     fread(&strsiz, sizeof (long), 1, fp);
 108:     if  (strsiz > 48 * 1024L)
 109:         {
 110:         fprintf(stderr, "%s: string table > 48kb\n", Pgm);
 111:         exit(EX_DATAERR);
 112:         }
 113:     strtab = (char *)malloc((int)strsiz);
 114:     if  (!strtab)
 115:         {
 116:         fprintf(stderr, "%s: no memory for strings\n", Pgm);
 117:         exit(EX_OSERR);
 118:         }
 119: /*
 120:  * Now read the string table into memory.  Reduce the size read because
 121:  * we've already retrieved the string table size longword.  Adjust the
 122:  * address used so that we don't have to adjust each symbol table entry's
 123:  * string offset.
 124: */
 125:     cnt = fread(strtab + sizeof (long), 1, (int)strsiz - sizeof (long), fp);
 126:     if  (cnt != (int)strsiz - sizeof (long))
 127:         {
 128:         fprintf(stderr, "%s: Premature EOF reading strings\n", Pgm);
 129:         exit(EX_DATAERR);
 130:         }
 131: /*
 132:  * Seek to the symbol table.  Scan it and count how many symbols are
 133:  * significant.
 134: */
 135:     fseek(fp, symoff, L_SET);
 136:     cnt = 0;
 137:     for (i = 0; i < nsyms; i++)
 138:         {
 139:         fread(&syment, sizeof (syment), 1, fp);
 140:         if  (exclude(&syment))
 141:             continue;
 142:         cnt++;
 143:         }
 144: 
 145: /*
 146:  * Allocate memory for the symbol table.
 147: */
 148:     symtab = (struct nlist *)malloc(cnt * sizeof (struct nlist));
 149:     if  (!symtab)
 150:         {
 151:         fprintf(stderr, "%s: no memory for symbols\n", Pgm);
 152:         exit(EX_OSERR);
 153:         }
 154: 
 155: /*
 156:  * Now read the symbols in, excluding the same ones as before, and
 157:  * assign the in-memory string addresses at the same time
 158: */
 159:     sp = symtab;
 160:     fseek(fp, symoff, L_SET);
 161: 
 162:     for (i = 0; i < nsyms; i++)
 163:         {
 164:         fread(&syment, sizeof (syment), 1, fp);
 165:         if  (exclude(&syment))
 166:             continue;
 167:         bcopy(&syment, sp, sizeof (syment));
 168:         sp->n_un.n_name = strtab + (int)sp->n_un.n_strx;
 169:         sp++;
 170:         }
 171:     symtabend = &symtab[cnt];
 172: 
 173: /*
 174:  * Now look for symbols with overlay numbers of 0 (root/base segment) and
 175:  * of type 'text'.  For each symbol found check if there exists both a '~'
 176:  * and '_' prefixed form of the symbol.  Preserve the '_' form and clear
 177:  * the '~' entry by zeroing the string address of the '~' symbol.
 178: */
 179:     for (sp = symtab; sp < symtabend; sp++)
 180:         {
 181:         if  (sp->n_ovly)
 182:             continue;
 183:         if  ((sp->n_type & N_TYPE) != N_TEXT)
 184:             continue;
 185:         if  (sp->n_un.n_name[0] != '~')
 186:             continue;
 187: /*
 188:  * At this point we have the '~' form of a non overlaid text symbol.  Look
 189:  * thru the symbol table for the '_' form.  All of 1) symbol type, 2) Symbol
 190:  * value and 3) symbol name (starting after the first character) must match.
 191: */
 192:         for (sp2 = symtab; sp2 < symtabend; sp2++)
 193:             {
 194:             if  (sp2->n_ovly)
 195:                 continue;
 196:             if  ((sp2->n_type & N_TYPE) != N_TEXT)
 197:                 continue;
 198:             if  (sp2->n_un.n_name[0] != '_')
 199:                 continue;
 200:             if  (sp2->n_value != sp->n_value)
 201:                 continue;
 202:             if  (strcmp(sp->n_un.n_name+1, sp2->n_un.n_name+1))
 203:                 continue;
 204: /*
 205:  * Found a match.  Null out the '~' symbol's string address.
 206: */
 207:             symsremoved++;
 208:             sp->n_un.n_strx = NULL;
 209:             break;
 210:             }
 211:         }
 212: /*
 213:  * Done with the nested scanning of the symbol table.  Now create a new
 214:  * string table (from the remaining symbols) in a temporary file.
 215: */
 216:     strcpy(strtmp, "/tmp/strXXXXXX");
 217:     mktemp(strtmp);
 218:     strfp = fopen(strtmp, "w+");
 219:     if  (!strfp)
 220:         {
 221:         fprintf(stderr, "%s: can't create '%s'\n", Pgm, strtmp);
 222:         exit(EX_CANTCREAT);
 223:         }
 224:     setbuf(strfp, fbuf2);
 225: 
 226: /*
 227:  * As each symbol is written to the tmp file the symbol's string offset
 228:  * is updated with the new file string table offset.
 229: */
 230:     ltmp = sizeof (long);
 231:     for (sp = symtab; sp < symtabend; sp++)
 232:         {
 233:         if  (!sp->n_un.n_name)
 234:             continue;
 235:         len = strlen(sp->n_un.n_name) + 1;
 236:         fwrite(sp->n_un.n_name, len, 1, strfp);
 237:         sp->n_un.n_strx = ltmp;
 238:         ltmp += len;
 239:         }
 240: /*
 241:  * We're done with the memory string table - give it back.  Then reposition
 242:  * the new string table file to the beginning.
 243: */
 244:     free(strtab);
 245:     rewind(strfp);
 246: 
 247: /*
 248:  * Position the executable file to where the symbol table begins.  Truncate
 249:  * the file.  Write out the valid symbols, counting each one so that the
 250:  * a.out header can be updated when we're done.
 251: */
 252:     nsyms = 0;
 253:     fseek(fp, symoff, L_SET);
 254:     ftruncate(fileno(fp), ftell(fp));
 255:     for (sp = symtab; sp < symtabend; sp++)
 256:         {
 257:         if  (sp->n_un.n_strx == 0)
 258:             continue;
 259:         nsyms++;
 260:         fwrite(sp, sizeof (struct nlist), 1, fp);
 261:         }
 262: /*
 263:  * Next write out the string table size longword.
 264: */
 265:     fwrite(&ltmp, sizeof (long), 1, fp);
 266: /*
 267:  * We're done with the in memory symbol table, release it.  Then append
 268:  * the string table to the executable file.
 269: */
 270:     free(symtab);
 271:     while   ((c = getc(strfp)) != EOF)
 272:         putc(c, fp);
 273:     fclose(strfp);
 274:     rewind(fp);
 275:     xhdr.e.a_syms = nsyms * sizeof (struct nlist);
 276:     fwrite(&xhdr.e, sizeof (xhdr.e), 1, fp);
 277:     fclose(fp);
 278:     printf("%s: %d symbols removed\n", Pgm, symsremoved);
 279:     cleanup();
 280:     }
 281: 
 282: void
 283: cleanup()
 284:     {
 285:     if  (strtmp[0])
 286:         unlink(strtmp);
 287:     exit(EX_OK);
 288:     }
 289: 
 290: /*
 291:  * Place any symbol exclusion rules in this routine, return 1 if the
 292:  * symbol is to be excluded, 0 if the symbol is to be retained.
 293: */
 294: 
 295: exclude(sp)
 296:     register struct nlist *sp;
 297:     {
 298: 
 299:     if  (sp->n_type == N_REG)
 300:         return(1);
 301:     if  (sp->n_un.n_strx == 0)
 302:         return(1);
 303:     return(0);
 304:     }

Defined functions

cleanup defined in line 282; used 5 times
exclude defined in line 295; used 2 times
main defined in line 49; never used

Defined variables

Pgm defined in line 46; used 12 times
strtmp defined in line 47; used 6 times
Last modified: 1994-02-12
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 3200
Valid CSS Valid XHTML 1.0 Strict