1: /* 2: * mkovmake.c by dennisf@ndcvx.cc.nd.edu March 1990 3: * makes an overlay makefile for specified object modules. 4: * v1.1: adds -v option, and #defines for ovinit and module[].overlay. 5: * v1.2: -o option renamed to -f, new -o and -l options for output name 6: * and libraries. 7: * v2: Overlay optimizer! Many changes, practically different program. 8: * v3: Modified to use new object file (strings table) format. 1/9/94 - sms. 9: */ 10: 11: #include <stdio.h> 12: #include <strings.h> 13: #include <ctype.h> 14: #include <sys/param.h> 15: #include <a.out.h> 16: #include <sys/file.h> 17: 18: #define MAXSYMLEN 32 19: #define IN_BASE 0 20: #define UNCOMMITTED -1 21: #define isobj(name) name[0] && name[0] != '-' && rindex(name,'.') \ 22: && !strcmp(rindex(name,'.'), ".o") 23: #define isarc(name) name[0] && name[0] != '-' && rindex(name,'.') \ 24: && !strcmp(rindex(name,'.'), ".a") 25: 26: struct modstruct 27: { 28: char *name; 29: unsigned text; 30: short overlay; 31: char **textnames; 32: char **undfnames; 33: } *module; 34: FILE *output; 35: char *malloc(), *realloc(), *adlib(), *libs; 36: int optimize, listnames; 37: double metoo(); 38: 39: main(argc, argv) 40: int argc; 41: char **argv; 42: { 43: register i, n; 44: int ovinit; /* initial ov number, IN_BASE or UNCOMMITTED */ 45: int j; /* redundant-module index */ 46: int nobj; /* number of modules, used for malloc()ing */ 47: long ovtext; /* total size of text of UNCOMMITTED modules */ 48: int ov; /* overlay number, used in for loop */ 49: int max_ovs; /* max number of ovs mkovmake can make */ 50: int ovs_used; /* number of ovs actually used */ 51: int modsleftout;/* number of modules not assigned to an ov */ 52: unsigned max_ovsize; /* sizeof biggest overlay, multiple of 8k */ 53: unsigned bigovmod; /* sizeof biggest module not assigned to base */ 54: unsigned ovspace; /* space occupied in current ov */ 55: unsigned basesize; /* limit on base, if optimizing */ 56: int mostroutines; /* module with biggest global text routines 57: per kb text ratio, if optimizing base */ 58: double baseopt; /* the best such ratio so far */ 59: int wannabe; /* module that most wants to be on the overlay, 60: if optimizing */ 61: double affinity;/* metoo(ov,wannabe) */ 62: double affinn; /* metoo(ov,n) */ 63: int Zused; /* -Z option specified somewhere used in -O2 */ 64: long tmpl; 65: char *makename, *program; 66: char *arg, switchc; 67: 68: /* Usage */ 69: if (argc == 1) 70: { 71: usage: fprintf(stderr, 72: "usage: mkovmake [-On [basesize] [-n]] [-fmakefile] [-sovsize] [-vmax_ovs]\n"); 73: fprintf(stderr, "\t\t[-oprogram] [-llibs ...] bases.o ... -Z ovmodules.o ...\n"); 74: exit(1); 75: } 76: 77: /* Set defaults */ 78: Zused = listnames = bigovmod = ovtext = nobj = optimize = 0; 79: output = stdout; 80: max_ovsize = basesize = UNCOMMITTED; 81: ovinit = IN_BASE; 82: max_ovs = NOVL; 83: program = "$(PROGRAM)"; 84: libs = malloc(2); 85: libs[0] = 0; 86: /* First parsing: get options, count object modules */ 87: for (i = 1; i < argc; ++i) 88: { 89: if (argv[i][0] != '-') 90: { 91: if (isobj(argv[i])) 92: ++nobj; 93: else if (isarc(argv[i])) 94: adlib(argv[i]); 95: else 96: { 97: fprintf(stderr, "mkovmake: %s: unknown file type.\n", 98: argv[i]); 99: exit(5); 100: } 101: } 102: else 103: { 104: switchc = argv[i][1]; 105: arg = argv[i] + 2; 106: if (!arg[0]) 107: arg = argv[++i]; 108: switch (switchc) 109: { 110: case 'O': 111: optimize = 1; /* Use given BASE */ 112: if (arg[0] == '2') 113: { 114: optimize = 2; /* Determine BASE */ 115: if (isdigit(argv[i+1][0])) 116: { 117: basesize = atoi(argv[++i]); 118: if (index(argv[i],'k') 119: || index(argv[i],'K')) 120: basesize *= 1024; 121: if (basesize < 10) 122: basesize *= 8192; 123: } 124: } 125: else 126: --i; /* no argument */ 127: break; 128: case 'n': 129: ++listnames; 130: --i; /* no argument */ 131: break; 132: case 'Z': 133: if (optimize != 2 && !nobj) 134: fprintf(stderr, "Nothing in the BASE? Ok...\n"); 135: ++Zused; 136: --i; /* no argument */ 137: break; 138: case 'f': 139: makename = arg; 140: if ((output = fopen(makename, "w")) == NULL) 141: { 142: fprintf(stderr, 143: "%s: cannot open for output.\n", makename); 144: exit(2); 145: } 146: break; 147: case 's': 148: max_ovsize = atoi(arg); 149: if (index(arg,'k') || index(arg,'K')) 150: max_ovsize *= 1024; 151: if (max_ovsize < 10) 152: max_ovsize *= 8192; 153: break; 154: case 'v': 155: max_ovs = atoi(arg); 156: if (max_ovs > NOVL) 157: { 158: fprintf(stderr, 159: "mkovmake: can only use %d overlays.\n", 160: NOVL); 161: max_ovs = NOVL; 162: } 163: break; 164: case 'o': 165: program = arg; 166: break; 167: case 'l': 168: adlib("-l"); 169: adlib(arg); 170: break; 171: default: 172: goto usage; 173: } 174: } 175: } 176: if (!libs[0]) 177: { 178: free(libs); 179: libs = "$(LIBS) "; 180: } 181: if (!Zused && optimize == 2) 182: ovinit = UNCOMMITTED; 183: 184: /* Second parsing: malloc for module[] array and load its members */ 185: if (!(module = (struct modstruct *) malloc(sizeof(struct modstruct) * ++nobj))) 186: { 187: fprintf(stderr, "mkovmake: not enough memory for module list.\n"); 188: fprintf(stderr, "mkovmake: can't use mkovmake! Help!\n"); 189: exit(6); 190: } 191: for (i = 1, n = 0; i < argc; ++i) 192: { 193: for (j = 1; j < i; ++j) 194: if (!strcmp(argv[i], argv[j])) 195: break; 196: if (argv[i][0] == '-' && argv[i][1] == 'Z') 197: ovinit = UNCOMMITTED; 198: else if (j == i && isobj(argv[i])) 199: { 200: module[n].name = argv[i]; 201: module[n].overlay = ovinit; 202: getnames(n); /* gets sizeof text and name lists */ 203: if (ovinit != IN_BASE) 204: { 205: ovtext += module[n].text; 206: if (module[n].text > bigovmod) 207: bigovmod = module[n].text; 208: } 209: ++n; 210: } 211: } 212: module[n].name = ""; 213: if (max_ovsize == UNCOMMITTED) 214: { 215: max_ovsize = (unsigned) (ovtext / (7680L * max_ovs) + 1) * 8192; 216: if (bigovmod > max_ovsize) 217: max_ovsize = (bigovmod / 8192 + 1) * 8192; 218: fprintf(output, "# Using %dk overlays.\n", max_ovsize/1024); 219: } 220: 221: /* 222: * Optimizer levels: 223: * 1: use given BASE, all other modules are UNCOMMITTED. 224: * 2: determine BASE, all modules are UNCOMMITTED. 225: * 3: programmer gets COMMITTED. 226: */ 227: if (optimize == 2) 228: { 229: if (basesize == UNCOMMITTED) 230: { 231: /* is this a fudge or what?? */ 232: tmpl = ((tmpl = 2048 + nlibs()*2048L + ovtext/5) 233: > 24576L) ? 24576L : tmpl; 234: basesize = (65536L - max_ovsize - tmpl); 235: fprintf(output, "# Using %u-byte base, without libraries.\n", 236: basesize); 237: /* If enough people are interested, I'll make a version 238: of this that adds up routines used within libraries */ 239: } 240: n = -1; 241: while (module[++n].name[0]) 242: if (module[n].overlay == IN_BASE) 243: basesize -= module[n].text; 244: if (basesize < 0) 245: { 246: fprintf(stderr, "mkovmake: specified modules don't fit in base.\n"); 247: fprintf(stderr, "mkovmake: specify fewer modules or larger base.\n"); 248: exit(9); 249: } 250: do /* load the base */ 251: { 252: baseopt = 0.; 253: n = -1; 254: while(module[++n].name[0]) 255: if (module[n].overlay != IN_BASE 256: && module[n].text 257: && module[n].text <= basesize 258: && (double) (sizeof(module[n].textnames)-1) 259: / module[n].text > baseopt) 260: { 261: mostroutines = n; 262: baseopt = (double) 263: (sizeof(module[n].textnames)-1) 264: / module[n].text; 265: } 266: if (baseopt) 267: { 268: module[mostroutines].overlay = IN_BASE; 269: basesize -= module[mostroutines].text; 270: } 271: } while(baseopt); 272: } 273: listmodules(IN_BASE); 274: 275: /* 276: * overlay packing: 277: * If not optimizing, just pack modules until no more can fit. 278: * Otherwise, add a module only if it's the one thats to be on 279: * the ov the most, using metoo(). 280: */ 281: for (ov = 1; ov <= max_ovs; ++ov) 282: { 283: ovspace = 0; 284: addmod: n = -1; 285: while (module[++n].name[0]) 286: { 287: if (module[n].overlay == UNCOMMITTED 288: && module[n].text + ovspace <= max_ovsize) 289: { 290: module[n].overlay = ov; 291: ovspace += module[n].text; 292: /* optimizer needs one */ 293: if (optimize && module[n].text) 294: break; 295: } 296: } 297: if (!ovspace) /* max_ovsize is too small for a module */ 298: break; 299: if (optimize && module[n].name[0]) 300: { 301: for (;;) /* only escape is the goto! yuck! */ 302: { 303: affinity = 0.; 304: n = -1; 305: while (module[++n].name[0]) 306: { 307: if (module[n].overlay == UNCOMMITTED 308: && module[n].text 309: && module[n].text + ovspace <= max_ovsize 310: && (affinn = metoo(ov,n)) > affinity) 311: { 312: wannabe = n; 313: affinity = affinn; 314: } 315: } 316: if (!affinity) 317: goto addmod; /* will another mod fit? */ 318: module[wannabe].overlay = ov; 319: ovspace += module[wannabe].text; 320: } 321: } 322: listmodules(ov); 323: } 324: ovs_used = ov; 325: 326: /* And what if they just don't all fit? */ 327: n = modsleftout = 0; 328: while (module[n].name[0]) 329: if (module[n++].overlay == UNCOMMITTED) 330: ++modsleftout; 331: if (modsleftout) 332: { 333: fprintf(stderr, "\nAfter %d overlay", ovs_used-1); 334: if (ovs_used != 2) fprintf(stderr, "s"); 335: fprintf(stderr, ", the following "); 336: if (modsleftout == 1) 337: fprintf(stderr, "module was\n"); 338: else 339: fprintf(stderr, "%d modules were\n", modsleftout); 340: fprintf(stderr, 341: "left out of the BASE and OVerlay definitions:\n"); 342: n = -1; 343: while (module[++n].name[0]) 344: if (module[n].overlay == UNCOMMITTED) 345: fprintf(stderr, " %s\n", module[n].name); 346: fprintf(stderr, 347: "\nYou can 1) Use more or bigger overlays,\n"); 348: fprintf(stderr, " 2) Use a smaller base, or\n"); 349: fprintf(stderr, " 3) \"Go buy a VAX.\"\n"); 350: fclose(output); 351: exit(3); 352: } 353: 354: fprintf(output, 355: "%s:\n\t/bin/ld -i -X -o %s /lib/crt0.o \\\n\t", program, program); 356: fprintf(output, "$(BASE) "); 357: for (ov = 1; ov < ovs_used; ++ov) 358: { 359: if (ov % 4 == 1) 360: fprintf(output, "\\\n\t"); 361: fprintf(output, "-Z $(OV%d) ", ov); 362: } 363: fprintf(output, "\\\n\t-Y %s-lc\n", libs); 364: fclose(output); 365: free((char *) module); 366: free(libs); 367: exit(0); 368: } 369: 370: /* 371: * listmodules(ov) 372: * lists modules in overlay ov (ov=0 is BASE), each line 373: * preceded by a tab and not exceeding LISTWIDTH characters. 374: */ 375: 376: #define LISTWIDTH 60 377: 378: listmodules(ov) 379: int ov; 380: { 381: int currentwidth = 0, n = -1, namelength; 382: unsigned listovspace = 0; 383: 384: if (ov == IN_BASE) 385: fprintf(output, "\nBASE=\t"); 386: else 387: fprintf(output, "OV%d=\t", ov); 388: while (module[++n].name[0]) 389: { 390: if (module[n].overlay == ov) 391: { 392: namelength = strlen(module[n].name); 393: if (currentwidth + namelength > LISTWIDTH) 394: { 395: fprintf(output, "\\\n\t"); 396: currentwidth = 0; 397: } 398: currentwidth += (namelength + 1); 399: fprintf(output, "%s ", module[n].name); 400: listovspace += module[n].text; 401: } 402: } 403: fprintf(output, "\n# %u bytes.\n\n", listovspace); 404: } 405: 406: /* 407: * metoo() returns how much a module wants to be on an overlay. 408: */ 409: double 410: metoo(ov, mod) 411: int ov, mod; 412: { 413: int n, postnews; 414: 415: if (!module[mod].text) 416: return(0.); 417: postnews = 0; 418: n = -1; 419: while (module[++n].name[0]) 420: if (module[n].overlay == ov) 421: postnews += ilikeu(n, mod) + ilikeu(mod, n); 422: return((double) postnews / module[mod].text); 423: } 424: 425: /* 426: * ilikeu() returns how much one module likes another. 427: * Just like life, it's not necessarily symmetrical. 428: */ 429: ilikeu(me, you) 430: int me, you; 431: { 432: int friendly; 433: char **ineed, **youhave; 434: 435: friendly = 0; /* Who are you? */ 436: ineed = module[me].undfnames; 437: youhave = module[you].textnames; 438: while(**ineed) 439: { 440: while(**youhave) 441: { 442: if (!strcmp(*ineed, *youhave++)) 443: { 444: ++friendly; 445: break; 446: } 447: } 448: ++ineed; 449: } 450: return(friendly); 451: } 452: 453: /* 454: * adlib(s) adds s onto libs. 455: */ 456: char * 457: adlib(s) 458: char *s; 459: { 460: char *morelibs; 461: 462: if (!(morelibs = realloc(libs, strlen(libs)+strlen(s)+3))) 463: { 464: fprintf(stderr, "mkovmake: not enough memory for library names.\n"); 465: exit(7); 466: } 467: strcat(morelibs, s); 468: if (s[0] != '-') 469: strcat(morelibs, " "); 470: libs = morelibs; 471: return(morelibs); 472: } 473: 474: /* 475: * nlibs() How many libs are there? 476: */ 477: nlibs() 478: { 479: int i=0; 480: char *s; 481: s = libs; 482: while (*s) 483: if (*s++ == ' ') 484: ++i; 485: return(i); 486: } 487: 488: /* 489: * getnames(n) opens object module n and gets size of text, 490: * and name lists if using optimizer. 491: */ 492: getnames(n) 493: int n; 494: { 495: struct xexec exp; 496: struct nlist namentry; 497: FILE *obj, *strfp = NULL; 498: off_t stroff; 499: int nundf, ntext; 500: char name[MAXSYMLEN + 2]; 501: 502: bzero(name, sizeof (name)); 503: if ((obj = fopen(module[n].name,"r")) == NULL) 504: { 505: fprintf(stderr, "mkovmake: cannot open %s.\n", module[n].name); 506: exit(8); 507: } 508: fread((char *)&exp, 1, sizeof(exp), obj); 509: module[n].text = exp.e.a_text; 510: if (!optimize) 511: { 512: fclose(obj); 513: return(0); 514: } 515: 516: fseek(obj, N_SYMOFF(exp), L_SET); 517: 518: ntext = nundf = 0; 519: while (fread((char *)&namentry, sizeof(namentry), 1, obj) == 1) 520: { 521: if (feof(obj) || ferror(obj)) 522: break; 523: if (namentry.n_type & N_EXT) 524: { 525: switch (namentry.n_type&N_TYPE) 526: { 527: case N_UNDF: 528: if (!namentry.n_value) 529: ++nundf; 530: break; 531: case N_TEXT: 532: ++ntext; 533: break; 534: } 535: } 536: } 537: module[n].textnames = (char **) malloc(++ntext * 2); 538: module[n].undfnames = (char **) malloc(++nundf * 2); 539: if (!module[n].textnames || !module[n].undfnames) 540: { 541: nosyms: fprintf(stderr, "mkovmake: out of memory for symbols list.\n"); 542: fprintf(stderr, "mkovmake: can't optimize.\n"); 543: optimize = 0; 544: fclose(obj); 545: if (strfp) 546: fclose(strfp); 547: return(1); 548: } 549: 550: strfp = fopen(module[n].name, "r"); 551: ntext = nundf = 0; 552: fseek(obj, N_SYMOFF(exp), L_SET); 553: stroff = N_STROFF(exp); 554: while (fread((char *)&namentry, sizeof(namentry), 1, obj) == 1) 555: { 556: if (namentry.n_type & N_EXT) 557: { 558: switch (namentry.n_type&N_TYPE) 559: { 560: case N_UNDF: 561: if (!namentry.n_value) 562: { 563: fseek(strfp, 564: stroff + namentry.n_un.n_strx, 565: L_SET); 566: fread(name, sizeof (name), 1, strfp); 567: if (!(module[n].undfnames[nundf] 568: = strdup(name))) 569: goto nosyms; 570: nundf++; 571: if (listnames) 572: pname(n, name, 0); 573: } 574: break; 575: case N_TEXT: 576: fseek(strfp, stroff + namentry.n_un.n_strx, 577: L_SET); 578: fread(name, sizeof (name), 1, strfp); 579: if (!(module[n].textnames[ntext]= strdup(name))) 580: goto nosyms; 581: ntext++; 582: if (listnames) 583: pname(n,name,1); 584: break; 585: } 586: } 587: } 588: module[n].undfnames[nundf] = ""; 589: module[n].textnames[ntext] = ""; 590: fclose(obj); 591: fclose(strfp); 592: return(0); 593: } 594: 595: /* 596: * pname(n,s,t) 597: * prints global Text(t=1) and Undf(t=0) name s encountered in module n. 598: */ 599: pname(n,s,t) 600: int n,t; 601: char *s; 602: { 603: if (t) 604: fprintf(stderr, "%s: T %s\n", module[n].name, s); 605: else 606: fprintf(stderr, "%s: U %s\n", module[n].name, s); 607: }