home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / oxcc1433.zip / SRC / OXCCL.C < prev    next >
C/C++ Source or Header  |  1995-11-05  |  82KB  |  3,716 lines

  1. /*
  2.     oxccl.c -- v1.430 architecture neutral format (anf) linker
  3.  
  4.     Copyright (c) 1995
  5.     Norman D. Culver dba
  6.     Oxbow Software
  7.     1323 S.E. 17th Street #662
  8.     Ft. Lauderdale, FL 33316
  9.     (305) 527-1663 Voice
  10.     (305) 760-7584 Fax
  11.     (305) 760-4679 Data
  12.     norman.culver@channel1.com
  13.     All rights reserved.
  14.  
  15.  * Redistribution and use in source and binary forms are permitted
  16.  * provided that: (1) source distributions retain this entire copyright
  17.  * notice and comment, and (2) distributions including binaries display
  18.  * the following acknowledgement:  ``This product includes software
  19.  * developed by Norman D. Culver dba Oxbow Software''
  20.  * in the documentation or other materials provided with the distribution
  21.  * and in all advertising materials mentioning features or use of this
  22.  * software.
  23.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  24.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  25.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  26.  
  27. */
  28. #define MAJOR_VERSION 1
  29. #define MINOR_VERSION 433
  30.  
  31. #include <stdlib.h>
  32. #include <string.h>
  33. #include <stdio.h>
  34. #include <setjmp.h>
  35.  
  36. #define NEED_FUNCTHUNK 1
  37. #define NEED_ANFDEFS 1
  38. #include "oxanf.h"
  39.  
  40. #define PROG oxccl
  41. #define USING_FRAMEWORK 1
  42. #define HOST_IS_LITTLE_ENDIAN 1
  43. #define REALLY_NEED_OFFSETS 0
  44.  
  45. #define PRINTF printf
  46. #define VFPRINTF(a,b) vfprintf(stderr,a,b)
  47. #define PERROR prerror
  48. #define PWARN prwarn
  49. static void prerror(const char*, ...);
  50. static void prwarn(const char*, ...);
  51.  
  52. #define FILEWRITE(buf, cnt)\
  53. {if(!iv->errors){if(fwrite(buf, 1, cnt, iv->outfile) != cnt)iv->errors = 12;}}
  54. #define ROUNDING(a,b) ((b-(a&(b-1)))&(b-1))
  55. #define ROUNDUP(a,b) a += ROUNDING(a,b)
  56.  
  57. /* ======================== CONCATENIZATION MACROS ==================== */
  58.  
  59. #define    _cat2_(a, b)    a##b
  60. #define _cat_(a, b)    _cat2_(a, b)
  61. #define Global(a) _cat_(PROG, a)
  62.  
  63. #define _pname2_(x)    #x
  64. #define _pname1_(x)    _pname2_(x)
  65. #define pName        _pname1_(PROG)
  66.  
  67.  
  68. /* ============== ENDIAN MACROS (input format is litle endian) ==== */
  69.  
  70. #if HOST_IS_LITTLE_ENDIAN
  71. #define GL(a) a
  72. #define GS(a) a
  73. #define PL(a) a
  74. #define PS(a) a
  75. #else
  76. #endif
  77.  
  78. /* =================== INPUT DATA FORMATS ========================== */
  79.  
  80. #define INFILE_SYMNUM 1
  81. #define OUTFILE_SYMNUM 2
  82.  
  83.  
  84. /* ====================== STRUCTURES AND TYPEDEFS ======================== */
  85.  
  86. typedef struct _jl {
  87.     struct _jl *next;
  88.     void *p;
  89.     char *q;
  90.     long *plabelval;
  91.     long offset;
  92. } *PJL;
  93.  
  94. typedef struct _afile {
  95.     unsigned char *file_p;
  96.     PopI header_p;
  97.     PopI size_p;
  98.     unsigned char *symtext_p;
  99.     unsigned char *prog_p;
  100.     unsigned char *data_p;
  101.     unsigned char *switch_p;
  102.     unsigned char *decl_p;
  103.     unsigned char *maxtemp_p;
  104.     unsigned char *seg_p;
  105.     unsigned char **symaddr;
  106.     unsigned char **decladdr;
  107.     unsigned long thunk_offset;
  108.     unsigned long bss_offset;
  109.     int maxtemp;
  110.     int maxtempclass;
  111.     void *datatbl;
  112.     short *symtran;
  113.     unsigned short *decltran;
  114.     int filenum;
  115.     int numsyms;
  116.     int numdecls;
  117.     int numrelocs;
  118.     int numsegs;
  119. } *Pafile;
  120.  
  121. typedef struct _iv {
  122.     int category;
  123.     FILE *outfile;
  124.     int remove_infile;
  125.     int argc;
  126.     char **argv;
  127.     unsigned char **symaddr;
  128.     unsigned char **decladdr;
  129.     int numfiles;
  130.     int lastlabel;
  131.     int errors;
  132.     int numsyms;
  133.     int numdecls;
  134.     int numsegs;
  135.     int maxtemp;
  136.     int maxtempclass;
  137.     unsigned long total_size;
  138.     unsigned long thunk_offset;
  139.     unsigned long bss_offset;
  140.     long first_temp;
  141.     long killop;
  142.     void *reloctbl;
  143.     void *extrntbl;
  144.     void *gbltbl;
  145.     void *symtbl;
  146.     void *labeltbl;
  147.     void *newlabeltbl;
  148.     void *tmptbl;
  149.     void *segtbl;
  150.     int temps_written;
  151.     unsigned char *obuf;
  152.     unsigned char *obufstart;
  153.     PJL jbuf;
  154.     void *jbufstart;
  155.     int jmpcnt;
  156.     int jbufcnt;
  157.     long obufcnt;
  158.     long out_offset;
  159.     long func_offset;
  160.     int filenum;
  161.     Pafile files[1024];
  162.     char debug;
  163.     char only_debug;
  164.     char strip;
  165. } *Piv;
  166.  
  167. struct _gloval {
  168.     char *symname;
  169.     unsigned char *p;
  170.     Pafile pf;
  171.     int symnum;
  172. };
  173.  
  174.  
  175. /* Internal User API */
  176. static void *Cmalloc(int category, unsigned amount);
  177. static void *Ccalloc(int category, unsigned nelems, unsigned elemsize);
  178. static void *Crealloc(int category, void* buf, unsigned newsize);
  179. static void Cfree(int category, void* buf);
  180. static void Cfreecat(int category);
  181. static int Cmemrange(int category, unsigned* minp, unsigned* maxp);
  182. static int Cusedrange(int category, unsigned* minp, unsigned* maxp);
  183. static void Ctotrange(unsigned* minp,unsigned* maxp);
  184. static int Cnewcat(void);
  185. static void Cguard(int category);
  186. static void* NewSymTable(int category, int nbins);
  187. static int SymFind(void *tbl, void *key, void *result);
  188. static int SymFindRange(void *tbl, void *key, void *result);
  189. static void *SymInsert(void *tbl, void *key, void *value, int datsiz);
  190. static int StringInsert(void *tbl, char *string, void *result);
  191. static int StringFind(void *tbl, char *string, void *result);
  192. static void SymDelete(void *tbl, void *key);
  193. static int SymHead(void *tbl);
  194. static int SymNext(void *tbl);
  195. static void SymGetMark(void *tbl, void *markptr);
  196. static int SymMarkNext(void *tbl, void *mark);
  197. static void SymSetMark(void *tbl, void *markptr);
  198. static void SymKey(void *tbl, void *keyptr);
  199. static void SymValue(void *tbl, void *datptr);
  200. static void *seg_find(Piv iv, int id);
  201. static char *filenameof(char *path);
  202. static char *propernameof(Piv iv, char *name);
  203.  
  204. /* END: User API */
  205.  
  206. /* ====================== PUT UNIQUE CODE HERE ========================= */
  207. /* ===================== LINKER OUTPUT GENERATOR ======================= */
  208. static void
  209. gen_infop3(Piv iv, int op, long a, long b, long c)
  210. {
  211. struct {
  212.     unsigned char op[2];
  213.     short pad;
  214.     long next;
  215.     long a;
  216.     long b;
  217.     long c;
  218. }immed;
  219.  
  220.     immed.op[0] = op;
  221.     immed.op[1] = OPIMMED3|12;
  222.     immed.pad = 0;
  223.     immed.next = sizeof(immed);
  224.     immed.a = a;
  225.     immed.b = b;
  226.     immed.c = c;
  227.     FILEWRITE(&immed, sizeof(immed))
  228. }
  229. static void
  230. gen_infop1(Piv iv, int op, long a)
  231. {
  232. struct {
  233.     unsigned char op[2];
  234.     short pad;
  235.     long next;
  236.     long a;
  237. }immed;
  238.  
  239.     immed.op[0] = op;
  240.     immed.op[1] = OPIMMED1|4;
  241.     immed.pad = 0;
  242.     immed.next = sizeof(immed);
  243.     immed.a = a;
  244.     FILEWRITE(&immed, sizeof(immed))
  245. }
  246. static void
  247. gen_infop0(Piv iv, int op)
  248. {
  249. struct {
  250.     unsigned char op[2];
  251.     short pad;
  252.     long next;
  253. }immed;
  254.  
  255.     immed.op[0] = op;
  256.     immed.op[1] = 0;
  257.     immed.pad = 0;
  258.     immed.next = sizeof(immed);
  259.     FILEWRITE(&immed, sizeof(immed))
  260. }
  261.  
  262. static void
  263. dump_header(Piv iv)
  264. {
  265. Pafile pf;
  266. unsigned char *p, *next;
  267.     pf = iv->files[0];
  268.     p = pf->file_p;
  269.     next = POP->next;
  270.     PL(POP->next) = (void*)20;        /* unlink node */
  271.     FILEWRITE(p, 20)
  272.     PL(POP->next) = next;    /* relink node */
  273.     gen_infop3(iv, dataop, iv->total_size, iv->thunk_offset, iv->bss_offset);
  274. }
  275. static void
  276. dump_symbols(Piv iv)
  277. {
  278. extern void *Cmalloc();
  279. int sym_offset = 0;
  280. int pad;
  281. int i;
  282. int *symlens = Cmalloc(iv->category, sizeof(int)*iv->numsyms);
  283.  
  284.     /* Symbol Count */
  285.     gen_infop1(iv, symbop, iv->numsyms);
  286.     /* Symbol offsets */
  287.     for(i = 0; i < iv->numsyms; ++i)
  288.     {
  289.         gen_infop1(iv, symoffsetop, sym_offset);
  290.         symlens[i] = strlen(iv->symaddr[i])+1;
  291.         sym_offset += symlens[i];
  292.     }
  293.  
  294.     /* Contiguous block of symbol strings */
  295.     gen_infop1(iv, symblockop,sym_offset);    
  296.     for(i = 0; i < iv->numsyms; ++i) {
  297.         FILEWRITE(iv->symaddr[i], symlens[i])
  298.     }
  299.  
  300.     /* Alignment is 4 bytes */
  301.     pad = (4-(sym_offset&3))&3;
  302.     if(pad == 1)
  303.         FILEWRITE("", 1)
  304.     else if(pad == 2)
  305.         FILEWRITE(" ", 2)
  306.     else if(pad == 3)
  307.         FILEWRITE("  ", 3)
  308. }
  309. static void
  310. dump_files(Piv iv)
  311. {
  312. Pafile pf;
  313. unsigned char *p, *next;
  314. int i, dsize;
  315.  
  316.     /* Output could be neatened up by collecting various subgroups
  317.         but it would require several passes over the files */
  318.     
  319.     for(i = 0; i < iv->numfiles; ++i)
  320.     {
  321.         pf = iv->files[i];
  322.         p = pf->file_p;
  323.         while(*p != endfileop)
  324.         {
  325.             next = POP->next;
  326.             dsize = 0;
  327.  
  328.             switch(*p)
  329.             {
  330.                 case    0:
  331.                 case    headerop:
  332.                 case    dataop:
  333.                 case    symoffsetop:
  334.                 case    symblockop:
  335.                 case    symbop:
  336.                     break;
  337.                 case    stringblockop:
  338.                 case    datablockop:
  339.                 case    mallocblockop:
  340.                 case    thunkblockop:
  341.                     dsize = GL(POP->data);
  342.                     dsize += ((4-(dsize&3))&3); /* alignment */
  343.                 /* FALL THROUGH */
  344.                 default:
  345.                 {
  346.                 size_t size = next - p;
  347.                     PL(POP->next) = (void*)(size - dsize);    /* unlink node */
  348.                     FILEWRITE(p, size)
  349.                     break;
  350.                 }
  351.             }
  352.             p = next;
  353.         }
  354.     }
  355. }
  356. static void
  357. dump_trailer(Piv iv)
  358. {
  359.     gen_infop0(iv, endfileop);
  360.     gen_infop0(iv, endallop);
  361. }
  362.  
  363. static int
  364. gen_output(Piv iv, char *outpath)
  365. {/* Linker output */
  366. char *cp;
  367. int i;
  368. char outname[256];
  369.  
  370.     strcpy(outname, outpath);
  371.     if((cp = strrchr(outname, '.')))
  372.     {
  373. #if 0
  374.         strcpy(cp, ".anf");
  375. #endif
  376.     }
  377.     else
  378.     {
  379.         strcat(outname, ".anf");
  380.     }
  381.     for(i = 1; i < iv->argc; ++i)
  382.     {
  383.       if(!strcmp(outname, iv->argv[i]))
  384.       {
  385.         PERROR(pName ": ERROR output file `%s' is same as input file\n", outname);
  386.       }
  387.     }
  388.     if(!(iv->outfile = fopen(outname, "wb")))
  389.     {
  390.         PERROR(pName ": Cannot open output file %s\n", outname);
  391.     }
  392.     dump_header(iv);
  393.     dump_symbols(iv);
  394.     dump_files(iv);
  395.     dump_trailer(iv);
  396.     fclose(iv->outfile);
  397.     iv->outfile = 0;    
  398.     return iv->errors;
  399. }
  400. /* ======================= END LINKER OUTPUT GENERATOR ==================== */
  401.  
  402. /* ===================== GENERIC CODE BELOW THIS POINT ================== */
  403. static jmp_buf run_env;
  404. static void
  405. prerror(const char *fmt, ...)
  406. {
  407.     VFPRINTF(fmt, (char *)(((int *)(&fmt))+1));
  408.     longjmp(run_env, 3);
  409. }
  410. static void
  411. prwarn(const char *fmt, ...)
  412. {
  413.     VFPRINTF(fmt, (char *)(((int *)(&fmt))+1));
  414. }
  415. /* ========================= MULTI HEAP MALLOC ========================== */
  416. #define LOCAL static
  417.  
  418. #if USING_FRAMEWORK
  419. #define THEWELL(a) mallocC(local_category, a)
  420. static int local_category;
  421. static int num_instance;
  422. extern void *mallocC(int, int);
  423. extern void freecat(int);
  424. extern void oxlink_clear_bss();
  425. extern int NewMallocCategory();
  426. #endif /* USING_FRAMEWORK */
  427.  
  428. #define BASE_CATEGORY 0
  429. #define MEMORY_BUG 0
  430. #define PRINT_RAWDATA 0
  431.  
  432. #if MEMORY_BUG == 1
  433. #define MPRINTF printf
  434. #else
  435. #define MPRINTF(args...)
  436. #endif
  437.  
  438. #define PAGESIZE (4096)    /* can use `pagesize' function in OS */
  439. #define ALIGNMENTM (sizeof(unsigned long))
  440. #define MAL_MAXLEVEL (12)
  441. #define ROUNDINGM(a) ((ALIGNMENTM-(a&(ALIGNMENTM-1)))&(ALIGNMENTM-1))
  442. #define ALLOCSIZE (4096)
  443. #define FRNTGUARD (0x544e5246UL)
  444. #define BACKGUARD (0x48434142UL)
  445. #ifndef THEWELL
  446. #define THEWELL do_sbrk
  447. #endif
  448. #define NUMTYPES 3
  449. #define SIZEH 0
  450. #define FREEH 1
  451. #define USEDH 2
  452.  
  453. #define SKIPVARS NodePM update[MAL_MAXLEVEL+1];NodePM node,prev;int level
  454.  
  455. #define DELETENODE(TYPE) \
  456. {for(level=0;level<=bp->TYPE##level; level++)\
  457. {if(update[level]->fptr[level] == node)\
  458. update[level]->fptr[level] = node->fptr[level];else break;}\
  459. while(bp->TYPE##level>0 && bp->TYPE##header->fptr[bp->TYPE##level]==_NILLL)\
  460. bp->TYPE##level--;free_Mnode(bp,node,TYPE);}
  461.  
  462. #define INSERT() \
  463. {while(level >= 0){\
  464. node->fptr[level] = update[level]->fptr[level];\
  465. update[level]->fptr[level] = node;level--;}}
  466.  
  467. #define SETLEVEL(TYPE) \
  468. {level = getMlevel(bp, bp->TYPE##level);\
  469. while(bp->TYPE##level < level)update[++bp->TYPE##level]=bp->TYPE##header;}
  470.  
  471. #define FINDKEY(TYPE, KEYVAL)\
  472. {node = bp->TYPE##header;\
  473. for(level = bp->TYPE##level; level >= 0; level--){\
  474. while(node->fptr[level]->key < KEYVAL)\
  475. node = node->fptr[level];\
  476. update[level] = node;}prev=node;node=node->fptr[0];}
  477.  
  478. #define DETACH(SN)\
  479. {SN->bptr->fptr=SN->fptr;if(SN->fptr)SN->fptr->bptr=SN->bptr;}
  480.  
  481. #define UNLINK(SN, N)\
  482. {if(!sp->fptr&&sp->bptr->bptr<=(AddrP)(MAL_MAXLEVEL+1))dsize[N]=sp->size;\
  483. DETACH(SN);free_addr(bp,SN);}
  484.  
  485. #define CHECKGUARDS(MSG)\
  486. {if(bp->guarded){\
  487. unsigned *p2;\
  488. p2 = (void*)((char*)address+cursize-ALIGNMENTM);\
  489. if(*address != FRNTGUARD)\
  490. PERROR(pName #MSG ":%d: corrupted at 0x%x\n", bp->bincat, addr);\
  491. if(*p2 != BACKGUARD)\
  492. PERROR(pName #MSG ":%d: corrupted by 0x%x\n", bp->bincat, addr);}}
  493.  
  494. #if MEMORY_BUG == 1
  495. #define HEAPCHECK \
  496. {void *lastaddr;\
  497. if(category > 0){\
  498. Cguard(category);\
  499. if((lastaddr = Cheapcheck(category, NULL))){\
  500. FINDKEY(USEDH, (unsigned)lastaddr-ALIGNMENTM)\
  501. MPRINTF("bad heap at %x c:%u size=%u\n", lastaddr, category, node->value);\
  502. (void)print_rawdata(lastaddr-ALIGNMENTM, node->value);\
  503. abort();}}}
  504. #else
  505. #define HEAPCHECK
  506. #endif
  507.  
  508. struct _catlocs {
  509.     void *addr;
  510.     struct _catlocs *fptr;
  511. };
  512.  
  513. typedef struct _nodeM
  514. {
  515.     unsigned key;
  516.     unsigned value;
  517.     unsigned levels;    /* must always be after value */
  518.     struct _nodeM *fptr[1];
  519. } NodeM, *NodePM;
  520.  
  521. typedef struct _addr
  522. {
  523.     struct _addr *fptr;
  524.     struct _addr *bptr;
  525.     NodePM maddr;
  526.     unsigned size;
  527. } *AddrP;
  528.  
  529. struct _bins {
  530.     unsigned bits;
  531.     unsigned nbits;
  532.     NodePM SIZEHheader;
  533.     int SIZEHlevel;
  534.     NodePM FREEHheader;
  535.     int FREEHlevel; 
  536.     NodePM USEDHheader;
  537.     int USEDHlevel;
  538.  
  539.     unsigned bincat;
  540.     unsigned maxloc;
  541.     unsigned minloc;
  542.     struct _catlocs *catlocs;
  543.     struct _bins *fptr;
  544.     NodePM freenodes[NUMTYPES][MAL_MAXLEVEL+2];
  545.     struct _addr *freeaddrlocs;
  546.     char *chunkbase[NUMTYPES];
  547.     int chunksize[NUMTYPES];
  548.     int guarded;
  549.     int addrbump;
  550. };
  551.  
  552. static struct _bins zbp;
  553. static struct _bins *hmap[1009];
  554. static struct _nodeM _nilll = {0xffffffff,0,0,{0}};
  555. static struct _nodeM *_NILLL = &_nilll;
  556. static unsigned maxloc;
  557. static unsigned minloc;
  558. static struct _bins *freebinlocs;
  559. static struct _catlocs *freecatlocs;
  560. static char *binbase;
  561. static int binsize;
  562. static int chunksizes[] = {ALLOCSIZE,3*ALLOCSIZE,2*ALLOCSIZE};
  563.  
  564.  
  565. static long randtbl[32]    = { 0L,
  566.     0x9a319039L, 0x32d9c024L, 0x9b663182L, 0x5da1f342L, 
  567.     0xde3b81e0L, 0xdf0a6fb5L, 0xf103bc02L, 0x48f340fbL, 
  568.     0x7449e56bL, 0xbeb1dbb0L, 0xab5c5918L, 0x946554fdL, 
  569.     0x8c2e680fL, 0xeb3d799fL, 0xb11ee0b7L, 0x2d436b86L, 
  570.     0xda672e2aL, 0x1588ca88L, 0xe369735dL, 0x904f35f7L, 
  571.     0xd7158fd6L, 0x6fa6f051L, 0x616e6b96L, 0xac94efdcL, 
  572.     0x36413f93L, 0xc622c298L, 0xf5a42ab8L, 0x8a88d77bL, 
  573.     0xf5ad9d0eL, 0x8999220bL, 0x27fb47b9L
  574. };
  575.  
  576. static  long *fptr    = &randtbl[4];
  577. static  long *rptr    = &randtbl[1];
  578.  
  579. /* ======================== START OF CODE =========================== */
  580. #if PRINT_RAWDATA == 1
  581. static char
  582. hexbyte(unsigned int c)
  583. {
  584. char x = c & 0xf;
  585.  
  586.     return x + ((x>9) ? 55 : 48);
  587. }
  588. static void
  589. print_rawdata(void *rawdata, long size)
  590. {
  591. unsigned long vaddr = 0;
  592. unsigned char *d = rawdata;
  593. int i,j;
  594. char addr[9];
  595. char hex1[24];
  596. char hex2[24];
  597. char side1[9];
  598. char side2[9];
  599.  
  600.     addr[8] = 0;
  601.     hex1[23] = 0;
  602.     hex2[23] = 0;
  603.     side1[8] = 0;
  604.     side2[8] = 0;
  605.     while(size > 0)
  606.     {
  607.     unsigned long qaddr = vaddr;
  608.         memset(addr, '0', 8);
  609.         memset(hex1, ' ', 23);
  610.         memset(hex2, ' ', 23);
  611.         memset(side1, ' ', 8);
  612.         memset(side2, ' ', 8);
  613.         i = 7;
  614.         while(qaddr)
  615.         {
  616.             addr[i--] = hexbyte(qaddr);
  617.             qaddr >>= 4;
  618.         }
  619.         for(i=0,j=0; i < 8; ++i)
  620.         {
  621.             if(--size >= 0)
  622.             {
  623.             unsigned int c = *d++;
  624.                 if(isprint(c))
  625.                     side1[i] = c;
  626.                 else
  627.                     side1[i] = '.';
  628.                 hex1[j++] = hexbyte(c>>4);
  629.                 hex1[j++] = hexbyte(c);
  630.                     ++j;
  631.             }
  632.             else break;
  633.         }
  634.         for(i=0,j=0; i < 8; ++i)
  635.         {
  636.             if(--size >= 0)
  637.             {
  638.             unsigned int c = *d++;
  639.                 if(isprint(c))
  640.                     side2[i] = c;                    
  641.                 else
  642.                     side2[i] = '.';
  643.                 hex2[j++] = hexbyte(c>>4);
  644.                 hex2[j++] = hexbyte(c);
  645.                 ++j;
  646.             }
  647.             else break;
  648.         }
  649.         VPRINTF("%s  %s%s%s  %s%s%s\n",addr,hex1," | ",hex2,side1,"|",side2);
  650.         vaddr += 16;
  651.     }
  652. }
  653. #endif
  654.  
  655. /*
  656.  * Returns a really good 31-bit random number.
  657.  */
  658. static long
  659. lrandom()
  660. {
  661. long i;
  662.     
  663.     *fptr += *rptr;
  664.     i = (*fptr >> 1) & 0x7fffffffUL;
  665.     if(++fptr > &randtbl[31])
  666.     {
  667.         fptr = &randtbl[1];
  668.         ++rptr;
  669.     }
  670.     else
  671.     {
  672.         if(++rptr > &randtbl[31])  
  673.             rptr = &randtbl[1];
  674.     }
  675.     return( i );
  676. }
  677. #if !USING_FRAMEWORK
  678. static void *
  679. do_sbrk(unsigned amount)
  680. {
  681. void *address;
  682.  
  683.     address = sbrk(amount);    /* OR WHATEVER TO ACCESS THE OPERATING SYSTEM */
  684.     if(address == (void*)-1)
  685.     {
  686.         PERROR(pName "\nsystem out of memory, requested %u bytes\n", amount);
  687.     }
  688.     return address;
  689. }
  690. #endif
  691.  
  692. static struct _catlocs *
  693. new_catloc(void)
  694. {
  695. struct _catlocs *p;
  696.     if((p=freecatlocs))
  697.     {
  698.         freecatlocs = p->fptr;
  699.         return p;
  700.     }
  701.     if(binsize < sizeof(struct _catlocs))
  702.     {
  703.         binbase = THEWELL(4096);
  704.         binsize = 4096;
  705.     }
  706.     binsize -= sizeof(struct _catlocs);
  707.     p = (void*)binbase;
  708.     binbase += sizeof(struct _catlocs);
  709.     return p;
  710. }
  711. static void
  712. free_catloc(struct _catlocs *p)
  713. {
  714.     p->fptr = freecatlocs;
  715.     freecatlocs = p;
  716. }
  717. static void *
  718. new_chunk(struct _bins *bp, int size, int type)
  719. {
  720. char *p;
  721.      if(bp->chunksize[type] < size)
  722.     {
  723.         if(bp->bincat == 0) {
  724.             bp->chunkbase[type] = THEWELL(chunksizes[type]);
  725.             bp->chunksize[type] = chunksizes[type];
  726.         }
  727.         else {
  728.         struct _catlocs *cl;
  729.             bp->chunkbase[type] = Cmalloc(0,chunksizes[type]-zbp.guarded);
  730.             bp->chunksize[type] = chunksizes[type]-zbp.guarded;
  731.             cl = new_catloc();
  732.             cl->addr = bp->chunkbase[type];
  733.             cl->fptr = bp->catlocs;
  734.             bp->catlocs = cl;
  735.         }
  736.     }
  737.     bp->chunksize[type] -= size;
  738.     p = bp->chunkbase[type];
  739.     bp->chunkbase[type] += size;
  740.     return p;
  741. }
  742. static void *
  743. new_Mnode(struct _bins *bp, int levels, int type)
  744. {
  745. int size;
  746. NodePM p;
  747.  
  748.     if((p=bp->freenodes[type][levels]))
  749.     {
  750.         bp->freenodes[type][levels] = p->fptr[0];
  751.         p->value = 0;
  752.         return p;
  753.     }
  754.      size = sizeof(struct _nodeM) + levels * sizeof(void*);
  755.     p = new_chunk(bp, size, type);
  756.     p->levels = levels;
  757.     p->value = 0;
  758.     return p;    
  759. }
  760. static void
  761. free_Mnode(struct _bins *bp, NodePM p, int type)
  762. {
  763.     p->fptr[0] = bp->freenodes[type][p->levels];
  764.     bp->freenodes[type][p->levels] = p;
  765. }
  766. static struct _addr *
  767. new_addr(struct _bins *bp)
  768. {
  769. struct _addr *p;
  770.     if((p=bp->freeaddrlocs))
  771.     {
  772.         bp->freeaddrlocs = p->fptr;
  773.         return p;
  774.     }
  775.     return new_chunk(bp, sizeof(struct _addr), FREEH);
  776. }
  777. static void
  778. free_addr(struct _bins *bp, struct _addr *p)
  779. {
  780.     p->fptr = bp->freeaddrlocs;
  781.     bp->freeaddrlocs = p;
  782. }
  783. static struct _bins *
  784. new_bins(void)
  785. {
  786. struct _bins *p;
  787.     if((p=freebinlocs))
  788.     {
  789.         freebinlocs = p->fptr;
  790.         return p;
  791.     }
  792.      if(binsize < sizeof(struct _bins))
  793.     {
  794.         binbase = THEWELL(4096);
  795.         binsize = 4096;
  796.     }
  797.     binsize -= sizeof(struct _bins);
  798.     p = (struct _bins*)binbase;
  799.     binbase += sizeof(struct _bins);
  800.     return p;
  801. }
  802. static void
  803. free_bins(struct _bins *p)
  804. {
  805.     p->fptr = freebinlocs;
  806.     freebinlocs = p;
  807. }
  808. static int
  809. getMlevel (struct _bins *p, int binlevel)
  810. {
  811. int level = -1;
  812. int bits = 0;
  813.  
  814.     while(bits == 0)
  815.     {
  816.         if (p->nbits == 0)
  817.         {
  818.             p->bits = lrandom();
  819.             p->nbits = 15;
  820.         }
  821.         bits = p->bits & 3;
  822.         p->bits >>= 2;
  823.         p->nbits--;
  824.  
  825.         if(++level > binlevel)
  826.             break;
  827.     }
  828.     return (level > MAL_MAXLEVEL) ? MAL_MAXLEVEL : level;
  829. }
  830.  
  831. static void
  832. init_bins(struct _bins *bp, int category)
  833. {
  834. int i;
  835. int binnum = category % 1009;
  836.  
  837.     bzero(bp, sizeof(struct _bins));
  838.     bp->bincat = category;
  839.     bp->minloc = 0xffffffff;
  840.     bp->fptr = hmap[binnum];
  841.     hmap[binnum] = bp;
  842.     bp->SIZEHheader = new_Mnode(bp, MAL_MAXLEVEL+1, SIZEH);
  843.     bp->FREEHheader = new_Mnode(bp, MAL_MAXLEVEL+1, FREEH);
  844.     bp->USEDHheader = new_Mnode(bp, MAL_MAXLEVEL+1, USEDH);
  845.  
  846.     for(i = 0; i <= MAL_MAXLEVEL; ++i)
  847.     {
  848.         bp->SIZEHheader->fptr[i] = _NILLL;
  849.         bp->FREEHheader->fptr[i] = _NILLL;
  850.         bp->USEDHheader->fptr[i] = _NILLL;
  851.     }
  852. }
  853.  
  854. static struct _bins*
  855. getcat(int category)
  856. {
  857. struct _bins *hbp;
  858.  
  859.     hbp = hmap[category % 1009];
  860.     while(hbp)
  861.     {
  862.         if(hbp->bincat == category)
  863.             return hbp;
  864.         hbp = hbp->fptr;
  865.     }
  866.     return 0;
  867. }
  868. static struct _bins *
  869. initcat(int category)
  870. {
  871. struct _bins *bp;
  872.  
  873.     if(category == 0)
  874.     {
  875.         bp = &zbp;
  876.         if(zbp.SIZEHheader == 0)
  877.             init_bins(bp, category);
  878.         return bp;
  879.     }
  880.     /* do this to set zbp.guarded properly on startup */
  881.     if(zbp.SIZEHheader == 0)
  882.         initcat(0);
  883.  
  884.     if((bp = new_bins()))
  885.     {
  886.         init_bins(bp, category);
  887.         return bp;
  888.     }
  889.     return 0;
  890. }
  891. static void *
  892. getspace(struct _bins *bp, unsigned size, unsigned *remainder)
  893. {
  894. unsigned desired;
  895. void *address;
  896.   
  897.     desired = ((size+ALLOCSIZE-1)/ALLOCSIZE)*ALLOCSIZE;
  898.     if(bp->bincat == 0)
  899.     {
  900.         address = THEWELL(desired);
  901.         *remainder = desired - size;
  902.     }
  903.     else
  904.     {
  905.     struct _catlocs *cl;
  906.  
  907.         if((desired-size) > zbp.guarded)
  908.             desired -= zbp.guarded;
  909.         
  910.         address = Cmalloc(0, desired);
  911.         *remainder = desired - size;
  912.  
  913.         /* save the gross allocations for the category */
  914.         cl = new_catloc();
  915.         cl->addr = address;
  916.         cl->fptr = bp->catlocs;
  917.         bp->catlocs = cl;
  918.     }
  919.     /* maintain address range info */
  920.     if((unsigned)address < bp->minloc)
  921.         bp->minloc = (unsigned)address;
  922.     if(((unsigned)address + desired) > bp->maxloc)
  923.         bp->maxloc = (unsigned)address + desired;
  924.      if(bp->minloc < minloc)
  925.          minloc = bp->minloc;
  926.      if(bp->maxloc > maxloc)
  927.          maxloc = bp->maxloc;
  928.     return address;
  929. }
  930. static void
  931. addto_sizelist(struct _bins *bp, AddrP ap)
  932. {
  933. SKIPVARS;
  934.  
  935.     /* INSERT IN SIZE LIST */
  936.     FINDKEY(SIZEH, ap->size)
  937.  
  938.     if(node->key == ap->size)
  939.     {/* size node exists */
  940.         ap->fptr = (AddrP)node->value;
  941.         ap->bptr = (AddrP)&node->value;
  942.         if(ap->fptr) ap->fptr->bptr = ap;
  943.         node->value = (unsigned)ap;
  944.     }
  945.     else
  946.     {/* create new size node */
  947.         SETLEVEL(SIZEH)
  948.         node = new_Mnode(bp, level, SIZEH);
  949.         node->key = ap->size;
  950.         node->value = (unsigned)ap;
  951.         ap->fptr = 0;
  952.         ap->bptr = (AddrP)&node->value;
  953.         INSERT()
  954.     }
  955. }
  956. static void
  957. addto_freelist(struct _bins *bp, void *addr, unsigned size)
  958. {
  959. SKIPVARS;
  960. AddrP ap,sp;
  961. unsigned dsize[2];
  962.  
  963.     /* GET NEW ADDR STRUCT */
  964.     ap = new_addr(bp);
  965.     ap->size = size;
  966.  
  967.     dsize[1] = dsize[0] = 0; /* sizenode deletion markers */
  968.  
  969.     /* CHECK FREE LIST */
  970.     FINDKEY(FREEH, (unsigned)addr)
  971.  
  972.     /* CHECK FOR MERGE OR INSERT */
  973.     if(prev->value && prev->key+((AddrP)prev->value)->size == (unsigned)addr)
  974.     {/* merge with previous block */
  975.         ap->size += ((AddrP)prev->value)->size;
  976.  
  977.         if(prev->key + ap->size == node->key)
  978.         {/* merge with previous and next block */
  979.             sp = (AddrP) node->value;;
  980.             ap->size += sp->size;
  981.  
  982.             /* delete size struct for next block */
  983.             UNLINK(sp, 0)
  984.  
  985.             /* delete next block */
  986.             DELETENODE(FREEH);
  987.         }
  988.         /* delete size struct for prev block */
  989.         sp = (AddrP)prev->value;
  990.         UNLINK(sp, 1)
  991.  
  992.         /* set new address struct */
  993.         prev->value = (unsigned)ap;
  994.         ap->maddr = prev;
  995.     }
  996.     else if(node->value && (char*)addr + size == (void*)node->key)
  997.     {/* merge with next block */
  998.         sp = (AddrP) node->value;;
  999.         node->key = (unsigned)addr;
  1000.         ap->size += sp->size;
  1001.  
  1002.         /* unlink size struct for next block */
  1003.         UNLINK(sp,0)
  1004.  
  1005.         /* set new address struct */
  1006.         node->value = (unsigned)ap;
  1007.         ap->maddr = node;
  1008.     }
  1009.     else
  1010.     {/* insert in free list */
  1011.  
  1012.         SETLEVEL(FREEH)
  1013.         node = new_Mnode(bp, level, FREEH);
  1014.         node->key = (unsigned)addr;
  1015.         node->value = (unsigned)ap;
  1016.         ap->maddr = node;
  1017.         INSERT()
  1018.     }
  1019.     addto_sizelist(bp, ap);
  1020.  
  1021.     /* Remove sizenodes eliminated by merge */
  1022.     if(dsize[0])
  1023.     {
  1024.         FINDKEY(SIZEH, dsize[0])
  1025.         if(node->value == 0)
  1026.           DELETENODE(SIZEH)
  1027.     }
  1028.     if(dsize[1])
  1029.     {
  1030.         FINDKEY(SIZEH, dsize[1])
  1031.         if(node->value == 0)
  1032.           DELETENODE(SIZEH)
  1033.     }
  1034. }
  1035.  
  1036. LOCAL void* 
  1037. Cmemalign(int category, unsigned alignment, unsigned req)
  1038. {
  1039. SKIPVARS;
  1040. NodePM fnode;
  1041. unsigned remainder;
  1042. unsigned *address;
  1043. struct _bins *bp;
  1044. unsigned mask, size;
  1045.  
  1046.  
  1047.     if(!(bp = getcat(category)))
  1048.       if(!(bp = initcat(category)))
  1049.         return 0;
  1050. HEAPCHECK
  1051.     if(req == 0)
  1052.         req = ALIGNMENTM;
  1053.     else
  1054.         req += ROUNDINGM(req);
  1055.     size = req += bp->guarded;
  1056.  
  1057.     if(alignment)
  1058.     {
  1059.         alignment += ROUNDINGM(alignment);
  1060.         if(alignment > ALIGNMENTM)
  1061.         {
  1062.             mask = alignment -1;
  1063.             size = req + alignment + bp->guarded;
  1064.         }
  1065.         else
  1066.         {
  1067.             alignment = 0;
  1068.         }
  1069.     }
  1070.  
  1071.     /* check sizelist for candidate */
  1072.     FINDKEY(SIZEH, size)
  1073.     fnode = node;
  1074. trynext:
  1075.     if(node->key != 0xffffffff)
  1076.     {/* found an appropriately sized block */
  1077.     AddrP sp = (AddrP)node->value;
  1078.  
  1079.         if(!sp && node == fnode)
  1080.         {
  1081.         NodePM q;
  1082.             q = node->fptr[0];
  1083.             DELETENODE(SIZEH)
  1084.             node = q;
  1085.             goto trynext;
  1086.         }
  1087.         if(!sp)
  1088.         {/* no available space at this size */
  1089.             node = node->fptr[0];
  1090.             goto trynext;
  1091.         }
  1092.  
  1093.         /* extract some space from this block */
  1094.         remainder = node->key - size;
  1095.         address = (void*)sp->maddr->key;
  1096.         sp->maddr->key += size;
  1097.         DETACH(sp);
  1098.  
  1099.         if(node->value == 0)
  1100.         {/* no more blocks of this size, delete sizenode */
  1101.             if(node != fnode)
  1102.               FINDKEY(SIZEH, size)
  1103.             DELETENODE(SIZEH)
  1104.         }
  1105.  
  1106.         if(remainder == 0)
  1107.         {/* no remaining space,the node in freelist is exhausted, delete it */
  1108.             FINDKEY(FREEH, sp->maddr->key)
  1109.             DELETENODE(FREEH)
  1110.             free_addr(bp, sp);
  1111.         }
  1112.         else
  1113.         {/* space remains in block, move it to new size loc */
  1114.             sp->size = remainder;
  1115.             addto_sizelist(bp, sp);
  1116.         }
  1117.     }
  1118.     else
  1119.     {
  1120.         address = getspace(bp, size, &remainder);
  1121.         if(remainder)
  1122.           addto_freelist(bp, ((char*)address)+size, remainder);
  1123.     }
  1124.     if(alignment)
  1125.     {
  1126.     unsigned diff;
  1127.         if((diff = (unsigned)address & mask))
  1128.         {/* move address forward */
  1129.         char *naddress;
  1130.         unsigned lose;
  1131.             lose = alignment - diff;
  1132.             naddress = (char*)address + lose;
  1133.             addto_freelist(bp, address, lose);
  1134.             address = (unsigned*)naddress;
  1135.         }
  1136.     }
  1137.     if(bp->guarded)
  1138.     {
  1139.       *address = FRNTGUARD;
  1140.       *((unsigned*)(((char*)address)+req-ALIGNMENTM)) = BACKGUARD;
  1141.  
  1142.     }
  1143.  
  1144.     FINDKEY(USEDH, (unsigned)address)
  1145.  
  1146.     if(node->key == (unsigned)address) {
  1147.       PERROR(pName "allocC:%d: bookkeeping nodes are corrupted at:0x%x\n",
  1148.           category, address);
  1149.     }
  1150.     SETLEVEL(USEDH)
  1151.     node = new_Mnode(bp, level, USEDH);
  1152.     node->key = (unsigned)address;
  1153.     node->value = req;
  1154.     INSERT()    
  1155.  
  1156.     return address+bp->addrbump;
  1157. }
  1158. LOCAL void*
  1159. Ccalloc(int category, unsigned cnt, unsigned elem_size)
  1160. {
  1161. unsigned size = cnt * elem_size;
  1162. void* buf;;
  1163.  
  1164.   if((buf = Cmalloc(category, size)))
  1165.       bzero(buf, size);
  1166.   return buf;
  1167. };
  1168. LOCAL void
  1169. Cfree(int category, void* addr)
  1170. {
  1171. unsigned cursize;
  1172. unsigned *address;
  1173. struct _bins *bp;
  1174. SKIPVARS;
  1175.     if(addr)
  1176.     {
  1177.         if(!(bp = getcat(category))) {
  1178.             PERROR(pName "Cfree:%d: non-existant category at:0x%x\n",category,addr);
  1179.         }
  1180. HEAPCHECK
  1181.         address = (void*) ((unsigned*)addr - bp->addrbump);
  1182.         FINDKEY(USEDH, (unsigned)address)
  1183.         if(node->key != (unsigned)address) {
  1184.           PERROR(pName "Cfree:%d: bogus address=0x%x\n", category, addr);
  1185.         }
  1186.         cursize = node->value;
  1187.         CHECKGUARDS(Cfree)
  1188.         DELETENODE(USEDH)
  1189.  
  1190.         addto_freelist(bp, address, cursize);
  1191.     }
  1192.     else PERROR(pName "Cfree:%d: null pointer\n", category);
  1193. }
  1194. LOCAL void* 
  1195. Crealloc(int category, void* addr, unsigned newsize)
  1196. {
  1197. SKIPVARS;
  1198. unsigned cursize;
  1199. unsigned *address;
  1200. struct _bins *bp;
  1201. NodePM onode;
  1202.  
  1203.     if(addr == 0) 
  1204.         return Cmalloc(category, newsize);
  1205.     else
  1206.     {
  1207.         if(!(bp = getcat(category))) {
  1208.            PERROR(pName "reallocC:%d: non-existant category at:%x\n",category,addr);
  1209.         }
  1210. HEAPCHECK 
  1211.         if(newsize == 0)
  1212.             newsize = ALIGNMENTM;
  1213.         else
  1214.             newsize += ROUNDINGM(newsize);
  1215.         newsize += bp->guarded;
  1216.  
  1217.         address = (void*)(((char*)addr)-(bp->guarded/2));
  1218.         FINDKEY(USEDH, (unsigned)address)
  1219.         if(node->key != (unsigned)address) {
  1220.           PERROR(pName "reallocC:%d: bogus address=0x%x\n", category, addr);
  1221.         }
  1222.         cursize = node->value;
  1223.         node->value = newsize;
  1224.         onode = node;
  1225.  
  1226.         CHECKGUARDS(reallocC)
  1227.  
  1228.         if(newsize == cursize)
  1229.             return addr;
  1230.         if(newsize > cursize)
  1231.         {/* check if block can be extended */
  1232.         void *taddr = ((char*)address) + cursize;
  1233.         unsigned extendsize = newsize-cursize;
  1234.  
  1235.             /* check freelist for an available block at the right address */
  1236.             FINDKEY(FREEH, (unsigned)taddr)
  1237.             if(node->key == (unsigned)taddr)
  1238.             {
  1239.             AddrP sp = (AddrP)node->value;
  1240.                 if(sp->size >= extendsize)
  1241.                 {/* BLOCK CAN BE EXTENDED INTERNALLY */
  1242.                     node->key += extendsize;
  1243.                     sp->size -= extendsize;
  1244.                     DETACH(sp)
  1245.                     if(sp->size == 0)
  1246.                     {/* the extension block is used up, delete this node */
  1247.                         free_addr(bp, sp);
  1248.                         DELETENODE(FREEH)
  1249.                     }
  1250.                     else
  1251.                     {/* shift the remainder in the sizelist */
  1252.                         addto_sizelist(bp, sp);
  1253.                     }
  1254.                     /* SUCCESS */
  1255.                     if(bp->guarded)
  1256.                     {
  1257.                         *((unsigned*)(((char*)address)+newsize-ALIGNMENTM))
  1258.                             = BACKGUARD;
  1259.                     }
  1260.                     return addr;
  1261.                 }
  1262.             }
  1263.             /* HERE WE COULD CHECK OTHER SOURCES OF SPACE */
  1264.  
  1265.             /* can't extend block, malloc some new space */
  1266.             if((taddr = Cmalloc(category,newsize-bp->guarded)))
  1267.             {
  1268.                 memmove(taddr,addr,cursize-bp->guarded);
  1269.                 onode->value = cursize;
  1270.                 Cfree(category, addr);
  1271.             }
  1272.             /* SUCCESS */
  1273.             return taddr;
  1274.         }
  1275.         else
  1276.         {/* shrink block */
  1277.             if(bp->guarded)
  1278.             {
  1279.                 *((unsigned*)(((char*)address)+newsize-ALIGNMENTM))
  1280.                     = BACKGUARD;
  1281.             }
  1282.             addto_freelist(bp, ((char*)address)+newsize, cursize-newsize); 
  1283.             return addr;
  1284.         }
  1285.       }
  1286. }
  1287. LOCAL void
  1288. Cfreecat(int category)
  1289. {
  1290. struct _bins *bp;
  1291.  
  1292.     if(category == 0)
  1293.         return;
  1294.  
  1295.     if((bp = getcat(category)))
  1296.     {
  1297.     struct _catlocs *cl = bp->catlocs;
  1298.     struct _bins *hbp;
  1299.     struct _bins *prev;
  1300.  
  1301.         while(cl)
  1302.         {/* Space allocated to the category is moved to category 0 */
  1303.         void *ql = cl->fptr;
  1304.  
  1305.             Cfree(0, cl->addr);
  1306.             free_catloc(cl);
  1307.             cl = ql;
  1308.         }
  1309.         /* space for the _bins struct is placed on a free list */
  1310.         hbp = hmap[category % 1009];
  1311.         prev = 0;
  1312.         while(hbp)
  1313.         {
  1314.             if(hbp->bincat == category)
  1315.             {
  1316.                 if(prev == 0)
  1317.                     hmap[category % 1009] = hbp->fptr;
  1318.                 else
  1319.                     prev->fptr = hbp->fptr;
  1320.                 free_bins(hbp);
  1321.                 return;
  1322.             }
  1323.             prev = hbp;
  1324.             hbp = hbp->fptr;
  1325.         }
  1326.     }
  1327. }
  1328. LOCAL int
  1329. Cmemrange(int category, unsigned *min, unsigned *max)
  1330. {
  1331. struct _bins *bp;
  1332.  
  1333.     if((bp = getcat(category)))
  1334.     {
  1335.         *min = bp->minloc;
  1336.         *max = bp->maxloc;
  1337.         return 1;
  1338.     }
  1339.     return 0;
  1340. }
  1341. LOCAL int
  1342. Cusedrange(int category, unsigned *min, unsigned *max)
  1343. {
  1344. struct _bins *bp;
  1345. NodePM node;
  1346. int level;
  1347.  
  1348.     if((bp = getcat(category)))
  1349.     {
  1350.         node = bp->USEDHheader;
  1351.         *min = node->fptr[0]->key;
  1352.         for(level = bp->USEDHlevel; level >= 0; level--)
  1353.           while(node->fptr[level]->key < 0xffffffff)
  1354.             node = node->fptr[level];
  1355.         *max = node->key;
  1356.         return 1;
  1357.     }
  1358.     return 0;
  1359. }
  1360. LOCAL void
  1361. Ctotrange(unsigned *min, unsigned *max)
  1362. {
  1363.     *min = minloc;
  1364.     *max = maxloc;
  1365. }
  1366. LOCAL void
  1367. Cguard(int category)
  1368. {
  1369. struct _bins *bp;
  1370.  
  1371.     if(!(bp = getcat(category)))
  1372.       if(!(bp = initcat(category)))
  1373.           return;
  1374.  
  1375.     if(!bp->guarded)
  1376.     {
  1377.         bp->guarded = 2*ALIGNMENTM;
  1378.         bp->addrbump = 1;
  1379.     }
  1380. }
  1381. LOCAL void*
  1382. Cheapcheck(int category, void *start)
  1383. {
  1384. struct _bins *bp;
  1385. NodePM node,prev;
  1386. unsigned *p1,*p2;
  1387.  
  1388.     if((bp = getcat(category)))
  1389.     {
  1390.         if(bp->guarded)
  1391.         {
  1392.             prev = 0;
  1393.             node = bp->USEDHheader;
  1394.             while(        (node = node->fptr[0]) != (NodePM)0xffffffff
  1395.                     &&    node->key != 0xffffffffUL)
  1396.             {
  1397.                 if((void*)node->key > start)
  1398.                 {
  1399.                     p1 = (unsigned*)node->key;
  1400.                     if(*p1 != FRNTGUARD)
  1401.                     {
  1402.                         if(prev)
  1403.                             return (char*)prev->key+ALIGNMENTM;
  1404.                         else
  1405.                             return (void*)1;
  1406.                     }
  1407.                     p2 = (unsigned*)(((char*)p1)+node->value-ALIGNMENTM);
  1408.                     if(*p2 != BACKGUARD)
  1409.                         return (char*)node->key+ALIGNMENTM;
  1410.                 }
  1411.                 prev = node;
  1412.             }
  1413.         }
  1414.     }
  1415.     return 0;
  1416. }
  1417. LOCAL void* 
  1418. Cmalloc(int category, unsigned size)
  1419. {
  1420.     return Cmemalign(category, 0, size);
  1421. }
  1422.  
  1423. LOCAL void* 
  1424. Cvalloc(int category, unsigned bytes)
  1425. {
  1426.   return Cmemalign (category, PAGESIZE, bytes);
  1427. }
  1428. LOCAL unsigned
  1429. Cmallocsize(int category, void* addr)
  1430. {
  1431. struct _bins *bp;
  1432. SKIPVARS;
  1433.  
  1434.     if(addr && (bp = getcat(category)))
  1435.     {
  1436.     unsigned address = (unsigned)((unsigned*)addr - bp->addrbump);
  1437.         FINDKEY(USEDH, address)
  1438.         if(node->key == address)
  1439.             return node->value - bp->guarded;
  1440.     }
  1441.     return 0;
  1442. }
  1443.  
  1444. LOCAL int
  1445. Cnewcat()
  1446. {
  1447. static unsigned int cat = BASE_CATEGORY;
  1448.     return ++cat;
  1449. }
  1450.  
  1451.  
  1452. /* ====================== END MULTI-HEAP MALLOC ============================ */
  1453.  
  1454. /* ====================== SYMBOL TABLE HANDLERS ============================ */
  1455.  
  1456. typedef struct _key
  1457. {
  1458.     unsigned long k[2];
  1459.     unsigned long hv;
  1460. } KEY, *KEYP;
  1461.  
  1462. typedef struct _nodeS
  1463. {/* 40 bytes -- adjust size to suit application */
  1464.     unsigned long value[4];    /* 16 bytes */
  1465.     unsigned long key[2];    /* 8 bytes */
  1466.     struct _nodeS *fptr[4];    /* 16 bytes */
  1467. } NodeS, *NodePS;
  1468.  
  1469. typedef struct _pbuf
  1470. {/* symbol table object */
  1471.     int    nbins;            /* number of bins in dictionary */
  1472.     int lastbin;        /* for seq access */
  1473.     NodePS lastptr;        /* ditto */
  1474.     int category;        /* heap number */
  1475.     char *chunkbase;    /* node allocation base */
  1476.     int chunksize;        /* number of bytes available in current chunk */
  1477.     NodePS freelist;    /* list of freed nodes for allocation */
  1478.     int level;            /* sorted level */
  1479.     int bits;            /* sorted bits */
  1480.     int bitcnt;            /* sorted bitcnt */
  1481.     NodePS header;        /* sorted header */
  1482.     NodePS bins[0];        /* bins if hashed dictionary */
  1483. } *PbufP;
  1484.  
  1485. #define SYM_MAXLEVEL 12
  1486. #define TBL ((PbufP)tbl)
  1487. #define KEYEQ(a,b) ((a)[0] == (b)[0] && (a)[1] == (b)[1])
  1488. #define KEYLT(a,b) (((a)[1] < (b)[1]) || ((a)[1] == (b)[1] && (a)[0] < (b)[0]))
  1489. #define MIN(a,b) (((a) < (b)) ? (a) : (b))
  1490.  
  1491. static struct _nodeS _nnil = {{0,0,0,0},{0xffffffff,0xffffffff},{0,0,0,0}};
  1492. static struct _nodeS *_NNIL = &_nnil;
  1493.  
  1494. static int
  1495. getSlevel (PbufP tbl)
  1496. {
  1497. int level = -1;
  1498. int bits = 0;
  1499.  
  1500.     while (bits == 0)
  1501.     {
  1502.         if (tbl->bitcnt == 0)
  1503.         {
  1504.             tbl->bits = lrandom();
  1505.             tbl->bitcnt = 15;
  1506.         }
  1507.  
  1508.         bits = tbl->bits & 3;
  1509.         tbl->bits >>= 2;
  1510.         tbl->bitcnt--;
  1511.  
  1512.         if(++level > tbl->level)
  1513.             break;
  1514.     }
  1515.     return (level > SYM_MAXLEVEL) ? SYM_MAXLEVEL : level;
  1516.  
  1517. }
  1518.  
  1519. static void
  1520. hash(void *key, KEY *cat)
  1521. {
  1522.     cat->k[0] = ((unsigned long*)key)[0];
  1523.     cat->k[1] = ((unsigned long*)key)[1];
  1524.     cat->hv = ((cat->k[0] ^ cat->k[1]) * 1103515245UL) + 12345;
  1525. }
  1526. static void
  1527. sym_hash(unsigned long *key, char *symb)
  1528. {
  1529. int len = strlen(symb);
  1530. int i;
  1531.     for(i = 0; i < len; ++i)
  1532.       ((unsigned char *)key)[i & 7] ^= symb[i];
  1533.     key[0] = ((key[0] ^ key[1]) * 1103515245UL) + 12345;
  1534.     key[1] = len;
  1535. }
  1536. static void *
  1537. new_Snode(PbufP tbl, int levels)
  1538. {
  1539. NodePS p;
  1540. int size;
  1541.     if(levels <= 3)
  1542.     {
  1543.         if(tbl->freelist)
  1544.         {
  1545.             p = tbl->freelist;
  1546.             tbl->freelist = p->fptr[0];
  1547.             p->fptr[0] = 0;
  1548.             return p;
  1549.         }
  1550.     }
  1551.     size = sizeof(struct _nodeS) + ((levels-3) * sizeof(void*));
  1552.     if(tbl->chunksize < size)
  1553.     {
  1554.         tbl->chunkbase = Ccalloc(tbl->category, 1, 4080);
  1555.         tbl->chunksize = 4080;
  1556.     } 
  1557.     tbl->chunksize -= size;
  1558.     p = (NodePS)tbl->chunkbase;
  1559.     tbl->chunkbase += size;
  1560.     return p;
  1561. }
  1562. static void
  1563. free_Snode(PbufP tbl, NodePS node)
  1564. {
  1565.     bzero(node, sizeof(struct _nodeS));
  1566.     node->fptr[0] = tbl->freelist;
  1567.     tbl->freelist = node;
  1568. }
  1569.  
  1570. static void*
  1571. NewSymTable(int category, int nbins)
  1572. {
  1573. PbufP tbl;
  1574.  
  1575.     tbl = Ccalloc(category, 1, nbins*sizeof(NodePS) + sizeof(struct _pbuf));
  1576.     if(nbins == 0)
  1577.     {/* sorted dictionary */
  1578.     int i;
  1579.         tbl->header = new_Snode(tbl, SYM_MAXLEVEL+1);
  1580.         for(i = 0; i <= SYM_MAXLEVEL; ++i)
  1581.             tbl->header->fptr[i] = _NNIL;
  1582.     }
  1583.     tbl->nbins = nbins;
  1584.     tbl->category = category;
  1585.     return tbl;
  1586. }
  1587. static int
  1588. SymFind(void *tbl, void *key, void *result)
  1589. {
  1590. NodePS node;
  1591.  
  1592.     if(tbl && key)
  1593.     {
  1594.       if(TBL->nbins)
  1595.       {/* hashed dictionary */
  1596.       KEY cat;
  1597.  
  1598.         hash(key, &cat);
  1599.         if((node = TBL->bins[cat.hv % TBL->nbins]))
  1600.         {
  1601.             do {
  1602.                 if(        node->key[0] == cat.k[0]
  1603.                     &&    node->key[1] == cat.k[1])
  1604.                 {
  1605.                     if(result)
  1606.                       *((NodePS *)result) = node;
  1607.                     TBL->lastbin = cat.hv % TBL->nbins;
  1608.                     TBL->lastptr = node;
  1609.                     return 1;
  1610.                 }
  1611.              } while((node = node->fptr[0]));
  1612.         }
  1613.         return 0;
  1614.       }
  1615.       else
  1616.       {/* sorted dictionary */
  1617.       int level;
  1618.  
  1619.         node = TBL->header;
  1620.         for(level = TBL->level; level >= 0; level--)
  1621.         {
  1622.           while( KEYLT(node->fptr[level]->key, ((unsigned long*)key)) )
  1623.             node = node->fptr[level];
  1624.         }
  1625.         node = node->fptr[0];
  1626.  
  1627.         TBL->lastptr = node;
  1628.         if(result)
  1629.             *((NodePS *)result) = node;
  1630.         return (KEYEQ(node->key, ((unsigned long*)key))) ? 1 : 0;
  1631.       }
  1632.     }
  1633.     return -1;
  1634. }
  1635. static int
  1636. SymFindRange(void *tbl, void *key, void *result)
  1637. {/* assumes 4 byte key and value (the value can be bigger) */
  1638. NodePS node;
  1639.  
  1640.     if(tbl && key)
  1641.     {
  1642.       if(TBL->nbins)
  1643.       {/* hashed dictionary */
  1644.         return 0;
  1645.       }
  1646.       else
  1647.       {/* sorted dictionary */
  1648.       NodePS prev;
  1649.       int level;
  1650.  
  1651.         node = TBL->header;
  1652.         for(level = TBL->level; level >= 0; level--)
  1653.         {
  1654.           while ( node->fptr[level]->key[0] < ((unsigned long*)key)[0] )
  1655.             node = node->fptr[level];
  1656.         }
  1657.         prev = node;
  1658.         node = node->fptr[0];
  1659.  
  1660.         if( node->key[0] == ((unsigned long*)key)[0] )
  1661.         {
  1662.             TBL->lastptr = node;
  1663.             if(result)
  1664.                 *((NodePS *)result) = node;
  1665.             return 1;
  1666.         }        
  1667.         if( ((unsigned long*)key)[0] < prev->key[0]+prev->value[0] )
  1668.         {
  1669.             TBL->lastptr = prev;
  1670.             if(result)
  1671.                 *((NodePS *)result) = prev;
  1672.             return 1;
  1673.         }
  1674.         return 0;
  1675.       }
  1676.     }
  1677.     return -1;
  1678. }
  1679. static void*
  1680. SymInsert(void *tbl, void *key, void *value, int datsiz)
  1681. {
  1682. NodePS node;
  1683.  
  1684.     if(tbl && key)
  1685.     {
  1686.       if(TBL->nbins)
  1687.       {/* hashed dictionary */
  1688.       KEY cat;
  1689.       NodePS *binp;
  1690.         hash(key, &cat);
  1691.         node = new_Snode(tbl, 0);
  1692.         TBL->lastbin = cat.hv % TBL->nbins;
  1693.         TBL->lastptr = node;
  1694.         binp = &TBL->bins[TBL->lastbin];
  1695.         if(value && datsiz)
  1696.           memcpy(node, value, MIN(datsiz,16));
  1697.         node->key[0] = cat.k[0];
  1698.         node->key[1] = cat.k[1];
  1699.         node->fptr[0] = *binp;
  1700.         *binp = node;
  1701.         return node;
  1702.       }
  1703.       else
  1704.       {/* sorted dictionary */
  1705.       int level;
  1706.       NodePS update[SYM_MAXLEVEL+1];
  1707.  
  1708.         node = TBL->header;
  1709.         for (level = TBL->level; level >= 0; level--)
  1710.         {
  1711.           while ( KEYLT(node->fptr[level]->key,((unsigned long*)key)) )
  1712.             node = node->fptr[level];
  1713.           update[level] = node;
  1714.         }
  1715.  
  1716.         level = getSlevel(tbl);
  1717.  
  1718.         while(TBL->level < level)
  1719.             update[++TBL->level] = TBL->header;
  1720.  
  1721.         node = new_Snode(tbl, level);
  1722.  
  1723.         if(value && datsiz)
  1724.           memcpy(node, value, MIN(datsiz,16));
  1725.         node->key[0] = ((unsigned long*)key)[0];
  1726.         node->key[1] = ((unsigned long*)key)[1];
  1727.  
  1728.         while(level >= 0)
  1729.         {
  1730.             node->fptr[level] = update[level]->fptr[level];
  1731.             update[level]->fptr[level] = node;
  1732.             level--;
  1733.         }
  1734.         TBL->lastptr = node;
  1735.         return node;
  1736.      }
  1737.     }
  1738.     return 0;
  1739. }
  1740. static int
  1741. StringFind(void *tbl, char *string, void *result)
  1742. {
  1743. unsigned long key[2];
  1744. struct {
  1745.     char *symname;
  1746. } *valp;
  1747.  
  1748.     key[0] = 0;
  1749.     key[1] = 0;
  1750.     sym_hash(key, string);
  1751.  
  1752.     if(SymFind(tbl, key, &valp) == 1)
  1753.     {
  1754.     unsigned long *key1;
  1755.         do {
  1756.             if(!strcmp(string, valp->symname))
  1757.             {
  1758.                 if(result)
  1759.                     *((void **)result) = valp;
  1760.                 return 1;
  1761.             }
  1762.             /* Check duplicates */
  1763.             if(!SymNext(tbl))
  1764.                 break;
  1765.             SymKey(tbl, &key1);
  1766.             SymValue(tbl, &valp);
  1767.         } while(KEYEQ(key, key1));
  1768.     }
  1769.     return 0;
  1770. }
  1771. static int
  1772. StringInsert(void *tbl, char *string, void *result)
  1773. {
  1774. unsigned long key[2];
  1775. struct {
  1776.     char *symname;
  1777. } *valp;
  1778.  
  1779.     key[0] = 0;
  1780.     key[1] = 0;
  1781.     sym_hash(key, string);
  1782.     if(SymFind(tbl, key, &valp) == 1)
  1783.     {/* hash keys match */
  1784.     unsigned long *key1;
  1785.         do {
  1786.             if(!strcmp(string, valp->symname))
  1787.             {
  1788.                 if(result)
  1789.                     *((void **)result) = valp;
  1790.                 return 1;
  1791.             }
  1792.             /* Check duplicates */
  1793.             if(!SymNext(tbl))
  1794.                 break;
  1795.             SymKey(tbl, &key1);
  1796.             SymValue(tbl, &valp);
  1797.         } while(KEYEQ(key, key1));
  1798.     }
  1799.     /* NOMATCH */
  1800.     valp = SymInsert(tbl, key, &string, 4);
  1801.     if(result)
  1802.         *((void**)result) = valp;
  1803.     return 0;
  1804. }
  1805. static void
  1806. SymDelete(void *tbl, void *key)
  1807. {
  1808. NodePS node;
  1809.  
  1810.     if(tbl && key)
  1811.     {
  1812.       if(TBL->nbins)
  1813.       {/* hashed dictionary */
  1814.       KEY cat;
  1815.       NodePS *binp;
  1816.       NodePS prev = 0;
  1817.  
  1818.         hash(key, &cat);
  1819.         binp = &TBL->bins[cat.hv % TBL->nbins];
  1820.         if((node = *binp))
  1821.         {
  1822.             do {
  1823.                 if(        node->key[0] == cat.k[0]
  1824.                     &&    node->key[0] == cat.k[1])
  1825.                 {
  1826.                     if(prev)
  1827.                         prev->fptr[0] = node->fptr[0];
  1828.                     else
  1829.                         *binp = node->fptr[0];
  1830.  
  1831.                     free_Snode(tbl, node);
  1832.                     if(TBL->lastptr == node)
  1833.                     {
  1834.                         TBL->lastptr = 0;
  1835.                         TBL->lastbin = TBL->nbins;
  1836.                     }
  1837.                     return;
  1838.                 }
  1839.                 prev = node;
  1840.              } while((node = node->fptr[0]));
  1841.         }
  1842.       }
  1843.       else
  1844.       {/* sorted dictionary */
  1845.       int level;
  1846.       NodePS update[SYM_MAXLEVEL+1];
  1847.  
  1848.         node = TBL->header;
  1849.         for(level = TBL->level; level >= 0; level--)
  1850.         {
  1851.           while ( KEYLT(node->fptr[level]->key, ((unsigned long*)key)) )
  1852.             node = node->fptr[level];
  1853.           update[level] = node;
  1854.         }
  1855.         node = node->fptr[0];
  1856.  
  1857.         if( KEYEQ(node->key, ((unsigned long*)key)) )
  1858.         {
  1859.             for(level = 0; level <= TBL->level; level++)
  1860.             {
  1861.                 if (update[level]->fptr[level] == node)
  1862.                      update[level]->fptr[level] = node->fptr[level];
  1863.                 else break;
  1864.             }
  1865.  
  1866.             while((TBL->level > 0) && (TBL->header->fptr[TBL->level] == _NNIL))
  1867.                 TBL->level--;
  1868.  
  1869.             if(TBL->lastptr == node)
  1870.                 TBL->lastptr = 0;
  1871.             free_Snode(tbl, node);
  1872.         }
  1873.       }
  1874.     }
  1875. }
  1876. static int
  1877. SymHead(void *tbl)
  1878. {/* Set up for sequential access */
  1879. int nbins;
  1880.  
  1881.     if(tbl)
  1882.     {
  1883.       if((nbins = TBL->nbins))
  1884.       {/* hashed dictionary */
  1885.       NodePS node;
  1886.       int i;
  1887.         TBL->lastptr = 0;
  1888.         for(i = 0; i < nbins; ++i)
  1889.         {
  1890.             if( (node = TBL->bins[i]) != 0)
  1891.             {
  1892.                 TBL->lastbin = i;
  1893.                 return 1;
  1894.             }
  1895.         }
  1896.         TBL->lastbin = nbins;
  1897.         return 0; /* empty */
  1898.       }
  1899.       else
  1900.       {/* sorted dictionary */
  1901.         TBL->lastptr = TBL->header;
  1902.         return (TBL->lastptr->fptr[0] == _NNIL) ? 0 : 1;
  1903.       }
  1904.     }
  1905.     return 0;
  1906. }
  1907. static int
  1908. SymNext(void *tbl)
  1909. {/* Move to next sequential entry */
  1910. int nbins;
  1911.  
  1912.     if(tbl)
  1913.     {
  1914.       if((nbins = TBL->nbins))
  1915.       {/* hashed dictionary */
  1916.         if(TBL->lastptr && ((TBL->lastptr = TBL->lastptr->fptr[0])))
  1917.             return 1;
  1918.         else
  1919.         {
  1920.         int i;
  1921.             for(i = TBL->lastbin; i < nbins; ++i)
  1922.             {
  1923.                 if((TBL->lastptr = TBL->bins[i]) != 0)
  1924.                 {
  1925.                     TBL->lastbin = i+1;
  1926.                     return 1;
  1927.                 }
  1928.             }
  1929.             return 0;
  1930.         }
  1931.       }
  1932.       else
  1933.       {/* sorted dictionary */
  1934.         if(TBL->lastptr)
  1935.         {
  1936.             if(TBL->lastptr != _NNIL)
  1937.                 TBL->lastptr = TBL->lastptr->fptr[0];
  1938.             return (TBL->lastptr == _NNIL) ? 0 : 1;
  1939.         }
  1940.       }
  1941.     }
  1942.     return 0;
  1943. }
  1944. static void
  1945. SymGetMark(void *tbl, void *markptr)
  1946. {
  1947.     if(tbl && markptr)
  1948.     {
  1949.         ((long*)markptr)[0] = TBL->lastbin;
  1950.         ((long*)markptr)[1] = (long)TBL->lastptr;
  1951.     }
  1952. }
  1953. static int
  1954. SymMarkNext(void *tbl, void *mark)
  1955. {/* Mark current position, and move to next sequential entry */
  1956.     SymGetMark(tbl, mark);
  1957.     return SymNext(tbl);
  1958. }
  1959. static void
  1960. SymSetMark(void *tbl, void *markptr)
  1961. {
  1962.     if(tbl && markptr)
  1963.     {
  1964.         TBL->lastbin = ((long*)markptr)[0];
  1965.         TBL->lastptr = (NodePS)((long*)markptr)[1];
  1966.     }
  1967. }
  1968. static void
  1969. SymKey(void *tbl, void *keyptr)
  1970. {/* Retrieve key info pointer for current spot */
  1971.  
  1972.     if(tbl && keyptr && TBL->lastptr)
  1973.         *((unsigned long**)keyptr) = &TBL->lastptr->key[0];
  1974. }
  1975. static void
  1976. SymValue(void *tbl, void *datptr)
  1977. {/* Retrieve value pointer for current spot */
  1978.  
  1979.     if(tbl && datptr && TBL->lastptr)
  1980.         *((unsigned long**)datptr) = &TBL->lastptr->value[0];
  1981. }
  1982.  
  1983. /* ==================== END SYMBOL TABLE HANDLERS ========================== */
  1984.  
  1985. /* ========================== OPTIMIZATION ================================= */
  1986. static int
  1987. forward(unsigned char *p)
  1988. {
  1989. unsigned char *next;
  1990.  
  1991.     do {
  1992.         next = (void*)((Pop)p)->next;
  1993.         while(        *next == 0
  1994.                 ||    *next == lineop
  1995.                 ||    *next == labelop)
  1996.             next = (void*)((Pop)next)->next;
  1997.  
  1998.         if(*next == endop)
  1999.         {
  2000.             if(*p == *(next+8))
  2001.             {
  2002.                 *p = 0;
  2003.                 *next = 0;
  2004.                 return 1;
  2005.             }
  2006.             return 0;
  2007.         }
  2008.     } while(forward(next));
  2009.  
  2010.     return 0;
  2011. }
  2012. static void
  2013. eliminate_extraneous_infops(Piv iv, int level)
  2014. {
  2015. Pafile pf;
  2016. unsigned char *p;
  2017. int i;
  2018.     for(i = 0; i < iv->numfiles; ++i)
  2019.     {
  2020.         iv->filenum = i;
  2021.         pf = iv->files[i];
  2022.         if(!(p = pf->prog_p))
  2023.             continue;
  2024.         if(pf->header_p->hdr.opt_level >= level)
  2025.             continue;
  2026.         pf->header_p->hdr.opt_level = level;
  2027.         while(*p != endfileop)
  2028.         {
  2029.             switch(*p)
  2030.             {
  2031.                 case    unopop:
  2032.                 case    arrayelemop:
  2033.                 case    ptrelemop:
  2034.                 case    strelemop:
  2035.                 case    ptrdimsop:
  2036.                 case    arraydimsop:
  2037.                     forward(p);
  2038.                     break;
  2039.             }
  2040.             p = POP->next;
  2041.         }
  2042.     }
  2043. }
  2044.  
  2045. static void
  2046. clean_temps(Piv iv)
  2047. {
  2048. long *key;
  2049. long *val;
  2050. long hitemp = iv->first_temp & 0xffff0000;
  2051.  
  2052.     if(iv->temps_written == 0)
  2053.         return;
  2054.     if(SymHead(iv->tmptbl))
  2055.     {
  2056.         while(SymNext(iv->tmptbl))
  2057.         {
  2058.             SymKey(iv->tmptbl, &key);
  2059.  
  2060.             if((key[0] & 0xffff0000) == hitemp)
  2061.             {
  2062.             char *ptr;
  2063.             long saveit;
  2064.  
  2065.                 SymValue(iv->tmptbl, &val);
  2066.                 saveit = val[1];
  2067.                 ptr = (void*)val[0];
  2068.  
  2069.                 val[0] = 0;    /* allow reuse of this slot */
  2070.                 val[1] = 0;
  2071.  
  2072.                 while(ptr)
  2073.                 {
  2074.                 void *nptr = (void*)((PopT)ptr)->tmpnum;
  2075.                     ((PopT)ptr)->tmpnum = key[0];
  2076.                     if(!saveit)
  2077.                     {
  2078.                         *(ptr-8) = 0;                        
  2079.                         ++iv->killop;
  2080.                     }
  2081.                     ptr = nptr;
  2082.                 }
  2083.             }
  2084.         }
  2085.         if(!hitemp)
  2086.             iv->temps_written = 0;
  2087.     }
  2088. }
  2089.  
  2090. static void
  2091. read_temp(Piv iv, PopT ptr, unsigned long last)
  2092. {
  2093. unsigned long key[2];
  2094. long *result;
  2095.  
  2096.     if(last == ptr->tmpnum)
  2097.         return;
  2098.  
  2099.     key[0] = ptr->tmpnum;
  2100.     key[1] = 0;
  2101.  
  2102.     if(SymFind(iv->tmptbl, key, &result) == 1)
  2103.     {
  2104.         result[1] = 1;
  2105.     }
  2106.     else PERROR(pName ":Syserr: read temp %d not found\n", key[0]);
  2107. }
  2108. static long
  2109. write_temp(Piv iv, PopT ptr)
  2110. {
  2111. long key[2];
  2112. long val[2];
  2113. long *result;
  2114. long hitemp = ptr->tmpnum & 0xffff0000;
  2115.  
  2116.     if(ptr->atype & A_MEMADDR)
  2117.     {/* actually reading from this destination slot */
  2118.         read_temp(iv, ptr, 0);
  2119.         return 0;
  2120.     }
  2121.  
  2122.     if(hitemp > (iv->first_temp & 0xffff0000))
  2123.     {/* Inner block, CompoundExp or NestedFunc */
  2124.         iv->first_temp = hitemp + 1;
  2125.     }
  2126.     else if(hitemp < (iv->first_temp & 0xffff0000))
  2127.     {/* Exit inner block */
  2128.         while(hitemp < (iv->first_temp & 0xffff0000))
  2129.         {
  2130.             clean_temps(iv);
  2131.             iv->first_temp -= 0x00010000;
  2132.         }
  2133.     }
  2134.     if(ptr->tmpnum == iv->first_temp)
  2135.     {
  2136.         clean_temps(iv);
  2137.     }
  2138.     ++iv->temps_written;
  2139.     key[0] = ptr->tmpnum;
  2140.     key[1] = 0;
  2141.  
  2142.     if(SymFind(iv->tmptbl, key, &result) == 1)
  2143.     {
  2144.     PopT optr = (PopT)result[0];
  2145.         result[0] = (long)ptr;
  2146.         ptr->tmpnum = (long)optr;
  2147.     }
  2148.     else
  2149.     {
  2150.         val[0] = (long)ptr;
  2151.         val[1] = 0;
  2152.         SymInsert(iv->tmptbl, key, val, 8);
  2153.         ptr->tmpnum = 0;
  2154.     }
  2155.     return key[0];
  2156. }
  2157. static void
  2158. eliminate_unused_temps(Piv iv, int level)
  2159. {
  2160. Pafile pf;
  2161. unsigned char *p;
  2162. int i;
  2163. long last_write;
  2164.  
  2165.     iv->tmptbl = NewSymTable(iv->category, 111);
  2166.     for(i = 0; i < iv->numfiles; ++i)
  2167.     {
  2168.         iv->filenum = i;
  2169.         pf = iv->files[i];
  2170.         if(pf->header_p->hdr.opt_level >= level)
  2171.             continue;
  2172.         pf->header_p->hdr.opt_level = level;
  2173. rekill:
  2174.         if(!(p = pf->prog_p))
  2175.             continue;
  2176.         iv->first_temp = 1;
  2177.         iv->temps_written = 0;
  2178.         iv->killop = 0;
  2179.         while(*p != endfileop)
  2180.         {
  2181.             if(*p < labelop)
  2182.             {
  2183.                 if(*p == truthop)
  2184.                 {/* truthops of single chars are unnecessary */
  2185.                   if((p[2] & 0xe0) == OPTEMP)
  2186.                   {
  2187.                     if(((PopT)(p+20))->dsize == 1)
  2188.                     {
  2189.                         if(((PopT)(p+8))->tmpnum == ((PopT)(p+20))->tmpnum)
  2190.                         {
  2191.                             *p = 0;
  2192.                         }
  2193.                         else
  2194.                         {/* may be needed for code generation */
  2195.                             *p = aliastmpop;
  2196.                         }
  2197.                     }
  2198.                   }
  2199.                 }
  2200.                 if(*p)
  2201.                 {
  2202.                     if(*p == jmptrueop || *p == jmpfalseop)
  2203.                         read_temp(iv,(PopT)(p+4), 0);
  2204.                     else
  2205.                     {
  2206.                         last_write = 0;
  2207.                         if((p[1] & 0xe0) == OPTEMP)
  2208.                             last_write = write_temp(iv, (PopT)(p+8));
  2209.                         if((p[2] & 0xe0) == OPTEMP)
  2210.                             read_temp(iv, (PopT)(p+8+(p[1]&0x1f)), last_write);
  2211.                         if((p[3] & 0xe0) == OPTEMP)
  2212.                             read_temp(iv, (PopT)(p+8+(p[1]&0x1f)+(p[2]&0x1f)), last_write);
  2213.                     }
  2214.                 }
  2215.             }
  2216.             p = POP->next;
  2217.         }
  2218.         do {
  2219.             clean_temps(iv);
  2220.             iv->first_temp -= 0x00010000;
  2221.         } while(iv->first_temp > 0);
  2222.         if(iv->killop)
  2223.             goto rekill;
  2224.     }
  2225. }
  2226. static void
  2227. retarget_jmps(Piv iv, int level)
  2228. {
  2229. Pafile pf;
  2230. unsigned char *p;
  2231. int i;
  2232.     for(i = 0; i < iv->numfiles; ++i)
  2233.     {
  2234.         iv->filenum = i;
  2235.         pf = iv->files[i];
  2236.         if(!(p = pf->prog_p))
  2237.             continue;
  2238.         if(pf->header_p->hdr.opt_level >= level)
  2239.             continue;
  2240. #if 0
  2241.         pf->header_p->hdr.opt_level = level;
  2242.         while(*p != endfileop)
  2243.         {
  2244.             p = POP->next;
  2245.         }
  2246. #endif
  2247.     }
  2248. }
  2249.  
  2250. static void
  2251. optimize(Piv iv)
  2252. {
  2253.     eliminate_extraneous_infops(iv, 50);
  2254.     eliminate_unused_temps(iv, 51);
  2255.     retarget_jmps(iv, 52);
  2256. }
  2257. /* ========================== END OPTIMIZATION ============================= */
  2258. /* ====================== BASIC INPUT FILE PROCESSING ====================== */
  2259. static long
  2260. label_insert(Piv iv, long label, int filenum)
  2261. {
  2262. struct {
  2263.     long k1;
  2264.     long k2;
  2265. } key;
  2266.  
  2267. struct {
  2268.     long newlabel;
  2269. } val;
  2270.  
  2271.     key.k1 = label;
  2272.     key.k2 = filenum;
  2273.     val.newlabel = ++iv->lastlabel;
  2274.  
  2275.     SymInsert(iv->labeltbl, &key, &val, 4);
  2276. #if REALLY_NEED_OFFSETS
  2277.     key.k1 = val.newlabel;
  2278.     val.newlabel = -1;
  2279.     SymInsert(iv->newlabeltbl, &key, &val, 4);
  2280. #endif
  2281.     return iv->lastlabel;
  2282. }
  2283. static long
  2284. label_find(Piv iv, long label, int filenum)
  2285. {
  2286. struct {
  2287.     long k1;
  2288.     long k2;
  2289. } key;
  2290.  
  2291. long *result;
  2292.  
  2293.     key.k1 = label;
  2294.     key.k2 = filenum;
  2295.  
  2296.     if(SymFind(iv->labeltbl, &key, &result) == 1)
  2297.         return *result;
  2298.     else
  2299.         return 0;
  2300. }
  2301. #if REALLY_NEED_OFFSETS
  2302. static long
  2303. newlabel_find(Piv iv, long label, int filenum)
  2304. {
  2305. struct {
  2306.     long k1;
  2307.     long k2;
  2308. } key;
  2309.  
  2310. long *result;
  2311.  
  2312.     key.k1 = label;
  2313.     key.k2 = filenum;
  2314.  
  2315.     if(SymFind(iv->newlabeltbl, &key, &result) == 1)
  2316.         return *result;
  2317.     else
  2318.         return 0;
  2319. }
  2320. #endif /* REALLY_NEED_OFFSETS */
  2321.  
  2322. static void
  2323. extern_insert(Piv iv, unsigned char *p, int filenum)
  2324. {
  2325. struct {
  2326.     short k1;
  2327.     short k2;
  2328.     long k3;
  2329. } key;
  2330. struct {
  2331.     unsigned char *p;
  2332. } val;
  2333.  
  2334.     key.k1 = GS(POPI->s.symnum);
  2335.     key.k2 = filenum;
  2336.     key.k3 = 0;
  2337.  
  2338.     val.p = p;
  2339.     SymInsert(iv->extrntbl, &key, &val, 4);
  2340. }
  2341. static void
  2342. reloc_insert(Piv iv, int fileno, unsigned char *p)
  2343. {
  2344. struct {
  2345.     unsigned long spot;
  2346.     short fileno;
  2347.     char opcode;
  2348.     char rsize;
  2349. } key;
  2350. struct {
  2351.     unsigned char *p;
  2352.     unsigned long base;
  2353.     long offset;
  2354.     short rsym;
  2355. } val;
  2356.  
  2357.     key.spot = GL(POPI->reloc.spot);        /* reloc target offset */
  2358.     key.fileno = (short)fileno;                /* fileno */
  2359.     key.opcode = *p;                        /* opcode */
  2360.     key.rsize = GL(POPI->reloc.rsize);        /* reloc size */
  2361.  
  2362.     val.p = p;                                /* pointer to input buffer */
  2363.     val.base = GL(POPI->reloc.base);        /* base of data object pointed to */
  2364.     val.offset = GL(POPI->reloc.offset);    /* offset to be added to base */
  2365.     val.rsym = GL(POPI->reloc.rsym);        /* symbol number if external */
  2366.  
  2367.     SymInsert(iv->reloctbl, &key, &val, 14);
  2368. }
  2369. static void
  2370. data_insert(void *tbl, unsigned long offset, unsigned long size, void *p)
  2371. {
  2372. struct {
  2373.     unsigned long k1;
  2374.     long k2;
  2375. } key;
  2376. struct {
  2377.     unsigned long size;
  2378.     void *p;
  2379. } val;
  2380.  
  2381.     key.k1 = offset;
  2382.     key.k2 = 0;
  2383.  
  2384.     val.size = size;
  2385.     val.p = p;
  2386.  
  2387.     SymInsert(tbl, &key, &val, sizeof(val));
  2388. }
  2389.  
  2390. static void
  2391. global_insert(Piv iv, Pafile pf, unsigned char *p)
  2392. {
  2393. unsigned long key[2];
  2394. struct _gloval val;
  2395. PopI pp;
  2396. unsigned char opcode = *p;
  2397.  
  2398.     if(opcode == extvarop)
  2399.         pp = POPI;
  2400.     else
  2401.         pp = (PopI)(POP->next+8);
  2402.  
  2403.     key[0] = 0;
  2404.     key[1] = 0;
  2405.  
  2406.     val.symnum = GS(pp->s.symnum);
  2407.     val.symname = pf->symaddr[val.symnum];
  2408.     val.p = p;
  2409.     val.pf = pf;
  2410.  
  2411.     sym_hash(key, val.symname);
  2412.     SymInsert(iv->gbltbl, key, &val, sizeof(val));
  2413. }
  2414.  
  2415. static int
  2416. setup_nodelinks(Piv iv, char *infile_name, void *inbuf, int insize)
  2417. {
  2418. unsigned char *p = inbuf;
  2419. unsigned char *endbuf = inbuf+insize;
  2420. Pafile pf=0;
  2421. long lastline = 0;
  2422. unsigned char *funcp;
  2423. unsigned char *nfuncp;
  2424.  
  2425.     while(p < endbuf && *p != endallop)
  2426.     {
  2427.     unsigned char *q = p;
  2428.         if(iv->debug)
  2429.         {
  2430.             PRINTF("OP(%d '%s' p=%p line=%ld)\n", *p, oxgenops[*p], p, lastline);
  2431.         }
  2432.         switch(*p)
  2433.         {
  2434.             case headerop:
  2435.                 if(iv->numfiles >= 1024) {
  2436.                     PERROR(pName ": Sorry, too many files\n");
  2437.                     return 1;
  2438.                 }
  2439.                 pf = iv->files[iv->numfiles] = 
  2440.                     Ccalloc(iv->category, 1, sizeof(struct _afile));
  2441.                 pf->filenum = iv->numfiles++;
  2442.                 pf->file_p = p;
  2443.                 pf->header_p = POPI;
  2444.                 if(iv->strip)
  2445.                 {/* Gonna strip declarations and line numbers */
  2446.                     pf->header_p->hdr.target_debugger = 0;
  2447.                 }
  2448.                 break;
  2449.  
  2450.             case dataop:
  2451.                 pf->size_p = POPI;
  2452.                 pf->thunk_offset = GL(POPI->dat.thunk_offset);
  2453.                 pf->bss_offset = GL(POPI->dat.bss_offset);
  2454.                 break;
  2455.             case gfuncdefop:
  2456.             case sfuncdefop:
  2457.                 if(pf->prog_p == 0)
  2458.                     pf->prog_p = p;
  2459.                 funcp = p;
  2460.                 break;
  2461.             case funcexitop:
  2462.                 PS(((PopI)(funcp+8))->funcdef.tempmax) = GL(POPI->funcexit.tempmax);
  2463.                 break;
  2464.             case nestedfuncdefop:
  2465.                 nfuncp = p;
  2466.                 break;
  2467.             case nestedfuncexitop:
  2468.                 PS(((PopI)(nfuncp+8))->funcdef.tempmax) = GL(POPI->funcexit.tempmax);
  2469.                 break;
  2470.             case segdefop:
  2471.                 if(pf->seg_p == 0)
  2472.                     pf->seg_p = p;
  2473.                 pf->numsegs += 1;
  2474.                 iv->numsegs += 1;
  2475.                 break;
  2476.             case lineop:
  2477.                 lastline = GL( POPI->line.line );
  2478.                 if(iv->strip)
  2479.                     *p = 0;        /* strip line numbers */
  2480.                 break;
  2481.             case declop:
  2482.                 if(iv->strip)
  2483.                 {/* strip declarations */
  2484.                     do {
  2485.                         *p = 0;
  2486.                         q += (long)GL(POP->next);
  2487.                         POP->next = q;
  2488.                         p = q;
  2489.                     } while(*p != endop);                    
  2490.                     *p = 0;
  2491.                 }
  2492.                 else
  2493.                 {
  2494.                     if(pf->decl_p == 0)
  2495.                         pf->decl_p = p;
  2496.                     pf->numdecls += 1;
  2497.                     iv->numdecls += 1;
  2498.                 }
  2499.                 break;
  2500.             case switchidop:
  2501.                 if(pf->switch_p == 0)
  2502.                     pf->switch_p = p;
  2503.             /* FALL THROUGH */
  2504.             case labelop:
  2505.                 PL( POP->data ) = 
  2506.                         label_insert(iv, GL( POP->data ), pf->filenum);
  2507.                 break;            
  2508.             case symbop:
  2509.                 pf->numsyms = GL(POP->data);
  2510.                 iv->numsyms += pf->numsyms;
  2511.                 break;
  2512.             case symblockop:
  2513.                 pf->symtext_p = p + 12;
  2514.                 goto blka;
  2515.             case stringblockop:
  2516.             case datablockop:
  2517.             case mallocblockop:
  2518.             case thunkblockop:
  2519.             {
  2520.             long size;
  2521.                 if(pf->data_p == 0)
  2522.                     pf->data_p = p;
  2523. blka:
  2524.                 size = GL(POP->data);
  2525.                 q += size+((4-(size&3))&3);
  2526.                 break;
  2527.             }
  2528.             case glofuncop:
  2529.             case extfuncop:
  2530.             case glodatop:
  2531.             case globssop:
  2532.             case extvarop:
  2533.             case bssblockop:
  2534.                 if(pf->data_p == 0)
  2535.                     pf->data_p = p;
  2536.                 break;
  2537.             case maxtempop:
  2538.                 pf->maxtemp = GL(POP->data);
  2539.                 pf->maxtempclass = GL(POP->data1);
  2540.                 pf->maxtemp_p = p;
  2541.                 break;
  2542.         }
  2543.         q += (long)GL(POP->next);
  2544.         POP->next = q;
  2545.         p = q;
  2546.     }
  2547.     if(*p != endallop)
  2548.     {
  2549.         PERROR(pName ": Malformed input file: %s\n", infile_name);
  2550.         return 1;
  2551.     }
  2552.     return 0;
  2553. }
  2554. static void
  2555. setup_syms_decls(Piv iv)
  2556. {
  2557. int i;
  2558.  
  2559.     for(i = 0; i < iv->numfiles; ++i)
  2560.     {
  2561.     int symnum = 0;
  2562.     Pafile pf = iv->files[i];
  2563.     unsigned char *p = pf->file_p;
  2564.  
  2565.         pf->symaddr = Ccalloc(iv->category, sizeof(void*), pf->numsyms);
  2566.         pf->decladdr = Ccalloc(iv->category, sizeof(void*), pf->numdecls);
  2567.  
  2568.         while(*p != endfileop)
  2569.         {
  2570.             switch(*p)
  2571.             {
  2572.                 case    symoffsetop:
  2573.                   pf->symaddr[symnum] = pf->symtext_p + GL(POP->data);
  2574.                   ++symnum;
  2575.                   break;
  2576.  
  2577.                 case    declop:
  2578.                   pf->decladdr[GS(POPI->dcl.declnum)] = p;
  2579.                   break;
  2580.  
  2581.                 case    relocop:
  2582.                 case    extlocop:
  2583.                   ++pf->numrelocs;
  2584.                   reloc_insert(iv, i, p);
  2585.                   break;
  2586.  
  2587.                 case    glodatop:
  2588.                 case    globssop:
  2589.                 case    glofuncop:
  2590.                 case    extfuncop:
  2591.                   global_insert(iv, pf, p);
  2592.                   break;
  2593.  
  2594.                 case    extvarop:
  2595.                   extern_insert(iv, p, i);
  2596.                   global_insert(iv, pf, p);
  2597.                   break;
  2598.  
  2599.                 case    stringblockop:
  2600.                 case    datablockop:
  2601.                 case    mallocblockop:
  2602.                 case    thunkblockop:
  2603.                 case    bssblockop:
  2604.                   if(!pf->datatbl)
  2605.                     pf->datatbl = NewSymTable(iv->category, 0);  /* sorted */
  2606.  
  2607.                   data_insert(pf->datatbl,GL(DATI.offset),GL(DATI.size),p);
  2608.  
  2609.                   if(*p == thunkblockop) {
  2610.                     PL(POP->data4) = label_find(iv, GL(POP->data4),i);
  2611.                   }
  2612.                   break;
  2613.  
  2614.                 case    jmploopop:
  2615.                 case    jmpcontinueop:
  2616.                 case    jmpbreakop:
  2617.                 case    jmpgotoop:
  2618.                 case    jmptrueop:
  2619.                 case    jmpfalseop:
  2620.                   PL(POP->data) = label_find(iv, GL(POP->data), i);
  2621.                   break;
  2622.                 case    switchidop:
  2623.                   if(GL(POP->data1))
  2624.                     PL(POP->data1) = label_find(iv, GL(POP->data1), i);
  2625.                   break;
  2626.                 case    switchop:
  2627.                   PL(POP->data) = label_find(iv, GL(POP->data), i);
  2628.                   PL(POP->data1) = label_find(iv, GL(POP->data1), i);
  2629.                   break;
  2630.                 case casevalop:
  2631.                   PL(POP->data1) = label_find(iv, GL(POP->data1), i);
  2632.                   break;
  2633.             }
  2634.             p = POP->next;
  2635.         }
  2636.     }
  2637. }
  2638. static int
  2639. sym_insert(Piv iv, char *symname, int symnum)
  2640. {/* Used only for combining symbols in link phase */
  2641. struct {
  2642.     char *symname;
  2643.     int symnum;
  2644. } *valp;
  2645.  
  2646.     if(StringInsert(iv->symtbl, symname, &valp))
  2647.         return -valp->symnum;    /* MATCH */
  2648.     valp->symnum = symnum;
  2649.     return symnum;
  2650. }
  2651. static void
  2652. combine_syms_decls(Piv iv)
  2653. {
  2654. int i,j;
  2655. Pafile pf;
  2656. int numsyms;
  2657. int numdecls;
  2658.  
  2659.  
  2660.     /* COMBINE SYMBOLS */
  2661.     pf = iv->files[0];
  2662.     numsyms = pf->numsyms;
  2663.     pf->symtran = Ccalloc(iv->category, sizeof(short), pf->numsyms);
  2664.     memcpy(iv->symaddr, pf->symaddr, sizeof(void*) * numsyms);
  2665.  
  2666.  
  2667.     for(i = 0; i < numsyms; ++i)
  2668.     {/* file 0 */
  2669.         sym_insert(iv, pf->symaddr[i], i);
  2670.         pf->symtran[i] = i;
  2671.     }
  2672.     for(i = 1; i < iv->numfiles; ++i)
  2673.     {
  2674.     int start;
  2675.         pf = iv->files[i];
  2676.         pf->symtran = Ccalloc(iv->category, sizeof(short), pf->numsyms);
  2677.         if(pf->header_p->hdr.target_debugger)
  2678.             start = 1;
  2679.         else
  2680.             start = 3;
  2681.         for(j = start; j < pf->numsyms; ++j)
  2682.         {
  2683.         int k;
  2684.           if((k = sym_insert(iv, pf->symaddr[j], numsyms)) > 0)
  2685.           { /* new entry */
  2686.             iv->symaddr[numsyms++] = pf->symaddr[j];
  2687.             pf->symtran[j] = k;
  2688.           }
  2689.           else pf->symtran[j] = -k;
  2690.         }
  2691.     }
  2692.     iv->numsyms = numsyms;
  2693.  
  2694.     /* COMBINE DECLARATIONS */
  2695.     pf = iv->files[0];
  2696.     numdecls = pf->numdecls;
  2697.     pf->decltran = Ccalloc(iv->category, sizeof(short), pf->numdecls);
  2698.     memcpy(iv->decladdr, pf->decladdr, sizeof(void*) * numdecls);
  2699.  
  2700.     for(i = 0; i < numdecls; ++i)
  2701.     {/* file 0 */
  2702.         pf->decltran[i] = i;
  2703.     }
  2704.     for(i = 1; i < iv->numfiles; ++i)
  2705.     {
  2706.         pf = iv->files[i];
  2707.         pf->decltran = Ccalloc(iv->category, sizeof(short), pf->numdecls);
  2708.         if(pf->numdecls < 21)
  2709.             continue;
  2710.         for(j = 1; j <= 21; ++j)
  2711.             pf->decltran[j] = j;
  2712.         for(j = 22; j < pf->numdecls; ++j) {
  2713.             iv->decladdr[numdecls] = pf->decladdr[j];
  2714.             pf->decltran[j] = numdecls++;
  2715.         }
  2716.     }
  2717.     iv->numdecls = numdecls;
  2718. }
  2719.  
  2720. static void
  2721. link_dups(Piv iv, int dupcnt, struct _gloval *valp[])
  2722. {
  2723. int i;
  2724. int vars[5] = {0,0,0,0,0};
  2725. unsigned long cdsize = 0;
  2726. unsigned long cdoffset = 0;
  2727. short cdfile = 0;
  2728. int cdnum = 0;
  2729. short segid = 0;
  2730.  
  2731. #define GDAT vars[0]
  2732. #define GBSS vars[1]
  2733. #define GFUNC vars[2]
  2734. #define EVAR vars[3]
  2735. #define EFUNC vars[4]
  2736.  
  2737.     /* Count the types of matches */
  2738.     for(i = 0; i <= dupcnt; ++i)
  2739.         vars[*(valp[i]->p) - glodatop] += 1;
  2740.  
  2741.     /* Check for errors */
  2742.     if(        GDAT > 1 
  2743.         ||    GFUNC > 1
  2744.         ||    (GFUNC && (GDAT || GBSS || EVAR))
  2745.         ||    (EFUNC && (GDAT || GBSS || EVAR)))
  2746.     {
  2747.         ++iv->errors;
  2748.         for(i = 0; i < dupcnt; ++i)
  2749.         {
  2750.             PWARN(pName ": Symbol `%s' multiply defined or mistyped.\n",
  2751.                   valp[i]->symname);
  2752.             PWARN(pName ":  In file: `%s'\n", valp[i]->pf->symaddr[INFILE_SYMNUM]);
  2753.         }
  2754.         return;
  2755.     }
  2756.     if(EFUNC && GFUNC)
  2757.     {/* match up functions */
  2758.     Pop dp;
  2759.         for(i = 0; i <= dupcnt; ++i)
  2760.           if(*(valp[i]->p) == glofuncop)
  2761.             break;
  2762.         dp = (Pop)((Pop)valp[i]->p)->next;    /* points to thunkblockop */
  2763.         cdoffset = GL(dp->data1);            /* save this offset */
  2764.         cdfile = valp[i]->pf->filenum;        /* save this file */
  2765.  
  2766.         for(i = 0; i <= dupcnt; ++i)
  2767.         {
  2768.           if(*(valp[i]->p) == extfuncop)
  2769.           {
  2770.             *(valp[i]->p) = 0;                    /* convert to nilop */
  2771.             dp = (Pop)((Pop)valp[i]->p)->next;    /* points to thunkblockop */
  2772.  
  2773.             /* Kill the functhunk */
  2774.             *((char*)dp) = 0;
  2775.             PL(dp->data4) = cdoffset;            /* use this offset for access */
  2776.             PS(((short*)dp)[1]) = cdfile;        /* fileno to unused slots */
  2777.           }
  2778.         }
  2779.     }
  2780.     else if(EFUNC)
  2781.     {/* multiple references to external function */
  2782.     Pop    dp = (Pop)((Pop)valp[0]->p)->next;    /* points to first thunkblockop */
  2783.  
  2784.         cdoffset = GL(dp->data1);            /* save first offset */
  2785.         cdfile = valp[0]->pf->filenum;        /* save first file */
  2786.         for(i = 1; i <= dupcnt; ++i)
  2787.         {/* Kill all thunkblocks except the first */
  2788.             *(valp[i]->p) = 0;                    /* convert to nilop */
  2789.             dp = (Pop)((Pop)valp[i]->p)->next;    /* points to thunkblockop */
  2790.             *((char*)dp) = 0;
  2791.             PL(dp->data4) = cdoffset;            /* use this offset for access */
  2792.             PS(((short*)dp)[1]) = cdfile;        /* fileno to unused slots */
  2793.         }
  2794.     }
  2795.     else if(GBSS)
  2796.     {/* comdefs */
  2797.     int multsize = 0;
  2798.  
  2799.         /* PICK THE BIGGEST GLOBAL BSS (comdef) */
  2800.         for(i = 0; i <= dupcnt; ++i)
  2801.         {
  2802.         Pop dp = (Pop)((Pop)valp[i]->p)->next;    /* points to bssblockop */
  2803.           if((short)dp->data4 && segid == 0)
  2804.           {
  2805.             segid = (short)dp->data4;
  2806.           }
  2807.           else if((short)dp->data4 && (short)dp->data4 != segid)
  2808.           {
  2809.             ++iv->errors;
  2810.             PWARN(pName, ": Variable `%s' defined in multiple segments.\n",
  2811.                 valp[i]->symname);
  2812.             PWARN(pName ": In file: `%s'\n", valp[i]->pf->symaddr[INFILE_SYMNUM]);
  2813.           }
  2814.           if(*(valp[i]->p) == globssop)
  2815.           {
  2816.           long size = GL(dp->data);
  2817.             if(cdsize && size != cdsize)
  2818.                 multsize = 1;
  2819.             if(size > cdsize) {
  2820.                 cdsize = size;
  2821.                 cdoffset = GL(dp->data1);
  2822.                 cdfile = valp[i]->pf->filenum;
  2823.                 cdnum = i;
  2824.             }
  2825.           }
  2826.         }
  2827.         if(GDAT)
  2828.         {
  2829.           /* INITIALIZED DATA WILL ALWAYS OVERRIDE BSS */
  2830.           for(i = 0; i <= dupcnt; ++i)
  2831.           {
  2832.             if(*(valp[i]->p) == glodatop)
  2833.             {
  2834.             Pop dp = (Pop)((Pop)valp[i]->p)->next;    /* points to datablockop */
  2835.             long size = GL(dp->data);
  2836.               if(cdsize && size != cdsize)
  2837.                   multsize = 1;
  2838.               if(size < cdsize)
  2839.               {
  2840.             ++iv->errors;
  2841.             PWARN(pName ": Initialized variable `%s' of size (%d)\n",
  2842.               valp[i]->symname, size);
  2843.             PWARN(pName ":  In file: `%s'\n",
  2844.               valp[i]->pf->symaddr[INFILE_SYMNUM]);
  2845.             PWARN(pName ":  Is incommensurate with common size (%d).\n",
  2846.               cdsize);
  2847.               }
  2848.               else
  2849.               {
  2850.                   cdsize = size;
  2851.                   cdoffset = GL(dp->data1);
  2852.                   cdfile = valp[i]->pf->filenum;
  2853.                   cdnum = i;
  2854.               }
  2855.             }
  2856.           }
  2857.         }
  2858.         if(multsize)
  2859.         {
  2860.           PWARN(pName ":warning: Common Variable `%s' has multiple sizes.\n",
  2861.               valp[0]->symname);
  2862.           for(i = 0; i <= dupcnt; ++i)
  2863.           {
  2864.           unsigned char opcode = *(valp[i]->p);
  2865.             if(opcode == globssop || opcode == glodatop)
  2866.             {
  2867.                 PWARN(pName ":  Size=%d in file: `%s'\n",
  2868.                   GL(((Pop)((Pop)valp[i]->p)->next)->data),
  2869.                   valp[i]->pf->symaddr[INFILE_SYMNUM]);
  2870.             }
  2871.           }
  2872.         }
  2873.         /* FINALLY, LINK COMMONS TO THE CHOSEN ONE */
  2874.         for(i = 0; i <= dupcnt; ++i)
  2875.         {
  2876.           if(i != cdnum && *(valp[i]->p) == globssop)
  2877.           {
  2878.           Pop dp = (Pop)((Pop)valp[i]->p)->next;    /* points to bssblockop */
  2879.  
  2880.             *(valp[i]->p) = 0;            /* globssop becomes nilop */
  2881.             *((char*)dp) = 0;            /* bssblockop becomes nilop */
  2882.             PL(dp->data1) = cdoffset;    /* use this new offset for access */
  2883.             PS(((short*)dp)[1]) = cdfile;    /* put fileno in unused slots */
  2884.           }
  2885.         }
  2886.     }
  2887.     else if(GDAT)
  2888.     {
  2889.         for(i = 0; i <= dupcnt; ++i)
  2890.         {
  2891.         Pop dp = (Pop)((Pop)valp[i]->p)->next;    /* points to datablockop */
  2892.           if((short)dp->data4 && segid == 0)
  2893.           {
  2894.             segid = (short)dp->data4;
  2895.           }
  2896.           else if((short)dp->data4 && (short)dp->data4 != segid)
  2897.           {
  2898.             ++iv->errors;
  2899.             PWARN(pName, ": Variable `%s' defined in multiple segments.\n",
  2900.                 valp[i]->symname);
  2901.             PWARN(pName ": In file: `%s'\n", valp[i]->pf->symaddr[INFILE_SYMNUM]);
  2902.           }
  2903.           if(*(valp[i]->p) == glodatop)
  2904.           {
  2905.             cdsize = GL(dp->data);
  2906.             cdoffset = GL(dp->data1);
  2907.             cdfile = valp[i]->pf->filenum;
  2908.             cdnum = i;
  2909.             break;
  2910.           }
  2911.         }
  2912.     }
  2913.     if(EVAR && (GDAT || GBSS))
  2914.     {/* match up variables */
  2915.         /* LINK EXTERNS TO THE CHOSEN ONE */
  2916.         for(i = 0; i <= dupcnt; ++i)
  2917.         {
  2918.           if(*(valp[i]->p) == extvarop)
  2919.           {
  2920.           Pop dp = (Pop)valp[i]->p;
  2921.  
  2922.             *((char*)dp) = 0;            /* extvarop becomes nilop */
  2923.             PL(dp->data1) = cdoffset;    /* use this new offset for access */
  2924.             PS(((short*)dp)[1]) = cdfile;    /* put fileno in unused slots */
  2925.             PS(dp->data4) = segid;
  2926.             break;
  2927.           }
  2928.         }
  2929.     }
  2930. #undef GDAT
  2931. #undef GBSS
  2932. #undef GFUNC
  2933. #undef EVAR
  2934. #undef EFUNC
  2935.  
  2936. }
  2937. static void
  2938. link_globals(Piv iv)
  2939. {
  2940.     if(SymHead(iv->gbltbl))
  2941.     {
  2942.     struct _gloval *valp[1024];    /* pointers to symtable value structs */
  2943.  
  2944.       /* Pass over the sorted symbol table and process duplicate entries */
  2945.       while(SymNext(iv->gbltbl))
  2946.       {
  2947.       unsigned long *key;
  2948.       long mark[2];                            /* Table position saver */
  2949.       int dupcnt = 0;
  2950.         SymKey(iv->gbltbl, &key);            /* Pointer to first key */
  2951.         SymValue(iv->gbltbl, &valp[0]);        /* Pointer to first value */
  2952.  
  2953.         while(SymMarkNext(iv->gbltbl, mark))
  2954.         {/* Look forward for duplicates */
  2955.         unsigned long *key1;
  2956.           SymKey(iv->gbltbl, &key1);                /* Pointer to next key */
  2957.           if(KEYEQ(key, key1))
  2958.           {/* Hashed keys match, check the strings */
  2959.             SymValue(iv->gbltbl, &valp[dupcnt+1]);    /* Pointer to next value */
  2960.             if(!strcmp(valp[dupcnt]->symname, valp[dupcnt+1]->symname))
  2961.             {/* Duplicate entry found */
  2962.                 ++dupcnt;
  2963.                 continue;
  2964.             }
  2965.           }
  2966.           break;
  2967.         }
  2968.         if(dupcnt > 0)
  2969.         {/* Process a collection of duplicate symbol names */
  2970.           link_dups(iv, dupcnt, valp);
  2971.         }
  2972.         SymSetMark(iv->gbltbl, mark);
  2973.  
  2974.       }/* END: while(SymNext) */
  2975.     }/* END: if(SymHead) */
  2976. }
  2977. static void
  2978. realloc_data(Piv iv)
  2979. {
  2980. int i;
  2981. Pafile pf;
  2982. unsigned char *p;
  2983. unsigned long offset = 0;
  2984.  
  2985.     for(i = 0; i < iv->numfiles; ++i)
  2986.     {
  2987.         pf = iv->files[i];
  2988.         p = pf->data_p;
  2989.  
  2990.         while(*p != endfileop)
  2991.         {
  2992.             if(        *p == datablockop 
  2993.                 ||    *p == mallocblockop
  2994.                 ||    *p == stringblockop)
  2995.             {
  2996.                 PL(POP->data1) = offset;                
  2997.                 offset += GL(POP->data);
  2998.                 ROUNDUP(offset, 4);
  2999.             }
  3000.             p =  POP->next;
  3001.         }
  3002.     }
  3003.     iv->thunk_offset = offset;
  3004.  
  3005.     for(i = 0; i < iv->numfiles; ++i)
  3006.     {
  3007.         pf = iv->files[i];
  3008.         p = pf->data_p;
  3009.  
  3010.         while(*p != endfileop)
  3011.         {
  3012.             if(*p == thunkblockop) {
  3013.                 PL(POP->data1) = offset;
  3014.                 offset += GL(POP->data);
  3015.                 ROUNDUP(offset, 4);
  3016.             }
  3017.             p = POP->next;
  3018.         }
  3019.     }
  3020.     iv->bss_offset = offset;
  3021.  
  3022.     for(i = 0; i < iv->numfiles; ++i)
  3023.     {
  3024.         pf = iv->files[i];
  3025.         p = pf->data_p;
  3026.  
  3027.         while(*p != endfileop)
  3028.         {
  3029.             if(*p == bssblockop) {
  3030.                 PL(POP->data1) = offset;
  3031.                 offset += GL(POP->data);
  3032.                 ROUNDUP(offset, 4);
  3033.             }
  3034.             p = POP->next;
  3035.         }
  3036.     }
  3037.     iv->total_size = offset;
  3038. }
  3039. static void
  3040. reset_data_relocs(Piv iv)
  3041. {/* Pass over initialized data and set new offsets in each relocatable slot */
  3042. struct _rkey {/* key area of reloctbl node */
  3043.     unsigned long offset;
  3044.     short fileno;
  3045.     unsigned char opcode;
  3046.     char rsize;
  3047. };
  3048. struct _rval {/* value area of reloctbl node */
  3049.     unsigned char *p;
  3050.     unsigned long base;
  3051.     long offset;
  3052.     short rsym;
  3053. };
  3054. struct _data {/* datatbl node */
  3055. /* value area 16 bytes */
  3056.     unsigned long size;
  3057.     unsigned char *p;
  3058.     unsigned long unused[2];
  3059. /* key area 8 bytes */
  3060.     unsigned long offset;
  3061.     long unused1;
  3062. };
  3063.  
  3064.     /* PASS OVER ALL THE ENTRIES IN `reloctbl' */
  3065.     if(SymHead(iv->reloctbl))
  3066.     {
  3067.         while(SymNext(iv->reloctbl))
  3068.         {
  3069.         struct _rkey *kp;
  3070.         struct _rval *vp;
  3071.         struct _data *dp, *ndp;
  3072.         unsigned char *p;
  3073.         Pafile pf, npf;
  3074.         unsigned long object_base;
  3075.  
  3076.           SymKey(iv->reloctbl, &kp);
  3077.           SymValue(iv->reloctbl, &vp);
  3078.           npf = pf = iv->files[kp->fileno];    /* pointer to file struct */
  3079.           p = vp->p;        /* pointer to relocop in input buffer */
  3080.  
  3081.           if(kp->opcode == extlocop)
  3082.           {/* External variable */
  3083.           short key[4];
  3084.           struct {
  3085.           unsigned char *p;    /* pointer to extvarop in input buffer */
  3086.           } *ep;
  3087.             key[0] = vp->rsym;         /* external symbol number */
  3088.             key[1] = pf->filenum;
  3089.             key[2] = 0;
  3090.             key[3] = 0;
  3091.  
  3092.             /* LOOK UP THE EXTERNAL SYMBOL */
  3093.             if(SymFind(iv->extrntbl, key, &ep) && *(ep->p) == 0)
  3094.             {/* symbol exists and the extvarop was filled in */
  3095.                 npf = iv->files[GS( ((short*)(ep->p))[1] )];
  3096.                 PL( POPI->reloc.base ) = GL( ((Pop)(ep->p))->data1 );
  3097.                 *p = relocop;    /* switch input file from `extlocop' */
  3098.             }
  3099.             else
  3100.             {/* Not found or not filled in, leave it alone */
  3101.                 continue;
  3102.             }
  3103.           }
  3104.  
  3105.           /* RESET THE ENTRY IN THE INITIALIZED DATA SLOT */
  3106.           if(SymFindRange(pf->datatbl, &kp->offset, &dp))
  3107.           {/* This entry describes a block of data containg the reloc target */
  3108.           unsigned char *ip = dp->p;    /* points to input buffer */
  3109.           unsigned long extra = kp->offset - dp->offset; /* offset into data */
  3110.  
  3111.             /* Reset the relocop target in the input file */
  3112.             PL( POPI->reloc.spot ) = GL( ((PopI)(ip+8))->s.offset ) + extra;
  3113.  
  3114.             if(kp->rsize == 4)
  3115.             {/* 32 bit relocation */
  3116.             unsigned long *lp;
  3117.  
  3118.                 lp = (unsigned long*)(ip+24+extra);    /* pointer to target */
  3119.                 object_base = GL( POPI->reloc.base );
  3120.  
  3121.                 /* Find the object that the target points to */
  3122. relink32:
  3123.                 if(SymFindRange(npf->datatbl, &object_base, &ndp))
  3124.                 {
  3125.                     if(*(ndp->p) == 0)
  3126.                     {/* The found object is a discarded thunkblock, relink */
  3127.                         npf = iv->files[GS( ((short*)(ndp->p))[1] )];
  3128.                         object_base = GL( ((Pop)(ndp->p))->data4 );
  3129.                         goto relink32;
  3130.                     }
  3131.                     else
  3132.                     {/* Use the new offset in the input file */
  3133.                         object_base = GL( ((Pop)(ndp->p))->data1 );
  3134.                     }
  3135.                     PL( POPI->reloc.base ) = object_base; /* the `relocop' */
  3136.                     PL(*lp) = object_base + GL( POPI->reloc.offset );/* data */
  3137.                 }
  3138.                 else
  3139.                 {
  3140.                     ++iv->errors;
  3141.                     PWARN(pName ":syserr: 32 bit object at offset %d not found\n",object_base);
  3142.                 }
  3143.             }
  3144.             else if(kp->rsize == 2)
  3145.             {/* 16 bit relocation (MORE WORK NEEDED) */
  3146.             unsigned short *sp;
  3147.  
  3148.                 sp = (unsigned short*)(ip+24+extra);    /* pointer to target */
  3149.                 object_base = GL( POPI->reloc.base );
  3150. relink16:
  3151.                 if(SymFindRange(npf->datatbl, &object_base, &ndp))
  3152.                 {
  3153.                     if(*(ndp->p) == 0)
  3154.                     {/* The found object is a discarded thunkblock, relink */
  3155.                         npf = iv->files[GS( ((short*)(ndp->p))[1] )];
  3156.                         object_base = GL( ((Pop)(ndp->p))->data4 );
  3157.                         goto relink16;
  3158.                     }
  3159.                     else
  3160.                     {/* Use the new offset in the input file */
  3161.                         object_base = GL( ((Pop)(ndp->p))->data1 );
  3162.                     }
  3163.                     PL( POPI->reloc.base ) = object_base; /* the `relocop' */
  3164.                     PS(*sp) = object_base + GL( POPI->reloc.offset );/* data */
  3165.                 }
  3166.                 else
  3167.                 {
  3168.                     ++iv->errors;
  3169.                     PWARN(pName ":syserr: 16 bit object at offset %d not found\n", object_base);
  3170.                 }
  3171.  
  3172.             }
  3173.           }
  3174.           else /* !SymFindRange */
  3175.           {
  3176.             ++iv->errors;
  3177.             PWARN(pName ":syserr: reloc not found at %d in file %d\n", 
  3178.                     kp->offset, kp->fileno);
  3179.           }
  3180.         }/* END: While(SymNext) */
  3181.     }/* END: if(SymHead) */
  3182. }
  3183. static void
  3184. reset_offset(Piv iv, Pafile pf, PopA pa)
  3185. {/* All offsets are guaranteed to be inside objects */
  3186. struct _data {/* datatbl node */
  3187. /* value area 16 bytes */
  3188.     unsigned long size;
  3189.     unsigned char *p;
  3190.     unsigned long unused[2];
  3191. /* key area 8 bytes */
  3192.     unsigned long offset;
  3193.     long unused1;
  3194. };
  3195.  
  3196. unsigned long offset;
  3197. struct _data *dp;
  3198. unsigned long object_base;
  3199. long extra;
  3200. unsigned short atype;
  3201. short symnum;
  3202.  
  3203.     offset = GL( pa->offset );
  3204.     atype = GS( pa->atype );
  3205.     symnum = GS( pa->symnum );
  3206.  
  3207.     PS( pa->symnum ) = pf->symtran[symnum];
  3208.     PS( pa->declnum ) = pf->decltran[GS(pa->declnum)];
  3209.  
  3210.     if(atype & A_EXTERN)
  3211.     {
  3212.     short key[4];
  3213.     struct {
  3214.     unsigned char *p;    /* pointer to extvarop in input buffer */
  3215.     } *ep;
  3216.         key[0] = symnum;         /* external symbol number */
  3217.         key[1] = pf->filenum;
  3218.         key[2] = 0;
  3219.         key[3] = 0;
  3220.  
  3221.             /* LOOK UP THE EXTERNAL SYMBOL */
  3222.         if(SymFind(iv->extrntbl, key, &ep) && *(ep->p) == 0)
  3223.         {/* symbol exists and the extvarop was filled in */
  3224.             pf = iv->files[GS( ((short*)(ep->p))[1] )];
  3225.             offset += GL( ((Pop)(ep->p))->data1 );
  3226.         }
  3227.         else
  3228.         {/* Not found or not filled in, leave it alone */
  3229.             return;
  3230.         }
  3231.     }
  3232.     extra = 0;    /* first time through */
  3233.     /* Find the object that the offset points to */
  3234. relink:
  3235.     if(SymFindRange(pf->datatbl, &offset, &dp))
  3236.     {
  3237.         if(extra == 0)
  3238.             extra = offset - dp->offset;
  3239.         object_base = dp->offset;
  3240.  
  3241.         if(*(dp->p) == 0)
  3242.         {/* The found object is a discarded block, relink */
  3243.             pf = iv->files[GS( ((short*)(dp->p))[1] )];
  3244.             offset = GL( ((Pop)(dp->p))->data4 );
  3245.             goto relink;
  3246.         }
  3247.         else
  3248.         {/* Use the adjusted offset in the input buffer */
  3249.             object_base = GL( ((Pop)(dp->p))->data1 );
  3250.         }
  3251.         PL( pa->offset ) = object_base + extra;
  3252.         if(atype & A_EXTERN)
  3253.         {
  3254.             PS( pa->atype ) = atype & ~A_EXTERN;        
  3255.         }
  3256.     }
  3257.     else
  3258.     {
  3259.         ++iv->errors;
  3260.         PWARN(pName ":syserr: object `%s' at offset %d not found\n", 
  3261.             pf->symaddr[symnum], offset);
  3262.     }
  3263. }
  3264. static void
  3265. reset_text_relocs(Piv iv)
  3266. {/* Pass over text and set new offsets in instructions that reference data */
  3267. int i;
  3268.  
  3269.     for(i = 0; i < iv->numfiles; ++i)
  3270.     {
  3271.     Pafile pf;
  3272.     unsigned char *p;
  3273.  
  3274.         pf = iv->files[i];
  3275.         if(!(p = pf->prog_p))
  3276.             continue;
  3277.  
  3278.         while(*p != endfileop)
  3279.         {
  3280.             if(*p && *p <= (unsigned char)100)
  3281.             {/* instruction */
  3282.             int inc = 8;
  3283.                 if((p[1] & 0xe0) == OPDATA)
  3284.                     reset_offset(iv, pf, POPA);
  3285.                 inc += (p[1] & 0x1f);
  3286.                 if((p[2] & 0xe0) == OPDATA)
  3287.                     reset_offset(iv, pf, POPA);
  3288.                 inc += (p[2] & 0x1f);
  3289.                 if((p[3] & 0xe0) == OPDATA)
  3290.                     reset_offset(iv, pf, POPA);
  3291.             }
  3292.             p = POP->next;                
  3293.         }
  3294.     }
  3295.  
  3296. }
  3297. static void *
  3298. seg_find(Piv iv, int id)
  3299. {
  3300. long key[2];
  3301. void **result;
  3302.  
  3303.     if(iv->segtbl)
  3304.     {
  3305.         key[0] = id;
  3306.         key[1] = 0;
  3307.         if(SymFind(iv->segtbl, key, &result) == 1)
  3308.             return *result;
  3309.     }
  3310.     return 0;    
  3311. }
  3312. static void
  3313. check_seg(Piv iv, unsigned char *p, Pafile pf)
  3314. {
  3315. PopI np, op;
  3316.     if(!(iv->segtbl))
  3317.     {
  3318.         iv->segtbl = NewSymTable(iv->category, 111);
  3319.     }
  3320.     if((op = seg_find(iv, GS(POPI->segdef.segid))))
  3321.     {
  3322.         np = POPI;
  3323.         if(        GL(np->segdef.v1) == GL(op->segdef.v1)
  3324.             &&    GL(np->segdef.v2) == GL(op->segdef.v2)
  3325.             &&    GL(np->segdef.v3) == GL(op->segdef.v3))
  3326.         {/* segments of same name have the same values */
  3327.             *p = 0;    /* kill the new definition */
  3328.             return;
  3329.         }
  3330.         else
  3331.         {/* segments of same name have different values */
  3332.             ++iv->errors;
  3333.             PWARN(pName ":Segment `%s' defined differently.\n",
  3334.                 iv->symaddr[GS(POPI->segdef.segid)]);
  3335.             PWARN(pName ":  In file: `%s'\n", pf->symaddr[INFILE_SYMNUM]);
  3336.             return;
  3337.         }
  3338.     }
  3339.     else
  3340.     {
  3341.     long key[2];
  3342.     PopI pp = POPI;
  3343.         key[0] = GS(POPI->segdef.segid);
  3344.         key[1] = 0;
  3345.         SymInsert(iv->segtbl, key, &pp, 4);
  3346.     }
  3347. }
  3348. static void
  3349. reset_syms_decls(Piv iv)
  3350. {
  3351. int i;
  3352.     for(i = 0; i < iv->numfiles; ++i)
  3353.     {
  3354.     Pafile pf;
  3355.     unsigned char *p;
  3356.  
  3357.         pf = iv->files[i];
  3358.         p = pf->file_p;
  3359.  
  3360.         while(*p != endfileop)
  3361.         {
  3362.           if(*p == segdefop)
  3363.           {
  3364.             PS(POPI->segdef.segid) = pf->symtran[GS(POPI->segdef.segid)];
  3365.             check_seg(iv, p, pf);
  3366.           }
  3367.           else if(i > 0)
  3368.           {
  3369.             switch(*p)
  3370.             {
  3371.                 case    declop:
  3372.                     if(GS(POPI->dcl.declnum) < 22)
  3373.                     {/* kill the base declarations */
  3374.                         *p = 0;
  3375.                         p = POP->next;                
  3376.                         *p = 0;
  3377.                     }
  3378.                     else
  3379.                      PS(POPI->dcl.declnum)=pf->decltran[GS(POPI->dcl.declnum)];
  3380.                     break;
  3381.                 case    extlocop:
  3382.                     PS(POPI->reloc.rsym) = pf->symtran[GS(POPI->reloc.rsym)];
  3383.                     break;
  3384.                 case    gfuncdefop:
  3385.                 case    sfuncdefop:
  3386.                     if(pf->numsegs)
  3387.                     PS(POPI->funcdef.segid) = pf->symtran[GS(POPI->funcdef.segid)];
  3388.                 case    nestedfuncdefop:
  3389.                     PL(POPI->funcdef.symnum)=pf->symtran[GL(POPI->funcdef.symnum)];
  3390.                     break;
  3391.                 case    bssblockop:
  3392.                 case    datablockop:
  3393.                     if(pf->numsegs)
  3394.                     PS( POPI->s.segid ) = pf->symtran[GS(POPI->s.segid)];
  3395.                 case    stringblockop:
  3396.                 case    mallocblockop:
  3397.                 case    thunkblockop:
  3398.                 case    extvarop:
  3399.                     PS( POPI->s.symnum ) = pf->symtran[GS(POPI->s.symnum)];
  3400.                     PS( POPI->s.declnum ) = pf->decltran[GS(POPI->s.declnum)];
  3401.                     break;
  3402.                 case    memberinfop:
  3403.                 case    bfieldinfop:
  3404.                     PS(POPI->memb.symnum) = pf->symtran[GS(POPI->memb.symnum)];
  3405.                     PS(POPI->memb.declnum) = pf->decltran[GS(POPI->memb.declnum)];
  3406.                     PS(POPI->memb.cdeclnum) = pf->decltran[GS(POPI->memb.cdeclnum)];
  3407.                     break;
  3408.                 case    structinfop:
  3409.                     PS(POPI->suinf.symnum) = pf->symtran[GS(POPI->suinf.symnum)];
  3410.                     break;
  3411.                 case    funcptrinfop:
  3412.                 case    ptrinfop:
  3413.                     PS(POPI->ptrinf.declnum) = pf->decltran[GS(POPI->ptrinf.declnum)];
  3414.                     break;
  3415.                 case    funcinfop:
  3416.                     PS(POPI->funcd.declnum) = pf->decltran[GS(POPI->funcd.declnum)];
  3417.                     PS(POPI->funcd.symnum) = pf->symtran[GS(POPI->funcd.symnum)];
  3418.                     break;
  3419.                 case    arrayinfop:
  3420.                     PS(POPI->ary.declnum) = pf->decltran[GS(POPI->ary.declnum)];
  3421.                     break;
  3422.                 case    lineop:
  3423.                     PL(POPI->line.filenamenum) = pf->symtran[GL(POPI->line.filenamenum)];
  3424.                     break;
  3425.             }/* END: switch(*p) */
  3426.           }/* END: i > 0 */
  3427.           p = POP->next;                
  3428.         }
  3429.     }
  3430. }
  3431.  
  3432. static int
  3433. link_files(Piv iv)
  3434. {
  3435.     iv->extrntbl = NewSymTable(iv->category, 4092);    /* hashed table */
  3436.     iv->reloctbl = NewSymTable(iv->category, 4092); /* hashed table */
  3437.     iv->gbltbl = NewSymTable(iv->category, 0);    /* sorted table */
  3438.  
  3439.     setup_syms_decls(iv);
  3440.  
  3441.     if(iv->numfiles > 1)
  3442.     {
  3443.         iv->symaddr = Ccalloc(iv->category, sizeof(void*), iv->numsyms);
  3444.         iv->decladdr = Ccalloc(iv->category, sizeof(void*), iv->numdecls);
  3445.         iv->symtbl = NewSymTable(iv->category, 0); /* sorted table */
  3446.         combine_syms_decls(iv);
  3447.  
  3448.         link_globals(iv);
  3449.         realloc_data(iv);
  3450.         reset_data_relocs(iv);
  3451.         reset_text_relocs(iv);
  3452.  
  3453.         reset_syms_decls(iv);
  3454.     }
  3455.     else
  3456.     {
  3457.         iv->symaddr = iv->files[0]->symaddr;
  3458.         iv->decladdr = iv->files[0]->decladdr;
  3459.         iv->symtbl = NewSymTable(iv->category, 0); /* sorted table */
  3460.         combine_syms_decls(iv);
  3461.  
  3462.         realloc_data(iv);
  3463.         reset_data_relocs(iv);
  3464.         reset_text_relocs(iv);
  3465.     }
  3466.     return iv->errors;
  3467. }
  3468.  
  3469. /* ======================== GLOBAL ROUTINES ========================== */
  3470. int
  3471. Global(readfile) (Piv iv, char *infile_name)
  3472. {
  3473. FILE *infile;
  3474. long infile_size;
  3475. char *inbuf;
  3476.  
  3477.     if(!(infile = fopen(infile_name, "rb")))
  3478.     {
  3479.         PERROR(pName ": Can't open input file: %s\n", infile_name);
  3480.         return 1;
  3481.     }
  3482.     fseek(infile, 0, SEEK_END);
  3483.     infile_size = ftell(infile);    
  3484.     fseek(infile, 0, SEEK_SET);
  3485.  
  3486.     if(infile_size == 0)
  3487.     {
  3488.         PERROR(pName ": Empty input file: %s\n", infile_name);
  3489.         return 2;
  3490.     }
  3491.     inbuf = Cmalloc(iv->category, infile_size);
  3492.  
  3493.     if(fread(inbuf, 1, infile_size, infile) != infile_size)
  3494.     {
  3495.         fclose(infile);
  3496.         PERROR(pName ": Error reading input file: %s\n", infile_name);
  3497.         return 3;
  3498.     }
  3499.     fclose(infile);
  3500.  
  3501.     if(setup_nodelinks(iv, infile_name, inbuf, infile_size))
  3502.         return 4;
  3503.     return 0;
  3504. }
  3505. int
  3506. Global(proc_files) (Piv iv, void *name)
  3507. {
  3508. int ret;
  3509.     if(!(ret = link_files(iv)))
  3510.     {
  3511.         optimize(iv);
  3512.         if(name)
  3513.           iv->symaddr[2] = name;    /* symbol 2 is the output filename */
  3514.         ret = gen_output(iv, iv->symaddr[2]);
  3515.     }
  3516.     return ret;
  3517. }
  3518. void *
  3519. Global(open_instance) (void)
  3520. {
  3521. Piv iv;
  3522. int category;
  3523. #if USING_FRAMEWORK
  3524.     if(num_instance <= 0)
  3525.     {
  3526.         oxlink_clear_bss(pName ".o");    /* reset global storage */
  3527.         local_category = NewMallocCategory();
  3528.     }
  3529.     ++num_instance;
  3530. #endif
  3531.     category = Cnewcat();
  3532.     iv = Ccalloc(category, 1, sizeof(struct _iv));
  3533.     iv->category = category;
  3534.     iv->obuf = (char*)&iv->obufstart;
  3535.     iv->obufcnt = 0;
  3536.     return iv;
  3537. }
  3538. void
  3539. Global(close_instance) (Piv iv)
  3540. {
  3541.     if(iv->outfile)
  3542.       fclose(iv->outfile);
  3543.     if(iv->remove_infile)
  3544.     {
  3545.     int i;
  3546.       for(i = 1; i < iv->argc; ++i)
  3547.         unlink(propernameof(iv, iv->argv[i]));
  3548.     }
  3549.     Cfreecat(iv->category);
  3550. #if USING_FRAMEWORK
  3551.     if(--num_instance == 0)
  3552.         freecat(local_category);
  3553. #endif
  3554. }
  3555.  
  3556. /* =========================== THE MAIN PROGRAM ======================= */
  3557.  
  3558. static char *
  3559. filenameof(char *path)
  3560. {
  3561. char *ret = path;
  3562. int i;
  3563.     for(i = 0; path[i]; ++i)
  3564.       if(path[i] == '/')
  3565.         ret = &path[i+1];
  3566.     return ret;
  3567. }
  3568.  
  3569. static char *
  3570. propernameof(Piv iv, char *path)
  3571. {
  3572. char *name = filenameof(path);
  3573. int namlen = strlen(name);
  3574. int i;
  3575.     for(i = namlen-1; i >= 0; --i)
  3576.     {
  3577.       if(name[i] == '/' || name[i] == '\\')
  3578.           break;
  3579.       else if(name[i] == '.')
  3580.         return path;
  3581.     }
  3582.     name = Cmalloc(iv->category, strlen(path)+8);
  3583.     strcpy(name, path);
  3584.     strcat(name, ".anf");
  3585.     return name;
  3586. }
  3587. static void
  3588. Usage()
  3589. {
  3590. fputs(
  3591. "Usage: " pName " [-odsDR] [infile...]\n"
  3592. "   -o outfile == name of output file\n"
  3593. "   -d == print debug output\n"
  3594. "   -D == only print debug output\n"
  3595. "   -s == strip declarations and line numbers\n"
  3596. "   -R == remove the input file\n"
  3597. "   -? == print this message\n"
  3598. "   Default input file is `code.anf'.\n"
  3599. "   Default output file is specified by the input.\n"
  3600. ,stderr);
  3601. }
  3602.  
  3603. #if USING_FRAMEWORK
  3604. int
  3605. PROG (int argc, char **argv)
  3606. #else
  3607. int
  3608. main (int argc, char **argv)
  3609. #endif
  3610. {
  3611. int i,j;
  3612. char *outfilename = 0;
  3613. volatile Piv iv;
  3614. char debug, only_debug, strip, remove_infile;
  3615. int ret;
  3616.  
  3617.     remove_infile = strip = debug = only_debug = 0;
  3618.  
  3619.     /* Get options */
  3620.     for(i = 1; i < argc; ++i)
  3621.     {
  3622.     int trimsize = 1;
  3623.         if(argv[i][0] == '-')
  3624.         {
  3625.             for (j=1; argv[i][j]; j++)
  3626.             {
  3627.                 switch(argv[i][j])
  3628.                 {    
  3629.                     case    'd':
  3630.                         debug = 1;
  3631.                         break;
  3632.                     case    'D':
  3633.                         debug = 1, only_debug = 1;
  3634.                         break;
  3635.                     case    's':
  3636.                         strip = 1;
  3637.                         break;
  3638.                     case    'o':
  3639.                         if(argv[i][j+1]) {
  3640.                             outfilename = &argv[i][j+1];
  3641.                         }
  3642.                         else if(i < argc-1) {
  3643.                             outfilename = argv[i+1];
  3644.                             trimsize = 2;
  3645.                         } else {
  3646.                             PWARN(pName ": no output filename\n");
  3647.                             Usage();
  3648.                             return 0;
  3649.                         }
  3650.                         goto trim;
  3651.                         break;
  3652.                     case 'R':
  3653.                         remove_infile = 1;
  3654.                         break;
  3655.                     case '?':
  3656.                         Usage();
  3657.                         return 0;
  3658.                     default:
  3659.                         PWARN(pName ": Invalid switch: %c\n", argv[i][j]);
  3660.                         Usage();
  3661.                         return 0;
  3662.                 }
  3663.             }/* END: for(j) */
  3664. trim:
  3665.             /* Trim switch */
  3666.             for(j = i; j < argc-trimsize; ++j)
  3667.                 argv[j] = argv[j+trimsize];
  3668.             argc -= trimsize;
  3669.             --i;
  3670.         }/* END: if('-') */
  3671.     }/* END: for(argc) */
  3672.  
  3673.     iv = Global(open_instance) ();
  3674.     if((ret = setjmp(run_env))) {
  3675.         Global(close_instance) (iv);
  3676. #if USING_FRAMEWORK
  3677.         return ret;
  3678. #else
  3679.         exit(ret);
  3680. #endif
  3681.     }
  3682.     iv->debug = debug;
  3683.     iv->only_debug = only_debug;
  3684.     iv->labeltbl = NewSymTable(iv->category, 4092);
  3685. #if REALLY_NEED_OFFSETS
  3686.     iv->newlabeltbl = NewSymTable(iv->category, 4092);
  3687. #endif
  3688.     iv->strip = strip;
  3689.     iv->remove_infile = remove_infile;
  3690.     iv->argc = argc;
  3691.     iv->argv = argv;
  3692.  
  3693.     if(argc < 2)
  3694.     {/* Default input filename is 'code.anf' */
  3695.         ret = Global(readfile) (iv, "code.anf");
  3696.     }
  3697.     else
  3698.     {/* READ EACH INPUT FILE */
  3699.     
  3700.         for(i = 1; i < argc; ++i)
  3701.           if((ret = Global(readfile) (iv, propernameof(iv, argv[i]))))
  3702.             break;
  3703.     }
  3704.     if(!ret && !iv->only_debug)
  3705.     {
  3706.         ret = Global(proc_files) (iv, outfilename);
  3707.     }
  3708.     Global(close_instance) (iv);
  3709. #if USING_FRAMEWORK
  3710.     return ret;
  3711. #else
  3712.     exit(ret);
  3713. #endif
  3714. }
  3715.  
  3716.