# 2.11BSD#431 - /usr/src/ucb/symcompact.c

##### Functions

    cleanup           X
    exclude           X
    main              X

##### Variables

    Pgm               X

       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

- in line 55, 65-67(3), 279

exclude defined in line 295; used 2 times

- in line 140, 165

main defined in line 49; never used

#### Defined variables

Pgm defined in line 46; used 12 times

- in line 64, 71, 77, 85-90(2), 96, 110, 116, 128, 151, 221, 278

strtmp defined in line 47; used 6 times

- in line 216-221(4), 285-286(2)

Last modified: 1994-02-12 Generated: 2016-12-26 | Generated by src2html V0.67 page hit count: 826 |