1: /* 2: * Program Name: strcompact.c 3: * Date: February 12, 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: * 2.0 12Feb94 2. Rewrite. Use new utility program 'symdump' 10: * and a multi-key sort to not only create 11: * shared symbol strings but remove identical 12: * symbols (identical absolute local symbols 13: * are quite common). Execution speed was 14: * speed up by about a factor of 4. 15: */ 16: 17: /* 18: * This program compacts the string table of an executable image by 19: * preserving only a single string definition of a symbol and updating 20: * the symbol table string offsets. Multiple symbols having the same 21: * string are very common - local symbols in a function often have the 22: * same name ('int error' inside a function for example). This program 23: * reduced the string table size of the kernel at least 25%! 24: * 25: * In addition, local symbols with the same value (frame offset within 26: * a function) are very common. By retaining only a single '~error=2' 27: * for example the symbol table is reduced even further (about 500 symbols 28: * are removed from a typical kernel). 29: */ 30: 31: #include <stdio.h> 32: #include <a.out.h> 33: #include <signal.h> 34: #include <string.h> 35: #include <sysexits.h> 36: #include <sys/file.h> 37: 38: char *Pgm; 39: char *Sort = "/usr/bin/sort"; 40: char *Symdump = "/usr/ucb/symdump"; 41: static char strfn[32], symfn[32]; 42: 43: main(argc, argv) 44: int argc; 45: char **argv; 46: { 47: struct nlist sym; 48: char buf1[128], symname[64], savedname[64]; 49: struct xexec xhdr; 50: int nsyms, len; 51: FILE *symfp, *strfp, *sortfp; 52: register FILE *fpin; 53: long stroff; 54: unsigned short type, value, ovly; 55: void cleanup(); 56: 57: Pgm = argv[0]; 58: signal(SIGQUIT, cleanup); 59: signal(SIGINT, cleanup); 60: signal(SIGHUP, cleanup); 61: 62: if (argc != 2) 63: { 64: fprintf(stderr, "%s: missing filename argument\n", Pgm); 65: exit(EX_USAGE); 66: } 67: fpin = fopen(argv[1], "r+"); 68: if (!fpin) 69: { 70: fprintf(stderr, "%s: can not open '%s' for update\n", 71: Pgm, argv[1]); 72: exit(EX_NOINPUT); 73: } 74: if (fread(&xhdr, 1, sizeof (xhdr), fpin) < sizeof (xhdr.e)) 75: { 76: fprintf(stderr, "%s: premature EOF\n", Pgm); 77: exit(EX_DATAERR); 78: } 79: if (N_BADMAG(xhdr.e)) 80: { 81: fprintf(stderr, "%s: Bad magic number\n", Pgm); 82: exit(EX_DATAERR); 83: } 84: nsyms = xhdr.e.a_syms / sizeof (struct nlist); 85: if (!nsyms) 86: { 87: fprintf(stderr, "%s: '%s' stripped\n", Pgm, argv[1]); 88: exit(EX_OK); 89: } 90: 91: strcpy(strfn, "/tmp/strXXXXXX"); 92: mktemp(strfn); 93: strcpy(symfn, "/tmp/symXXXXXX"); 94: mktemp(symfn); 95: 96: sprintf(buf1, "%s %s | %s +0 -1 +1n -2 +2n -3 +3n -4 -u", Symdump, 97: argv[1], Sort); 98: sortfp = popen(buf1, "r"); 99: if (!sortfp) 100: { 101: fprintf(stderr, "%s: symdump | sort failed\n", Pgm); 102: exit(EX_SOFTWARE); 103: } 104: symfp = fopen(symfn, "w+"); 105: strfp = fopen(strfn, "w+"); 106: if (!symfp || !strfp) 107: { 108: fprintf(stderr, "%s: can't create %s or %s\n", symfn, strfn); 109: exit(EX_CANTCREAT); 110: } 111: 112: stroff = sizeof (long); 113: len = 0; 114: nsyms = 0; 115: while (fscanf(sortfp, "%s %u %u %u\n", symname, &type, &ovly, 116: &value) == 4) 117: { 118: if (strcmp(symname, savedname)) 119: { 120: stroff += len; 121: len = strlen(symname) + 1; 122: fwrite(symname, len, 1, strfp); 123: strcpy(savedname, symname); 124: } 125: sym.n_un.n_strx = stroff; 126: sym.n_type = type; 127: sym.n_ovly = ovly; 128: sym.n_value = value; 129: fwrite(&sym, sizeof (sym), 1, symfp); 130: nsyms++; 131: } 132: stroff += len; 133: 134: pclose(sortfp); 135: rewind(symfp); 136: rewind(strfp); 137: 138: if (nsyms == 0) 139: { 140: fprintf(stderr, "%s: No symbols - %s not modified\n", argv[1]); 141: cleanup(); 142: } 143: 144: fseek(fpin, N_SYMOFF(xhdr), L_SET); 145: 146: /* 147: * Now append the new symbol table. Then write the string table length 148: * followed by the string table. Finally truncate the file to the new 149: * length, reflecting the smaller string table. 150: */ 151: copyfile(symfp, fpin); 152: fwrite(&stroff, sizeof (long), 1, fpin); 153: copyfile(strfp, fpin); 154: ftruncate(fileno(fpin), ftell(fpin)); 155: 156: /* 157: * Update the header with the correct symbol table size. 158: */ 159: rewind(fpin); 160: xhdr.e.a_syms = nsyms * sizeof (sym); 161: fwrite(&xhdr, sizeof (xhdr.e), 1, fpin); 162: 163: fclose(fpin); 164: fclose(symfp); 165: fclose(strfp); 166: cleanup(); 167: } 168: 169: copyfile(in, out) 170: register FILE *in, *out; 171: { 172: register int c; 173: 174: while ((c = getc(in)) != EOF) 175: putc(c, out); 176: } 177: 178: fatal(str) 179: char *str; 180: { 181: 182: if (strfn[0]) 183: unlink(strfn); 184: if (symfn[0]) 185: unlink(symfn); 186: if (!str) 187: exit(EX_OK); 188: fprintf(stderr, "%s: %s\n", str); 189: exit(EX_SOFTWARE); 190: } 191: 192: void 193: cleanup() 194: { 195: fatal((char *)NULL); 196: }